{"vulnerability": "cve-2024-0039", "sightings": [{"uuid": "f22879d9-1fff-405f-92dc-8f0594d8a319", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2024-0039", "type": "published-proof-of-concept", "source": "https://t.me/GithubRedTeam/7455", "content": "GitHub\u76d1\u63a7\u6d88\u606f\u63d0\u9192\uff01\uff01\uff01 \n\n\u66f4\u65b0\u4e86\uff1aCVE-2024\n\u63cf\u8ff0\uff1aCVE-2024-4956 : Nexus Repository Manager 3 poc exploit\nURL\uff1ahttps://github.com/41yn14/CVE-2024-0039-Exploit\n\n\u6807\u7b7e\uff1a#CVE-2024", "creation_timestamp": "2024-05-29T22:14:33.000000Z"}, {"uuid": "d1b4fa71-a262-4fa5-9dc6-d80bc07e8d58", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2024-0039", "type": "seen", "source": "https://t.me/ctinow/204926", "content": "https://ift.tt/OBt8yX6\nCVE-2024-0039", "creation_timestamp": "2024-03-11T18:26:35.000000Z"}, {"uuid": "c68a3cf2-d7c1-4794-a92e-8e126e091f51", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2024-0039", "type": "seen", "source": "https://t.me/ctinow/204939", "content": "https://ift.tt/OBt8yX6\nCVE-2024-0039", "creation_timestamp": "2024-03-11T18:26:48.000000Z"}, {"uuid": "f99ae90a-1575-4f9f-abb7-013715adce79", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2024-0039", "type": "seen", "source": "https://gist.github.com/ShaiOnionGod/bb378bb47a2626f2a0b85bb402724549", "content": "\n\n  \n    \n    \n    Axonius \u2014 Dashboard prototype\n    \n    \n      {\n        \"imports\": {\n          \"react\": \"https://esm.sh/react@18.3.1\",\n          \"react-dom\": \"https://esm.sh/react-dom@18.3.1\",\n          \"react-dom/client\": \"https://esm.sh/react-dom@18.3.1/client\",\n          \"lucide-react\": \"https://esm.sh/lucide-react@0.456.0?deps=react@18.3.1\"\n        }\n      }\n    \n    \n    \n      html, body { margin: 0; height: 100%; background: #191A23; font-family: 'Hanken Grotesk', -apple-system, BlinkMacSystemFont, sans-serif; }\n      #root { height: 100%; }\n      .sb-tag { position: fixed; right: 14px; bottom: 12px; z-index: 99999; font: 700 10px/1 ui-monospace, monospace; letter-spacing: .14em; color: #0D5ED7; background: rgba(255,255,255,.9); border: 1px solid #E0E4EC; border-radius: 999px; padding: 6px 10px; box-shadow: 0 6px 18px rgba(27,32,70,.12); pointer-events: none; }\n    \n  \n  \n    \n\n    \nSANDBOX\n\n    \nimport React, { useState, useRef, useCallback, useEffect } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { createPortal } from \"react-dom\";\nimport {\n  Search, Star, MoreHorizontal, Info, ListFilter, ArrowUpDown, Columns3,\n  Plus, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, ChevronDown,\n  ArrowUpRight, ArrowDownRight, LayoutGrid, Server, ShieldCheck, Boxes,\n  Workflow, Cable, Bell, CircleHelp, Clock, Play, Grip, PanelLeftClose,\n  PanelLeftOpen, Download, GripVertical, X, Settings, ShieldAlert, Crosshair,\n  Pin, PinOff, RotateCw, Filter, Table2, ChevronsUpDown, Pencil, Check, Trash2,\n  Users, Layers, RotateCcw, Save, Copy, Calendar, Menu, Zap, Link, BarChart3, Sun, Moon,\n  Globe, Lock, Folder, FolderOpen\n} from \"lucide-react\";\n\n/**\n * Axonius \u2014 Dashboard + Assets table views\n * Collapsible side panel \u00b7 resizable + reorderable dashboard tiles\n * Real Axonius header \u00b7 Twenty-style table \u00b7 tokens from Figma source\n */\n\nfunction AxoniusLogo() {\n  return `.replaceAll('fill=\"black\"', `fill=\"${T.ink}\"`) }} /&gt;;\n}\n\n// Data / highlight palette \u2014 bright fills used in both themes (light-mode text variants applied where colored text is needed)\nconst VIZ = { green: \"#5BC4BF\", greenDeep: \"#247D78\", mint: \"#8ED0FF\", lilac: \"#AD85FF\", lilacPale: \"#CDB4FF\", orange: \"#FF8C66\", amber: \"#FFB286\" };\nconst FONT = \"'Hanken Grotesk', -apple-system, sans-serif\", DISPLAY = \"'Schibsted Grotesk', -apple-system, sans-serif\";\nconst THEMES = {\n  dark: {\n    ink: \"#E4E8F0\", body: \"#AEB7CC\", muted: \"#8494B5\", faint: \"#69738C\",\n    line: \"rgba(132,148,181,0.20)\", lineSoft: \"rgba(132,148,181,0.12)\", hair: \"rgba(132,148,181,0.09)\", lineStrong: \"rgba(132,148,181,0.42)\",\n    bg100: \"#AEB7CC\", bg90: \"#9AA3BC\", bg80: \"#8494B5\", bg40: \"#8494B5\",\n    blue: \"#5C7CFF\", blueDeep: \"#4E6CF5\", green: \"#5BC4BF\", red: \"#FF8C66\",\n    shell: \"#191A23\", headerBg: \"#191A23\", canvas: \"#191A23\", surface: \"#222431\", surface2: \"#2A2D3C\", control: \"#262838\",\n    white: \"#FFFFFF\", onAccent: \"#191A23\", isLight: false, coin: \"#2A2D3C\", accentSoft: \"rgba(92,124,255,0.16)\", accentText: \"#5C7CFF\", accentBorder: \"rgba(92,124,255,0.50)\",\n    viz: VIZ, shadow: \"0 1px 2px rgba(0,0,0,0.4), 0 14px 34px rgba(0,0,0,0.5)\", font: FONT, display: DISPLAY,\n  },\n  light: {\n    ink: \"#2E3850\", body: \"#465472\", muted: \"#6B7894\", faint: \"#8494B5\",\n    line: \"rgba(132,148,181,0.30)\", lineSoft: \"rgba(132,148,181,0.18)\", hair: \"rgba(132,148,181,0.12)\", lineStrong: \"rgba(132,148,181,0.55)\",\n    bg100: \"#465472\", bg90: \"#5A6889\", bg80: \"#8494B5\", bg40: \"#8494B5\",\n    blue: \"#4361EE\", blueDeep: \"#3A55D6\", green: \"#247D78\", red: \"#BF4B26\",\n    shell: \"#F9FAFB\", headerBg: \"#F9FAFB\", canvas: \"#FFFFFF\", surface: \"#FFFFFF\", surface2: \"#F1F2F6\", control: \"#FFFFFF\",\n    white: \"#FFFFFF\", onAccent: \"#FFFFFF\", isLight: true, coin: \"#FFFFFF\", accentSoft: \"rgba(67,97,238,0.10)\", accentText: \"#4361EE\", accentBorder: \"rgba(67,97,238,0.45)\",\n    viz: VIZ, shadow: \"0 1px 2px rgba(70,84,114,0.06), 0 10px 26px rgba(70,84,114,0.08)\", font: FONT, display: DISPLAY,\n  },\n};\nlet T = THEMES.dark;\n// Severity scale stays semantic (red \u2192 orange \u2192 yellow \u2192 green, neutral for informational) in both themes\nconst SEVC = { critical: \"#E5484D\", high: \"#F0743E\", medium: \"#F5C28C\", low: \"#4F8FE3\", info: \"#CFC4F2\" };\nconst fmt = (n) =&gt; n.toLocaleString(\"en-US\");\nconst tnum = { fontFeatureSettings: '\"tnum\" 1', fontVariantNumeric: \"tabular-nums\" };\n\n/* ============ vendor logos ============ */\nfunction LogoMark({ brand, size = 32 }) {\n  const glyph = {\n    aws: aws,\n    microsoft: ,\n    azure: ,\n    googlecloud: ,\n    oracle: ,\n    vmware: vm,\n    okta: ,\n    crowdstrike: ,\n    active_directory: ,\n    sentinelone: ,\n    service_now: ,\n    cisco: cisco,\n    cisco_meraki: ,\n    cisco_ise: cisco,\n    checkpoint: ,\n    chef: ,\n    claroty: ,\n    cylance: ,\n    epo: ,\n    paloalto: ,\n    tanium: ,\n    tenable: ,\n    forescout: ,\n    zoom: ,\n    miro: ,\n    dropbox: ,\n    salesforce: ,\n    slack: ,\n    office365: ,\n    google_workspace: ,\n  }[brand] || {(brand || \"?\").slice(0, 2).toUpperCase()};\n  return \n{glyph};\n}\n\n/* ============ chips ============ */\n// Tags use the dashboard data palette (turquoise / purple / baby-blue / orange) \u2014 dark text variant in light mode, bright in dark\nconst TAGV = [{ b: \"#5BC4BF\", d: \"#247D78\" }, { b: \"#AD85FF\", d: \"#683CB5\" }, { b: \"#8ED0FF\", d: \"#1E75B3\" }, { b: \"#FF8C66\", d: \"#BF4B26\" }];\nfunction Tag({ label }) {\n  let n = 0; for (let i = 0; i &lt; label.length; i++) n = (n * 31 + label.charCodeAt(i)) &gt;&gt;&gt; 0;\n  const t = TAGV[n % TAGV.length];\n  return {label};\n}\n// Cursor-following tooltip (like sandbox 2) \u2014 surface card with readable dark text\nfunction FloatTip({ x, y, children }) {\n  return createPortal(\n{children}, document.body);\n}\nfunction UserAvatar({ name, size = 24 }) {\n  const s = name || \"?\"; let n = 0; for (let i = 0; i &lt; s.length; i++) n = (n * 31 + s.charCodeAt(i)) &gt;&gt;&gt; 0;\n  const t = TAGV[n % TAGV.length];\n  return {s.trim()[0] || \"?\"};\n}\nconst APP_LOGO_MAP = {\n  Zoom: \"zoom\", \"Zoom One Pro\": \"zoom\",\n  Miro: \"miro\",\n  Dropbox: \"dropbox\",\n  Salesforce: \"salesforce\",\n  Slack: \"slack\",\n  Google: \"googlecloud\", \"Google WS Ent. Starter\": \"google_workspace\", \"Google WS Ent. Standard\": \"google_workspace\", \"Google WS Business\": \"google_workspace\",\n  Office365: \"office365\", \"Microsoft 365 G3 GCC\": \"office365\", \"Microsoft 365 E5\": \"office365\", \"Microsoft Power Aut\u2026\": \"office365\",\n  Microsoft: \"microsoft\",\n};\nfunction AppAvatar({ name, size = 22 }) {\n  const brand = APP_LOGO_MAP[name];\n  if (brand) return ;\n  const s = name || \"?\"; let n = 0; for (let i = 0; i &lt; s.length; i++) n = (n * 31 + s.charCodeAt(i)) &gt;&gt;&gt; 0;\n  const t = TAGV[n % TAGV.length];\n  return {s.trim()[0] || \"?\"};\n}\nconst STATUS = { Active: T.green, Warning: T.viz.amber, Inactive: T.faint, Error: T.red };\nfunction StatusChip({ status }) {\n  return {status};\n}\nconst RISK = { Critical: SEVC.critical, High: SEVC.high, Medium: SEVC.medium, Low: SEVC.low };\nfunction RiskChip({ level }) {\n  const c = RISK[level];\n  return {level};\n}\nfunction Delta({ up, children }) {\n  const color = up ? T.green : T.red;\n  return {up ?  : }{children};\n}\nfunction IconBtn({ children, onClick }) {\n  const [h, setH] = useState(false);\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ width: 26, height: 26, borderRadius: 6, border: \"none\", cursor: \"pointer\", background: h ? T.surface2 : \"transparent\", color: h ? T.ink : T.faint, display: \"flex\", alignItems: \"center\", justifyContent: \"center\" }}&gt;{children};\n}\n\n/* ============ KPIs ============ */\nconst KPIS = [\n  { label: \"Total Assets\", value: 84355, delta: \"12.4%\", up: true },\n  { label: \"Cloud Coverage\", value: 96.2, suffix: \"%\", delta: \"2.1%\", up: true },\n  { label: \"Open Vulnerabilities\", value: 382, delta: \"8.0%\", up: false },\n  { label: \"Unmanaged Devices\", value: 1204, delta: \"3.2%\", up: false },\n];\nfunction useCountUp(target, dur = 950) {\n  const [v, setV] = useState(0);\n  useEffect(() =&gt; {\n    let raf; const start = performance.now();\n    const tick = (now) =&gt; { const p = Math.min(1, (now - start) / dur); setV(target * (1 - Math.pow(1 - p, 3))); if (p &lt; 1) raf = requestAnimationFrame(tick); };\n    raf = requestAnimationFrame(tick); return () =&gt; cancelAnimationFrame(raf);\n  }, [target]);\n  return v;\n}\nfunction KpiValue({ value, suffix }) {\n  const v = useCountUp(value);\n  const text = suffix === \"%\" ? v.toFixed(1) : fmt(Math.round(v));\n  return {text}{suffix || \"\"};\n}\nfunction KpiRow() {\n  return (\n    \n\n      {KPIS.map((k, i) =&gt; (\n        \n\n          \n{k.label}\n          \n\n            \n            {k.delta}\n          \n        \n      ))}\n    \n  );\n}\n\n/* ============ chart bodies ============ */\nconst PIE = [\n  { c: \"green\", label: \"Windows Assets\", val: 1236 }, { c: \"greenDeep\", label: \"Active Directory\", val: 411 },\n  { c: \"mint\", label: \"SCCM Managed\", val: 198 }, { c: \"lilac\", label: \"Intune Managed\", val: 89 }, { c: \"lilacPale\", label: \"Unmanaged\", val: 43 },\n];\nfunction DonutBody() {\n  const [hi, setHi] = useState(null);\n  const [tip, setTip] = useState(null);\n  const [off, setOff] = useState(() =&gt; new Set());\n  const [drawn, setDrawn] = useState(false);\n  useEffect(() =&gt; { const id = setTimeout(() =&gt; setDrawn(true), 60); return () =&gt; clearTimeout(id); }, []);\n  const r = 46, sw = 14, C = 2 * Math.PI * r, gap = 5;\n  const toggle = (i) =&gt; setOff(s =&gt; { const n = new Set(s); n.has(i) ? n.delete(i) : n.add(i); return n; });\n  const visTotal = PIE.reduce((a, p, i) =&gt; a + (off.has(i) ? 0 : p.val), 0) || 1;\n  let acc = 0;\n  const segs = PIE.map((p, i) =&gt; {\n    if (off.has(i)) return null;\n    const len = (p.val / visTotal) * C;\n    const seg = Math.max(1, len - gap);\n    const active = hi === i, dim = hi !== null &amp;&amp; !off.has(hi) &amp;&amp; !active;\n    const node = (\n       { setHi(i); setTip({ i, x: e.clientX, y: e.clientY }); }} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; { setHi(null); setTip(null); }} onClick={() =&gt; toggle(i)}\n        style={{ opacity: dim ? 0.35 : 1, cursor: \"pointer\", transition: \"stroke-dasharray .8s cubic-bezier(.22,1,.36,1), stroke-width .18s ease, opacity .18s ease\" }} /&gt;\n    );\n    acc += len; return node;\n  });\n  const liveHi = hi !== null &amp;&amp; !off.has(hi);\n  const center = liveHi ? { big: ((PIE[hi].val / visTotal) * 100).toFixed(1) + \"%\", small: PIE[hi].label } : { big: fmt(visTotal), small: \"Total Assets\" };\n  return (\n    \n\n      \n\n        \n          \n          {segs}\n        \n        \n\n          {center.big}\n          {center.small}\n        \n      \n      \n\n        {PIE.map((p, i) =&gt; {\n          const isOff = off.has(i);\n          return (\n            \n { setHi(i); if (!isOff) setTip({ i, x: e.clientX, y: e.clientY }); }} onMouseMove={(e) =&gt; !isOff &amp;&amp; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; { setHi(null); setTip(null); }} onClick={() =&gt; toggle(i)}\n              title={isOff ? \"Click to show\" : \"Click to hide\"}\n              style={{ display: \"flex\", alignItems: \"center\", gap: 9, padding: \"5px 6px\", borderRadius: 6, cursor: \"pointer\", background: hi === i &amp;&amp; !isOff ? T.canvas : \"transparent\", transition: \"background .12s\" }}&gt;\n              \n              {p.label}\n              {isOff ? \"Hidden\" : (hi === i ? fmt(p.val) : ((p.val / visTotal) * 100).toFixed(1) + \"%\")}\n            \n          );\n        })}\n      \n      {tip !== null &amp;&amp; !off.has(tip.i) &amp;&amp; \n        \n{PIE[tip.i].label}\n        \n{fmt(PIE[tip.i].val)}\n        \n{(PIE[tip.i].val / visTotal * 100).toFixed(1)}% of assets\n      }\n    \n  );\n}\nconst LINE_LABELS = [\"W1\", \"W2\", \"W3\", \"W4\", \"W5\", \"W6\", \"W7\", \"W8\", \"W9\", \"W10\", \"W11\", \"W12\"];\nconst LINE_SERIES = [\n  { key: \"all\", label: \"All Devices\", color: T.viz.green, pts: [38000, 41200, 44500, 47800, 51000, 55300, 59800, 63200, 68500, 72100, 78400, 84355] },\n  { key: \"managed\", label: \"Managed\", color: T.viz.lilac, pts: [29000, 31000, 33500, 35800, 38000, 41000, 44500, 47200, 50500, 54100, 58400, 61200] },\n  { key: \"cloud\", label: \"Cloud\", color: T.viz.orange, pts: [8000, 9200, 10500, 11800, 13000, 14300, 15800, 17200, 18500, 20100, 21400, 22097] },\n  { key: \"unmanaged\", label: \"Unmanaged\", color: T.viz.greenDeep, pts: [3200, 3100, 3300, 3000, 3500, 3300, 3100, 2900, 2700, 2500, 2300, 2100] },\n];\nfunction LineBody() {\n  const [off, setOff] = useState(() =&gt; new Set());\n  const [hov, setHov] = useState(null);\n  const w = 680, h = 196, pad = 12, n = LINE_LABELS.length, max = 90000;\n  const X = (i) =&gt; pad + (i / (n - 1)) * (w - pad * 2);\n  const Y = (v) =&gt; h - pad - (v / max) * (h - pad * 2);\n  const smooth = (pts) =&gt; { let d = `M ${X(0)} ${Y(pts[0])}`; for (let i = 1; i &lt; n; i++) { const cx = (X(i - 1) + X(i)) / 2; d += ` C ${cx} ${Y(pts[i - 1])}, ${cx} ${Y(pts[i])}, ${X(i)} ${Y(pts[i])}`; } return d; };\n  const toggle = (k) =&gt; setOff(s =&gt; { const x = new Set(s); x.has(k) ? x.delete(k) : x.add(k); return x; });\n  const visible = LINE_SERIES.filter(s =&gt; !off.has(s.key));\n  const xPct = (i) =&gt; (X(i) / w) * 100, yPct = (v) =&gt; (Y(v) / h) * 100;\n  return (\n    \n\n      \n setHov(null)}&gt;\n        \n          {[0, 1, 2, 3].map(i =&gt; )}\n          {hov &amp;&amp; }\n          {visible.map(s =&gt; )}\n        \n        {/* a hoverable dot on every point \u2014 hovering one shows just that series */}\n        {visible.map(s =&gt; s.pts.map((v, i) =&gt; {\n          const isHov = hov &amp;&amp; hov.s.key === s.key &amp;&amp; hov.i === i, dim = hov &amp;&amp; !isHov;\n          return (\n            \n setHov({ s, i })}\n              style={{ position: \"absolute\", left: `${xPct(i)}%`, top: `${yPct(v)}%`, transform: \"translate(-50%, -50%)\", width: 20, height: 20, display: \"flex\", alignItems: \"center\", justifyContent: \"center\", cursor: \"pointer\", zIndex: isHov ? 4 : 2 }}&gt;\n              \n            \n          );\n        }))}\n        {hov &amp;&amp; (\n          \n n - 4 ? \"calc(-100% - 12px)\" : hov.i &lt; 3 ? \"12px\" : \"-50%\"}, calc(-100% - 14px))`, background: T.surface, border: `1px solid ${T.line}`, borderRadius: 10, boxShadow: T.shadow, padding: \"9px 12px\", whiteSpace: \"nowrap\", pointerEvents: \"none\", zIndex: 6 }}&gt;\n            \n{hov.s.label}\n            \n{fmt(hov.s.pts[hov.i])}\n            {hov.i &gt; 0 &amp;&amp; (() =&gt; { const pct = (hov.s.pts[hov.i] - hov.s.pts[hov.i - 1]) / hov.s.pts[hov.i - 1] * 100; const up = pct &gt;= 0; return \n{up ?  : }{up ? \"+\" : \"\"}{pct.toFixed(1)}% from previous; })()}\n            \n{LINE_LABELS[hov.i]}\n          \n        )}\n      \n      \n\n        {LINE_SERIES.map(s =&gt; {\n          const isOff = off.has(s.key);\n          return (\n             toggle(s.key)} title={isOff ? \"Show series\" : \"Hide series\"} className=\"ax-press\"\n              style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6, padding: \"3px 9px\", borderRadius: 999, border: `1px solid ${isOff ? T.lineSoft : T.line}`, background: isOff ? \"transparent\" : T.canvas, cursor: \"pointer\", fontFamily: T.font, fontSize: 11.5, fontWeight: 500, color: isOff ? T.faint : T.body, transition: \"all .14s\" }}&gt;\n              \n              {s.label}\n            \n          );\n        })}\n      \n    \n  );\n}\nconst STACK = [[\"Jan\", 40, 25, 20], [\"Feb\", 35, 30, 15], [\"Mar\", 52, 22, 26], [\"Apr\", 30, 35, 18], [\"May\", 48, 28, 24], [\"Jun\", 58, 32, 28]];\nconst STACK_KEYS = [[\"Cloud\", T.viz.green], [\"On-prem\", T.viz.mint], [\"SaaS\", T.viz.lilac]];\nfunction StackedBody() {\n  const [hi, setHi] = useState(null);\n  const [tip, setTip] = useState(null);\n  const max = 130;\n  return (\n    \n\n      {tip &amp;&amp; \n{STACK[tip.i][0]}\n{fmt((STACK[tip.i][1] + STACK[tip.i][2] + STACK[tip.i][3]) * 86)}\ntotal assets}\n      \n\n        {[0, 1, 2, 3].map(i =&gt; \n)}\n        {STACK.map((s, i) =&gt; {\n          const total = s[1] + s[2] + s[3];\n          const active = hi === i, dim = hi !== null &amp;&amp; !active;\n          return (\n            \n { setHi(i); setTip({ i, x: e.clientX, y: e.clientY }); }} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; { setHi(null); setTip(null); }}\n              style={{ flex: 1, display: \"flex\", flexDirection: \"column\", alignItems: \"center\", gap: 8, height: \"100%\", justifyContent: \"flex-end\", zIndex: 1, cursor: \"pointer\", position: \"relative\" }}&gt;\n              \n\n                \n\n                \n\n\n              \n              {s[0]}\n            \n          );\n        })}\n      \n      \n\n        {STACK_KEYS.map(([label, color], i) =&gt; (\n          {label}\n        ))}\n      \n    \n  );\n}\nconst SEV = [[\"Critical\", 142, 100, SEVC.critical], [\"High\", 98, 70, SEVC.high], [\"Medium\", 76, 54, SEVC.medium], [\"Low\", 45, 32, SEVC.low], [\"Info\", 21, 15, SEVC.info]];\nconst SEV_ASSETS = {\n  Critical: [[\"PC-CURTIS-WILLIAMS\", \"CVE-2024-21412 \u00b7 SmartScreen bypass\"], [\"srv-db-fin-04\", \"CVE-2024-3094 \u00b7 xz-utils backdoor\"], [\"esx-infranginx-5567897\", \"CVE-2023-46604 \u00b7 ActiveMQ RCE\"], [\"WIN-RUTHD\", \"CVE-2024-21413 \u00b7 Outlook RCE\"]],\n  High: [[\"macbook-pro-jdoe\", \"CVE-2024-23222 \u00b7 WebKit type confusion\"], [\"azure-infra9274676\", \"CVE-2024-21401 \u00b7 Entra ID elevation\"], [\"lablb-2918146-beta\", \"CVE-2024-1709 \u00b7 ScreenConnect auth bypass\"]],\n  Medium: [[\"iphone-asmith\", \"CVE-2024-23225 \u00b7 kernel memory\"], [\"sepio-external3026786\", \"CVE-2024-0519 \u00b7 V8 out-of-bounds\"]],\n  Low: [[\"android-pixel-7\", \"CVE-2024-0039 \u00b7 System component\"]],\n  Info: [[\"win-marychasse\", \"Informational \u00b7 TLS 1.0 enabled\"]],\n};\nfunction SeverityDrawer({ sev, close }) {\n  const list = SEV_ASSETS[sev[0]] || [];\n  return createPortal(&lt;&gt;\n    \n\n    \n\n      \n\n        \n        \n\n          \n{sev[0]} severity\n          \n{sev[1]} open vulnerabilities \u00b7 {list.length} assets shown\n        \n        \n      \n      \n\n        {list.map(([host, cve], i) =&gt; (\n          \n\n            \n\n              {host}\n              {sev[0]}\n            \n            {cve}\n          \n        ))}\n      \n      \n\n        View all {sev[1]} in Inventory\n      \n    \n  , document.body);\n}\nfunction SeverityBody() {\n  const [hi, setHi] = useState(null);\n  const [drill, setDrill] = useState(null);\n  const [tip, setTip] = useState(null);\n  const sevTotal = SEV.reduce((a, b) =&gt; a + b[1], 0);\n  return (&lt;&gt;\n    \n\n      {SEV.map((b, i) =&gt; {\n        const active = hi === i, dim = hi !== null &amp;&amp; !active;\n        return (\n          \n setDrill(b)} onMouseEnter={(e) =&gt; { setHi(i); setTip({ i, x: e.clientX, y: e.clientY }); }} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; { setHi(null); setTip(null); }}\n            style={{ display: \"flex\", alignItems: \"center\", gap: 12, opacity: dim ? 0.5 : 1, transition: \"opacity .15s\", cursor: \"pointer\" }}&gt;\n            {b[0]}\n            \n\n\n            {active ? b[1] + \" open\" : b[1]}\n          \n        );\n      })}\n    \n    {tip &amp;&amp; \n{SEV[tip.i][0]}\n{fmt(SEV[tip.i][1])}\n{Math.round(SEV[tip.i][1] / sevTotal * 100)}% of open findings}\n    {drill &amp;&amp;  setDrill(null)} /&gt;}\n  );\n}\nconst ST_COLOR = { ok: T.viz.green, warn: T.viz.amber, err: T.red };\n\n/* ===== System Lifecycle (discovery cycle) ===== */\nconst LIFECYCLE = [\n  { name: \"Fetch\", pct: 100 }, { name: \"Clean\", pct: 100 }, { name: \"Correlate\", pct: 100 },\n  { name: \"Enrich\", pct: 78 }, { name: \"Calculate\", pct: 0 },\n];\nfunction LifecycleBody() {\n  const [tip, setTip] = useState(null);\n  const done = LIFECYCLE.filter(s =&gt; s.pct === 100).length, total = LIFECYCLE.length;\n  const overall = Math.round(LIFECYCLE.reduce((a, s) =&gt; a + s.pct, 0) / total);\n  const r = 42, sw = 11, C = 2 * Math.PI * r, dash = (overall / 100) * C;\n  return (\n    \n\n      {tip &amp;&amp; \n{LIFECYCLE[tip.i].name} stage\n{LIFECYCLE[tip.i].pct &gt; 0 ? LIFECYCLE[tip.i].pct + \"% complete\" : \"Not started\"}}\n      \n\n        \n\n          \n            \n            \n          \n          \n\n            {done}/{total}\n            Stages\n          \n        \n        \n\n          {LIFECYCLE.map((s, i) =&gt; {\n            const c = s.pct === 100 ? T.viz.green : s.pct &gt; 0 ? T.blue : T.bg40;\n            return (\n              \n setTip({ i, x: e.clientX, y: e.clientY })} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; setTip(null)} style={{ display: \"flex\", alignItems: \"center\", gap: 10, cursor: \"default\" }}&gt;\n                {s.name}\n                \n\n                  \n\n                \n                 0 ? T.blue : T.bg40, ...tnum }}&gt;{s.pct &gt; 0 ? s.pct + \"%\" : \"\u2014\"}\n              \n            );\n          })}\n        \n      \n      \n\n        {[[\"Cycle started\", \"09:00:04\"], [\"Duration\", \"00:42:18\"], [\"Next cycle\", \"13:17:42\"]].map(([k, v], i) =&gt; (\n          \n\n            \n{k}\n            \n{v}\n          \n        ))}\n      \n    \n  );\n}\n\n/* ===== Discovery Log ===== */\nconst DISC_PHASES = [[\"Fetch\", T.viz.green], [\"Clean\", T.viz.mint], [\"Correlate\", T.viz.lilac], [\"Enrich\", T.viz.lilacPale], [\"Calculate\", T.viz.amber], [\"Save\", T.viz.orange]];\nconst DISCOVERY = [\n  { started: \"Jun 15, 09:00\", completed: \"Jun 15, 09:35\", duration: \"35min 22sec\", ph: [40, 12, 18, 10, 12, 8] },\n  { started: \"Jun 14, 09:00\", completed: \"Jun 14, 09:35\", duration: \"35min 59sec\", ph: [38, 14, 17, 11, 12, 8] },\n  { started: \"Jun 13, 09:00\", completed: \"Jun 13, 09:35\", duration: \"35min 29sec\", ph: [41, 11, 18, 10, 12, 8] },\n  { started: \"Jun 12, 09:00\", completed: \"Jun 12, 09:35\", duration: \"35min 11sec\", ph: [39, 13, 17, 11, 12, 8] },\n  { started: \"Jun 11, 09:00\", completed: \"Jun 11, 09:35\", duration: \"35min 58sec\", ph: [44, 12, 16, 9, 11, 8] },\n  { started: \"Jun 10, 09:00\", completed: \"Jun 10, 09:30\", duration: \"30min 54sec\", ph: [36, 12, 18, 12, 14, 8] },\n  { started: \"Jun 9, 09:00\", completed: \"Jun 9, 09:34\", duration: \"34min 02sec\", ph: [37, 13, 17, 11, 13, 9] },\n  { started: \"Jun 8, 09:00\", completed: \"Jun 8, 09:31\", duration: \"31min 38sec\", ph: [40, 12, 17, 10, 13, 8] },\n];\nfunction DiscoveryBody() {\n  const [hi, setHi] = useState(null);\n  const [tip, setTip] = useState(null);\n  const cols = \"minmax(70px, 1.6fr) 104px 92px\";\n  const durToSec = (s) =&gt; { let t = 0; const m = s.match(/(\\d+)\\s*min/), sec = s.match(/(\\d+)\\s*sec/); if (m) t += +m[1] * 60; if (sec) t += +sec[1]; return t; };\n  const fmtDur = (x) =&gt; { x = Math.round(x); const m = Math.floor(x / 60), s = x % 60; return m &gt; 0 ? `${m}min ${s}sec` : `${s}sec`; };\n  return (\n    \n\n      \n\n        {[\"Latest Discoveries\", \"Started\", \"Duration\"].map((c, i) =&gt; (\n          {c}\n        ))}\n      \n      \n\n        {DISCOVERY.map((d, i) =&gt; (\n          \n setHi(i)} onMouseLeave={() =&gt; { setHi(null); setTip(null); }}\n            style={{ display: \"grid\", gridTemplateColumns: cols, gap: 12, alignItems: \"center\", padding: \"7px 6px\", borderBottom: i &lt; DISCOVERY.length - 1 ? `1px solid ${T.hair}` : \"none\", background: hi === i ? T.canvas : \"transparent\", borderRadius: 6, transition: \"background .12s\" }}&gt;\n            \n\n              {d.ph.map((w, j) =&gt;  setTip({ d, j, x: e.clientX, y: e.clientY })} onMouseMove={(e) =&gt; setTip({ d, j, x: e.clientX, y: e.clientY })}\n                style={{ width: `${w}%`, height: \"100%\", background: DISC_PHASES[j][1], cursor: \"pointer\" }} /&gt;)}\n            \n            {d.started}\n            {d.duration}\n          \n        ))}\n      \n      {tip &amp;&amp; \n        \n{DISC_PHASES[tip.j][0]}\n        \n{fmtDur(durToSec(tip.d.duration) * tip.d.ph[tip.j] / 100)}\n        \n{tip.d.ph[tip.j]}% of cycle\n      }\n    \n  );\n}\n\n/* ===== Adapter Connections (status + logo coin + preview) ===== */\nconst ADAPTER_CONN = [\n  { brand: \"crowdstrike\", name: \"CrowdStrike\", st: \"ok\", desc: \"9,120 devices \u00b7 synced 4m ago\" },\n  { brand: \"aws\", name: \"Amazon Web Services\", st: \"ok\", desc: \"12,400 assets \u00b7 synced 6m ago\" },\n  { brand: \"azure\", name: \"Microsoft Azure\", st: \"ok\", desc: \"22,097 assets \u00b7 synced 5m ago\" },\n  { brand: \"okta\", name: \"Okta\", st: \"ok\", desc: \"9,870 users \u00b7 synced 8m ago\" },\n  { short: \"Jm\", color: \"#3B3B3B\", name: \"Jamf Pro\", st: \"err\", desc: \"Connection timeout \u2014 check credentials\" },\n  { short: \"now\", color: \"#2E8B57\", name: \"ServiceNow\", st: \"warn\", desc: \"Rate limited \u00b7 retrying\" },\n  { brand: \"googlecloud\", name: \"Google Cloud\", st: \"ok\", desc: \"9,055 assets \u00b7 synced 7m ago\" },\n  { brand: \"vmware\", name: \"VMware vCenter\", st: \"ok\", desc: \"4,310 VMs \u00b7 synced 11m ago\" },\n];\nconst ST_LABEL = { ok: \"Connected\", warn: \"Degraded\", err: \"Error\" };\nfunction AdapterCoin({ a }) {\n  if (a.brand) return ;\n  return {a.short};\n}\nfunction AdaptersBody() {\n  const connected = ADAPTER_CONN.filter(a =&gt; a.st === \"ok\").length;\n  const attention = ADAPTER_CONN.length - connected;\n  return (\n    \n\n      \n\n        {connected}\n        connected sources\n        {attention &gt; 0 &amp;&amp; {attention} need attention}\n      \n      \n\n        {ADAPTER_CONN.map((a, i) =&gt; {\n          const ring = ST_COLOR[a.st];\n          return (\n            \n\n              \n              \n\n                \n{a.name}\n                \n\n                  \n                  {a.desc}\n                \n              \n            \n          );\n        })}\n      \n    \n  );\n}\nconst HEALTH_OK_BRANDS = [\"crowdstrike\", \"aws\", \"azure\", \"okta\", \"googlecloud\", \"vmware\"];\nfunction HealthOkBody() {\n  return (\n    \n\n      \n\n        33\n        adapters syncing successfully\n      \n      \n\n        {HEALTH_OK_BRANDS.map((b, i) =&gt; )}\n        +27\n      \n      \n\n         100% healthy \u00b7 last full sync 4m ago\n      \n    \n  );\n}\nconst HEALTH_FAIL = [\n  { short: \"Jm\", color: \"#3B3B3B\", name: \"Jamf Pro\", reason: \"Connection timeout \u2014 check credentials\" },\n  { short: \"now\", color: \"#2E8B57\", name: \"ServiceNow\", reason: \"Rate limited \u00b7 retrying\" },\n];\nfunction HealthFailBody() {\n  return (\n    \n\n      \n\n        {HEALTH_FAIL.length}\n        adapters need attention\n      \n      \n\n        {HEALTH_FAIL.map((a, i) =&gt; (\n          \n\n            {a.short}\n            \n\n              \n{a.name}\n              \n{a.reason}\n            \n            Fix\n          \n        ))}\n      \n    \n  );\n}\n/* ===== Cost Optimization dashboard ===== */\nconst fmtMoney = (n) =&gt; n.toLocaleString(\"en-US\");\nfunction CostKPI({ value, unit }) {\n  return (\n    \n\n      {value}\n      {unit &amp;&amp; {unit}}\n    \n  );\n}\nfunction HBarList({ rows, accent, prefix, avatar, appLogo }) {\n  const max = Math.max(...rows.map(r =&gt; r[1]), 1);\n  const totalVal = rows.reduce((a, r) =&gt; a + r[1], 0) || 1;\n  const [tip, setTip] = useState(null);\n  return (\n    \n\n      {rows.map(([label, val], i) =&gt; {\n        const pct = Math.max(4, (val / max) * 100), inside = pct &gt; 24;\n        return (\n          \n setTip({ i, x: e.clientX, y: e.clientY })} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; setTip(null)}\n            style={{ display: \"flex\", alignItems: \"center\", gap: 12, cursor: \"default\" }}&gt;\n            {avatar &amp;&amp; }{appLogo &amp;&amp; }{label}\n            \n\n              \n\n                {inside &amp;&amp; {prefix || \"\"}{fmtMoney(val)}}\n              \n              {!inside &amp;&amp; {prefix || \"\"}{fmtMoney(val)}}\n            \n          \n        );\n      })}\n      {tip &amp;&amp; \n        \n{rows[tip.i][0]}\n        \n{prefix || \"\"}{fmtMoney(rows[tip.i][1])}\n        \n{(rows[tip.i][1] / totalVal * 100).toFixed(1)}% of shown total\n      }\n    \n  );\n}\nconst COST_CATEGORY = [[\"Productivity\", 141993], [\"Video Conference\", 55928], [\"File Sharing\", 52943], [\"Authentication\", 11440], [\"CRM\", 9870]];\nconst COST_APP = [[\"Zoom\", 55928], [\"Miro\", 52885], [\"Dropbox\", 50431], [\"Salesforce\", 43176], [\"Slack\", 38420]];\nconst COST_TOPLIC = [[\"Zoom One Pro\", 70800], [\"Google WS Ent. Starter\", 27450], [\"Google WS Ent. Standard\", 12985], [\"Google WS Business\", 8640], [\"Microsoft 365 G3 GCC\", 1930]];\nconst COST_USAGE = [[\"aaron.church@demo.local\", 29], [\"aaron.daniels@demo.local\", 29], [\"ada.pires@demo.local\", 29], [\"adelaide.gercak@demo.local\", 29], [\"adrian.williams@demo.local\", 29]];\nconst COST_RENEWALS = [\n  { app: \"Office365\", name: \"Microsoft 365 E5\", date: \"2026-07-06\", cost: \"3,175.50\", term: \"Yearly\", unit: \"54.75\" },\n  { app: \"Office365\", name: \"Microsoft Power Aut\u2026\", date: \"2026-08-07\", cost: \"6,518.75\", term: \"Yearly\", unit: \"37.25\" },\n];\nfunction CostExpAllBody() { return ; }\nfunction CostLicAllBody() { return ; }\nfunction CostExp2024Body() { return ; }\nfunction CostLicTotalBody() { return ; }\nfunction CostCategoryBody() { return ; }\nfunction CostAppBody() { return ; }\nfunction CostTopLicBody() { return ; }\nfunction CostUsageBody() { return ; }\nfunction CostRenewalsBody() {\n  const cols = [\n    { label: \"Application\", render: r =&gt; {r.app} },\n    { label: \"Name\", render: r =&gt; {r.name} },\n    { label: \"Renewal Date\", render: r =&gt; {r.date} },\n    { label: \"Total Cost\", align: \"right\", render: r =&gt; ${r.cost} },\n    { label: \"Term\", render: r =&gt; {r.term} },\n    { label: \"Unit\", align: \"right\", render: r =&gt; ${r.unit} },\n  ];\n  return (\n    \n\n      \n\n        \n          \n            {cols.map((c, i) =&gt; {c.label})}\n          \n        \n        \n          {COST_RENEWALS.map((r, ri) =&gt; (\n            \n              {cols.map((c, i) =&gt; {c.render(r)})}\n            \n          ))}\n        \n      \n    \n  );\n}\nfunction ResetViewBtn({ disabled, onReset }) {\n  const [h, setH] = useState(false);\n  return (\n     setH(true)} onMouseLeave={() =&gt; setH(false)}\n      title={disabled ? \"Layout is at its default\" : \"Restore the default tile layout\"}\n      style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6, height: 30, padding: \"0 13px\", borderRadius: 999, fontFamily: T.font, fontSize: 13, fontWeight: 600, cursor: disabled ? \"default\" : \"pointer\", border: `1px solid ${disabled ? T.lineSoft : h ? T.lineStrong : T.line}`, background: disabled ? \"transparent\" : h ? T.surface2 : T.control, color: disabled ? T.faint : T.body, transition: \"all .14s\" }}&gt;\n       Reset view\n    \n  );\n}\n\nconst TILE_META = {\n  line: { eyebrow: \"Activity\", title: \"Device Discovery Over Time\", Body: LineBody },\n  donut: { eyebrow: \"Composition\", title: \"Windows Distribution\", Body: DonutBody },\n  lifecycle: { eyebrow: \"Pipeline\", title: \"System Lifecycle\", Body: LifecycleBody },\n  discovery: { eyebrow: \"Activity\", title: \"Discovery Log\", Body: DiscoveryBody },\n  adapters: { eyebrow: \"Connections\", title: \"Adapter Connections\", Body: AdaptersBody },\n  stacked: { eyebrow: \"Trend\", title: \"Asset Growth by Category\", Body: StackedBody, footer: 12.4% },\n  severity: { eyebrow: \"Risk\", title: \"Vulnerabilities by Severity\", Body: SeverityBody, footer: 18 resolved },\n  healthOk: { eyebrow: \"Adapters\", title: \"Adapter Health \u00b7 Successful\", Body: HealthOkBody },\n  healthFail: { eyebrow: \"Adapters\", title: \"Adapter Health \u00b7 Attention\", Body: HealthFailBody },\n  costExpAll: { eyebrow: \"Spend\", title: \"Total Expenses (All Time)\", Body: CostExpAllBody },\n  costExp2024: { eyebrow: \"Spend\", title: \"Total Expenses (2024)\", Body: CostExp2024Body },\n  costLicAll: { eyebrow: \"Licenses\", title: \"Total License Cost (All Time)\", Body: CostLicAllBody },\n  costLicTotal: { eyebrow: \"Licenses\", title: \"Total License Cost\", Body: CostLicTotalBody },\n  costRenewals: { eyebrow: \"Renewals\", title: \"Upcoming Renewals (next 90 days)\", Body: CostRenewalsBody, footer: View all results, noPad: true },\n  costCategory: { eyebrow: \"Spend\", title: \"Expenses by Category (2024)\", Body: CostCategoryBody },\n  costApp: { eyebrow: \"Spend\", title: \"Expenses by App (2024)\", Body: CostAppBody },\n  costTopLic: { eyebrow: \"Licenses\", title: \"Most Expensive Licenses (2024)\", Body: CostTopLicBody },\n  costUsage: { eyebrow: \"Usage\", title: \"Azure AD Logons \u00b7 last 30 days\", Body: CostUsageBody },\n};\n\n/* ============ resizable grid (corner drag, neighbors reflow) ============ */\nconst GRID_COLS = 12, ROW_UNIT = 40, GAP = 16;\nconst INITIAL_TILES = [\n  { id: \"line\", w: 8, h: 7 }, { id: \"donut\", w: 4, h: 7 },\n  { id: \"lifecycle\", w: 5, h: 7 }, { id: \"discovery\", w: 7, h: 7 },\n  { id: \"adapters\", w: 7, h: 6 }, { id: \"severity\", w: 5, h: 6 },\n  { id: \"healthOk\", w: 6, h: 5 }, { id: \"healthFail\", w: 6, h: 5 },\n  { id: \"stacked\", w: 12, h: 5 },\n];\nconst COST_TILES = [\n  { id: \"costExpAll\", w: 3, h: 4 }, { id: \"costExp2024\", w: 3, h: 4 }, { id: \"costLicAll\", w: 3, h: 4 }, { id: \"costLicTotal\", w: 3, h: 4 },\n  { id: \"costRenewals\", w: 12, h: 6 },\n  { id: \"costCategory\", w: 6, h: 6 }, { id: \"costApp\", w: 6, h: 6 },\n  { id: \"costTopLic\", w: 6, h: 6 }, { id: \"costUsage\", w: 6, h: 6 },\n];\nconst DASH_TILESETS = { \"Cost Optimization\": COST_TILES };\nfunction DashboardGrid({ tileSet = INITIAL_TILES }) {\n  const [tiles, setTiles] = useState(tileSet);\n  const [hoverId, setHoverId] = useState(null);\n  const [resizingId, setResizingId] = useState(null);\n  const [drag, setDrag] = useState(null);\n  const dragId = drag ? drag.id : null;\n  const ref = useRef(null);\n  const tileEls = useRef({});\n  const justDragged = useRef(false);\n\n  const startDrag = (e, id, immediate) =&gt; {\n    if (e.button || (e.target.closest &amp;&amp; (e.target.closest(\"[data-resize]\") || e.target.closest(\"button\")))) return;\n    const startX = e.clientX, startY = e.clientY;\n    let dragging = false;\n    const begin = (cx, cy) =&gt; {\n      const el = tileEls.current[id]; if (!el) return;\n      const rect = el.getBoundingClientRect();\n      dragging = true;\n      setDrag({ id, x: cx, y: cy, ox: cx - rect.left, oy: cy - rect.top, w: rect.width, h: rect.height });\n      document.body.style.userSelect = \"none\";\n    };\n    const timer = immediate ? null : setTimeout(() =&gt; begin(startX, startY), 300);\n    const onMove = (ev) =&gt; {\n      if (!dragging) {\n        const moved = Math.abs(ev.clientX - startX) &gt; (immediate ? 4 : 8) || Math.abs(ev.clientY - startY) &gt; (immediate ? 4 : 8);\n        if (!moved) return;\n        if (immediate) begin(ev.clientX, ev.clientY); else { end(); return; }\n        if (!dragging) return;\n      }\n      setDrag(d =&gt; d ? { ...d, x: ev.clientX, y: ev.clientY } : d);\n      for (const tid in tileEls.current) {\n        const el = tileEls.current[tid];\n        if (!el || tid === id) continue;\n        const r = el.getBoundingClientRect();\n        if (ev.clientX &gt;= r.left &amp;&amp; ev.clientX &lt;= r.right &amp;&amp; ev.clientY &gt;= r.top &amp;&amp; ev.clientY &lt;= r.bottom) {\n          setTiles(ts =&gt; { const from = ts.findIndex(x =&gt; x.id === id), to = ts.findIndex(x =&gt; x.id === tid); if (from &lt; 0 || to &lt; 0 || from === to) return ts; const n = ts.slice(); const [mv] = n.splice(from, 1); n.splice(to, 0, mv); return n; });\n          break;\n        }\n      }\n    };\n    const end = () =&gt; { clearTimeout(timer); if (dragging) { justDragged.current = true; setTimeout(() =&gt; { justDragged.current = false; }, 60); } dragging = false; setDrag(null); document.body.style.userSelect = \"\"; window.removeEventListener(\"pointermove\", onMove); window.removeEventListener(\"pointerup\", end); };\n    window.addEventListener(\"pointermove\", onMove); window.addEventListener(\"pointerup\", end);\n  };\n\n  const startResize = (e, id) =&gt; {\n    e.preventDefault(); e.stopPropagation();\n    setResizingId(id);\n    const rect = ref.current.getBoundingClientRect();\n    const colW = (rect.width - GAP * (GRID_COLS - 1)) / GRID_COLS;\n    const t = tiles.find(x =&gt; x.id === id);\n    const startWpx = t.w * colW + (t.w - 1) * GAP;\n    const startHpx = t.h * ROW_UNIT + (t.h - 1) * GAP;\n    const sx = e.clientX, sy = e.clientY;\n    const onMove = (ev) =&gt; {\n      let w = Math.round((startWpx + (ev.clientX - sx) + GAP) / (colW + GAP));\n      let h = Math.round((startHpx + (ev.clientY - sy) + GAP) / (ROW_UNIT + GAP));\n      w = Math.max(3, Math.min(GRID_COLS, w));\n      h = Math.max(4, Math.min(14, h));\n      setTiles(ts =&gt; ts.map(x =&gt; x.id === id ? { ...x, w, h } : x));\n    };\n    const onUp = () =&gt; { setResizingId(null); document.body.style.cursor = \"\"; window.removeEventListener(\"mousemove\", onMove); window.removeEventListener(\"mouseup\", onUp); };\n    document.body.style.cursor = \"nwse-resize\";\n    window.addEventListener(\"mousemove\", onMove); window.addEventListener(\"mouseup\", onUp);\n  };\n\n  const isDefault = JSON.stringify(tiles) === JSON.stringify(tileSet);\n  return (\n    &lt;&gt;\n      \n\n         setTiles(tileSet)} /&gt;\n      \n    \n\n      {tiles.map((t, ti) =&gt; {\n        const m = TILE_META[t.id];\n        const isHover = hoverId === t.id, isResizing = resizingId === t.id, isDragging = dragId === t.id, anyDrag = dragId !== null;\n        return (\n          \n (tileEls.current[t.id] = el)}\n            onPointerDown={(e) =&gt; startDrag(e, t.id)}\n            onClickCapture={(e) =&gt; { if (justDragged.current) { e.stopPropagation(); justDragged.current = false; } }}\n            onMouseEnter={() =&gt; setHoverId(t.id)} onMouseLeave={() =&gt; setHoverId(null)}\n            style={{ gridColumn: `span ${t.w}`, gridRow: `span ${t.h}`, position: \"relative\", minWidth: 0, zIndex: 1 }}&gt;\n            {isDragging ? (\n              \n\n            ) : (&lt;&gt;\n            \n\n              \n { e.stopPropagation(); startDrag(e, t.id, true); }} title=\"Drag to move\" style={{ padding: \"13px 20px 12px\", borderBottom: `1px solid ${T.hair}`, display: \"flex\", alignItems: \"center\", gap: 8, cursor: \"grab\" }}&gt;\n                \n\n                  \n{m.eyebrow}\n                  \n{m.title}\n                \n                \n              \n              \n\n              {m.footer &amp;&amp; \n{m.footer}}\n            \n            \n startResize(e, t.id)} data-resize title=\"Drag to resize\"\n              style={{ position: \"absolute\", right: 0, bottom: 0, width: 20, height: 20, cursor: \"nwse-resize\", display: \"flex\", alignItems: \"flex-end\", justifyContent: \"flex-end\", padding: 4, opacity: isHover || isResizing ? 1 : 0, transition: \"opacity .15s\" }}&gt;\n              \n            \n            )}\n          \n        );\n      })}\n    \n    {drag &amp;&amp; (() =&gt; { const m = TILE_META[drag.id]; return createPortal(\n      \n\n        \n\n          \n\n            \n\n              \n{m.eyebrow}\n              \n{m.title}\n            \n            \n          \n          \nDrop to reorder\n        \n      , document.body); })()}\n    \n  );\n}\n\n/* ============ Assets table view (real device schema) ============ */\nconst ADAPTERS = {\n  aws_adapter: { brand: \"aws\" }, active_directory_adapter: { brand: \"active_directory\" },\n  crowd_strike_adapter: { brand: \"crowdstrike\" }, google_mdm_adapter: { brand: \"googlecloud\" },\n  esx_adapter: { brand: \"vmware\" }, sentinelone_adapter: { brand: \"sentinelone\" },\n  service_now_adapter: { brand: \"service_now\" }, epo_adapter: { brand: \"epo\" },\n  paloalto_panorama_adapter: { brand: \"paloalto\" }, cisco_meraki_adapter: { brand: \"cisco_meraki\" },\n  cisco_ise_adapter: { brand: \"cisco_ise\" }, cisco_adapter: { brand: \"cisco\" },\n  tanium_adapter: { brand: \"tanium\" }, tanium_asset_adapter: { brand: \"tanium\" },\n  claroty_adapter: { brand: \"claroty\" }, counter_act_adapter: { brand: \"forescout\" },\n  tenable_security_center_adapter: { brand: \"tenable\" }, zoom_adapter: { brand: \"zoom\" },\n  checkpoint_r80_adapter: { brand: \"checkpoint\" }, cylance_adapter: { brand: \"cylance\" },\n  chef_adapter: { brand: \"chef\" }, axonius_network_inspector_adapter: { short: \"NP\", color: \"#1C1D1F\" },\n};\nfunction AdapterAvatar({ k, size = 32 }) {\n  const a = ADAPTERS[k] || { short: k.slice(0, 2).toUpperCase(), color: \"#939598\" };\n  if (a.brand) return ;\n  return \n 28 ? 11 : 9, fontWeight: 700, color: a.color }}&gt;{a.short};\n}\nfunction AdapterStack({ list }) {\n  const shown = list.slice(0, 3), extra = list.length - shown.length;\n  return (\n    \n      \n      {shown.map((k, i) =&gt; )}\n      {extra &gt; 0 &amp;&amp; +{extra}}\n    \n  );\n}\n/* OS category icons */\nfunction OsIcon({ os }) {\n  const c = { Windows: \"#0078D4\", Linux: \"#1C1D1F\", \"OS X\": \"#555\", iOS: \"#111\", Android: \"#3DDC84\", VMWare: \"#607078\" }[os] || T.faint;\n  const mc = T.isLight ? \"#1B2030\" : \"#D6DAE6\"; // monochrome marks adapt to theme\n  const g = {\n    Windows: ,\n    \"OS X\": ,\n    iOS: ,\n    Android: ,\n    Linux: ,\n    VMWare: vm,\n  }[os];\n  if (!os) return \u2014;\n  return {g || }{os};\n}\nconst DEVICES = [\n  { name: \"PC-CURTIS-WILLIAMS\", host: \"PC-CURTIS-WILLIAMS.demo.local\", os: \"Windows\", ip: \"10.0.49.148\", mac: \"88:53:2E:12:45:C4\", seen: \"2026-06-08 09:34\", tags: [\"Corporate\", \"Managed\"], adapters: [\"active_directory_adapter\", \"crowd_strike_adapter\", \"epo_adapter\", \"google_mdm_adapter\", \"tanium_adapter\", \"sentinelone_adapter\", \"cisco_ise_adapter\"] },\n  { name: \"infranginx-5567897-stg\", host: \"esx-infranginx-5567897-stg.demo.local\", os: \"Linux\", ip: \"10.0.63.107\", mac: \"00:0C:29:12:55:38\", seen: \"2026-06-08 11:43\", tags: [\"Staging\", \"Cloud\"], adapters: [\"cisco_ise_adapter\", \"claroty_adapter\", \"counter_act_adapter\", \"epo_adapter\", \"tanium_adapter\", \"esx_adapter\", \"aws_adapter\"] },\n  { name: \"WIN-RUTHD\", host: \"WIN-RUTHD.demo.local\", os: \"Windows\", ip: \"10.0.48.107\", mac: \"88:53:2E:12:44:9B\", seen: \"2026-06-08 13:18\", tags: [\"Corporate\"], adapters: [\"active_directory_adapter\", \"cisco_adapter\", \"crowd_strike_adapter\", \"cylance_adapter\", \"epo_adapter\", \"tanium_adapter\"] },\n  { name: \"external3026786-prd\", host: \"sepio-external3026786-prd.demo.local\", os: \"Linux\", ip: \"10.0.64.36\", mac: \"88:53:2E:12:56:12\", seen: \"2026-06-08 05:54\", tags: [\"Production\", \"Internet-facing\"], adapters: [\"checkpoint_r80_adapter\", \"chef_adapter\", \"epo_adapter\", \"paloalto_panorama_adapter\", \"axonius_network_inspector_adapter\", \"claroty_adapter\", \"tenable_security_center_adapter\"] },\n  { name: \"macbook-pro-jdoe\", host: \"macbook-pro-jdoe.demo.local\", os: \"OS X\", ip: \"10.0.51.22\", mac: \"A4:83:E7:9C:11:04\", seen: \"2026-06-08 12:02\", tags: [\"Endpoint\", \"BYOD\"], adapters: [\"google_mdm_adapter\", \"crowd_strike_adapter\", \"sentinelone_adapter\"] },\n  { name: \"lablb-2918146-beta\", host: \"esx-lablb-2918146-beta.manufacturing.com\", os: \"Linux\", ip: \"10.0.56.90\", mac: \"00:0C:29:12:4C:BF\", seen: \"2026-06-08 11:30\", tags: [\"Lab\"], adapters: [\"cisco_meraki_adapter\", \"claroty_adapter\", \"epo_adapter\", \"esx_adapter\", \"tanium_asset_adapter\", \"counter_act_adapter\", \"service_now_adapter\"] },\n  { name: \"iphone-asmith\", host: \"\u2014\", os: \"iOS\", ip: \"10.0.77.51\", mac: \"F0:18:98:22:7D:AA\", seen: \"2026-06-08 11:58\", tags: [\"Mobile\", \"BYOD\"], adapters: [\"google_mdm_adapter\", \"zoom_adapter\"] },\n  { name: \"srv-db-fin-04\", host: \"srv-db-fin-04.healthcare-subsidiary.com\", os: \"Linux\", ip: \"10.0.40.12\", mac: \"00:50:56:9A:3C:11\", seen: \"2026-06-08 07:12\", tags: [\"Production\", \"Database\", \"PCI\"], adapters: [\"service_now_adapter\", \"tenable_security_center_adapter\", \"tanium_adapter\", \"epo_adapter\", \"aws_adapter\", \"claroty_adapter\"] },\n  { name: \"azure-infra9274676-prd\", host: \"azure-infra9274676-prd.demo.local\", os: \"Windows\", ip: \"10.0.61.5\", mac: \"00:0D:3A:1F:8E:22\", seen: \"2026-06-08 10:47\", tags: [\"Production\", \"Cloud\"], adapters: [\"active_directory_adapter\", \"aws_adapter\", \"sentinelone_adapter\", \"service_now_adapter\"] },\n  { name: \"android-pixel-7\", host: \"\u2014\", os: \"Android\", ip: \"10.0.78.130\", mac: \"3C:28:6D:55:01:9F\", seen: \"2026-06-08 09:05\", tags: [\"Mobile\"], adapters: [\"google_mdm_adapter\"] },\n  { name: \"Win-MaryChasse\", host: \"WIN-MARYCHASSE.demo.local\", os: \"Windows\", ip: \"10.0.49.201\", mac: \"88:53:2E:12:48:7E\", seen: \"2026-06-07 22:41\", tags: [\"Corporate\"], adapters: [\"active_directory_adapter\", \"epo_adapter\", \"cisco_meraki_adapter\"] },\n  { name: \"esx-mail-2231-prd\", host: \"esx-mail-2231-prd.manufacturing.com\", os: \"VMWare\", ip: \"10.0.62.18\", mac: \"00:0C:29:44:1A:E0\", seen: \"2026-06-08 06:33\", tags: [\"Production\"], adapters: [\"esx_adapter\", \"tenable_security_center_adapter\", \"paloalto_panorama_adapter\"] },\n  { name: \"PC-Doris9920\", host: \"PC-DORIS9920.demo.local\", os: \"Windows\", ip: \"10.0.50.66\", mac: \"88:53:2E:12:51:C9\", seen: \"2026-06-08 08:59\", tags: [\"Corporate\", \"Managed\"], adapters: [\"active_directory_adapter\", \"crowd_strike_adapter\", \"tanium_adapter\", \"google_mdm_adapter\"] },\n  { name: \"kiosk-lobby-03\", host: \"kiosk-lobby-03.demo.local\", os: \"Linux\", ip: \"10.0.44.7\", mac: \"B8:27:EB:0C:5A:31\", seen: \"2026-06-07 19:20\", tags: [\"IoT\", \"Unmanaged\"], adapters: [\"counter_act_adapter\", \"claroty_adapter\"] },\n];\n\nconst INIT_COLS = [\n  { key: \"adapters\", label: \"Adapter Connections\", w: 230, pinned: false },\n  { key: \"name\", label: \"Asset Name\", w: 230, pinned: false },\n  { key: \"host\", label: \"Host Name\", w: 300, pinned: false },\n  { key: \"os\", label: \"OS Type\", w: 140, pinned: false },\n  { key: \"ip\", label: \"IP Address\", w: 140, pinned: false },\n  { key: \"mac\", label: \"MAC Address\", w: 160, pinned: false },\n  { key: \"seen\", label: \"Last Seen (UTC)\", w: 170, pinned: false },\n  { key: \"tags\", label: \"Tags\", w: 220, pinned: false },\n];\nconst CB_W = 46;\nconst mono = { fontFamily: \"ui-monospace, 'SF Mono', monospace\" };\nfunction cellContent(key, r) {\n  switch (key) {\n    case \"adapters\": return ;\n    case \"name\": return {r.name};\n    case \"host\": return {r.host};\n    case \"os\": return ;\n    case \"ip\": return {r.ip};\n    case \"mac\": return {r.mac};\n    case \"seen\": return {r.seen};\n    case \"tags\": return {r.tags.slice(0, 2).map((t, j) =&gt; )}{r.tags.length &gt; 2 &amp;&amp; +{r.tags.length - 2}};\n    default: return null;\n  }\n}\n\nfunction HeaderCell({ col, left, isLastPinned, onResize, onPin, onDragStart, regRef, dragging }) {\n  const [h, setH] = useState(false);\n  const sticky = col.pinned;\n  return (\n    \n regRef(col.key, el)} onPointerDown={(e) =&gt; onDragStart(e, col.key)} onMouseEnter={() =&gt; setH(true)} onMouseLeave={() =&gt; setH(false)}\n      style={{ width: col.w, flexShrink: 0, position: sticky ? \"sticky\" : \"relative\", left: sticky ? left : undefined, zIndex: sticky ? 4 : 1, background: T.canvas, height: 40, display: \"flex\", alignItems: \"center\", gap: 6, padding: \"0 12px\", boxShadow: isLastPinned ? \"2px 0 5px rgba(27,32,70,0.06)\" : \"none\", cursor: \"grab\", opacity: dragging ? 0.4 : 1 }}&gt;\n      {col.label}\n      {(h || col.pinned) &amp;&amp; (\n         onPin(col.key)} title={col.pinned ? \"Unpin column\" : \"Pin column\"}\n          style={{ width: 24, height: 24, borderRadius: 6, border: \"none\", cursor: \"pointer\", background: \"transparent\", color: col.pinned ? T.blue : T.faint, display: \"flex\", alignItems: \"center\", justifyContent: \"center\", transform: col.pinned ? \"none\" : \"rotate(45deg)\", flexShrink: 0 }}&gt;\n          \n        \n      )}\n      \n onResize(e, col.key)} data-colresize title=\"Drag to resize\"\n        style={{ position: \"absolute\", right: -3, top: 8, width: 6, height: 24, cursor: \"col-resize\", display: \"flex\", justifyContent: \"center\", zIndex: 5 }}&gt;\n        \n      \n    \n  );\n}\n\nfunction AssetsTable() {\n  const [columns, setColumns] = useState(INIT_COLS);\n  const [hoverRow, setHoverRow] = useState(null);\n  const [perPage, setPerPage] = useState(20);\n  const [dragCol, setDragCol] = useState(null);\n  const colEls = useRef({});\n  const regRef = (k, el) =&gt; { colEls.current[k] = el; };\n\n  const startColDrag = (e, key) =&gt; {\n    if (e.button || (e.target.closest &amp;&amp; (e.target.closest(\"[data-colresize]\") || e.target.closest(\"button\")))) return;\n    const startX = e.clientX; let dragging = false;\n    const onMove = (ev) =&gt; {\n      if (!dragging) { if (Math.abs(ev.clientX - startX) &gt; 6) { dragging = true; setDragCol(key); document.body.style.userSelect = \"none\"; } else return; }\n      for (const k in colEls.current) {\n        const el = colEls.current[k]; if (!el || k === key) continue;\n        const r = el.getBoundingClientRect();\n        if (ev.clientX &gt;= r.left &amp;&amp; ev.clientX &lt;= r.right) {\n          setColumns(cs =&gt; { const from = cs.findIndex(c =&gt; c.key === key), to = cs.findIndex(c =&gt; c.key === k); if (from &lt; 0 || to &lt; 0 || from === to) return cs; const n = cs.slice(); const [m] = n.splice(from, 1); n.splice(to, 0, m); return n; });\n          break;\n        }\n      }\n    };\n    const onUp = () =&gt; { dragging = false; setDragCol(null); document.body.style.userSelect = \"\"; window.removeEventListener(\"pointermove\", onMove); window.removeEventListener(\"pointerup\", onUp); };\n    window.addEventListener(\"pointermove\", onMove); window.addEventListener(\"pointerup\", onUp);\n  };\n\n  const startColResize = (e, key) =&gt; {\n    e.preventDefault(); e.stopPropagation();\n    const sx = e.clientX, startW = columns.find(c =&gt; c.key === key).w;\n    const onMove = (ev) =&gt; { const w = Math.max(90, startW + (ev.clientX - sx)); setColumns(cs =&gt; cs.map(c =&gt; c.key === key ? { ...c, w } : c)); };\n    const onUp = () =&gt; { document.body.style.cursor = \"\"; window.removeEventListener(\"mousemove\", onMove); window.removeEventListener(\"mouseup\", onUp); };\n    document.body.style.cursor = \"col-resize\";\n    window.addEventListener(\"mousemove\", onMove); window.addEventListener(\"mouseup\", onUp);\n  };\n  const togglePin = (key) =&gt; setColumns(cs =&gt; cs.map(c =&gt; c.key === key ? { ...c, pinned: !c.pinned } : c));\n\n  const pinned = columns.filter(c =&gt; c.pinned), unpinned = columns.filter(c =&gt; !c.pinned);\n  const ordered = [...pinned, ...unpinned];\n  const leftMap = {}; let acc = CB_W;\n  pinned.forEach(c =&gt; { leftMap[c.key] = acc; acc += c.w; });\n  const lastPinned = pinned.length ? pinned[pinned.length - 1].key : null;\n  const totalW = CB_W + columns.reduce((a, c) =&gt; a + c.w, 0);\n\n  return (\n    \n\n      \n\n        \n\n          {/* header */}\n          \n\n            \n\n              \n            \n            {ordered.map(c =&gt; )}\n            \n\n          \n          {/* rows */}\n          {DEVICES.map((r, i) =&gt; {\n            const rowBg = hoverRow === i ? T.surface2 : T.surface;\n            return (\n              \n setHoverRow(i)} onMouseLeave={() =&gt; setHoverRow(null)}\n                style={{ display: \"flex\", height: 52, borderBottom: i &lt; DEVICES.length - 1 ? `1px solid ${T.hair}` : \"none\", background: rowBg }}&gt;\n                \n\n                  {hoverRow === i ?  : {i + 1}}\n                \n                {ordered.map(c =&gt; {\n                  const sticky = c.pinned;\n                  return (\n                    \n\n                      {cellContent(c.key, r)}\n                    \n                  );\n                })}\n                \n\n              \n            );\n          })}\n        \n      \n      {/* footer */}\n      \n\n        \n\n          Results per page:\n          \n\n            {[20, 50, 100].map(n =&gt;  setPerPage(n)} style={{ minWidth: 30, height: 28, borderRadius: 8, border: \"none\", cursor: \"pointer\", fontFamily: T.font, fontSize: 13, fontWeight: 500, ...tnum, background: perPage === n ? T.blue : \"transparent\", color: perPage === n ? T.white : T.body }}&gt;{n})}\n          \n        \n        \n\n          1\u2013{perPage} of 12,409\n          \n\n            \n            1234\n            \u2026621\n            \n          \n        \n      \n    \n  );\n}\n\nfunction QueryPill({ children, primary, active, onClick }) {\n  const [h, setH] = useState(false);\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6, height: 32, padding: \"0 14px\", borderRadius: 999, cursor: \"pointer\", fontFamily: T.font, fontSize: 13.5, fontWeight: 600, border: primary ? \"none\" : `1px solid ${active || h ? T.lineStrong : T.line}`, background: primary ? T.blue : active || h ? T.surface2 : T.control, color: primary ? T.onAccent : T.body }}&gt;{children};\n}\nfunction ToolLink({ icon: Icon, children }) {\n  const [h, setH] = useState(false);\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6, height: 30, padding: \"0 10px\", border: \"none\", borderRadius: 999, background: h ? T.surface2 : \"transparent\", color: T.body, fontSize: 13.5, fontWeight: 600, cursor: \"pointer\", fontFamily: T.font }}&gt;{Icon &amp;&amp; }{children};\n}\nfunction SegTool({ icon: Icon, title, first }) {\n  const [h, setH] = useState(false);\n  return (\n     setH(true)} onMouseLeave={() =&gt; setH(false)}&gt;\n      \n      {h &amp;&amp; {title}}\n    \n  );\n}\nfunction IconTool({ icon: Icon, title }) {\n  const [h, setH] = useState(false);\n  return (\n     setH(true)} onMouseLeave={() =&gt; setH(false)}&gt;\n      \n      {h &amp;&amp; {title}}\n    \n  );\n}\nfunction Segmented({ options, value, onChange }) {\n  const idx = Math.max(0, options.indexOf(value));\n  const wpct = 100 / options.length;\n  return (\n    \n\n      \n      {options.map(o =&gt; (\n         onChange(o)} style={{ position: \"relative\", zIndex: 1, minWidth: 62, padding: \"0 12px\", border: \"none\", background: \"transparent\", color: value === o ? T.onAccent : T.body, fontSize: 13.5, fontWeight: value === o ? 600 : 500, cursor: \"pointer\", fontFamily: T.font, transition: \"color .2s\" }}&gt;{o}\n      ))}\n    \n  );\n}\n\nfunction QueriesPanel({ close }) {\n  const recent = [\n    { nm: \"FH: 1.4 Asset Context.Business Importance\", sub: \"Shared Queries\" },\n    { nm: \"low Risk Score_2025-12-24T11-53\", sub: \"Public Queries / Predefined Queries\" },\n    { nm: \"Unmanaged endpoints seen &lt; 7d\", sub: \"Shared Queries\" },\n    { nm: \"Critical CVEs on internet-facing\", sub: \"Public Queries / Predefined Queries\" },\n  ];\n  return createPortal(&lt;&gt;\n    \n\n    \n\n      \n\n        Queries\n        \n        \n        \n      \n      \n\n        \n\n          \n        \n      \n      \n\n        \nFavorites\n        \nRecently Used Saved Queries\n        {recent.map((q, i) =&gt; (\n           (e.currentTarget.style.background = T.surface2)} onMouseLeave={(e) =&gt; (e.currentTarget.style.background = \"transparent\")}\n            style={{ display: \"flex\", alignItems: \"center\", gap: 11, width: \"100%\", border: \"none\", background: \"transparent\", borderRadius: 10, cursor: \"pointer\", padding: \"9px\", textAlign: \"left\", fontFamily: T.font }}&gt;\n            \n            \n              {q.nm}\n              {q.sub}\n            \n          \n        ))}\n      \n    \n  , document.body);\n}\nfunction AssetsView() {\n  const [mode, setMode] = useState(\"Wizard\");\n  const [enrichOpen, setEnrichOpen] = useState(false);\n  const [queriesOpen, setQueriesOpen] = useState(false);\n  return (\n    \n\n      \n\n      {/* breadcrumb + title + module actions */}\n      \n\n        \n\n          \nInventory / Assets\n          \nDevices\n        \n        \n\n          \n\n             setEnrichOpen(o =&gt; !o)}&gt;Enrichment &amp; Investigation \n            {enrichOpen &amp;&amp; (&lt;&gt;\n              \n setEnrichOpen(false)} style={{ position: \"fixed\", inset: 0, zIndex: 40 }} /&gt;\n              \n\n                {[\"Business Data Enrichment\", \"Device Inventory Classification\", \"Asset Investigation\"].map(o =&gt; (\n                   setEnrichOpen(false)} onMouseEnter={(e) =&gt; (e.currentTarget.style.background = T.surface2)} onMouseLeave={(e) =&gt; (e.currentTarget.style.background = \"transparent\")}\n                    style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", gap: 10, width: \"100%\", border: \"none\", background: \"transparent\", borderRadius: 8, cursor: \"pointer\", padding: \"9px 11px\", fontSize: 13, fontWeight: 500, fontFamily: T.font, color: T.body, textAlign: \"left\" }}&gt;\n                    {o} \n                  \n                ))}\n              \n            )}\n          \n          \n        \n      \n      {/* query toolbar */}\n      \n\n        New Query\n        Save As\n        Reset\n        Copy Query\n        \n\n        Display by Date\n        \n\n         setQueriesOpen(o =&gt; !o)}&gt;{queriesOpen ?  : &lt;&gt; Queries}\n        \n      \n      {/* search + wizard / basic filters */}\n      {mode === \"Wizard\" ? (\n        \n\n          \n\n            \n            \n          \n          Query Wizard\n        \n      ) : (\n        \n\n          \n          \n          \nLast Seen\n          \nTags\n           Filter\n        \n      )}\n      {/* stats toolbar */}\n      \n\n        Total 12,409\n         Last updated: 2026-06-08 17:07:59\n        \n\n        \n\n          \n\n            \n            \n            \n          \n           New Asset\n        \n      \n      {/* end flexShrink header */}\n      \n\n        \n      \n      {queriesOpen &amp;&amp;  setQueriesOpen(false)} /&gt;}\n    \n  );\n}\nfunction PageBtn({ children, active, disabled, wide }) {\n  const [h, setH] = useState(false);\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ minWidth: wide ? \"auto\" : 30, height: 30, padding: wide ? \"0 10px\" : 0, borderRadius: 999, border: active ? \"none\" : `1px solid ${h &amp;&amp; !disabled ? T.lineStrong : \"transparent\"}`, background: active ? T.blue : h &amp;&amp; !disabled ? T.surface2 : \"transparent\", color: active ? T.onAccent : disabled ? T.faint : T.body, fontSize: 13, fontWeight: 500, cursor: disabled ? \"default\" : \"pointer\", display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\", fontFamily: T.font, ...tnum }}&gt;{children};\n}\n\n/* ============ Inventory tree panel (assets view) ============ */\nconst INV_GROUPS_INIT = [\n  { name: \"Compute\", icon: Server, open: true, items: [\n    { icon: Server, label: \"Corporate Devices\", count: \"8,204\", fav: true },\n    { icon: ShieldAlert, label: \"Internet-facing Assets\", count: \"312\", fav: true },\n    { folder: \"Endpoint\", open: true, items: [\n      { icon: Server, label: \"Devices\", count: \"12,409\", active: true },\n      { icon: Workflow, label: \"Processes\", count: \"0\" },\n    ]},\n    { folder: \"Infrastructure\", open: false, items: [\n      { icon: Boxes, label: \"Compute Services\", count: \"14\" },\n      { icon: Cable, label: \"Databases\", count: \"36\" },\n      { icon: Boxes, label: \"Containers\", count: \"258\" },\n      { icon: Cable, label: \"Serverless Functions\", count: \"103\" },\n      { icon: Boxes, label: \"Compute Images\", count: \"25\" },\n    ]},\n    { icon: Settings, label: \"Configurations\", count: \"0\" },\n    { icon: Clock, label: \"Latest Devices\", count: \"12,409\" },\n  ] },\n  { name: \"Identity\", icon: Users, open: false, items: [\n    { folder: \"Directory\", open: false, items: [\n      { icon: Users, label: \"Users\", count: \"4,821\" },\n      { icon: Users, label: \"Groups\", count: \"312\" },\n    ]},\n    { icon: ShieldAlert, label: \"Service Accounts\", count: \"87\" },\n  ] },\n  { name: \"Applications\", icon: Layers, open: false, items: [\n    { icon: Layers, label: \"SaaS Apps\", count: \"143\" },\n    { icon: Layers, label: \"Installed Software\", count: \"2,904\" },\n  ] },\n  { name: \"Tickets\", icon: Bell, open: false, items: [\n    { icon: Bell, label: \"Open Tickets\", count: \"48\" },\n    { icon: Bell, label: \"Resolved\", count: \"203\" },\n  ] },\n];\nfunction InventoryPanel({ collapsed, setCollapsed }) {\n  const [groups, setGroups] = useState(INV_GROUPS_INIT);\n  const [favOpen, setFavOpen] = useState(true);\n\n  const collectItems = (items) =&gt; items.flatMap(it =&gt; it.folder ? collectItems(it.items) : [it]);\n  const favItems = groups.flatMap(g =&gt; collectItems(g.items)).filter(it =&gt; it.fav);\n\n  const toggleFavInItems = (items, label) =&gt; items.map(it =&gt;\n    it.folder ? { ...it, items: toggleFavInItems(it.items, label) }\n              : it.label === label ? { ...it, fav: !it.fav } : it\n  );\n  const toggleFav = (label) =&gt; setGroups(gs =&gt; gs.map(g =&gt; ({ ...g, items: toggleFavInItems(g.items, label) })));\n  if (collapsed) {\n    const compute = groups.find(g =&gt; g.name === \"Compute\");\n    return (\n      \n\n         setCollapsed(false)} title=\"Expand inventory\" className=\"ax-edge-collapse\"\n          style={{ position: \"absolute\", top: 16, right: -14, zIndex: 6, width: 28, height: 28, borderRadius: \"50%\", border: `1px solid ${T.line}`, background: T.surface, color: T.muted, cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", boxShadow: T.shadow }}&gt;\n          \n        \n        \n\n          \n        \n        \n\n        {(compute ? compute.items : []).map((it, i) =&gt; {\n          const Icon = it.icon;\n          return (\n            \n\n              \n            \n          );\n        })}\n      \n    );\n  }\n  return (\n    \n\n       setCollapsed(true)} title=\"Collapse panel\" className=\"ax-edge-collapse\"\n        style={{ position: \"absolute\", top: 16, right: -14, zIndex: 6, width: 28, height: 28, borderRadius: \"50%\", border: `1px solid ${T.line}`, background: T.surface, color: T.muted, cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", boxShadow: T.shadow }}&gt;\n        \n      \n      \n\n        \n\n          \n        \n      \n      \n\n        \n\n          \n setFavOpen(o =&gt; !o)} style={{ display: \"flex\", alignItems: \"center\", gap: 9, padding: \"9px 8px\", cursor: \"pointer\", borderRadius: 8, color: T.body }}&gt;\n            \n            \n            Favorites\n            {favItems.length}\n          \n          {favOpen &amp;&amp; favItems.map((it, ii) =&gt; )}\n        \n        {groups.map((g, gi) =&gt; { const Icon = g.icon; return (\n          \n\n            \n setGroups(gs =&gt; gs.map((x, i) =&gt; i === gi ? { ...x, open: !x.open } : x))}\n              style={{ display: \"flex\", alignItems: \"center\", gap: 9, padding: \"9px 8px\", cursor: \"pointer\", borderRadius: 8, color: g.open ? T.accentText : T.body }}&gt;\n              \n              \n              {g.name}\n            \n            {g.open &amp;&amp; g.items.map((it, ii) =&gt; it.folder ?  : )}\n          \n        ); })}\n      \n    \n  );\n}\nfunction InvFolder({ folder, toggleFav }) {\n  const [open, setOpen] = useState(folder.open);\n  const [h, setH] = useState(false);\n  const FIcon = open ? FolderOpen : Folder;\n  return (\n    \n\n      \n setH(true)} onMouseLeave={() =&gt; setH(false)} onClick={() =&gt; setOpen(o =&gt; !o)}\n        style={{ display: \"flex\", alignItems: \"center\", gap: 8, height: 34, padding: \"0 8px 0 22px\", borderRadius: 8, cursor: \"pointer\", background: h ? T.surface2 : \"transparent\", transition: \"background .12s\" }}&gt;\n        \n        \n        {folder.folder}\n      \n      {open &amp;&amp; folder.items.map((it, i) =&gt; )}\n    \n  );\n}\nfunction InvRow({ icon: Icon, label, count, active, fav, indent, toggleFav }) {\n  const [h, setH] = useState(false);\n  const left = indent || 28;\n  return (\n    \n setH(true)} onMouseLeave={() =&gt; setH(false)}\n      style={{ position: \"relative\", display: \"flex\", alignItems: \"center\", gap: 11, height: 36, margin: \"1px 0\", padding: `0 8px 0 ${left}px`, borderRadius: 8, cursor: \"pointer\", background: active ? T.accentSoft : h ? T.surface2 : \"transparent\", transition: \"background .14s\" }}&gt;\n      \n      {label}\n      {(h || fav) &amp;&amp; toggleFav &amp;&amp; (\n         { e.stopPropagation(); toggleFav(label); }} title={fav ? \"Remove from favorites\" : \"Add to favorites\"} className=\"ax-star\"\n          style={{ width: 22, height: 22, borderRadius: 6, border: \"none\", background: \"transparent\", cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", padding: 0, flexShrink: 0 }}&gt;\n          \n        \n      )}\n      {!h &amp;&amp; !fav &amp;&amp; {count}}\n    \n  );\n}\n\n/* ============ chrome ============ */\nfunction AppHeader({ theme, setTheme }) {\n  return (\n    \n\n      \n\n        \n      \n      \n\n        \n\n          Search Axonius\n          \u2318K\n        \n      \n      \n\n        New navigation BETA\n         setTheme(theme === \"dark\" ? \"light\" : \"dark\")} title=\"Toggle light / dark\"&gt;{theme === \"dark\" ?  : }\n        \n        \n        \nSB\n      \n    \n  );\n}\nfunction HBtn({ children, onClick, title }) {\n  const [h, setH] = useState(false);\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ width: 32, height: 32, borderRadius: 8, border: \"none\", cursor: \"pointer\", background: h ? T.surface2 : \"transparent\", color: h ? T.ink : T.bg80, display: \"flex\", alignItems: \"center\", justifyContent: \"center\" }}&gt;{children};\n}\n\nconst HICONS = {\n  dashboard: '',\n  inventory: '',\n  shield: '',\n  bolt: '',\n  link: '',\n  chart: '',\n  cog: '',\n};\nfunction HIcon({ name, size = 20, color = \"currentColor\", sw = 1.6, className }) {\n  return ${HICONS[name] || \"\"}` }} /&gt;;\n}\nconst RAIL = [\n  { key: \"dashboard\", hi: \"dashboard\", label: \"Dashboard\" }, { key: \"assets\", hi: \"inventory\", label: \"Inventory\" },\n  { key: \"exposures\", hi: \"shield\", label: \"Exposures\" }, { key: \"action\", hi: \"bolt\", label: \"Action Center\" },\n  { key: \"adapters\", hi: \"link\", label: \"Adapters\" }, { key: \"analysis\", hi: \"chart\", label: \"Analysis\" },\n];\nfunction IconRail({ view, setView }) {\n  return (\n    \n\n      {RAIL.map(r =&gt;  setView(r.key)} /&gt;)}\n      \n\n       {}} /&gt;\n      \n\n    \n  );\n}\nfunction RailGlyph({ hi, label, active, onClick }) {\n  const [h, setH] = useState(false);\n  return (\n    \n setH(true)} onMouseLeave={() =&gt; setH(false)} title={label} className=\"ax-rail ax-press\"\n      style={{ position: \"relative\", width: 44, height: 44, borderRadius: 14, cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", background: active ? T.accentSoft : h ? T.surface2 : \"transparent\", transition: \"background .15s\" }}&gt;\n      \n    \n  );\n}\n\nconst DASH_TREE_INIT = [\n  { g: \"Favorites\", open: true, items: [\n    { nm: \"My Dashboard\", fav: true }, { nm: \"Asset Profile - Copy_2024-06-09\", fav: true },\n    { nm: \"Axonius Dashboard\", fav: true, active: true, def: true }, { nm: \"Cost Optimization\", fav: true }, { nm: \"Cloud Compliance\", fav: true },\n  ] },\n  { g: \"Public\", open: false, items: [\n    { folder: \"Security\", open: false, items: [{ nm: \"SecOps Overview\" }, { nm: \"Threat Intelligence\" }] },\n    { folder: \"Executive\", open: false, items: [{ nm: \"Executive Summary\" }, { nm: \"Board Report\" }] },\n    { nm: \"Asset Inventory V 1.0\" }, { nm: \"Active Directory Insights\" },\n  ] },\n  { g: \"Shared\", open: false, items: [\n    { folder: \"Team SOC\", open: false, items: [{ nm: \"Vulnerability Posture\" }, { nm: \"Incident Response\" }] },\n    { nm: \"Cloud Inventory\" }, { nm: \"Compliance Overview\" },\n  ] },\n  { g: \"Private\", open: false, items: [{ nm: \"My Drafts\" }, { nm: \"Work in Progress\" }] },\n  { g: \"Managed by Axonius\", open: false, items: [{ nm: \"Device Overview\" }, { nm: \"User Overview\" }, { nm: \"Adapters Health\" }, { nm: \"Coverage &amp; Gaps\" }] },\n];\nfunction PanelBtn({ primary, filled, icon: Icon, children, onClick }) {\n  const [h, setH] = useState(false);\n  return (\n     setH(true)} onMouseLeave={() =&gt; setH(false)} className={filled ? \"ax-primary\" : \"ax-press\"}\n      style={{ height: 38, borderRadius: 999, border: filled ? \"none\" : primary ? `1.5px solid ${T.accentText}` : `1px solid ${h ? T.lineStrong : T.line}`, cursor: \"pointer\", width: \"100%\", background: filled ? (h ? T.blueDeep : T.blue) : primary ? (h ? T.accentSoft : \"transparent\") : h ? T.surface2 : \"transparent\", color: filled ? T.onAccent : primary ? T.accentText : T.body, fontSize: 13, fontWeight: 600, fontFamily: T.font, display: \"flex\", alignItems: \"center\", justifyContent: \"center\", gap: 7, boxShadow: \"none\", transition: \"background .14s ease, border-color .14s ease\" }}&gt;\n       {children}\n    \n  );\n}\nfunction CreateDashModal({ onCreate, close }) {\n  const [name, setName] = useState(\"\");\n  const [tpl, setTpl] = useState(\"blank\");\n  const tpls = [{ k: \"blank\", t: \"Blank dashboard\", d: \"Start from an empty canvas\" }, { k: \"template\", t: \"From a template\", d: \"Prebuilt charts to tweak\" }];\n  return createPortal(\n    \n\n      \n e.stopPropagation()} style={{ width: 480, maxWidth: \"92vw\", background: T.canvas, border: `1px solid ${T.line}`, borderRadius: 14, boxShadow: \"0 30px 80px rgba(0,0,0,.55)\", overflow: \"hidden\", animation: \"axRise .26s cubic-bezier(.22,1,.36,1) both\" }}&gt;\n        \n\n          Create dashboard\n          \n        \n        \n\n          \n\n            Dashboard name\n             setName(e.target.value)} placeholder=\"e.g. Security Posture\" style={{ width: \"100%\", height: 40, padding: \"0 14px\", border: `1px solid ${T.line}`, borderRadius: 8, background: T.control, color: T.ink, fontFamily: T.font, fontSize: 14, outline: \"none\", boxSizing: \"border-box\" }} /&gt;\n          \n          \n\n            Starting point\n            \n\n              {tpls.map(o =&gt; (\n                 setTpl(o.k)} style={{ flex: 1, textAlign: \"left\", padding: \"12px 13px\", borderRadius: 10, border: `1.5px solid ${tpl === o.k ? T.accentText : T.line}`, background: tpl === o.k ? T.accentSoft : \"transparent\", cursor: \"pointer\", fontFamily: T.font }}&gt;\n                  \n{o.t}\n                  \n{o.d}\n                \n              ))}\n            \n          \n        \n        \n\n          Cancel\n           name.trim() &amp;&amp; onCreate(name.trim())} className=\"ax-press\" style={{ height: 38, padding: \"0 18px\", borderRadius: 999, border: \"none\", background: name.trim() ? T.blue : T.surface2, color: name.trim() ? T.onAccent : T.faint, fontSize: 13.5, fontWeight: 600, cursor: name.trim() ? \"pointer\" : \"default\", fontFamily: T.font }}&gt;Create dashboard\n        \n      \n    , document.body);\n}\nfunction SidePanel({ collapsed, setCollapsed, activeDash, setActiveDash }) {\n  const [tree, setTree] = useState(DASH_TREE_INIT);\n  const [menu, setMenu] = useState(null);\n  const [editing, setEditing] = useState(null);\n  const [createOpen, setCreateOpen] = useState(false);\n\n  const mut = (fn) =&gt; setTree(t =&gt; fn(t.map(g =&gt; ({ ...g, items: g.items.map(it =&gt; ({ ...it })) }))));\n  const toggleGroup = (gi) =&gt; setTree(t =&gt; t.map((g, i) =&gt; i === gi ? { ...g, open: !g.open } : g));\n  const setActive = (gi, ii) =&gt; { mut(t =&gt; { t.forEach(g =&gt; g.items.forEach(it =&gt; it.active = false)); t[gi].items[ii].active = true; return t; }); if (setActiveDash) setActiveDash(tree[gi].items[ii].nm); };\n  const toggleFav = (gi, ii) =&gt; mut(t =&gt; { t[gi].items[ii].fav = !t[gi].items[ii].fav; return t; });\n  const setDefault = (gi, ii) =&gt; mut(t =&gt; { t.forEach(g =&gt; g.items.forEach(it =&gt; it.def = false)); t[gi].items[ii].def = true; return t; });\n  const duplicate = (gi, ii) =&gt; mut(t =&gt; { t[gi].items.splice(ii + 1, 0, { nm: t[gi].items[ii].nm + \" (copy)\" }); return t; });\n  const rename = (gi, ii, nm) =&gt; mut(t =&gt; { t[gi].items[ii].nm = nm || t[gi].items[ii].nm; return t; });\n  const remove = (gi, ii) =&gt; mut(t =&gt; { t[gi].items.splice(ii, 1); return t; });\n  const createDash = (nm) =&gt; mut(t =&gt; { const p = t.find(g =&gt; g.g === \"Private\"); p.open = true; p.items.push({ nm: nm || \"Untitled dashboard\" }); return t; });\n  const openMenu = (gi, ii, e) =&gt; { const r = e.currentTarget.getBoundingClientRect(); setMenu({ gi, ii, top: r.bottom + 6, left: Math.max(8, r.right - 196) }); };\n\n  if (collapsed) {\n    const favItems = tree.flatMap(g =&gt; g.items).filter(it =&gt; it.fav || it.active);\n    return (\n      \n\n         setCollapsed(false)} title=\"Expand dashboards\" className=\"ax-edge-collapse\"\n          style={{ position: \"absolute\", top: 16, right: -14, zIndex: 6, width: 28, height: 28, borderRadius: \"50%\", border: `1px solid ${T.line}`, background: T.surface, color: T.muted, cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", boxShadow: T.shadow }}&gt;\n          \n        \n         setCreateOpen(true)} style={{ width: 38, height: 38, borderRadius: 8, border: `1.5px solid ${T.accentText}`, background: \"transparent\", cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", color: T.accentText }}&gt;\n          \n        \n        \n\n        {favItems.map((s, i) =&gt; (\n          \n\n            \n            {s.fav &amp;&amp; }\n          \n        ))}\n        {createOpen &amp;&amp;  { createDash(nm); setCreateOpen(false); }} close={() =&gt; setCreateOpen(false)} /&gt;}\n      \n    );\n  }\n  return (\n    \n\n       setCollapsed(true)} title=\"Collapse panel\" className=\"ax-edge-collapse\"\n        style={{ position: \"absolute\", top: 16, right: -14, zIndex: 6, width: 28, height: 28, borderRadius: \"50%\", border: `1px solid ${T.line}`, background: T.surface, color: T.muted, cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", boxShadow: T.shadow }}&gt;\n        \n      \n      \n\n         setCreateOpen(true)}&gt;Create Dashboard\n        Manage Dashboards\n      \n      \n\n        \n\n          \n        \n      \n      \n\n        {tree.map((g, gi) =&gt; (\n          \n        ))}\n      \n      {menu &amp;&amp;  setMenu(null)}\n        actions={{ rename: () =&gt; setEditing({ gi: menu.gi, ii: menu.ii }), duplicate, toggleFav, setDefault, remove }} /&gt;}\n      {createOpen &amp;&amp;  { createDash(nm); setCreateOpen(false); }} close={() =&gt; setCreateOpen(false)} /&gt;}\n    \n  );\n}\nconst DASH_CAT_ICON = { Favorites: Star, Public: Globe, Shared: Users, Private: Lock, \"Managed by Axonius\": ShieldCheck };\nfunction DashGroup({ group, gi, toggleGroup, setActive, toggleFav, openMenu, editing, setEditing, rename }) {\n  const Icon = DASH_CAT_ICON[group.g] || LayoutGrid;\n  return (\n    \n\n       toggleGroup(gi)} className=\"ax-catrow\"\n        style={{ display: \"flex\", alignItems: \"center\", gap: 9, width: \"100%\", border: \"none\", background: \"transparent\", cursor: \"pointer\", padding: \"8px 8px\", borderRadius: 8, fontFamily: T.font }}&gt;\n        \n        \n        {group.g}\n        {group.g === \"Favorites\" ? group.items.filter(it =&gt; it.fav !== false).length : group.items.length}\n      \n      {group.open &amp;&amp; group.items\n        .filter(it =&gt; group.g !== \"Favorites\" || it.fav !== false)\n        .map((it, ii) =&gt;\n          it.folder\n            ? \n            : \n        )}\n    \n  );\n}\nfunction DashFolder({ folder, indent, onToggle }) {\n  const [h, setH] = useState(false);\n  const [open, setOpen] = useState(folder.open);\n  const toggle = () =&gt; { setOpen(o =&gt; !o); if (onToggle) onToggle(!open); };\n  const FIcon = open ? FolderOpen : Folder;\n  return (\n    \n\n      \n setH(true)} onMouseLeave={() =&gt; setH(false)} onClick={toggle}\n        style={{ display: \"flex\", alignItems: \"center\", gap: 8, height: 34, padding: `0 8px 0 ${indent || 22}px`, borderRadius: 8, cursor: \"pointer\", background: h ? T.surface2 : \"transparent\", transition: \"background .12s\" }}&gt;\n        \n        \n        {folder.folder}\n      \n      {open &amp;&amp; folder.items.map((it, i) =&gt; (\n        \n e.currentTarget.style.background = T.surface2} onMouseLeave={(e) =&gt; e.currentTarget.style.background = \"transparent\"}&gt;\n          \n          {it.nm}\n        \n      ))}\n    \n  );\n}\nfunction DashItem({ item, gi, ii, setActive, toggleFav, openMenu, editing, setEditing, rename }) {\n  const [h, setH] = useState(false);\n  return (\n    \n setH(true)} onMouseLeave={() =&gt; setH(false)} onClick={() =&gt; !editing &amp;&amp; setActive(gi, ii)} className=\"ax-press\"\n      style={{ position: \"relative\", display: \"flex\", alignItems: \"center\", gap: 9, height: 36, padding: \"0 8px 0 28px\", margin: \"1px 0\", cursor: \"pointer\", borderRadius: 8, border: \"none\", background: item.active ? T.accentSoft : h ? T.surface2 : \"transparent\", transition: \"background .14s\" }}&gt;\n      \n      {editing ? (\n         e.stopPropagation()}\n          onBlur={(e) =&gt; { rename(gi, ii, e.target.value.trim()); setEditing(null); }}\n          onKeyDown={(e) =&gt; { if (e.key === \"Enter\") { rename(gi, ii, e.target.value.trim()); setEditing(null); } if (e.key === \"Escape\") setEditing(null); }}\n          style={{ flex: 1, minWidth: 0, border: `1px solid ${T.blue}`, borderRadius: 6, padding: \"2px 6px\", fontSize: 13.5, fontFamily: T.font, color: T.ink, outline: \"none\", background: T.surface }} /&gt;\n      ) : (\n        {item.nm}\n      )}\n      {(h || item.fav) &amp;&amp; !editing &amp;&amp; (\n         { e.stopPropagation(); toggleFav(gi, ii); }} title={item.fav ? \"Remove from favorites\" : \"Add to favorites\"} className=\"ax-star\"\n          style={{ width: 22, height: 22, borderRadius: 6, border: \"none\", background: \"transparent\", cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", padding: 0, flexShrink: 0 }}&gt;\n          \n        \n      )}\n      {h &amp;&amp; !editing &amp;&amp; (\n         { e.stopPropagation(); openMenu(gi, ii, e); }} title=\"More actions\"\n          style={{ width: 22, height: 22, borderRadius: 6, border: \"none\", background: \"transparent\", cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", padding: 0, flexShrink: 0, color: T.muted }}&gt;\n          \n        \n      )}\n    \n  );\n}\nfunction RowMenu({ menu, tree, close, actions }) {\n  const it = tree[menu.gi]?.items?.[menu.ii] || {};\n  const rows = [\n    { ic: Pencil, l: \"Rename\", fn: () =&gt; actions.rename() },\n    { ic: Copy, l: \"Duplicate\", fn: () =&gt; actions.duplicate(menu.gi, menu.ii) },\n    { ic: Star, l: it.fav ? \"Remove from favorites\" : \"Add to favorites\", fn: () =&gt; actions.toggleFav(menu.gi, menu.ii) },\n    { ic: Check, l: it.def ? \"Default dashboard\" : \"Set as default\", fn: () =&gt; actions.setDefault(menu.gi, menu.ii) },\n    { ic: Download, l: \"Export\", fn: () =&gt; {} },\n    { sep: true },\n    { ic: Trash2, l: \"Delete\", danger: true, fn: () =&gt; actions.remove(menu.gi, menu.ii) },\n  ];\n  return (\n    &lt;&gt;\n      \n\n      \n\n        {rows.map((a, i) =&gt; a.sep\n          ? \n\n          :  { a.fn(); close(); }}&gt;{a.l})}\n      \n    \n  );\n}\nfunction MenuRow({ icon: Icon, danger, children, onClick }) {\n  const [h, setH] = useState(false);\n  return (\n     setH(true)} onMouseLeave={() =&gt; setH(false)}\n      style={{ display: \"flex\", alignItems: \"center\", gap: 9, width: \"100%\", border: \"none\", borderRadius: 8, cursor: \"pointer\", padding: \"7px 9px\", fontSize: 13, fontFamily: T.font, fontWeight: 500, textAlign: \"left\", color: danger ? T.red : T.body, background: h ? (danger ? `${T.red}10` : T.canvas) : \"transparent\" }}&gt;\n       {children}\n    \n  );\n}\n\nfunction ModuleHeader({ view, activeDash }) {\n  const isDash = view === \"dashboard\";\n  return (\n    \n\n      \n{isDash ? \"Dashboards / Favorites\" : \"Assets / All Devices\"}\n      \n\n        \n\n          \n{isDash ? activeDash : \"Assets\"}\n          {isDash &amp;&amp; }\n        \n        \n\n          {isDash ? &lt;&gt;\n             Updated 2m ago\n            Add Chart\n           : &lt;&gt;\n            Export\n            New Query\n          }\n          \n        \n      \n    \n  );\n}\nfunction HdrBtn({ icon: Icon, children, primary, filled }) {\n  const [h, setH] = useState(false);\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ display: \"flex\", alignItems: \"center\", gap: 6, height: 34, padding: \"0 14px\", borderRadius: 999, cursor: \"pointer\", fontFamily: T.font, fontSize: 13.5, fontWeight: 600, border: filled ? \"none\" : (primary ? `1.5px solid ${T.accentText}` : `1px solid ${h ? T.lineStrong : T.line}`), background: filled ? (h ? T.blueDeep : T.blue) : (primary ? (h ? T.accentSoft : \"transparent\") : (h ? T.surface2 : T.control)), color: filled ? T.onAccent : (primary ? T.accentText : T.body) }}&gt;{children};\n}\n\nfunction AxoniusApp() {\n  const [view, setView] = useState(\"dashboard\");\n  const [collapsed, setCollapsed] = useState(false);\n  const [invCollapsed, setInvCollapsed] = useState(false);\n  const [theme, setTheme] = useState(\"dark\");\n  const [activeDash, setActiveDash] = useState(\"Axonius Dashboard\");\n  T = THEMES[theme];\n  useEffect(() =&gt; {\n    document.body.style.background = THEMES[theme].shell;\n    const el = document.documentElement;\n    el.classList.add(\"theming\");\n    const id = setTimeout(() =&gt; el.classList.remove(\"theming\"), 450);\n    return () =&gt; clearTimeout(id);\n  }, [theme]);\n  return (\n    \n\n      {`@import url('https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;500;600;700&amp;family=Schibsted+Grotesk:wght@500;600;700&amp;display=swap'); * { box-sizing: border-box; } .theming, .theming * { transition: background-color .4s ease, border-color .4s ease, color .35s ease, fill .3s ease, stroke .3s ease !important; } *::-webkit-scrollbar { width: 9px; height: 9px; } *::-webkit-scrollbar-thumb { background: ${T.bg40}; border-radius: 5px; } *::-webkit-scrollbar-track { background: transparent; }\n        .ax-tile *::-webkit-scrollbar-thumb { background: transparent; transition: background .2s ease; }\n        .ax-tile:hover *::-webkit-scrollbar-thumb { background: ${T.bg40}; }\n        .ax-tbl::-webkit-scrollbar-thumb { background: transparent; } .ax-tbl:hover::-webkit-scrollbar-thumb { background: ${T.bg40}; } .ax-tbl::-webkit-scrollbar-corner { background: transparent; }\n        input::placeholder { color: ${T.muted}; opacity: 1; }\n        .ax-catrow:hover { background: ${T.surface2}; }\n        .ax-catrow:hover .ax-favbtn { opacity: 1 !important; }\n        .ax-edge-collapse { opacity: 0; transform: scale(.8); transition: opacity .15s ease, transform .15s ease; }\n        .ax-sidepanel:hover .ax-edge-collapse { opacity: 1; transform: scale(1); }\n        button, [role=\"button\"] { transition: transform .14s cubic-bezier(.34,1.56,.64,1), background-color .15s ease, box-shadow .18s ease, border-color .15s ease, color .12s ease; }\n        button:not(:disabled):active { transform: scale(.92); }\n        .ax-press { transition: transform .14s cubic-bezier(.34,1.56,.64,1), background-color .14s ease; }\n        .ax-press:active { transform: scale(.95); }\n        .ax-card { transition: transform .2s cubic-bezier(.34,1.56,.64,1), box-shadow .2s ease, border-color .15s ease; }\n        .ax-card:hover { border-color: ${T.lineStrong} !important; box-shadow: ${T.shadow} !important; }\n        .ax-primary:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(37,99,235,.4) !important; }\n        .ax-primary:active { transform: translateY(0) scale(.96); }\n        @keyframes axRise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }\n        .ax-rise { animation: axRise .45s cubic-bezier(.22,1,.36,1) both; }\n        @keyframes axJiggle { 0%, 100% { transform: rotate(-0.5deg); } 50% { transform: rotate(0.5deg); } }\n        .ax-jiggle { animation: axJiggle .32s ease-in-out infinite; }\n        @keyframes axPop { 0% { transform: scale(1); } 45% { transform: scale(1.25) rotate(-8deg); } 100% { transform: scale(1); } }\n        .ax-star:hover { animation: axPop .4s ease; }\n        @keyframes axSpin { to { transform: rotate(360deg); } }\n        .ax-spin:hover { animation: axSpin .6s ease; }\n        button:not(:disabled):hover { transform: translateY(-1px); }\n        @keyframes axGrow { from { transform: scaleX(0); } to { transform: scaleX(1); } }\n        @keyframes axGrowY { from { transform: scaleY(0); } to { transform: scaleY(1); } }\n        @keyframes axDraw { to { stroke-dashoffset: 0; } }\n        @keyframes axFade { from { opacity: 0; } to { opacity: 1; } }\n        @keyframes axSlideIn { from { transform: translateX(100%); } to { transform: translateX(0); } }\n        @keyframes axBounce { 0% { transform: translateY(0) scale(1); } 35% { transform: translateY(-4px) scale(1.14); } 70% { transform: translateY(0) scale(1); } 100% { transform: translateY(0) scale(1); } }\n        .ax-rail:hover .ax-railicon { animation: axBounce .5s ease; }\n        .ax-flat:hover { transform: none !important; }`}\n      \n      \n\n        \n        \n\n          {view === \"dashboard\" &amp;&amp; }\n          {view === \"assets\" &amp;&amp; }\n          \n\n            {view === \"dashboard\" &amp;&amp; }\n            {view === \"dashboard\" ? (\n              \n\n                {DASH_TILESETS[activeDash]\n                  ? \n                  : &lt;&gt;}\n              \n            ) : view === \"assets\" ? (\n              \n            ) : (\n              \n\n                {RAIL.find(r =&gt; r.key === view)?.label} view \u2014 coming soon\n              \n            )}\n          \n        \n      \n    \n  );\n}\n\ncreateRoot(document.getElementById(\"root\")).render();\n    \n  \n    fetch('/.inspector/overlay.js')\n      .then(r =&gt; r.text())\n      .then(code =&gt; { const s = document.createElement('script'); s.textContent = code; document.head.appendChild(s); })\n      .catch(() =&gt; {});\n  \n  \n\n", "creation_timestamp": "2026-06-23T09:25:09.000000Z"}, {"uuid": "4cf78e08-6fa4-412b-adc4-fff2c322b7ed", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2024-0039", "type": "seen", "source": "https://gist.github.com/ShaiOnionGod/a2470d5624f426a312bf6d47e9b8a91c", "content": "\n\n  \n    \n    \n    Axonius \u2014 Dashboard prototype\n    \n    \n      {\n        \"imports\": {\n          \"react\": \"https://esm.sh/react@18.3.1\",\n          \"react-dom\": \"https://esm.sh/react-dom@18.3.1\",\n          \"react-dom/client\": \"https://esm.sh/react-dom@18.3.1/client\",\n          \"lucide-react\": \"https://esm.sh/lucide-react@0.456.0?deps=react@18.3.1\"\n        }\n      }\n    \n    \n    \n      html, body { margin: 0; height: 100%; background: #191A23; font-family: 'Hanken Grotesk', -apple-system, BlinkMacSystemFont, sans-serif; }\n      #root { height: 100%; }\n      .sb-tag { position: fixed; right: 14px; bottom: 12px; z-index: 99999; font: 700 10px/1 ui-monospace, monospace; letter-spacing: .14em; color: #0D5ED7; background: rgba(255,255,255,.9); border: 1px solid #E0E4EC; border-radius: 999px; padding: 6px 10px; box-shadow: 0 6px 18px rgba(27,32,70,.12); pointer-events: none; }\n    \n  \n  \n    \n\n    \nSANDBOX\n\n    \nimport React, { useState, useRef, useCallback, useEffect } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { createPortal } from \"react-dom\";\nimport {\n  Search, Star, MoreHorizontal, Info, ListFilter, ArrowUpDown, Columns3,\n  Plus, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, ChevronDown,\n  ArrowUpRight, ArrowDownRight, LayoutGrid, Server, ShieldCheck, Boxes,\n  Workflow, Cable, Bell, CircleHelp, Clock, Play, Grip, PanelLeftClose,\n  PanelLeftOpen, Download, GripVertical, X, Settings, ShieldAlert, Crosshair,\n  Pin, PinOff, RotateCw, Filter, Table2, ChevronsUpDown, Pencil, Check, Trash2,\n  Users, Layers, RotateCcw, Save, Copy, Calendar, Menu, Zap, Link, BarChart3, Sun, Moon,\n  Globe, Lock, Folder, FolderOpen\n} from \"lucide-react\";\n\n/**\n * Axonius \u2014 Dashboard + Assets table views\n * Collapsible side panel \u00b7 resizable + reorderable dashboard tiles\n * Real Axonius header \u00b7 Twenty-style table \u00b7 tokens from Figma source\n */\n\nfunction AxoniusLogo() {\n  return `.replaceAll('fill=\"black\"', `fill=\"${T.ink}\"`) }} /&gt;;\n}\n\n// Data / highlight palette \u2014 bright fills used in both themes (light-mode text variants applied where colored text is needed)\nconst VIZ = { green: \"#5BC4BF\", greenDeep: \"#247D78\", mint: \"#8ED0FF\", lilac: \"#AD85FF\", lilacPale: \"#CDB4FF\", orange: \"#FF8C66\", amber: \"#FFB286\" };\nconst FONT = \"'Hanken Grotesk', -apple-system, sans-serif\", DISPLAY = \"'Schibsted Grotesk', -apple-system, sans-serif\";\nconst THEMES = {\n  dark: {\n    ink: \"#E4E8F0\", body: \"#AEB7CC\", muted: \"#8494B5\", faint: \"#69738C\",\n    line: \"rgba(132,148,181,0.20)\", lineSoft: \"rgba(132,148,181,0.12)\", hair: \"rgba(132,148,181,0.09)\", lineStrong: \"rgba(132,148,181,0.42)\",\n    bg100: \"#AEB7CC\", bg90: \"#9AA3BC\", bg80: \"#8494B5\", bg40: \"#8494B5\",\n    blue: \"#5C7CFF\", blueDeep: \"#4E6CF5\", green: \"#5BC4BF\", red: \"#FF8C66\",\n    shell: \"#191A23\", headerBg: \"#191A23\", canvas: \"#191A23\", surface: \"#222431\", surface2: \"#2A2D3C\", control: \"#262838\",\n    white: \"#FFFFFF\", onAccent: \"#191A23\", isLight: false, coin: \"#2A2D3C\", accentSoft: \"rgba(92,124,255,0.16)\", accentText: \"#5C7CFF\", accentBorder: \"rgba(92,124,255,0.50)\",\n    viz: VIZ, shadow: \"0 1px 2px rgba(0,0,0,0.4), 0 14px 34px rgba(0,0,0,0.5)\", font: FONT, display: DISPLAY,\n  },\n  light: {\n    ink: \"#2E3850\", body: \"#465472\", muted: \"#6B7894\", faint: \"#8494B5\",\n    line: \"rgba(132,148,181,0.30)\", lineSoft: \"rgba(132,148,181,0.18)\", hair: \"rgba(132,148,181,0.12)\", lineStrong: \"rgba(132,148,181,0.55)\",\n    bg100: \"#465472\", bg90: \"#5A6889\", bg80: \"#8494B5\", bg40: \"#8494B5\",\n    blue: \"#4361EE\", blueDeep: \"#3A55D6\", green: \"#247D78\", red: \"#BF4B26\",\n    shell: \"#F9FAFB\", headerBg: \"#F9FAFB\", canvas: \"#FFFFFF\", surface: \"#FFFFFF\", surface2: \"#F1F2F6\", control: \"#FFFFFF\",\n    white: \"#FFFFFF\", onAccent: \"#FFFFFF\", isLight: true, coin: \"#FFFFFF\", accentSoft: \"rgba(67,97,238,0.10)\", accentText: \"#4361EE\", accentBorder: \"rgba(67,97,238,0.45)\",\n    viz: VIZ, shadow: \"0 1px 2px rgba(70,84,114,0.06), 0 10px 26px rgba(70,84,114,0.08)\", font: FONT, display: DISPLAY,\n  },\n};\nlet T = THEMES.dark;\n// Severity scale stays semantic (red \u2192 orange \u2192 yellow \u2192 green, neutral for informational) in both themes\nconst SEVC = { critical: \"#E5484D\", high: \"#F0743E\", medium: \"#F5C28C\", low: \"#4F8FE3\", info: \"#CFC4F2\" };\nconst fmt = (n) =&gt; n.toLocaleString(\"en-US\");\nconst tnum = { fontFeatureSettings: '\"tnum\" 1', fontVariantNumeric: \"tabular-nums\" };\n\n/* ============ vendor logos ============ */\nfunction LogoMark({ brand, size = 32 }) {\n  const glyph = {\n    aws: aws,\n    microsoft: ,\n    azure: ,\n    googlecloud: ,\n    oracle: ,\n    vmware: vm,\n    okta: ,\n    crowdstrike: ,\n    active_directory: ,\n    sentinelone: ,\n    service_now: ,\n    cisco: cisco,\n    cisco_meraki: ,\n    cisco_ise: cisco,\n    checkpoint: ,\n    chef: ,\n    claroty: ,\n    cylance: ,\n    epo: ,\n    paloalto: ,\n    tanium: ,\n    tenable: ,\n    forescout: ,\n    zoom: ,\n    miro: ,\n    dropbox: ,\n    salesforce: ,\n    slack: ,\n    office365: ,\n    google_workspace: ,\n  }[brand] || {(brand || \"?\").slice(0, 2).toUpperCase()};\n  return \n{glyph};\n}\n\n/* ============ chips ============ */\n// Tags use the dashboard data palette (turquoise / purple / baby-blue / orange) \u2014 dark text variant in light mode, bright in dark\nconst TAGV = [{ b: \"#5BC4BF\", d: \"#247D78\" }, { b: \"#AD85FF\", d: \"#683CB5\" }, { b: \"#8ED0FF\", d: \"#1E75B3\" }, { b: \"#FF8C66\", d: \"#BF4B26\" }];\nfunction Tag({ label }) {\n  let n = 0; for (let i = 0; i &lt; label.length; i++) n = (n * 31 + label.charCodeAt(i)) &gt;&gt;&gt; 0;\n  const t = TAGV[n % TAGV.length];\n  return {label};\n}\n// Cursor-following tooltip (like sandbox 2) \u2014 surface card with readable dark text\nfunction FloatTip({ x, y, children }) {\n  return createPortal(\n{children}, document.body);\n}\nfunction UserAvatar({ name, size = 24 }) {\n  const s = name || \"?\"; let n = 0; for (let i = 0; i &lt; s.length; i++) n = (n * 31 + s.charCodeAt(i)) &gt;&gt;&gt; 0;\n  const t = TAGV[n % TAGV.length];\n  return {s.trim()[0] || \"?\"};\n}\nconst APP_LOGO_MAP = {\n  Zoom: \"zoom\", \"Zoom One Pro\": \"zoom\",\n  Miro: \"miro\",\n  Dropbox: \"dropbox\",\n  Salesforce: \"salesforce\",\n  Slack: \"slack\",\n  Google: \"googlecloud\", \"Google WS Ent. Starter\": \"google_workspace\", \"Google WS Ent. Standard\": \"google_workspace\", \"Google WS Business\": \"google_workspace\",\n  Office365: \"office365\", \"Microsoft 365 G3 GCC\": \"office365\", \"Microsoft 365 E5\": \"office365\", \"Microsoft Power Aut\u2026\": \"office365\",\n  Microsoft: \"microsoft\",\n};\nfunction AppAvatar({ name, size = 22 }) {\n  const brand = APP_LOGO_MAP[name];\n  if (brand) return ;\n  const s = name || \"?\"; let n = 0; for (let i = 0; i &lt; s.length; i++) n = (n * 31 + s.charCodeAt(i)) &gt;&gt;&gt; 0;\n  const t = TAGV[n % TAGV.length];\n  return {s.trim()[0] || \"?\"};\n}\nconst STATUS = { Active: T.green, Warning: T.viz.amber, Inactive: T.faint, Error: T.red };\nfunction StatusChip({ status }) {\n  return {status};\n}\nconst RISK = { Critical: SEVC.critical, High: SEVC.high, Medium: SEVC.medium, Low: SEVC.low };\nfunction RiskChip({ level }) {\n  const c = RISK[level];\n  return {level};\n}\nfunction Delta({ up, children }) {\n  const color = up ? T.green : T.red;\n  return {up ?  : }{children};\n}\nfunction IconBtn({ children, onClick }) {\n  const [h, setH] = useState(false);\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ width: 26, height: 26, borderRadius: 6, border: \"none\", cursor: \"pointer\", background: h ? T.surface2 : \"transparent\", color: h ? T.ink : T.faint, display: \"flex\", alignItems: \"center\", justifyContent: \"center\" }}&gt;{children};\n}\n\n/* ============ KPIs ============ */\nconst KPIS = [\n  { label: \"Total Assets\", value: 84355, delta: \"12.4%\", up: true },\n  { label: \"Cloud Coverage\", value: 96.2, suffix: \"%\", delta: \"2.1%\", up: true },\n  { label: \"Open Vulnerabilities\", value: 382, delta: \"8.0%\", up: false },\n  { label: \"Unmanaged Devices\", value: 1204, delta: \"3.2%\", up: false },\n];\nfunction useCountUp(target, dur = 950) {\n  const [v, setV] = useState(0);\n  useEffect(() =&gt; {\n    let raf; const start = performance.now();\n    const tick = (now) =&gt; { const p = Math.min(1, (now - start) / dur); setV(target * (1 - Math.pow(1 - p, 3))); if (p &lt; 1) raf = requestAnimationFrame(tick); };\n    raf = requestAnimationFrame(tick); return () =&gt; cancelAnimationFrame(raf);\n  }, [target]);\n  return v;\n}\nfunction KpiValue({ value, suffix }) {\n  const v = useCountUp(value);\n  const text = suffix === \"%\" ? v.toFixed(1) : fmt(Math.round(v));\n  return {text}{suffix || \"\"};\n}\nfunction KpiRow() {\n  return (\n    \n\n      {KPIS.map((k, i) =&gt; (\n        \n\n          \n{k.label}\n          \n\n            \n            {k.delta}\n          \n        \n      ))}\n    \n  );\n}\n\n/* ============ chart bodies ============ */\nconst PIE = [\n  { c: \"green\", label: \"Windows Assets\", val: 1236 }, { c: \"greenDeep\", label: \"Active Directory\", val: 411 },\n  { c: \"mint\", label: \"SCCM Managed\", val: 198 }, { c: \"lilac\", label: \"Intune Managed\", val: 89 }, { c: \"lilacPale\", label: \"Unmanaged\", val: 43 },\n];\nfunction DonutBody() {\n  const [hi, setHi] = useState(null);\n  const [tip, setTip] = useState(null);\n  const [off, setOff] = useState(() =&gt; new Set());\n  const [drawn, setDrawn] = useState(false);\n  useEffect(() =&gt; { const id = setTimeout(() =&gt; setDrawn(true), 60); return () =&gt; clearTimeout(id); }, []);\n  const r = 46, sw = 14, C = 2 * Math.PI * r, gap = 5;\n  const toggle = (i) =&gt; setOff(s =&gt; { const n = new Set(s); n.has(i) ? n.delete(i) : n.add(i); return n; });\n  const visTotal = PIE.reduce((a, p, i) =&gt; a + (off.has(i) ? 0 : p.val), 0) || 1;\n  let acc = 0;\n  const segs = PIE.map((p, i) =&gt; {\n    if (off.has(i)) return null;\n    const len = (p.val / visTotal) * C;\n    const seg = Math.max(1, len - gap);\n    const active = hi === i, dim = hi !== null &amp;&amp; !off.has(hi) &amp;&amp; !active;\n    const node = (\n       { setHi(i); setTip({ i, x: e.clientX, y: e.clientY }); }} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; { setHi(null); setTip(null); }} onClick={() =&gt; toggle(i)}\n        style={{ opacity: dim ? 0.35 : 1, cursor: \"pointer\", transition: \"stroke-dasharray .8s cubic-bezier(.22,1,.36,1), stroke-width .18s ease, opacity .18s ease\" }} /&gt;\n    );\n    acc += len; return node;\n  });\n  const liveHi = hi !== null &amp;&amp; !off.has(hi);\n  const center = liveHi ? { big: ((PIE[hi].val / visTotal) * 100).toFixed(1) + \"%\", small: PIE[hi].label } : { big: fmt(visTotal), small: \"Total Assets\" };\n  return (\n    \n\n      \n\n        \n          \n          {segs}\n        \n        \n\n          {center.big}\n          {center.small}\n        \n      \n      \n\n        {PIE.map((p, i) =&gt; {\n          const isOff = off.has(i);\n          return (\n            \n { setHi(i); if (!isOff) setTip({ i, x: e.clientX, y: e.clientY }); }} onMouseMove={(e) =&gt; !isOff &amp;&amp; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; { setHi(null); setTip(null); }} onClick={() =&gt; toggle(i)}\n              title={isOff ? \"Click to show\" : \"Click to hide\"}\n              style={{ display: \"flex\", alignItems: \"center\", gap: 9, padding: \"5px 6px\", borderRadius: 6, cursor: \"pointer\", background: hi === i &amp;&amp; !isOff ? T.canvas : \"transparent\", transition: \"background .12s\" }}&gt;\n              \n              {p.label}\n              {isOff ? \"Hidden\" : (hi === i ? fmt(p.val) : ((p.val / visTotal) * 100).toFixed(1) + \"%\")}\n            \n          );\n        })}\n      \n      {tip !== null &amp;&amp; !off.has(tip.i) &amp;&amp; \n        \n{PIE[tip.i].label}\n        \n{fmt(PIE[tip.i].val)}\n        \n{(PIE[tip.i].val / visTotal * 100).toFixed(1)}% of assets\n      }\n    \n  );\n}\nconst LINE_LABELS = [\"W1\", \"W2\", \"W3\", \"W4\", \"W5\", \"W6\", \"W7\", \"W8\", \"W9\", \"W10\", \"W11\", \"W12\"];\nconst LINE_SERIES = [\n  { key: \"all\", label: \"All Devices\", color: T.viz.green, pts: [38000, 41200, 44500, 47800, 51000, 55300, 59800, 63200, 68500, 72100, 78400, 84355] },\n  { key: \"managed\", label: \"Managed\", color: T.viz.lilac, pts: [29000, 31000, 33500, 35800, 38000, 41000, 44500, 47200, 50500, 54100, 58400, 61200] },\n  { key: \"cloud\", label: \"Cloud\", color: T.viz.orange, pts: [8000, 9200, 10500, 11800, 13000, 14300, 15800, 17200, 18500, 20100, 21400, 22097] },\n  { key: \"unmanaged\", label: \"Unmanaged\", color: T.viz.greenDeep, pts: [3200, 3100, 3300, 3000, 3500, 3300, 3100, 2900, 2700, 2500, 2300, 2100] },\n];\nfunction LineBody() {\n  const [off, setOff] = useState(() =&gt; new Set());\n  const [hov, setHov] = useState(null);\n  const w = 680, h = 196, padT = 12, padB = 12, padL = 8, padR = 8, n = LINE_LABELS.length, max = 90000;\n  const yAxisW = 40;\n  const X = (i) =&gt; padL + (i / (n - 1)) * (w - padL - padR);\n  const Y = (v) =&gt; padT + (1 - v / max) * (h - padT - padB);\n  const smooth = (pts) =&gt; { let d = `M ${X(0)} ${Y(pts[0])}`; for (let i = 1; i &lt; n; i++) { const cx = (X(i - 1) + X(i)) / 2; d += ` C ${cx} ${Y(pts[i - 1])}, ${cx} ${Y(pts[i])}, ${X(i)} ${Y(pts[i])}`; } return d; };\n  const toggle = (k) =&gt; setOff(s =&gt; { const x = new Set(s); x.has(k) ? x.delete(k) : x.add(k); return x; });\n  const visible = LINE_SERIES.filter(s =&gt; !off.has(s.key));\n  const xPct = (i) =&gt; (X(i) / w) * 100, yPct = (v) =&gt; (Y(v) / h) * 100;\n  const yTicks = [90000, 60000, 30000, 0];\n  return (\n    \n\n      \n\n        {/* Y-axis labels */}\n        \n\n          {yTicks.map((v, i) =&gt; (\n            {v === 0 ? \"0\" : (v / 1000) + \"K\"}\n          ))}\n        \n        {/* Chart area */}\n        \n setHov(null)}&gt;\n          \n            {yTicks.map((v, i) =&gt; )}\n            {hov &amp;&amp; }\n            {visible.map(s =&gt; )}\n          \n          {visible.map(s =&gt; s.pts.map((v, i) =&gt; {\n            const isHov = hov &amp;&amp; hov.s.key === s.key &amp;&amp; hov.i === i, dim = hov &amp;&amp; !isHov;\n            return (\n              \n setHov({ s, i })}\n                style={{ position: \"absolute\", left: `${xPct(i)}%`, top: `${yPct(v)}%`, transform: \"translate(-50%, -50%)\", width: 20, height: 20, display: \"flex\", alignItems: \"center\", justifyContent: \"center\", cursor: \"pointer\", zIndex: isHov ? 4 : 2 }}&gt;\n                \n              \n            );\n          }))}\n          {hov &amp;&amp; (\n            \n n - 4 ? \"calc(-100% - 12px)\" : hov.i &lt; 3 ? \"12px\" : \"-50%\"}, calc(-100% - 14px))`, background: T.surface, border: `1px solid ${T.line}`, borderRadius: 10, boxShadow: T.shadow, padding: \"9px 12px\", whiteSpace: \"nowrap\", pointerEvents: \"none\", zIndex: 6 }}&gt;\n              \n{hov.s.label}\n              \n{fmt(hov.s.pts[hov.i])}\n              {hov.i &gt; 0 &amp;&amp; (() =&gt; { const pct = (hov.s.pts[hov.i] - hov.s.pts[hov.i - 1]) / hov.s.pts[hov.i - 1] * 100; const up = pct &gt;= 0; return \n{up ?  : }{up ? \"+\" : \"\"}{pct.toFixed(1)}% from prev; })()}\n              \n{LINE_LABELS[hov.i]}\n            \n          )}\n        \n      \n      {/* X-axis labels */}\n      \n\n        {LINE_LABELS.map((label, i) =&gt; (\n          \n{i % 3 === 0 ? label : \"\"}\n        ))}\n      \n      \n\n        {LINE_SERIES.map(s =&gt; {\n          const isOff = off.has(s.key);\n          return (\n             toggle(s.key)} title={isOff ? \"Show series\" : \"Hide series\"} className=\"ax-press\"\n              style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6, padding: \"3px 9px\", borderRadius: 999, border: `1px solid ${isOff ? T.lineSoft : T.line}`, background: isOff ? \"transparent\" : T.canvas, cursor: \"pointer\", fontFamily: T.font, fontSize: 11.5, fontWeight: 500, color: isOff ? T.faint : T.body, transition: \"all .14s\" }}&gt;\n              \n              {s.label}\n            \n          );\n        })}\n      \n    \n  );\n}\nconst STACK_DATA = [[\"Jan\", 40, 25, 20], [\"Feb\", 35, 30, 15], [\"Mar\", 52, 22, 26], [\"Apr\", 30, 35, 18], [\"May\", 48, 28, 24], [\"Jun\", 58, 32, 28]];\nconst STACK_SERIES = [\n  { key: \"cloud\", label: \"Cloud\", color: T.viz.green },\n  { key: \"onprem\", label: \"On-prem\", color: T.viz.mint },\n  { key: \"saas\", label: \"SaaS\", color: T.viz.lilac },\n];\nfunction StackedBody() {\n  const [off, setOff] = useState(() =&gt; new Set());\n  const [segHov, setSegHov] = useState(null);\n  const [tip, setTip] = useState(null);\n  const toggle = (key) =&gt; setOff(s =&gt; { const n = new Set(s); n.has(key) ? n.delete(key) : n.add(key); return n; });\n  const visSeries = STACK_SERIES.filter(s =&gt; !off.has(s.key));\n  const yAxisW = 34;\n  const allTotals = STACK_DATA.map(row =&gt; visSeries.reduce((sum, s) =&gt; sum + row[STACK_SERIES.findIndex(s2 =&gt; s2.key === s.key) + 1], 0));\n  const rawMax = Math.max(...allTotals, 1);\n  const yMax = Math.ceil(rawMax / 20) * 20;\n  const yTicks = [yMax, yMax * 0.75, yMax * 0.5, yMax * 0.25, 0];\n  const tipContent = tip &amp;&amp; segHov ? (() =&gt; {\n    const row = STACK_DATA[segHov.col];\n    const s = STACK_SERIES.find(s =&gt; s.key === segHov.key);\n    const idx = STACK_SERIES.findIndex(s2 =&gt; s2.key === segHov.key);\n    const val = row[idx + 1] * 86;\n    const totalVis = visSeries.reduce((sum, ss) =&gt; sum + row[STACK_SERIES.findIndex(s2 =&gt; s2.key === ss.key) + 1], 0);\n    const pct = (row[idx + 1] / (totalVis || 1) * 100).toFixed(1);\n    return { label: s.label, color: s.color, val, pct, month: row[0] };\n  })() : null;\n  return (\n    \n\n      {tip &amp;&amp; tipContent &amp;&amp; \n        \n{tipContent.month}\n        \n{tipContent.label}\n        \n{fmt(tipContent.val)}\n        \n{tipContent.pct}% of total\n      }\n      \n\n        {/* Y-axis */}\n        \n\n          {yTicks.map((v, i) =&gt; (\n            {v === 0 ? \"0\" : v + \"K\"}\n          ))}\n        \n        {/* Bars */}\n        \n\n          \n\n            {yTicks.map((v, i) =&gt; (\n              \n\n            ))}\n            {STACK_DATA.map((row, ci) =&gt; {\n              const total = visSeries.reduce((sum, s) =&gt; sum + row[STACK_SERIES.findIndex(s2 =&gt; s2.key === s.key) + 1], 0);\n              const colHov = segHov?.col === ci;\n              const dim = segHov &amp;&amp; !colHov;\n              return (\n                \n\n                  \n\n                    {visSeries.map((s, si) =&gt; {\n                      const val = row[STACK_SERIES.findIndex(s2 =&gt; s2.key === s.key) + 1];\n                      const isFirst = si === 0, isLast = si === visSeries.length - 1;\n                      const isHov = segHov?.col === ci &amp;&amp; segHov?.key === s.key;\n                      return (\n                        \n { setSegHov({ col: ci, key: s.key }); setTip({ x: e.clientX, y: e.clientY }); }}\n                          onMouseMove={(e) =&gt; setTip({ x: e.clientX, y: e.clientY })}\n                          onMouseLeave={() =&gt; { setSegHov(null); setTip(null); }}\n                          style={{ flex: val, background: s.color, borderRadius: isFirst ? \"6px 6px 0 0\" : isLast ? \"0 0 6px 6px\" : 0, filter: isHov ? \"brightness(1.18)\" : \"none\", transition: \"filter .15s\", cursor: \"pointer\" }} /&gt;\n                      );\n                    })}\n                  \n                  {row[0]}\n                \n              );\n            })}\n          \n        \n      \n      {/* Clickable legend */}\n      \n\n        {STACK_SERIES.map(s =&gt; {\n          const isOff = off.has(s.key);\n          return (\n             toggle(s.key)} className=\"ax-press\"\n              style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6, padding: \"3px 9px\", borderRadius: 999, border: `1px solid ${isOff ? T.lineSoft : T.line}`, background: isOff ? \"transparent\" : T.canvas, cursor: \"pointer\", fontFamily: T.font, fontSize: 11.5, fontWeight: 500, color: isOff ? T.faint : T.body, transition: \"all .14s\" }}&gt;\n              \n              {s.label}\n            \n          );\n        })}\n      \n    \n  );\n}\nconst SEV = [[\"Critical\", 142, 100, SEVC.critical], [\"High\", 98, 70, SEVC.high], [\"Medium\", 76, 54, SEVC.medium], [\"Low\", 45, 32, SEVC.low], [\"Info\", 21, 15, SEVC.info]];\nconst SEV_ASSETS = {\n  Critical: [[\"PC-CURTIS-WILLIAMS\", \"CVE-2024-21412 \u00b7 SmartScreen bypass\"], [\"srv-db-fin-04\", \"CVE-2024-3094 \u00b7 xz-utils backdoor\"], [\"esx-infranginx-5567897\", \"CVE-2023-46604 \u00b7 ActiveMQ RCE\"], [\"WIN-RUTHD\", \"CVE-2024-21413 \u00b7 Outlook RCE\"]],\n  High: [[\"macbook-pro-jdoe\", \"CVE-2024-23222 \u00b7 WebKit type confusion\"], [\"azure-infra9274676\", \"CVE-2024-21401 \u00b7 Entra ID elevation\"], [\"lablb-2918146-beta\", \"CVE-2024-1709 \u00b7 ScreenConnect auth bypass\"]],\n  Medium: [[\"iphone-asmith\", \"CVE-2024-23225 \u00b7 kernel memory\"], [\"sepio-external3026786\", \"CVE-2024-0519 \u00b7 V8 out-of-bounds\"]],\n  Low: [[\"android-pixel-7\", \"CVE-2024-0039 \u00b7 System component\"]],\n  Info: [[\"win-marychasse\", \"Informational \u00b7 TLS 1.0 enabled\"]],\n};\nfunction SeverityDrawer({ sev, close }) {\n  const list = SEV_ASSETS[sev[0]] || [];\n  return createPortal(&lt;&gt;\n    \n\n    \n\n      \n\n        \n        \n\n          \n{sev[0]} severity\n          \n{sev[1]} open vulnerabilities \u00b7 {list.length} assets shown\n        \n        \n      \n      \n\n        {list.map(([host, cve], i) =&gt; (\n          \n\n            \n\n              {host}\n              {sev[0]}\n            \n            {cve}\n          \n        ))}\n      \n      \n\n        View all {sev[1]} in Inventory\n      \n    \n  , document.body);\n}\nfunction SeverityBody() {\n  const [hi, setHi] = useState(null);\n  const [drill, setDrill] = useState(null);\n  const [tip, setTip] = useState(null);\n  const sevTotal = SEV.reduce((a, b) =&gt; a + b[1], 0);\n  return (&lt;&gt;\n    \n\n      {SEV.map((b, i) =&gt; {\n        const active = hi === i, dim = hi !== null &amp;&amp; !active;\n        return (\n          \n setDrill(b)} onMouseEnter={(e) =&gt; { setHi(i); setTip({ i, x: e.clientX, y: e.clientY }); }} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; { setHi(null); setTip(null); }}\n            style={{ display: \"flex\", alignItems: \"center\", gap: 12, opacity: dim ? 0.5 : 1, transition: \"opacity .15s\", cursor: \"pointer\" }}&gt;\n            {b[0]}\n            \n\n\n            {active ? b[1] + \" open\" : b[1]}\n          \n        );\n      })}\n    \n    {tip &amp;&amp; \n{SEV[tip.i][0]}\n{fmt(SEV[tip.i][1])}\n{Math.round(SEV[tip.i][1] / sevTotal * 100)}% of open findings}\n    {drill &amp;&amp;  setDrill(null)} /&gt;}\n  );\n}\nconst ST_COLOR = { ok: T.viz.green, warn: T.viz.amber, err: T.red };\n\n/* ===== System Lifecycle (discovery cycle) ===== */\nconst LIFECYCLE = [\n  { name: \"Fetch\", pct: 100 }, { name: \"Clean\", pct: 100 }, { name: \"Correlate\", pct: 100 },\n  { name: \"Enrich\", pct: 78 }, { name: \"Calculate\", pct: 0 },\n];\nfunction LifecycleBody() {\n  const [tip, setTip] = useState(null);\n  const done = LIFECYCLE.filter(s =&gt; s.pct === 100).length, total = LIFECYCLE.length;\n  const overall = Math.round(LIFECYCLE.reduce((a, s) =&gt; a + s.pct, 0) / total);\n  const r = 42, sw = 11, C = 2 * Math.PI * r, dash = (overall / 100) * C;\n  return (\n    \n\n      {tip &amp;&amp; \n{LIFECYCLE[tip.i].name} stage\n{LIFECYCLE[tip.i].pct &gt; 0 ? LIFECYCLE[tip.i].pct + \"% complete\" : \"Not started\"}}\n      \n\n        \n\n          \n            \n            \n          \n          \n\n            {done}/{total}\n            Stages\n          \n        \n        \n\n          {LIFECYCLE.map((s, i) =&gt; {\n            const c = s.pct === 100 ? T.viz.green : s.pct &gt; 0 ? T.blue : T.bg40;\n            return (\n              \n setTip({ i, x: e.clientX, y: e.clientY })} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; setTip(null)} style={{ display: \"flex\", alignItems: \"center\", gap: 10, cursor: \"default\" }}&gt;\n                {s.name}\n                \n\n                  \n\n                \n                 0 ? T.blue : T.bg40, ...tnum }}&gt;{s.pct &gt; 0 ? s.pct + \"%\" : \"\u2014\"}\n              \n            );\n          })}\n        \n      \n      \n\n        {[[\"Cycle started\", \"09:00:04\"], [\"Duration\", \"00:42:18\"], [\"Next cycle\", \"13:17:42\"]].map(([k, v], i) =&gt; (\n          \n\n            \n{k}\n            \n{v}\n          \n        ))}\n      \n    \n  );\n}\n\n/* ===== Discovery Log ===== */\nconst DISC_PHASES = [[\"Fetch\", T.viz.green], [\"Clean\", T.viz.mint], [\"Correlate\", T.viz.lilac], [\"Enrich\", T.viz.lilacPale], [\"Calculate\", T.viz.amber], [\"Save\", T.viz.orange]];\nconst DISCOVERY = [\n  { started: \"Jun 15, 09:00\", completed: \"Jun 15, 09:35\", duration: \"35min 22sec\", ph: [40, 12, 18, 10, 12, 8] },\n  { started: \"Jun 14, 09:00\", completed: \"Jun 14, 09:35\", duration: \"35min 59sec\", ph: [38, 14, 17, 11, 12, 8] },\n  { started: \"Jun 13, 09:00\", completed: \"Jun 13, 09:35\", duration: \"35min 29sec\", ph: [41, 11, 18, 10, 12, 8] },\n  { started: \"Jun 12, 09:00\", completed: \"Jun 12, 09:35\", duration: \"35min 11sec\", ph: [39, 13, 17, 11, 12, 8] },\n  { started: \"Jun 11, 09:00\", completed: \"Jun 11, 09:35\", duration: \"35min 58sec\", ph: [44, 12, 16, 9, 11, 8] },\n  { started: \"Jun 10, 09:00\", completed: \"Jun 10, 09:30\", duration: \"30min 54sec\", ph: [36, 12, 18, 12, 14, 8] },\n  { started: \"Jun 9, 09:00\", completed: \"Jun 9, 09:34\", duration: \"34min 02sec\", ph: [37, 13, 17, 11, 13, 9] },\n  { started: \"Jun 8, 09:00\", completed: \"Jun 8, 09:31\", duration: \"31min 38sec\", ph: [40, 12, 17, 10, 13, 8] },\n];\nfunction DiscoveryBody() {\n  const [hi, setHi] = useState(null);\n  const [tip, setTip] = useState(null);\n  const cols = \"minmax(70px, 1.6fr) 104px 92px\";\n  const durToSec = (s) =&gt; { let t = 0; const m = s.match(/(\\d+)\\s*min/), sec = s.match(/(\\d+)\\s*sec/); if (m) t += +m[1] * 60; if (sec) t += +sec[1]; return t; };\n  const fmtDur = (x) =&gt; { x = Math.round(x); const m = Math.floor(x / 60), s = x % 60; return m &gt; 0 ? `${m}min ${s}sec` : `${s}sec`; };\n  return (\n    \n\n      \n\n        {[\"Latest Discoveries\", \"Started\", \"Duration\"].map((c, i) =&gt; (\n          {c}\n        ))}\n      \n      \n\n        {DISCOVERY.map((d, i) =&gt; (\n          \n setHi(i)} onMouseLeave={() =&gt; { setHi(null); setTip(null); }}\n            style={{ display: \"grid\", gridTemplateColumns: cols, gap: 12, alignItems: \"center\", padding: \"7px 6px\", borderBottom: i &lt; DISCOVERY.length - 1 ? `1px solid ${T.hair}` : \"none\", background: hi === i ? T.canvas : \"transparent\", borderRadius: 6, transition: \"background .12s\" }}&gt;\n            \n\n              {d.ph.map((w, j) =&gt;  setTip({ d, j, x: e.clientX, y: e.clientY })} onMouseMove={(e) =&gt; setTip({ d, j, x: e.clientX, y: e.clientY })}\n                style={{ width: `${w}%`, height: \"100%\", background: DISC_PHASES[j][1], cursor: \"pointer\" }} /&gt;)}\n            \n            {d.started}\n            {d.duration}\n          \n        ))}\n      \n      {tip &amp;&amp; \n        \n{DISC_PHASES[tip.j][0]}\n        \n{fmtDur(durToSec(tip.d.duration) * tip.d.ph[tip.j] / 100)}\n        \n{tip.d.ph[tip.j]}% of cycle\n      }\n    \n  );\n}\n\n/* ===== Adapter Connections (status + logo coin + preview) ===== */\nconst ADAPTER_CONN = [\n  { brand: \"crowdstrike\", name: \"CrowdStrike\", st: \"ok\", desc: \"9,120 devices \u00b7 synced 4m ago\" },\n  { brand: \"aws\", name: \"Amazon Web Services\", st: \"ok\", desc: \"12,400 assets \u00b7 synced 6m ago\" },\n  { brand: \"azure\", name: \"Microsoft Azure\", st: \"ok\", desc: \"22,097 assets \u00b7 synced 5m ago\" },\n  { brand: \"okta\", name: \"Okta\", st: \"ok\", desc: \"9,870 users \u00b7 synced 8m ago\" },\n  { short: \"Jm\", color: \"#3B3B3B\", name: \"Jamf Pro\", st: \"err\", desc: \"Connection timeout \u2014 check credentials\" },\n  { short: \"now\", color: \"#2E8B57\", name: \"ServiceNow\", st: \"warn\", desc: \"Rate limited \u00b7 retrying\" },\n  { brand: \"googlecloud\", name: \"Google Cloud\", st: \"ok\", desc: \"9,055 assets \u00b7 synced 7m ago\" },\n  { brand: \"vmware\", name: \"VMware vCenter\", st: \"ok\", desc: \"4,310 VMs \u00b7 synced 11m ago\" },\n];\nconst ST_LABEL = { ok: \"Connected\", warn: \"Degraded\", err: \"Error\" };\nfunction AdapterCoin({ a }) {\n  if (a.brand) return ;\n  return {a.short};\n}\nfunction AdaptersBody() {\n  const connected = ADAPTER_CONN.filter(a =&gt; a.st === \"ok\").length;\n  const attention = ADAPTER_CONN.length - connected;\n  return (\n    \n\n      \n\n        {connected}\n        connected sources\n        {attention &gt; 0 &amp;&amp; {attention} need attention}\n      \n      \n\n        {ADAPTER_CONN.map((a, i) =&gt; {\n          const ring = ST_COLOR[a.st];\n          return (\n            \n\n              \n              \n\n                \n{a.name}\n                \n\n                  \n                  {a.desc}\n                \n              \n            \n          );\n        })}\n      \n    \n  );\n}\nconst HEALTH_OK_BRANDS = [\"crowdstrike\", \"aws\", \"azure\", \"okta\", \"googlecloud\", \"vmware\"];\nfunction HealthOkBody() {\n  return (\n    \n\n      \n\n        33\n        adapters syncing successfully\n      \n      \n\n        {HEALTH_OK_BRANDS.map((b, i) =&gt; )}\n        +27\n      \n      \n\n         100% healthy \u00b7 last full sync 4m ago\n      \n    \n  );\n}\nconst HEALTH_FAIL = [\n  { short: \"Jm\", color: \"#3B3B3B\", name: \"Jamf Pro\", reason: \"Connection timeout \u2014 check credentials\" },\n  { short: \"now\", color: \"#2E8B57\", name: \"ServiceNow\", reason: \"Rate limited \u00b7 retrying\" },\n];\nfunction HealthFailBody() {\n  return (\n    \n\n      \n\n        {HEALTH_FAIL.length}\n        adapters need attention\n      \n      \n\n        {HEALTH_FAIL.map((a, i) =&gt; (\n          \n\n            {a.short}\n            \n\n              \n{a.name}\n              \n{a.reason}\n            \n            Fix\n          \n        ))}\n      \n    \n  );\n}\n/* ===== Cost Optimization dashboard ===== */\nconst fmtMoney = (n) =&gt; n.toLocaleString(\"en-US\");\nfunction CostKPI({ value, unit }) {\n  return (\n    \n\n      {value}\n      {unit &amp;&amp; {unit}}\n    \n  );\n}\nfunction HBarList({ rows, accent, prefix, avatar, appLogo }) {\n  const max = Math.max(...rows.map(r =&gt; r[1]), 1);\n  const totalVal = rows.reduce((a, r) =&gt; a + r[1], 0) || 1;\n  const [tip, setTip] = useState(null);\n  return (\n    \n\n      {rows.map(([label, val], i) =&gt; {\n        const pct = Math.max(4, (val / max) * 100), inside = pct &gt; 24;\n        return (\n          \n setTip({ i, x: e.clientX, y: e.clientY })} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; setTip(null)}\n            style={{ display: \"flex\", alignItems: \"center\", gap: 12, cursor: \"default\" }}&gt;\n            {avatar &amp;&amp; }{appLogo &amp;&amp; }{label}\n            \n\n              \n\n                {inside &amp;&amp; {prefix || \"\"}{fmtMoney(val)}}\n              \n              {!inside &amp;&amp; {prefix || \"\"}{fmtMoney(val)}}\n            \n          \n        );\n      })}\n      {tip &amp;&amp; \n        \n{rows[tip.i][0]}\n        \n{prefix || \"\"}{fmtMoney(rows[tip.i][1])}\n        \n{(rows[tip.i][1] / totalVal * 100).toFixed(1)}% of shown total\n      }\n    \n  );\n}\nconst COST_CATEGORY = [[\"Productivity\", 141993], [\"Video Conference\", 55928], [\"File Sharing\", 52943], [\"Authentication\", 11440], [\"CRM\", 9870]];\nconst COST_APP = [[\"Zoom\", 55928], [\"Miro\", 52885], [\"Dropbox\", 50431], [\"Salesforce\", 43176], [\"Slack\", 38420]];\nconst COST_TOPLIC = [[\"Zoom One Pro\", 70800], [\"Google WS Ent. Starter\", 27450], [\"Google WS Ent. Standard\", 12985], [\"Google WS Business\", 8640], [\"Microsoft 365 G3 GCC\", 1930]];\nconst COST_USAGE = [[\"aaron.church@demo.local\", 29], [\"aaron.daniels@demo.local\", 29], [\"ada.pires@demo.local\", 29], [\"adelaide.gercak@demo.local\", 29], [\"adrian.williams@demo.local\", 29]];\nconst COST_RENEWALS = [\n  { app: \"Office365\", name: \"Microsoft 365 E5\", date: \"2026-07-06\", cost: \"3,175.50\", term: \"Yearly\", unit: \"54.75\" },\n  { app: \"Office365\", name: \"Microsoft Power Aut\u2026\", date: \"2026-08-07\", cost: \"6,518.75\", term: \"Yearly\", unit: \"37.25\" },\n];\nfunction CostExpAllBody() { return ; }\nfunction CostLicAllBody() { return ; }\nfunction CostExp2024Body() { return ; }\nfunction CostLicTotalBody() { return ; }\nfunction CostCategoryBody() { return ; }\nfunction CostAppBody() { return ; }\nfunction CostTopLicBody() { return ; }\nfunction CostUsageBody() { return ; }\nfunction CostRenewalsBody() {\n  const cols = [\n    { label: \"Application\", render: r =&gt; {r.app} },\n    { label: \"Name\", render: r =&gt; {r.name} },\n    { label: \"Renewal Date\", render: r =&gt; {r.date} },\n    { label: \"Total Cost\", align: \"right\", render: r =&gt; ${r.cost} },\n    { label: \"Term\", render: r =&gt; {r.term} },\n    { label: \"Unit\", align: \"right\", render: r =&gt; ${r.unit} },\n  ];\n  return (\n    \n\n      \n\n        \n          \n            {cols.map((c, i) =&gt; {c.label})}\n          \n        \n        \n          {COST_RENEWALS.map((r, ri) =&gt; (\n            \n              {cols.map((c, i) =&gt; {c.render(r)})}\n            \n          ))}\n        \n      \n    \n  );\n}\nfunction ResetViewBtn({ disabled, onReset }) {\n  const [h, setH] = useState(false);\n  return (\n     setH(true)} onMouseLeave={() =&gt; setH(false)}\n      title={disabled ? \"Layout is at its default\" : \"Restore the default tile layout\"}\n      style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6, height: 30, padding: \"0 13px\", borderRadius: 999, fontFamily: T.font, fontSize: 13, fontWeight: 600, cursor: disabled ? \"default\" : \"pointer\", border: `1px solid ${disabled ? T.lineSoft : h ? T.lineStrong : T.line}`, background: disabled ? \"transparent\" : h ? T.surface2 : T.control, color: disabled ? T.faint : T.body, transition: \"all .14s\" }}&gt;\n       Reset view\n    \n  );\n}\n\nconst TILE_META = {\n  line: { eyebrow: \"Activity\", title: \"Device Discovery Over Time\", Body: LineBody },\n  donut: { eyebrow: \"Composition\", title: \"Windows Distribution\", Body: DonutBody },\n  lifecycle: { eyebrow: \"Pipeline\", title: \"System Lifecycle\", Body: LifecycleBody },\n  discovery: { eyebrow: \"Activity\", title: \"Discovery Log\", Body: DiscoveryBody },\n  adapters: { eyebrow: \"Connections\", title: \"Adapter Connections\", Body: AdaptersBody },\n  stacked: { eyebrow: \"Trend\", title: \"Asset Growth by Category\", Body: StackedBody, footer: 12.4% },\n  severity: { eyebrow: \"Risk\", title: \"Vulnerabilities by Severity\", Body: SeverityBody, footer: 18 resolved },\n  healthOk: { eyebrow: \"Adapters\", title: \"Adapter Health \u00b7 Successful\", Body: HealthOkBody },\n  healthFail: { eyebrow: \"Adapters\", title: \"Adapter Health \u00b7 Attention\", Body: HealthFailBody },\n  costExpAll: { eyebrow: \"Spend\", title: \"Total Expenses (All Time)\", Body: CostExpAllBody },\n  costExp2024: { eyebrow: \"Spend\", title: \"Total Expenses (2024)\", Body: CostExp2024Body },\n  costLicAll: { eyebrow: \"Licenses\", title: \"Total License Cost (All Time)\", Body: CostLicAllBody },\n  costLicTotal: { eyebrow: \"Licenses\", title: \"Total License Cost\", Body: CostLicTotalBody },\n  costRenewals: { eyebrow: \"Renewals\", title: \"Upcoming Renewals (next 90 days)\", Body: CostRenewalsBody, footer: View all results, noPad: true },\n  costCategory: { eyebrow: \"Spend\", title: \"Expenses by Category (2024)\", Body: CostCategoryBody },\n  costApp: { eyebrow: \"Spend\", title: \"Expenses by App (2024)\", Body: CostAppBody },\n  costTopLic: { eyebrow: \"Licenses\", title: \"Most Expensive Licenses (2024)\", Body: CostTopLicBody },\n  costUsage: { eyebrow: \"Usage\", title: \"Azure AD Logons \u00b7 last 30 days\", Body: CostUsageBody },\n};\n\n/* ============ resizable grid (corner drag, neighbors reflow) ============ */\nconst GRID_COLS = 12, ROW_UNIT = 40, GAP = 16;\nconst INITIAL_TILES = [\n  { id: \"line\", w: 8, h: 7 }, { id: \"donut\", w: 4, h: 7 },\n  { id: \"lifecycle\", w: 5, h: 7 }, { id: \"discovery\", w: 7, h: 7 },\n  { id: \"adapters\", w: 7, h: 6 }, { id: \"severity\", w: 5, h: 6 },\n  { id: \"healthOk\", w: 6, h: 5 }, { id: \"healthFail\", w: 6, h: 5 },\n  { id: \"stacked\", w: 12, h: 5 },\n];\nconst COST_TILES = [\n  { id: \"costExpAll\", w: 3, h: 4 }, { id: \"costExp2024\", w: 3, h: 4 }, { id: \"costLicAll\", w: 3, h: 4 }, { id: \"costLicTotal\", w: 3, h: 4 },\n  { id: \"costRenewals\", w: 12, h: 6 },\n  { id: \"costCategory\", w: 6, h: 6 }, { id: \"costApp\", w: 6, h: 6 },\n  { id: \"costTopLic\", w: 6, h: 6 }, { id: \"costUsage\", w: 6, h: 6 },\n];\nconst DASH_TILESETS = { \"Cost Optimization\": COST_TILES };\nfunction DashboardGrid({ tileSet = INITIAL_TILES }) {\n  const [tiles, setTiles] = useState(tileSet);\n  const [hoverId, setHoverId] = useState(null);\n  const [resizingId, setResizingId] = useState(null);\n  const [drag, setDrag] = useState(null);\n  const dragId = drag ? drag.id : null;\n  const ref = useRef(null);\n  const tileEls = useRef({});\n  const justDragged = useRef(false);\n\n  const startDrag = (e, id, immediate) =&gt; {\n    if (e.button || (e.target.closest &amp;&amp; (e.target.closest(\"[data-resize]\") || e.target.closest(\"button\")))) return;\n    const startX = e.clientX, startY = e.clientY;\n    let dragging = false;\n    const begin = (cx, cy) =&gt; {\n      const el = tileEls.current[id]; if (!el) return;\n      const rect = el.getBoundingClientRect();\n      dragging = true;\n      setDrag({ id, x: cx, y: cy, ox: cx - rect.left, oy: cy - rect.top, w: rect.width, h: rect.height });\n      document.body.style.userSelect = \"none\";\n    };\n    const timer = immediate ? null : setTimeout(() =&gt; begin(startX, startY), 300);\n    const onMove = (ev) =&gt; {\n      if (!dragging) {\n        const moved = Math.abs(ev.clientX - startX) &gt; (immediate ? 4 : 8) || Math.abs(ev.clientY - startY) &gt; (immediate ? 4 : 8);\n        if (!moved) return;\n        if (immediate) begin(ev.clientX, ev.clientY); else { end(); return; }\n        if (!dragging) return;\n      }\n      setDrag(d =&gt; d ? { ...d, x: ev.clientX, y: ev.clientY } : d);\n      for (const tid in tileEls.current) {\n        const el = tileEls.current[tid];\n        if (!el || tid === id) continue;\n        const r = el.getBoundingClientRect();\n        if (ev.clientX &gt;= r.left &amp;&amp; ev.clientX &lt;= r.right &amp;&amp; ev.clientY &gt;= r.top &amp;&amp; ev.clientY &lt;= r.bottom) {\n          setTiles(ts =&gt; { const from = ts.findIndex(x =&gt; x.id === id), to = ts.findIndex(x =&gt; x.id === tid); if (from &lt; 0 || to &lt; 0 || from === to) return ts; const n = ts.slice(); const [mv] = n.splice(from, 1); n.splice(to, 0, mv); return n; });\n          break;\n        }\n      }\n    };\n    const end = () =&gt; { clearTimeout(timer); if (dragging) { justDragged.current = true; setTimeout(() =&gt; { justDragged.current = false; }, 60); } dragging = false; setDrag(null); document.body.style.userSelect = \"\"; window.removeEventListener(\"pointermove\", onMove); window.removeEventListener(\"pointerup\", end); };\n    window.addEventListener(\"pointermove\", onMove); window.addEventListener(\"pointerup\", end);\n  };\n\n  const startResize = (e, id) =&gt; {\n    e.preventDefault(); e.stopPropagation();\n    setResizingId(id);\n    const rect = ref.current.getBoundingClientRect();\n    const colW = (rect.width - GAP * (GRID_COLS - 1)) / GRID_COLS;\n    const t = tiles.find(x =&gt; x.id === id);\n    const startWpx = t.w * colW + (t.w - 1) * GAP;\n    const startHpx = t.h * ROW_UNIT + (t.h - 1) * GAP;\n    const sx = e.clientX, sy = e.clientY;\n    const onMove = (ev) =&gt; {\n      let w = Math.round((startWpx + (ev.clientX - sx) + GAP) / (colW + GAP));\n      let h = Math.round((startHpx + (ev.clientY - sy) + GAP) / (ROW_UNIT + GAP));\n      w = Math.max(3, Math.min(GRID_COLS, w));\n      h = Math.max(4, Math.min(14, h));\n      setTiles(ts =&gt; ts.map(x =&gt; x.id === id ? { ...x, w, h } : x));\n    };\n    const onUp = () =&gt; { setResizingId(null); document.body.style.cursor = \"\"; window.removeEventListener(\"mousemove\", onMove); window.removeEventListener(\"mouseup\", onUp); };\n    document.body.style.cursor = \"nwse-resize\";\n    window.addEventListener(\"mousemove\", onMove); window.addEventListener(\"mouseup\", onUp);\n  };\n\n  const isDefault = JSON.stringify(tiles) === JSON.stringify(tileSet);\n  return (\n    &lt;&gt;\n      \n\n         setTiles(tileSet)} /&gt;\n      \n    \n\n      {tiles.map((t, ti) =&gt; {\n        const m = TILE_META[t.id];\n        const isHover = hoverId === t.id, isResizing = resizingId === t.id, isDragging = dragId === t.id, anyDrag = dragId !== null;\n        return (\n          \n (tileEls.current[t.id] = el)}\n            onPointerDown={(e) =&gt; startDrag(e, t.id)}\n            onClickCapture={(e) =&gt; { if (justDragged.current) { e.stopPropagation(); justDragged.current = false; } }}\n            onMouseEnter={() =&gt; setHoverId(t.id)} onMouseLeave={() =&gt; setHoverId(null)}\n            style={{ gridColumn: `span ${t.w}`, gridRow: `span ${t.h}`, position: \"relative\", minWidth: 0, zIndex: 1 }}&gt;\n            {isDragging ? (\n              \n\n            ) : (&lt;&gt;\n            \n\n              \n { e.stopPropagation(); startDrag(e, t.id, true); }} title=\"Drag to move\" style={{ padding: \"13px 20px 12px\", borderBottom: `1px solid ${T.hair}`, display: \"flex\", alignItems: \"center\", gap: 8, cursor: \"grab\" }}&gt;\n                \n\n                  \n{m.eyebrow}\n                  \n{m.title}\n                \n                \n              \n              \n\n              {m.footer &amp;&amp; \n{m.footer}}\n            \n            \n startResize(e, t.id)} data-resize title=\"Drag to resize\"\n              style={{ position: \"absolute\", right: 0, bottom: 0, width: 20, height: 20, cursor: \"nwse-resize\", display: \"flex\", alignItems: \"flex-end\", justifyContent: \"flex-end\", padding: 4, opacity: isHover || isResizing ? 1 : 0, transition: \"opacity .15s\" }}&gt;\n              \n            \n            )}\n          \n        );\n      })}\n    \n    {drag &amp;&amp; (() =&gt; { const m = TILE_META[drag.id]; return createPortal(\n      \n\n        \n\n          \n\n            \n\n              \n{m.eyebrow}\n              \n{m.title}\n            \n            \n          \n          \nDrop to reorder\n        \n      , document.body); })()}\n    \n  );\n}\n\n/* ============ Assets table view (real device schema) ============ */\nconst ADAPTERS = {\n  aws_adapter: { brand: \"aws\" }, active_directory_adapter: { brand: \"active_directory\" },\n  crowd_strike_adapter: { brand: \"crowdstrike\" }, google_mdm_adapter: { brand: \"googlecloud\" },\n  esx_adapter: { brand: \"vmware\" }, sentinelone_adapter: { brand: \"sentinelone\" },\n  service_now_adapter: { brand: \"service_now\" }, epo_adapter: { brand: \"epo\" },\n  paloalto_panorama_adapter: { brand: \"paloalto\" }, cisco_meraki_adapter: { brand: \"cisco_meraki\" },\n  cisco_ise_adapter: { brand: \"cisco_ise\" }, cisco_adapter: { brand: \"cisco\" },\n  tanium_adapter: { brand: \"tanium\" }, tanium_asset_adapter: { brand: \"tanium\" },\n  claroty_adapter: { brand: \"claroty\" }, counter_act_adapter: { brand: \"forescout\" },\n  tenable_security_center_adapter: { brand: \"tenable\" }, zoom_adapter: { brand: \"zoom\" },\n  checkpoint_r80_adapter: { brand: \"checkpoint\" }, cylance_adapter: { brand: \"cylance\" },\n  chef_adapter: { brand: \"chef\" }, axonius_network_inspector_adapter: { short: \"NP\", color: \"#1C1D1F\" },\n};\nfunction AdapterAvatar({ k, size = 32 }) {\n  const a = ADAPTERS[k] || { short: k.slice(0, 2).toUpperCase(), color: \"#939598\" };\n  if (a.brand) return ;\n  return \n 28 ? 11 : 9, fontWeight: 700, color: a.color }}&gt;{a.short};\n}\nfunction AdapterStack({ list }) {\n  const shown = list.slice(0, 3), extra = list.length - shown.length;\n  return (\n    \n      \n      {shown.map((k, i) =&gt; )}\n      {extra &gt; 0 &amp;&amp; +{extra}}\n    \n  );\n}\n/* OS category icons */\nfunction OsIcon({ os }) {\n  const c = { Windows: \"#0078D4\", Linux: \"#1C1D1F\", \"OS X\": \"#555\", iOS: \"#111\", Android: \"#3DDC84\", VMWare: \"#607078\" }[os] || T.faint;\n  const mc = T.isLight ? \"#1B2030\" : \"#D6DAE6\"; // monochrome marks adapt to theme\n  const g = {\n    Windows: ,\n    \"OS X\": ,\n    iOS: ,\n    Android: ,\n    Linux: ,\n    VMWare: vm,\n  }[os];\n  if (!os) return \u2014;\n  return {g || }{os};\n}\nconst DEVICES = [\n  { name: \"PC-CURTIS-WILLIAMS\", host: \"PC-CURTIS-WILLIAMS.demo.local\", os: \"Windows\", ip: \"10.0.49.148\", mac: \"88:53:2E:12:45:C4\", seen: \"2026-06-08 09:34\", tags: [\"Corporate\", \"Managed\"], adapters: [\"active_directory_adapter\", \"crowd_strike_adapter\", \"epo_adapter\", \"google_mdm_adapter\", \"tanium_adapter\", \"sentinelone_adapter\", \"cisco_ise_adapter\"] },\n  { name: \"infranginx-5567897-stg\", host: \"esx-infranginx-5567897-stg.demo.local\", os: \"Linux\", ip: \"10.0.63.107\", mac: \"00:0C:29:12:55:38\", seen: \"2026-06-08 11:43\", tags: [\"Staging\", \"Cloud\"], adapters: [\"cisco_ise_adapter\", \"claroty_adapter\", \"counter_act_adapter\", \"epo_adapter\", \"tanium_adapter\", \"esx_adapter\", \"aws_adapter\"] },\n  { name: \"WIN-RUTHD\", host: \"WIN-RUTHD.demo.local\", os: \"Windows\", ip: \"10.0.48.107\", mac: \"88:53:2E:12:44:9B\", seen: \"2026-06-08 13:18\", tags: [\"Corporate\"], adapters: [\"active_directory_adapter\", \"cisco_adapter\", \"crowd_strike_adapter\", \"cylance_adapter\", \"epo_adapter\", \"tanium_adapter\"] },\n  { name: \"external3026786-prd\", host: \"sepio-external3026786-prd.demo.local\", os: \"Linux\", ip: \"10.0.64.36\", mac: \"88:53:2E:12:56:12\", seen: \"2026-06-08 05:54\", tags: [\"Production\", \"Internet-facing\"], adapters: [\"checkpoint_r80_adapter\", \"chef_adapter\", \"epo_adapter\", \"paloalto_panorama_adapter\", \"axonius_network_inspector_adapter\", \"claroty_adapter\", \"tenable_security_center_adapter\"] },\n  { name: \"macbook-pro-jdoe\", host: \"macbook-pro-jdoe.demo.local\", os: \"OS X\", ip: \"10.0.51.22\", mac: \"A4:83:E7:9C:11:04\", seen: \"2026-06-08 12:02\", tags: [\"Endpoint\", \"BYOD\"], adapters: [\"google_mdm_adapter\", \"crowd_strike_adapter\", \"sentinelone_adapter\"] },\n  { name: \"lablb-2918146-beta\", host: \"esx-lablb-2918146-beta.manufacturing.com\", os: \"Linux\", ip: \"10.0.56.90\", mac: \"00:0C:29:12:4C:BF\", seen: \"2026-06-08 11:30\", tags: [\"Lab\"], adapters: [\"cisco_meraki_adapter\", \"claroty_adapter\", \"epo_adapter\", \"esx_adapter\", \"tanium_asset_adapter\", \"counter_act_adapter\", \"service_now_adapter\"] },\n  { name: \"iphone-asmith\", host: \"\u2014\", os: \"iOS\", ip: \"10.0.77.51\", mac: \"F0:18:98:22:7D:AA\", seen: \"2026-06-08 11:58\", tags: [\"Mobile\", \"BYOD\"], adapters: [\"google_mdm_adapter\", \"zoom_adapter\"] },\n  { name: \"srv-db-fin-04\", host: \"srv-db-fin-04.healthcare-subsidiary.com\", os: \"Linux\", ip: \"10.0.40.12\", mac: \"00:50:56:9A:3C:11\", seen: \"2026-06-08 07:12\", tags: [\"Production\", \"Database\", \"PCI\"], adapters: [\"service_now_adapter\", \"tenable_security_center_adapter\", \"tanium_adapter\", \"epo_adapter\", \"aws_adapter\", \"claroty_adapter\"] },\n  { name: \"azure-infra9274676-prd\", host: \"azure-infra9274676-prd.demo.local\", os: \"Windows\", ip: \"10.0.61.5\", mac: \"00:0D:3A:1F:8E:22\", seen: \"2026-06-08 10:47\", tags: [\"Production\", \"Cloud\"], adapters: [\"active_directory_adapter\", \"aws_adapter\", \"sentinelone_adapter\", \"service_now_adapter\"] },\n  { name: \"android-pixel-7\", host: \"\u2014\", os: \"Android\", ip: \"10.0.78.130\", mac: \"3C:28:6D:55:01:9F\", seen: \"2026-06-08 09:05\", tags: [\"Mobile\"], adapters: [\"google_mdm_adapter\"] },\n  { name: \"Win-MaryChasse\", host: \"WIN-MARYCHASSE.demo.local\", os: \"Windows\", ip: \"10.0.49.201\", mac: \"88:53:2E:12:48:7E\", seen: \"2026-06-07 22:41\", tags: [\"Corporate\"], adapters: [\"active_directory_adapter\", \"epo_adapter\", \"cisco_meraki_adapter\"] },\n  { name: \"esx-mail-2231-prd\", host: \"esx-mail-2231-prd.manufacturing.com\", os: \"VMWare\", ip: \"10.0.62.18\", mac: \"00:0C:29:44:1A:E0\", seen: \"2026-06-08 06:33\", tags: [\"Production\"], adapters: [\"esx_adapter\", \"tenable_security_center_adapter\", \"paloalto_panorama_adapter\"] },\n  { name: \"PC-Doris9920\", host: \"PC-DORIS9920.demo.local\", os: \"Windows\", ip: \"10.0.50.66\", mac: \"88:53:2E:12:51:C9\", seen: \"2026-06-08 08:59\", tags: [\"Corporate\", \"Managed\"], adapters: [\"active_directory_adapter\", \"crowd_strike_adapter\", \"tanium_adapter\", \"google_mdm_adapter\"] },\n  { name: \"kiosk-lobby-03\", host: \"kiosk-lobby-03.demo.local\", os: \"Linux\", ip: \"10.0.44.7\", mac: \"B8:27:EB:0C:5A:31\", seen: \"2026-06-07 19:20\", tags: [\"IoT\", \"Unmanaged\"], adapters: [\"counter_act_adapter\", \"claroty_adapter\"] },\n];\n\nconst INIT_COLS = [\n  { key: \"adapters\", label: \"Adapter Connections\", w: 230, pinned: false },\n  { key: \"name\", label: \"Asset Name\", w: 230, pinned: false },\n  { key: \"host\", label: \"Host Name\", w: 300, pinned: false },\n  { key: \"os\", label: \"OS Type\", w: 140, pinned: false },\n  { key: \"ip\", label: \"IP Address\", w: 140, pinned: false },\n  { key: \"mac\", label: \"MAC Address\", w: 160, pinned: false },\n  { key: \"seen\", label: \"Last Seen (UTC)\", w: 170, pinned: false },\n  { key: \"tags\", label: \"Tags\", w: 220, pinned: false },\n];\nconst CB_W = 46;\nconst mono = { fontFamily: \"ui-monospace, 'SF Mono', monospace\" };\nfunction cellContent(key, r) {\n  switch (key) {\n    case \"adapters\": return ;\n    case \"name\": return {r.name};\n    case \"host\": return {r.host};\n    case \"os\": return ;\n    case \"ip\": return {r.ip};\n    case \"mac\": return {r.mac};\n    case \"seen\": return {r.seen};\n    case \"tags\": return {r.tags.slice(0, 2).map((t, j) =&gt; )}{r.tags.length &gt; 2 &amp;&amp; +{r.tags.length - 2}};\n    default: return null;\n  }\n}\n\nfunction HeaderCell({ col, left, isLastPinned, onResize, onPin, onDragStart, regRef, dragging }) {\n  const [h, setH] = useState(false);\n  const sticky = col.pinned;\n  return (\n    \n regRef(col.key, el)} onPointerDown={(e) =&gt; onDragStart(e, col.key)} onMouseEnter={() =&gt; setH(true)} onMouseLeave={() =&gt; setH(false)}\n      style={{ width: col.w, flexShrink: 0, position: sticky ? \"sticky\" : \"relative\", left: sticky ? left : undefined, zIndex: sticky ? 4 : 1, background: T.canvas, height: 40, display: \"flex\", alignItems: \"center\", gap: 6, padding: \"0 12px\", boxShadow: isLastPinned ? \"2px 0 5px rgba(27,32,70,0.06)\" : \"none\", cursor: \"grab\", opacity: dragging ? 0.4 : 1 }}&gt;\n      {col.label}\n      {(h || col.pinned) &amp;&amp; (\n         onPin(col.key)} title={col.pinned ? \"Unpin column\" : \"Pin column\"}\n          style={{ width: 24, height: 24, borderRadius: 6, border: \"none\", cursor: \"pointer\", background: \"transparent\", color: col.pinned ? T.blue : T.faint, display: \"flex\", alignItems: \"center\", justifyContent: \"center\", transform: col.pinned ? \"none\" : \"rotate(45deg)\", flexShrink: 0 }}&gt;\n          \n        \n      )}\n      \n onResize(e, col.key)} data-colresize title=\"Drag to resize\"\n        style={{ position: \"absolute\", right: -3, top: 8, width: 6, height: 24, cursor: \"col-resize\", display: \"flex\", justifyContent: \"center\", zIndex: 5 }}&gt;\n        \n      \n    \n  );\n}\n\nfunction AssetsTable() {\n  const [columns, setColumns] = useState(INIT_COLS);\n  const [hoverRow, setHoverRow] = useState(null);\n  const [perPage, setPerPage] = useState(20);\n  const [dragCol, setDragCol] = useState(null);\n  const colEls = useRef({});\n  const regRef = (k, el) =&gt; { colEls.current[k] = el; };\n\n  const startColDrag = (e, key) =&gt; {\n    if (e.button || (e.target.closest &amp;&amp; (e.target.closest(\"[data-colresize]\") || e.target.closest(\"button\")))) return;\n    const startX = e.clientX; let dragging = false;\n    const onMove = (ev) =&gt; {\n      if (!dragging) { if (Math.abs(ev.clientX - startX) &gt; 6) { dragging = true; setDragCol(key); document.body.style.userSelect = \"none\"; } else return; }\n      for (const k in colEls.current) {\n        const el = colEls.current[k]; if (!el || k === key) continue;\n        const r = el.getBoundingClientRect();\n        if (ev.clientX &gt;= r.left &amp;&amp; ev.clientX &lt;= r.right) {\n          setColumns(cs =&gt; { const from = cs.findIndex(c =&gt; c.key === key), to = cs.findIndex(c =&gt; c.key === k); if (from &lt; 0 || to &lt; 0 || from === to) return cs; const n = cs.slice(); const [m] = n.splice(from, 1); n.splice(to, 0, m); return n; });\n          break;\n        }\n      }\n    };\n    const onUp = () =&gt; { dragging = false; setDragCol(null); document.body.style.userSelect = \"\"; window.removeEventListener(\"pointermove\", onMove); window.removeEventListener(\"pointerup\", onUp); };\n    window.addEventListener(\"pointermove\", onMove); window.addEventListener(\"pointerup\", onUp);\n  };\n\n  const startColResize = (e, key) =&gt; {\n    e.preventDefault(); e.stopPropagation();\n    const sx = e.clientX, startW = columns.find(c =&gt; c.key === key).w;\n    const onMove = (ev) =&gt; { const w = Math.max(90, startW + (ev.clientX - sx)); setColumns(cs =&gt; cs.map(c =&gt; c.key === key ? { ...c, w } : c)); };\n    const onUp = () =&gt; { document.body.style.cursor = \"\"; window.removeEventListener(\"mousemove\", onMove); window.removeEventListener(\"mouseup\", onUp); };\n    document.body.style.cursor = \"col-resize\";\n    window.addEventListener(\"mousemove\", onMove); window.addEventListener(\"mouseup\", onUp);\n  };\n  const togglePin = (key) =&gt; setColumns(cs =&gt; cs.map(c =&gt; c.key === key ? { ...c, pinned: !c.pinned } : c));\n\n  const pinned = columns.filter(c =&gt; c.pinned), unpinned = columns.filter(c =&gt; !c.pinned);\n  const ordered = [...pinned, ...unpinned];\n  const leftMap = {}; let acc = CB_W;\n  pinned.forEach(c =&gt; { leftMap[c.key] = acc; acc += c.w; });\n  const lastPinned = pinned.length ? pinned[pinned.length - 1].key : null;\n  const totalW = CB_W + columns.reduce((a, c) =&gt; a + c.w, 0);\n\n  return (\n    \n\n      \n\n        \n\n          {/* header */}\n          \n\n            \n\n              \n            \n            {ordered.map(c =&gt; )}\n            \n\n          \n          {/* rows */}\n          {DEVICES.map((r, i) =&gt; {\n            const rowBg = hoverRow === i ? T.surface2 : T.surface;\n            return (\n              \n setHoverRow(i)} onMouseLeave={() =&gt; setHoverRow(null)}\n                style={{ display: \"flex\", height: 52, borderBottom: i &lt; DEVICES.length - 1 ? `1px solid ${T.hair}` : \"none\", background: rowBg }}&gt;\n                \n\n                  {hoverRow === i ?  : {i + 1}}\n                \n                {ordered.map(c =&gt; {\n                  const sticky = c.pinned;\n                  return (\n                    \n\n                      {cellContent(c.key, r)}\n                    \n                  );\n                })}\n                \n\n              \n            );\n          })}\n        \n      \n      {/* footer */}\n      \n\n        \n\n          Rows per page:\n           setPerPage(Number(e.target.value))}\n            style={{ height: 30, padding: \"0 28px 0 10px\", borderRadius: 999, border: `1px solid ${T.line}`, background: T.surface, color: T.ink, fontSize: 13, fontWeight: 500, fontFamily: T.font, cursor: \"pointer\", appearance: \"none\", WebkitAppearance: \"none\", backgroundImage: `url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238494B5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E\")`, backgroundRepeat: \"no-repeat\", backgroundPosition: \"right 8px center\", outline: \"none\" }}&gt;\n            {[20, 50, 100].map(n =&gt; {n})}\n          \n        \n        \n\n          1\u2013{perPage} of 12,409\n          \n\n            \n            1234\n            \u2026621\n            \n          \n        \n      \n    \n  );\n}\n\nfunction QueryPill({ children, primary, active, onClick }) {\n  const [h, setH] = useState(false);\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6, height: 32, padding: \"0 14px\", borderRadius: 999, cursor: \"pointer\", fontFamily: T.font, fontSize: 13.5, fontWeight: 600, border: primary ? \"none\" : `1px solid ${active || h ? T.lineStrong : T.line}`, background: primary ? T.blue : active || h ? T.surface2 : T.control, color: primary ? T.onAccent : T.body }}&gt;{children};\n}\nfunction ToolLink({ icon: Icon, children }) {\n  const [h, setH] = useState(false);\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6, height: 30, padding: \"0 10px\", border: \"none\", borderRadius: 999, background: h ? T.surface2 : \"transparent\", color: T.body, fontSize: 13.5, fontWeight: 600, cursor: \"pointer\", fontFamily: T.font }}&gt;{Icon &amp;&amp; }{children};\n}\nfunction SegTool({ icon: Icon, title, first }) {\n  const [h, setH] = useState(false);\n  return (\n     setH(true)} onMouseLeave={() =&gt; setH(false)}&gt;\n      \n      {h &amp;&amp; {title}}\n    \n  );\n}\nfunction IconTool({ icon: Icon, title }) {\n  const [h, setH] = useState(false);\n  return (\n     setH(true)} onMouseLeave={() =&gt; setH(false)}&gt;\n      \n      {h &amp;&amp; {title}}\n    \n  );\n}\nfunction Segmented({ options, value, onChange }) {\n  const idx = Math.max(0, options.indexOf(value));\n  const wpct = 100 / options.length;\n  return (\n    \n\n      \n      {options.map(o =&gt; (\n         onChange(o)} style={{ position: \"relative\", zIndex: 1, minWidth: 62, padding: \"0 12px\", border: \"none\", background: \"transparent\", color: value === o ? T.onAccent : T.body, fontSize: 13.5, fontWeight: value === o ? 600 : 500, cursor: \"pointer\", fontFamily: T.font, transition: \"color .2s\" }}&gt;{o}\n      ))}\n    \n  );\n}\n\nfunction QueriesPanel({ close }) {\n  const recent = [\n    { nm: \"FH: 1.4 Asset Context.Business Importance\", sub: \"Shared Queries\" },\n    { nm: \"low Risk Score_2025-12-24T11-53\", sub: \"Public Queries / Predefined Queries\" },\n    { nm: \"Unmanaged endpoints seen &lt; 7d\", sub: \"Shared Queries\" },\n    { nm: \"Critical CVEs on internet-facing\", sub: \"Public Queries / Predefined Queries\" },\n  ];\n  return createPortal(&lt;&gt;\n    \n\n    \n\n      \n\n        Queries\n        \n        \n        \n      \n      \n\n        \n\n          \n        \n      \n      \n\n        \nFavorites\n        \nRecently Used Saved Queries\n        {recent.map((q, i) =&gt; (\n           (e.currentTarget.style.background = T.surface2)} onMouseLeave={(e) =&gt; (e.currentTarget.style.background = \"transparent\")}\n            style={{ display: \"flex\", alignItems: \"center\", gap: 11, width: \"100%\", border: \"none\", background: \"transparent\", borderRadius: 10, cursor: \"pointer\", padding: \"9px\", textAlign: \"left\", fontFamily: T.font }}&gt;\n            \n            \n              {q.nm}\n              {q.sub}\n            \n          \n        ))}\n      \n    \n  , document.body);\n}\nfunction AssetsView() {\n  const [mode, setMode] = useState(\"Wizard\");\n  const [enrichOpen, setEnrichOpen] = useState(false);\n  const [queriesOpen, setQueriesOpen] = useState(false);\n  return (\n    \n\n      \n\n      {/* breadcrumb + title + module actions */}\n      \n\n        \n\n          \nInventory / Assets\n          \nDevices\n        \n        \n\n          \n\n             setEnrichOpen(o =&gt; !o)}&gt;Enrichment &amp; Investigation \n            {enrichOpen &amp;&amp; (&lt;&gt;\n              \n setEnrichOpen(false)} style={{ position: \"fixed\", inset: 0, zIndex: 40 }} /&gt;\n              \n\n                {[\"Business Data Enrichment\", \"Device Inventory Classification\", \"Asset Investigation\"].map(o =&gt; (\n                   setEnrichOpen(false)} onMouseEnter={(e) =&gt; (e.currentTarget.style.background = T.surface2)} onMouseLeave={(e) =&gt; (e.currentTarget.style.background = \"transparent\")}\n                    style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", gap: 10, width: \"100%\", border: \"none\", background: \"transparent\", borderRadius: 8, cursor: \"pointer\", padding: \"9px 11px\", fontSize: 13, fontWeight: 500, fontFamily: T.font, color: T.body, textAlign: \"left\" }}&gt;\n                    {o} \n                  \n                ))}\n              \n            )}\n          \n          \n        \n      \n      {/* query toolbar */}\n      \n\n        New Query\n        Save As\n        Reset\n        Copy Query\n        \n\n        Display by Date\n        \n\n         setQueriesOpen(o =&gt; !o)}&gt;{queriesOpen ?  : &lt;&gt; Queries}\n        \n      \n      {/* search + wizard / basic filters */}\n      {mode === \"Wizard\" ? (\n        \n\n          \n\n            \n            \n          \n          Query Wizard\n        \n      ) : (\n        \n\n          \n          \n          \nLast Seen\n          \nTags\n           Filter\n        \n      )}\n      {/* stats toolbar */}\n      \n\n        Total 12,409\n         Last updated: 2026-06-08 17:07:59\n        \n\n        \n\n          \n\n            \n            \n            \n          \n           New Asset\n        \n      \n      {/* end flexShrink header */}\n      \n\n        \n      \n      {queriesOpen &amp;&amp;  setQueriesOpen(false)} /&gt;}\n    \n  );\n}\nfunction PageBtn({ children, active, disabled, wide }) {\n  const [h, setH] = useState(false);\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ minWidth: wide ? \"auto\" : 30, height: 30, padding: wide ? \"0 10px\" : 0, borderRadius: 999, border: active ? \"none\" : `1px solid ${h &amp;&amp; !disabled ? T.lineStrong : \"transparent\"}`, background: active ? T.blue : h &amp;&amp; !disabled ? T.surface2 : \"transparent\", color: active ? T.onAccent : disabled ? T.faint : T.body, fontSize: 13, fontWeight: 500, cursor: disabled ? \"default\" : \"pointer\", display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\", fontFamily: T.font, ...tnum }}&gt;{children};\n}\n\n/* ============ Inventory tree panel (assets view) ============ */\nconst INV_GROUPS_INIT = [\n  { name: \"Compute\", icon: Server, open: true, items: [\n    { icon: Server, label: \"Corporate Devices\", count: \"8,204\", fav: true },\n    { icon: ShieldAlert, label: \"Internet-facing Assets\", count: \"312\", fav: true },\n    { folder: \"Endpoint\", open: true, items: [\n      { icon: Server, label: \"Devices\", count: \"12,409\", active: true },\n      { icon: Workflow, label: \"Processes\", count: \"0\" },\n    ]},\n    { folder: \"Infrastructure\", open: false, items: [\n      { icon: Boxes, label: \"Compute Services\", count: \"14\" },\n      { icon: Cable, label: \"Databases\", count: \"36\" },\n      { icon: Boxes, label: \"Containers\", count: \"258\" },\n      { icon: Cable, label: \"Serverless Functions\", count: \"103\" },\n      { icon: Boxes, label: \"Compute Images\", count: \"25\" },\n    ]},\n    { icon: Settings, label: \"Configurations\", count: \"0\" },\n    { icon: Clock, label: \"Latest Devices\", count: \"12,409\" },\n  ] },\n  { name: \"Identity\", icon: Users, open: false, items: [\n    { folder: \"Directory\", open: false, items: [\n      { icon: Users, label: \"Users\", count: \"4,821\" },\n      { icon: Users, label: \"Groups\", count: \"312\" },\n    ]},\n    { icon: ShieldAlert, label: \"Service Accounts\", count: \"87\" },\n  ] },\n  { name: \"Applications\", icon: Layers, open: false, items: [\n    { icon: Layers, label: \"SaaS Apps\", count: \"143\" },\n    { icon: Layers, label: \"Installed Software\", count: \"2,904\" },\n  ] },\n  { name: \"Tickets\", icon: Bell, open: false, items: [\n    { icon: Bell, label: \"Open Tickets\", count: \"48\" },\n    { icon: Bell, label: \"Resolved\", count: \"203\" },\n  ] },\n];\nfunction InventoryPanel({ collapsed, setCollapsed }) {\n  const [groups, setGroups] = useState(INV_GROUPS_INIT);\n  const [favOpen, setFavOpen] = useState(true);\n\n  const collectItems = (items) =&gt; items.flatMap(it =&gt; it.folder ? collectItems(it.items) : [it]);\n  const favItems = groups.flatMap(g =&gt; collectItems(g.items)).filter(it =&gt; it.fav);\n\n  const toggleFavInItems = (items, label) =&gt; items.map(it =&gt;\n    it.folder ? { ...it, items: toggleFavInItems(it.items, label) }\n              : it.label === label ? { ...it, fav: !it.fav } : it\n  );\n  const toggleFav = (label) =&gt; setGroups(gs =&gt; gs.map(g =&gt; ({ ...g, items: toggleFavInItems(g.items, label) })));\n  const compute = groups.find(g =&gt; g.name === \"Compute\");\n  const computeLeafItems = compute ? compute.items.filter(it =&gt; !it.folder) : [];\n  return (\n    \n\n       setCollapsed(!collapsed)} title={collapsed ? \"Expand inventory\" : \"Collapse panel\"} className=\"ax-edge-collapse\"\n        style={{ position: \"absolute\", top: 16, right: -14, zIndex: 6, width: 28, height: 28, borderRadius: \"50%\", border: `1px solid ${T.line}`, background: T.surface, color: T.muted, cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", boxShadow: T.shadow }}&gt;\n        {collapsed ?  : }\n      \n      \n\n        {collapsed ? (\n          \n\n            \n\n              \n            \n            \n\n            {computeLeafItems.map((it, i) =&gt; {\n              const Icon = it.icon;\n              return (\n                \n\n                  \n                \n              );\n            })}\n          \n        ) : (\n          &lt;&gt;\n            \n\n              \n\n                \n              \n            \n            \n\n              \n\n                \n setFavOpen(o =&gt; !o)} style={{ display: \"flex\", alignItems: \"center\", gap: 9, padding: \"9px 8px\", cursor: \"pointer\", borderRadius: 8, color: T.body }}&gt;\n                  \n                  \n                  Favorites\n                  {favItems.length}\n                \n                {favOpen &amp;&amp; favItems.map((it, ii) =&gt; )}\n              \n              {groups.map((g, gi) =&gt; { const Icon = g.icon; return (\n                \n\n                  \n setGroups(gs =&gt; gs.map((x, i) =&gt; i === gi ? { ...x, open: !x.open } : x))}\n                    style={{ display: \"flex\", alignItems: \"center\", gap: 9, padding: \"9px 8px\", cursor: \"pointer\", borderRadius: 8, color: g.open ? T.accentText : T.body }}&gt;\n                    \n                    \n                    {g.name}\n                  \n                  {g.open &amp;&amp; g.items.map((it, ii) =&gt; it.folder ?  : )}\n                \n              ); })}\n            \n          \n        )}\n      \n    \n  );\n}\nfunction InvFolder({ folder, toggleFav }) {\n  const [open, setOpen] = useState(folder.open);\n  const [h, setH] = useState(false);\n  const FIcon = open ? FolderOpen : Folder;\n  return (\n    \n\n      \n setH(true)} onMouseLeave={() =&gt; setH(false)} onClick={() =&gt; setOpen(o =&gt; !o)}\n        style={{ display: \"flex\", alignItems: \"center\", gap: 8, height: 34, padding: \"0 8px 0 22px\", borderRadius: 8, cursor: \"pointer\", background: h ? T.surface2 : \"transparent\", transition: \"background .12s\" }}&gt;\n        \n        \n        {folder.folder}\n      \n      {open &amp;&amp; folder.items.map((it, i) =&gt; )}\n    \n  );\n}\nfunction InvRow({ icon: Icon, label, count, active, fav, indent, toggleFav }) {\n  const [h, setH] = useState(false);\n  const left = indent || 28;\n  return (\n    \n setH(true)} onMouseLeave={() =&gt; setH(false)}\n      style={{ position: \"relative\", display: \"flex\", alignItems: \"center\", gap: 11, height: 36, margin: \"1px 0\", padding: `0 8px 0 ${left}px`, borderRadius: 8, cursor: \"pointer\", background: active ? T.accentSoft : h ? T.surface2 : \"transparent\", transition: \"background .14s\" }}&gt;\n      \n      {label}\n      {(h || fav) &amp;&amp; toggleFav &amp;&amp; (\n         { e.stopPropagation(); toggleFav(label); }} title={fav ? \"Remove from favorites\" : \"Add to favorites\"} className=\"ax-star\"\n          style={{ width: 22, height: 22, borderRadius: 6, border: \"none\", background: \"transparent\", cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", padding: 0, flexShrink: 0 }}&gt;\n          \n        \n      )}\n      {!h &amp;&amp; !fav &amp;&amp; {count}}\n    \n  );\n}\n\n/* ============ chrome ============ */\nfunction AppHeader({ theme, setTheme }) {\n  return (\n    \n\n      \n\n        \n      \n      \n\n        \n\n          Search Axonius\n          \u2318K\n        \n      \n      \n\n        New navigation BETA\n         setTheme(theme === \"dark\" ? \"light\" : \"dark\")} title=\"Toggle light / dark\"&gt;{theme === \"dark\" ?  : }\n        \n        \nSB\n      \n    \n  );\n}\nfunction HBtn({ children, onClick, title }) {\n  const [h, setH] = useState(false);\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ width: 32, height: 32, borderRadius: 8, border: \"none\", cursor: \"pointer\", background: h ? T.surface2 : \"transparent\", color: h ? T.ink : T.bg80, display: \"flex\", alignItems: \"center\", justifyContent: \"center\" }}&gt;{children};\n}\n\nconst HICONS = {\n  dashboard: '',\n  inventory: '',\n  shield: '',\n  bolt: '',\n  link: '',\n  chart: '',\n  cog: '',\n};\nfunction HIcon({ name, size = 20, color = \"currentColor\", sw = 1.6, className }) {\n  return ${HICONS[name] || \"\"}` }} /&gt;;\n}\nconst RAIL = [\n  { key: \"dashboard\", hi: \"dashboard\", label: \"Dashboard\" }, { key: \"assets\", hi: \"inventory\", label: \"Inventory\" },\n  { key: \"exposures\", hi: \"shield\", label: \"Exposures\" }, { key: \"action\", hi: \"bolt\", label: \"Action Center\" },\n  { key: \"adapters\", hi: \"link\", label: \"Adapters\" }, { key: \"analysis\", hi: \"chart\", label: \"Analysis\" },\n];\nfunction IconRail({ view, setView }) {\n  return (\n    \n\n      {RAIL.map(r =&gt;  setView(r.key)} /&gt;)}\n      \n\n      \n\n    \n  );\n}\nfunction RailGlyph({ hi, label, active, onClick }) {\n  const [h, setH] = useState(false);\n  return (\n    \n setH(true)} onMouseLeave={() =&gt; setH(false)} title={label} className=\"ax-rail ax-press\"\n      style={{ position: \"relative\", width: 44, height: 44, borderRadius: 14, cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", background: active ? T.accentSoft : h ? T.surface2 : \"transparent\", transition: \"background .15s\" }}&gt;\n      \n    \n  );\n}\n\nconst DASH_TREE_INIT = [\n  { g: \"Favorites\", open: true, items: [\n    { nm: \"My Dashboard\", fav: true }, { nm: \"Asset Profile - Copy_2024-06-09\", fav: true },\n    { nm: \"Axonius Dashboard\", fav: true, active: true, def: true }, { nm: \"Cost Optimization\", fav: true }, { nm: \"Cloud Compliance\", fav: true },\n  ] },\n  { g: \"Public\", open: false, items: [\n    { folder: \"Security\", open: false, items: [{ nm: \"SecOps Overview\" }, { nm: \"Threat Intelligence\" }] },\n    { folder: \"Executive\", open: false, items: [{ nm: \"Executive Summary\" }, { nm: \"Board Report\" }] },\n    { nm: \"Asset Inventory V 1.0\" }, { nm: \"Active Directory Insights\" },\n  ] },\n  { g: \"Shared\", open: false, items: [\n    { folder: \"Team SOC\", open: false, items: [{ nm: \"Vulnerability Posture\" }, { nm: \"Incident Response\" }] },\n    { nm: \"Cloud Inventory\" }, { nm: \"Compliance Overview\" },\n  ] },\n  { g: \"Private\", open: false, items: [{ nm: \"My Drafts\" }, { nm: \"Work in Progress\" }] },\n  { g: \"Managed by Axonius\", open: false, items: [{ nm: \"Device Overview\" }, { nm: \"User Overview\" }, { nm: \"Adapters Health\" }, { nm: \"Coverage &amp; Gaps\" }] },\n];\nfunction PanelBtn({ primary, filled, icon: Icon, children, onClick }) {\n  const [h, setH] = useState(false);\n  return (\n     setH(true)} onMouseLeave={() =&gt; setH(false)} className={filled ? \"ax-primary\" : \"ax-press\"}\n      style={{ height: 38, borderRadius: 999, border: filled ? \"none\" : primary ? `1.5px solid ${T.accentText}` : `1px solid ${h ? T.lineStrong : T.line}`, cursor: \"pointer\", width: \"100%\", background: filled ? (h ? T.blueDeep : T.blue) : primary ? (h ? T.accentSoft : \"transparent\") : h ? T.surface2 : \"transparent\", color: filled ? T.onAccent : primary ? T.accentText : T.body, fontSize: 13, fontWeight: 600, fontFamily: T.font, display: \"flex\", alignItems: \"center\", justifyContent: \"center\", gap: 7, boxShadow: \"none\", transition: \"background .14s ease, border-color .14s ease\" }}&gt;\n       {children}\n    \n  );\n}\nfunction CreateDashModal({ onCreate, close }) {\n  const [name, setName] = useState(\"\");\n  const [tpl, setTpl] = useState(\"blank\");\n  const tpls = [{ k: \"blank\", t: \"Blank dashboard\", d: \"Start from an empty canvas\" }, { k: \"template\", t: \"From a template\", d: \"Prebuilt charts to tweak\" }];\n  return createPortal(\n    \n\n      \n e.stopPropagation()} style={{ width: 480, maxWidth: \"92vw\", background: T.canvas, border: `1px solid ${T.line}`, borderRadius: 14, boxShadow: \"0 30px 80px rgba(0,0,0,.55)\", overflow: \"hidden\", animation: \"axRise .26s cubic-bezier(.22,1,.36,1) both\" }}&gt;\n        \n\n          Create dashboard\n          \n        \n        \n\n          \n\n            Dashboard name\n             setName(e.target.value)} placeholder=\"e.g. Security Posture\" style={{ width: \"100%\", height: 40, padding: \"0 14px\", border: `1px solid ${T.line}`, borderRadius: 8, background: T.control, color: T.ink, fontFamily: T.font, fontSize: 14, outline: \"none\", boxSizing: \"border-box\" }} /&gt;\n          \n          \n\n            Starting point\n            \n\n              {tpls.map(o =&gt; (\n                 setTpl(o.k)} style={{ flex: 1, textAlign: \"left\", padding: \"12px 13px\", borderRadius: 10, border: `1.5px solid ${tpl === o.k ? T.accentText : T.line}`, background: tpl === o.k ? T.accentSoft : \"transparent\", cursor: \"pointer\", fontFamily: T.font }}&gt;\n                  \n{o.t}\n                  \n{o.d}\n                \n              ))}\n            \n          \n        \n        \n\n          Cancel\n           name.trim() &amp;&amp; onCreate(name.trim())} className=\"ax-press\" style={{ height: 38, padding: \"0 18px\", borderRadius: 999, border: \"none\", background: name.trim() ? T.blue : T.surface2, color: name.trim() ? T.onAccent : T.faint, fontSize: 13.5, fontWeight: 600, cursor: name.trim() ? \"pointer\" : \"default\", fontFamily: T.font }}&gt;Create dashboard\n        \n      \n    , document.body);\n}\nfunction SidePanel({ collapsed, setCollapsed, activeDash, setActiveDash }) {\n  const [tree, setTree] = useState(DASH_TREE_INIT);\n  const [menu, setMenu] = useState(null);\n  const [editing, setEditing] = useState(null);\n  const [createOpen, setCreateOpen] = useState(false);\n\n  const mut = (fn) =&gt; setTree(t =&gt; fn(t.map(g =&gt; ({ ...g, items: g.items.map(it =&gt; ({ ...it })) }))));\n  const toggleGroup = (gi) =&gt; setTree(t =&gt; t.map((g, i) =&gt; i === gi ? { ...g, open: !g.open } : g));\n  const setActive = (gi, ii) =&gt; { mut(t =&gt; { t.forEach(g =&gt; g.items.forEach(it =&gt; it.active = false)); t[gi].items[ii].active = true; return t; }); if (setActiveDash) setActiveDash(tree[gi].items[ii].nm); };\n  const toggleFav = (gi, ii) =&gt; mut(t =&gt; { t[gi].items[ii].fav = !t[gi].items[ii].fav; return t; });\n  const setDefault = (gi, ii) =&gt; mut(t =&gt; { t.forEach(g =&gt; g.items.forEach(it =&gt; it.def = false)); t[gi].items[ii].def = true; return t; });\n  const duplicate = (gi, ii) =&gt; mut(t =&gt; { t[gi].items.splice(ii + 1, 0, { nm: t[gi].items[ii].nm + \" (copy)\" }); return t; });\n  const rename = (gi, ii, nm) =&gt; mut(t =&gt; { t[gi].items[ii].nm = nm || t[gi].items[ii].nm; return t; });\n  const remove = (gi, ii) =&gt; mut(t =&gt; { t[gi].items.splice(ii, 1); return t; });\n  const createDash = (nm) =&gt; mut(t =&gt; { const p = t.find(g =&gt; g.g === \"Private\"); p.open = true; p.items.push({ nm: nm || \"Untitled dashboard\" }); return t; });\n  const openMenu = (gi, ii, e) =&gt; { const r = e.currentTarget.getBoundingClientRect(); setMenu({ gi, ii, top: r.bottom + 6, left: Math.max(8, r.right - 196) }); };\n\n  if (collapsed) {\n    const favItems = tree.flatMap(g =&gt; g.items).filter(it =&gt; it.fav || it.active);\n    return (\n      \n\n         setCollapsed(false)} title=\"Expand dashboards\" className=\"ax-edge-collapse\"\n          style={{ position: \"absolute\", top: 16, right: -14, zIndex: 6, width: 28, height: 28, borderRadius: \"50%\", border: `1px solid ${T.line}`, background: T.surface, color: T.muted, cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", boxShadow: T.shadow }}&gt;\n          \n        \n         setCreateOpen(true)} style={{ width: 38, height: 38, borderRadius: 8, border: `1.5px solid ${T.accentText}`, background: \"transparent\", cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", color: T.accentText }}&gt;\n          \n        \n        \n\n        {favItems.map((s, i) =&gt; (\n          \n\n            \n            {s.fav &amp;&amp; }\n          \n        ))}\n        {createOpen &amp;&amp;  { createDash(nm); setCreateOpen(false); }} close={() =&gt; setCreateOpen(false)} /&gt;}\n      \n    );\n  }\n  return (\n    \n\n       setCollapsed(true)} title=\"Collapse panel\" className=\"ax-edge-collapse\"\n        style={{ position: \"absolute\", top: 16, right: -14, zIndex: 6, width: 28, height: 28, borderRadius: \"50%\", border: `1px solid ${T.line}`, background: T.surface, color: T.muted, cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", boxShadow: T.shadow }}&gt;\n        \n      \n      \n\n         setCreateOpen(true)}&gt;Create Dashboard\n        Manage Dashboards\n      \n      \n\n        \n\n          \n        \n      \n      \n\n        {tree.map((g, gi) =&gt; (\n          \n        ))}\n      \n      {menu &amp;&amp;  setMenu(null)}\n        actions={{ rename: () =&gt; setEditing({ gi: menu.gi, ii: menu.ii }), duplicate, toggleFav, setDefault, remove }} /&gt;}\n      {createOpen &amp;&amp;  { createDash(nm); setCreateOpen(false); }} close={() =&gt; setCreateOpen(false)} /&gt;}\n    \n  );\n}\nconst DASH_CAT_ICON = { Favorites: Star, Public: Globe, Shared: Users, Private: Lock, \"Managed by Axonius\": ShieldCheck };\nfunction DashGroup({ group, gi, toggleGroup, setActive, toggleFav, openMenu, editing, setEditing, rename }) {\n  const Icon = DASH_CAT_ICON[group.g] || LayoutGrid;\n  return (\n    \n\n       toggleGroup(gi)} className=\"ax-catrow\"\n        style={{ display: \"flex\", alignItems: \"center\", gap: 9, width: \"100%\", border: \"none\", background: \"transparent\", cursor: \"pointer\", padding: \"8px 8px\", borderRadius: 8, fontFamily: T.font }}&gt;\n        \n        \n        {group.g}\n        {group.g === \"Favorites\" ? group.items.filter(it =&gt; it.fav !== false).length : group.items.length}\n      \n      {group.open &amp;&amp; group.items\n        .filter(it =&gt; group.g !== \"Favorites\" || it.fav !== false)\n        .map((it, ii) =&gt;\n          it.folder\n            ? \n            : \n        )}\n    \n  );\n}\nfunction DashFolder({ folder, indent, onToggle }) {\n  const [h, setH] = useState(false);\n  const [open, setOpen] = useState(folder.open);\n  const toggle = () =&gt; { setOpen(o =&gt; !o); if (onToggle) onToggle(!open); };\n  const FIcon = open ? FolderOpen : Folder;\n  return (\n    \n\n      \n setH(true)} onMouseLeave={() =&gt; setH(false)} onClick={toggle}\n        style={{ display: \"flex\", alignItems: \"center\", gap: 8, height: 34, padding: `0 8px 0 ${indent || 22}px`, borderRadius: 8, cursor: \"pointer\", background: h ? T.surface2 : \"transparent\", transition: \"background .12s\" }}&gt;\n        \n        \n        {folder.folder}\n      \n      {open &amp;&amp; folder.items.map((it, i) =&gt; (\n        \n e.currentTarget.style.background = T.surface2} onMouseLeave={(e) =&gt; e.currentTarget.style.background = \"transparent\"}&gt;\n          \n          {it.nm}\n        \n      ))}\n    \n  );\n}\nfunction DashItem({ item, gi, ii, setActive, toggleFav, openMenu, editing, setEditing, rename }) {\n  const [h, setH] = useState(false);\n  return (\n    \n setH(true)} onMouseLeave={() =&gt; setH(false)} onClick={() =&gt; !editing &amp;&amp; setActive(gi, ii)} className=\"ax-press\"\n      style={{ position: \"relative\", display: \"flex\", alignItems: \"center\", gap: 9, height: 36, padding: \"0 8px 0 28px\", margin: \"1px 0\", cursor: \"pointer\", borderRadius: 8, border: \"none\", background: item.active ? T.accentSoft : h ? T.surface2 : \"transparent\", transition: \"background .14s\" }}&gt;\n      \n      {editing ? (\n         e.stopPropagation()}\n          onBlur={(e) =&gt; { rename(gi, ii, e.target.value.trim()); setEditing(null); }}\n          onKeyDown={(e) =&gt; { if (e.key === \"Enter\") { rename(gi, ii, e.target.value.trim()); setEditing(null); } if (e.key === \"Escape\") setEditing(null); }}\n          style={{ flex: 1, minWidth: 0, border: `1px solid ${T.blue}`, borderRadius: 6, padding: \"2px 6px\", fontSize: 13.5, fontFamily: T.font, color: T.ink, outline: \"none\", background: T.surface }} /&gt;\n      ) : (\n        {item.nm}\n      )}\n      {(h || item.fav) &amp;&amp; !editing &amp;&amp; (\n         { e.stopPropagation(); toggleFav(gi, ii); }} title={item.fav ? \"Remove from favorites\" : \"Add to favorites\"} className=\"ax-star\"\n          style={{ width: 22, height: 22, borderRadius: 6, border: \"none\", background: \"transparent\", cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", padding: 0, flexShrink: 0 }}&gt;\n          \n        \n      )}\n      {h &amp;&amp; !editing &amp;&amp; (\n         { e.stopPropagation(); openMenu(gi, ii, e); }} title=\"More actions\"\n          style={{ width: 22, height: 22, borderRadius: 6, border: \"none\", background: \"transparent\", cursor: \"pointer\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\", padding: 0, flexShrink: 0, color: T.muted }}&gt;\n          \n        \n      )}\n    \n  );\n}\nfunction RowMenu({ menu, tree, close, actions }) {\n  const it = tree[menu.gi]?.items?.[menu.ii] || {};\n  const rows = [\n    { ic: Pencil, l: \"Rename\", fn: () =&gt; actions.rename() },\n    { ic: Copy, l: \"Duplicate\", fn: () =&gt; actions.duplicate(menu.gi, menu.ii) },\n    { ic: Star, l: it.fav ? \"Remove from favorites\" : \"Add to favorites\", fn: () =&gt; actions.toggleFav(menu.gi, menu.ii) },\n    { ic: Check, l: it.def ? \"Default dashboard\" : \"Set as default\", fn: () =&gt; actions.setDefault(menu.gi, menu.ii) },\n    { ic: Download, l: \"Export\", fn: () =&gt; {} },\n    { sep: true },\n    { ic: Trash2, l: \"Delete\", danger: true, fn: () =&gt; actions.remove(menu.gi, menu.ii) },\n  ];\n  return (\n    &lt;&gt;\n      \n\n      \n\n        {rows.map((a, i) =&gt; a.sep\n          ? \n\n          :  { a.fn(); close(); }}&gt;{a.l})}\n      \n    \n  );\n}\nfunction MenuRow({ icon: Icon, danger, children, onClick }) {\n  const [h, setH] = useState(false);\n  return (\n     setH(true)} onMouseLeave={() =&gt; setH(false)}\n      style={{ display: \"flex\", alignItems: \"center\", gap: 9, width: \"100%\", border: \"none\", borderRadius: 8, cursor: \"pointer\", padding: \"7px 9px\", fontSize: 13, fontFamily: T.font, fontWeight: 500, textAlign: \"left\", color: danger ? T.red : T.body, background: h ? (danger ? `${T.red}10` : T.canvas) : \"transparent\" }}&gt;\n       {children}\n    \n  );\n}\n\nfunction ModuleHeader({ view, activeDash }) {\n  const isDash = view === \"dashboard\";\n  return (\n    \n\n      \n{isDash ? \"Dashboards / Favorites\" : \"Assets / All Devices\"}\n      \n\n        \n\n          \n{isDash ? activeDash : \"Assets\"}\n          {isDash &amp;&amp; }\n        \n        \n\n          {isDash ? &lt;&gt;\n             Updated 2m ago\n            Add Chart\n           : &lt;&gt;\n            Export\n            New Query\n          }\n          \n        \n      \n    \n  );\n}\nfunction HdrBtn({ icon: Icon, children, primary, filled }) {\n  const [h, setH] = useState(false);\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ display: \"flex\", alignItems: \"center\", gap: 6, height: 34, padding: \"0 14px\", borderRadius: 999, cursor: \"pointer\", fontFamily: T.font, fontSize: 13.5, fontWeight: 600, border: filled ? \"none\" : (primary ? `1.5px solid ${T.accentText}` : `1px solid ${h ? T.lineStrong : T.line}`), background: filled ? (h ? T.blueDeep : T.blue) : (primary ? (h ? T.accentSoft : \"transparent\") : (h ? T.surface2 : T.control)), color: filled ? T.onAccent : (primary ? T.accentText : T.body) }}&gt;{children};\n}\n\nfunction AxoniusApp() {\n  const [view, setView] = useState(\"dashboard\");\n  const [collapsed, setCollapsed] = useState(false);\n  const [invCollapsed, setInvCollapsed] = useState(false);\n  const [theme, setTheme] = useState(\"dark\");\n  const [activeDash, setActiveDash] = useState(\"Axonius Dashboard\");\n  T = THEMES[theme];\n  useEffect(() =&gt; {\n    document.body.style.background = THEMES[theme].shell;\n    const el = document.documentElement;\n    el.classList.add(\"theming\");\n    const id = setTimeout(() =&gt; el.classList.remove(\"theming\"), 450);\n    return () =&gt; clearTimeout(id);\n  }, [theme]);\n  return (\n    \n\n      {`@import url('https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;500;600;700&amp;family=Schibsted+Grotesk:wght@500;600;700&amp;display=swap'); * { box-sizing: border-box; } .theming, .theming * { transition: background-color .4s ease, border-color .4s ease, color .35s ease, fill .3s ease, stroke .3s ease !important; } *::-webkit-scrollbar { width: 9px; height: 9px; } *::-webkit-scrollbar-thumb { background: ${T.bg40}; border-radius: 5px; } *::-webkit-scrollbar-track { background: transparent; }\n        .ax-tile *::-webkit-scrollbar-thumb { background: transparent; transition: background .2s ease; }\n        .ax-tile:hover *::-webkit-scrollbar-thumb { background: ${T.bg40}; }\n        .ax-tbl::-webkit-scrollbar-thumb { background: transparent; } .ax-tbl:hover::-webkit-scrollbar-thumb { background: ${T.bg40}; } .ax-tbl::-webkit-scrollbar-corner { background: transparent; }\n        input::placeholder { color: ${T.muted}; opacity: 1; }\n        .ax-catrow:hover { background: ${T.surface2}; }\n        .ax-catrow:hover .ax-favbtn { opacity: 1 !important; }\n        .ax-edge-collapse { opacity: 0; transform: scale(.8); transition: opacity .15s ease, transform .15s ease; }\n        .ax-sidepanel:hover .ax-edge-collapse { opacity: 1; transform: scale(1); }\n        button, [role=\"button\"] { transition: transform .14s cubic-bezier(.34,1.56,.64,1), background-color .15s ease, box-shadow .18s ease, border-color .15s ease, color .12s ease; }\n        button:not(:disabled):active { transform: scale(.92); }\n        .ax-press { transition: transform .14s cubic-bezier(.34,1.56,.64,1), background-color .14s ease; }\n        .ax-press:active { transform: scale(.95); }\n        .ax-card { transition: transform .2s cubic-bezier(.34,1.56,.64,1), box-shadow .2s ease, border-color .15s ease; }\n        .ax-card:hover { border-color: ${T.lineStrong} !important; box-shadow: ${T.shadow} !important; }\n        .ax-primary:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(37,99,235,.4) !important; }\n        .ax-primary:active { transform: translateY(0) scale(.96); }\n        @keyframes axRise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }\n        .ax-rise { animation: axRise .45s cubic-bezier(.22,1,.36,1) both; }\n        @keyframes axJiggle { 0%, 100% { transform: rotate(-0.5deg); } 50% { transform: rotate(0.5deg); } }\n        .ax-jiggle { animation: axJiggle .32s ease-in-out infinite; }\n        @keyframes axPop { 0% { transform: scale(1); } 45% { transform: scale(1.25) rotate(-8deg); } 100% { transform: scale(1); } }\n        .ax-star:hover { animation: axPop .4s ease; }\n        @keyframes axSpin { to { transform: rotate(360deg); } }\n        .ax-spin:hover { animation: axSpin .6s ease; }\n        button:not(:disabled):hover { transform: translateY(-1px); }\n        @keyframes axGrow { from { transform: scaleX(0); } to { transform: scaleX(1); } }\n        @keyframes axGrowY { from { transform: scaleY(0); } to { transform: scaleY(1); } }\n        @keyframes axDraw { to { stroke-dashoffset: 0; } }\n        @keyframes axFade { from { opacity: 0; } to { opacity: 1; } }\n        @keyframes axSlideIn { from { transform: translateX(100%); } to { transform: translateX(0); } }\n        @keyframes axBounce { 0% { transform: translateY(0) scale(1); } 35% { transform: translateY(-4px) scale(1.14); } 70% { transform: translateY(0) scale(1); } 100% { transform: translateY(0) scale(1); } }\n        .ax-rail:hover .ax-railicon { animation: axBounce .5s ease; }\n        .ax-flat:hover { transform: none !important; }`}\n      \n      \n\n        \n        \n\n          {view === \"dashboard\" &amp;&amp; }\n          {view === \"assets\" &amp;&amp; }\n          \n\n            {view === \"dashboard\" &amp;&amp; }\n            {view === \"dashboard\" ? (\n              \n\n                {DASH_TILESETS[activeDash]\n                  ? \n                  : &lt;&gt;}\n              \n            ) : view === \"assets\" ? (\n              \n            ) : (\n              \n\n                {RAIL.find(r =&gt; r.key === view)?.label} view \u2014 coming soon\n              \n            )}\n          \n        \n      \n    \n  );\n}\n\ncreateRoot(document.getElementById(\"root\")).render();\n    \n  \n    fetch('/.inspector/overlay.js')\n      .then(r =&gt; r.text())\n      .then(code =&gt; { const s = document.createElement('script'); s.textContent = code; document.head.appendChild(s); })\n      .catch(() =&gt; {});\n  \n  \n\n", "creation_timestamp": "2026-06-23T12:21:01.000000Z"}, {"uuid": "5f76ea7a-3905-4f25-8c56-a7069ebffc25", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2024-0039", "type": "seen", "source": "https://gist.github.com/ShaiOnionGod/698e64623dff9eabc7bcf40ecdbc049d", "content": "\n\n\n  \n  \n  Design Editor \u2014 Axonius\n  \n  \n    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n    body { display: flex; flex-direction: column; height: 100vh; overflow: hidden; background: #13141c; color: #e2e8f0; font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; }\n    #toolbar { display: flex; align-items: center; gap: 10px; padding: 0 18px; height: 50px; background: #191a23; border-bottom: 1px solid #2a2d3c; flex-shrink: 0; user-select: none; }\n    #toolbar-title { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; }\n    #toolbar-title svg { flex-shrink: 0; opacity: .8; }\n    #toolbar-title span { font-size: 13.5px; font-weight: 600; letter-spacing: -.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n    #toolbar-title small { font-size: 11px; font-weight: 400; color: #8494b5; background: #222431; border: 1px solid #2a2d3c; border-radius: 5px; padding: 2px 7px; margin-left: 4px; }\n    .btn { display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 14px; border-radius: 999px; border: 1px solid #3a3d52; background: transparent; color: #c8d0e0; font-size: 12.5px; font-weight: 500; cursor: pointer; font-family: inherit; transition: background .12s, border-color .12s; white-space: nowrap; }\n    .btn:hover { background: #222431; border-color: #4f5470; }\n    .btn-primary { background: #4f6aff; border-color: #4f6aff; color: #fff; }\n    .btn-primary:hover { background: #3d57ff; border-color: #3d57ff; }\n    #layout { display: flex; flex: 1; min-height: 0; }\n    #editor-pane { width: 48%; flex-shrink: 0; display: flex; flex-direction: column; min-height: 0; border-right: 1px solid #2a2d3c; }\n    #pane-header { display: flex; align-items: center; gap: 8px; padding: 0 14px; height: 34px; background: rgba(22,23,32,.5); border-bottom: 1px solid #1e2030; font-size: 11.5px; color: #8494b5; flex-shrink: 0; }\n    #pane-header .filename { font-weight: 500; color: #bdc8e0; }\n    #status { margin-left: auto; font-size: 11px; }\n    #status.saving { color: #4ade80; }\n    #status.idle { color: #8494b5; }\n    #monaco-container { flex: 1; min-height: 0; }\n    #preview-pane { flex: 1; min-width: 0; display: flex; flex-direction: column; }\n    #preview-header { display: flex; align-items: center; gap: 8px; padding: 0 14px; height: 34px; background: rgba(22,23,32,.5); border-bottom: 1px solid #1e2030; font-size: 11.5px; color: #8494b5; flex-shrink: 0; }\n    #preview-dot { width: 7px; height: 7px; border-radius: 50%; background: #4ade80; flex-shrink: 0; }\n    #preview-dot.loading { background: #facc15; animation: pulse .8s ease-in-out infinite; }\n    @keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }\n    #preview { flex: 1; border: none; background: #fff; }\n    .divider { width: 4px; background: #2a2d3c; cursor: col-resize; flex-shrink: 0; transition: background .12s; }\n    .divider:hover, .divider.dragging { background: #4f6aff; }\n  \n\n\n  \n\n    \n\n      \n      Axonius Design Sandbox editor\n    \n    &#8635; Reset\n    &#11096; Copy HTML\n    &#8595; Download\n  \n\n  \n\n    \n\n      \n\n        design-sandbox3.html\n        ready\n      \n      \n\n    \n    \n\n    \n\n      \n\n        \n\n        Live Preview\n        updates 1s after edit\n      \n      \n    \n  \n\n  \n  \n    const INITIAL_SOURCE = \"\\n\\n  \\n    \\n    \\n    Axonius \\u2014 Dashboard prototype&lt;\\/title&gt;\\n    \\n    \\n      {\\n        \\\"imports\\\": {\\n          \\\"react\\\": \\\"https://esm.sh/react@18.3.1\\\",\\n          \\\"react-dom\\\": \\\"https://esm.sh/react-dom@18.3.1\\\",\\n          \\\"react-dom/client\\\": \\\"https://esm.sh/react-dom@18.3.1/client\\\",\\n          \\\"lucide-react\\\": \\\"https://esm.sh/lucide-react@0.456.0?deps=react@18.3.1\\\"\\n        }\\n      }\\n    &lt;\\/script&gt;\\n    &lt;\\/script&gt;\\n    \\n      html, body { margin: 0; height: 100%; background: #191A23; font-family: 'Hanken Grotesk', -apple-system, BlinkMacSystemFont, sans-serif; }\\n      #root { height: 100%; }\\n      .sb-tag { position: fixed; right: 14px; bottom: 12px; z-index: 99999; font: 700 10px/1 ui-monospace, monospace; letter-spacing: .14em; color: #0D5ED7; background: rgba(255,255,255,.9); border: 1px solid #E0E4EC; border-radius: 999px; padding: 6px 10px; box-shadow: 0 6px 18px rgba(27,32,70,.12); pointer-events: none; }\\n    &lt;\\/style&gt;\\n  &lt;\\/head&gt;\\n  \\n    \n&lt;\\/div&gt;\\n    \nSANDBOX&lt;\\/div&gt;\\n\\n    \\nimport React, { useState, useRef, useCallback, useEffect } from \\\"react\\\";\\nimport { createRoot } from \\\"react-dom/client\\\";\\nimport { createPortal } from \\\"react-dom\\\";\\nimport {\\n  Search, Star, MoreHorizontal, Info, ListFilter, ArrowUpDown, Columns3,\\n  Plus, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, ChevronDown,\\n  ArrowUpRight, ArrowDownRight, LayoutGrid, Server, ShieldCheck, Boxes,\\n  Workflow, Cable, Bell, CircleHelp, Clock, Play, Grip, PanelLeftClose,\\n  PanelLeftOpen, Download, GripVertical, X, Settings, ShieldAlert, Crosshair,\\n  Pin, PinOff, RotateCw, Filter, Table2, ChevronsUpDown, Pencil, Check, Trash2,\\n  Users, Layers, RotateCcw, Save, Copy, Calendar, Menu, Zap, Link, BarChart3, Sun, Moon,\\n  Globe, Lock, Folder, FolderOpen\\n} from \\\"lucide-react\\\";\\n\\n/**\\n * Axonius \\u2014 Dashboard + Assets table views\\n * Collapsible side panel \\u00b7 resizable + reorderable dashboard tiles\\n * Real Axonius header \\u00b7 Twenty-style table \\u00b7 tokens from Figma source\\n */\\n\\nfunction AxoniusLogo() {\\n  return &lt;\\/svg&gt;`.replaceAll('fill=\\\"black\\\"', `fill=\\\"${T.ink}\\\"`) }} /&gt;;\\n}\\n\\n// Data / highlight palette \\u2014 bright fills used in both themes (light-mode text variants applied where colored text is needed)\\nconst VIZ = { green: \\\"#5BC4BF\\\", greenDeep: \\\"#247D78\\\", mint: \\\"#8ED0FF\\\", lilac: \\\"#AD85FF\\\", lilacPale: \\\"#CDB4FF\\\", orange: \\\"#FF8C66\\\", amber: \\\"#FFB286\\\" };\\nconst FONT = \\\"'Hanken Grotesk', -apple-system, sans-serif\\\", DISPLAY = \\\"'Schibsted Grotesk', -apple-system, sans-serif\\\";\\nconst THEMES = {\\n  dark: {\\n    ink: \\\"#E4E8F0\\\", body: \\\"#AEB7CC\\\", muted: \\\"#8494B5\\\", faint: \\\"#69738C\\\",\\n    line: \\\"rgba(132,148,181,0.20)\\\", lineSoft: \\\"rgba(132,148,181,0.12)\\\", hair: \\\"rgba(132,148,181,0.09)\\\", lineStrong: \\\"rgba(132,148,181,0.42)\\\",\\n    bg100: \\\"#AEB7CC\\\", bg90: \\\"#9AA3BC\\\", bg80: \\\"#8494B5\\\", bg40: \\\"#8494B5\\\",\\n    blue: \\\"#5C7CFF\\\", blueDeep: \\\"#4E6CF5\\\", green: \\\"#5BC4BF\\\", red: \\\"#FF8C66\\\",\\n    shell: \\\"#191A23\\\", headerBg: \\\"#191A23\\\", canvas: \\\"#191A23\\\", surface: \\\"#222431\\\", surface2: \\\"#2A2D3C\\\", control: \\\"#262838\\\",\\n    white: \\\"#FFFFFF\\\", onAccent: \\\"#191A23\\\", isLight: false, coin: \\\"#2A2D3C\\\", accentSoft: \\\"rgba(92,124,255,0.16)\\\", accentText: \\\"#5C7CFF\\\", accentBorder: \\\"rgba(92,124,255,0.50)\\\",\\n    viz: VIZ, shadow: \\\"0 1px 2px rgba(0,0,0,0.4), 0 14px 34px rgba(0,0,0,0.5)\\\", font: FONT, display: DISPLAY,\\n  },\\n  light: {\\n    ink: \\\"#2E3850\\\", body: \\\"#465472\\\", muted: \\\"#6B7894\\\", faint: \\\"#8494B5\\\",\\n    line: \\\"rgba(132,148,181,0.30)\\\", lineSoft: \\\"rgba(132,148,181,0.18)\\\", hair: \\\"rgba(132,148,181,0.12)\\\", lineStrong: \\\"rgba(132,148,181,0.55)\\\",\\n    bg100: \\\"#465472\\\", bg90: \\\"#5A6889\\\", bg80: \\\"#8494B5\\\", bg40: \\\"#8494B5\\\",\\n    blue: \\\"#4361EE\\\", blueDeep: \\\"#3A55D6\\\", green: \\\"#247D78\\\", red: \\\"#BF4B26\\\",\\n    shell: \\\"#F9FAFB\\\", headerBg: \\\"#F9FAFB\\\", canvas: \\\"#FFFFFF\\\", surface: \\\"#FFFFFF\\\", surface2: \\\"#F1F2F6\\\", control: \\\"#FFFFFF\\\",\\n    white: \\\"#FFFFFF\\\", onAccent: \\\"#FFFFFF\\\", isLight: true, coin: \\\"#FFFFFF\\\", accentSoft: \\\"rgba(67,97,238,0.10)\\\", accentText: \\\"#4361EE\\\", accentBorder: \\\"rgba(67,97,238,0.45)\\\",\\n    viz: VIZ, shadow: \\\"0 1px 2px rgba(70,84,114,0.06), 0 10px 26px rgba(70,84,114,0.08)\\\", font: FONT, display: DISPLAY,\\n  },\\n};\\nlet T = THEMES.dark;\\n// Severity scale stays semantic (red \\u2192 orange \\u2192 yellow \\u2192 green, neutral for informational) in both themes\\nconst SEVC = { critical: \\\"#E5484D\\\", high: \\\"#F0743E\\\", medium: \\\"#F5C28C\\\", low: \\\"#4F8FE3\\\", info: \\\"#CFC4F2\\\" };\\nconst fmt = (n) =&gt; n.toLocaleString(\\\"en-US\\\");\\nconst tnum = { fontFeatureSettings: '\\\"tnum\\\" 1', fontVariantNumeric: \\\"tabular-nums\\\" };\\n\\n/* ============ vendor logos ============ */\\nfunction LogoMark({ brand, size = 32 }) {\\n  const glyph = {\\n    aws: aws&lt;\\/text&gt;&lt;\\/svg&gt;,\\n    microsoft: &lt;\\/svg&gt;,\\n    azure: &lt;\\/svg&gt;,\\n    googlecloud: &lt;\\/svg&gt;,\\n    oracle: &lt;\\/svg&gt;,\\n    vmware: vm&lt;\\/text&gt;&lt;\\/svg&gt;,\\n    okta: &lt;\\/svg&gt;,\\n    crowdstrike: &lt;\\/svg&gt;,\\n    active_directory: &lt;\\/svg&gt;,\\n    sentinelone: &lt;\\/svg&gt;,\\n    service_now: &lt;\\/svg&gt;,\\n    cisco: cisco&lt;\\/text&gt;&lt;\\/g&gt;&lt;\\/svg&gt;,\\n    cisco_meraki: &lt;\\/svg&gt;,\\n    cisco_ise: cisco&lt;\\/text&gt;&lt;\\/g&gt;&lt;\\/svg&gt;,\\n    checkpoint: &lt;\\/svg&gt;,\\n    chef: &lt;\\/svg&gt;,\\n    claroty: &lt;\\/svg&gt;,\\n    cylance: &lt;\\/svg&gt;,\\n    epo: &lt;\\/svg&gt;,\\n    paloalto: &lt;\\/svg&gt;,\\n    tanium: &lt;\\/svg&gt;,\\n    tenable: &lt;\\/svg&gt;,\\n    forescout: &lt;\\/svg&gt;,\\n    zoom: &lt;\\/svg&gt;,\\n    miro: &lt;\\/svg&gt;,\\n    dropbox: &lt;\\/svg&gt;,\\n    salesforce: &lt;\\/svg&gt;,\\n    slack: &lt;\\/svg&gt;,\\n    office365: &lt;\\/svg&gt;,\\n    google_workspace: &lt;\\/svg&gt;,\\n  }[brand] || {(brand || \\\"?\\\").slice(0, 2).toUpperCase()}&lt;\\/span&gt;;\\n  return \n{glyph}&lt;\\/span&gt;&lt;\\/div&gt;;\\n}\\n\\n/* ============ chips ============ */\\n// Tags use the dashboard data palette (turquoise / purple / baby-blue / orange) \\u2014 dark text variant in light mode, bright in dark\\nconst TAGV = [{ b: \\\"#5BC4BF\\\", d: \\\"#247D78\\\" }, { b: \\\"#AD85FF\\\", d: \\\"#683CB5\\\" }, { b: \\\"#8ED0FF\\\", d: \\\"#1E75B3\\\" }, { b: \\\"#FF8C66\\\", d: \\\"#BF4B26\\\" }];\\nfunction Tag({ label }) {\\n  let n = 0; for (let i = 0; i &lt; label.length; i++) n = (n * 31 + label.charCodeAt(i)) &gt;&gt;&gt; 0;\\n  const t = TAGV[n % TAGV.length];\\n  return {label}&lt;\\/span&gt;;\\n}\\n// Cursor-following tooltip (like sandbox 2) \\u2014 surface card with readable dark text\\nfunction FloatTip({ x, y, children }) {\\n  return createPortal(\n{children}&lt;\\/div&gt;, document.body);\\n}\\nfunction UserAvatar({ name, size = 24 }) {\\n  const s = name || \\\"?\\\"; let n = 0; for (let i = 0; i &lt; s.length; i++) n = (n * 31 + s.charCodeAt(i)) &gt;&gt;&gt; 0;\\n  const t = TAGV[n % TAGV.length];\\n  return {s.trim()[0] || \\\"?\\\"}&lt;\\/span&gt;;\\n}\\nconst APP_LOGO_MAP = {\\n  Zoom: \\\"zoom\\\", \\\"Zoom One Pro\\\": \\\"zoom\\\",\\n  Miro: \\\"miro\\\",\\n  Dropbox: \\\"dropbox\\\",\\n  Salesforce: \\\"salesforce\\\",\\n  Slack: \\\"slack\\\",\\n  Google: \\\"googlecloud\\\", \\\"Google WS Ent. Starter\\\": \\\"google_workspace\\\", \\\"Google WS Ent. Standard\\\": \\\"google_workspace\\\", \\\"Google WS Business\\\": \\\"google_workspace\\\",\\n  Office365: \\\"office365\\\", \\\"Microsoft 365 G3 GCC\\\": \\\"office365\\\", \\\"Microsoft 365 E5\\\": \\\"office365\\\", \\\"Microsoft Power Aut\\u2026\\\": \\\"office365\\\",\\n  Microsoft: \\\"microsoft\\\",\\n};\\nfunction AppAvatar({ name, size = 22 }) {\\n  const brand = APP_LOGO_MAP[name];\\n  if (brand) return ;\\n  const s = name || \\\"?\\\"; let n = 0; for (let i = 0; i &lt; s.length; i++) n = (n * 31 + s.charCodeAt(i)) &gt;&gt;&gt; 0;\\n  const t = TAGV[n % TAGV.length];\\n  return {s.trim()[0] || \\\"?\\\"}&lt;\\/span&gt;;\\n}\\nconst STATUS = { Active: T.green, Warning: T.viz.amber, Inactive: T.faint, Error: T.red };\\nfunction StatusChip({ status }) {\\n  return {status}&lt;\\/span&gt;;\\n}\\nconst RISK = { Critical: SEVC.critical, High: SEVC.high, Medium: SEVC.medium, Low: SEVC.low };\\nfunction RiskChip({ level }) {\\n  const c = RISK[level];\\n  return {level}&lt;\\/span&gt;;\\n}\\nfunction Delta({ up, children }) {\\n  const color = up ? T.green : T.red;\\n  return {up ?  : }{children}&lt;\\/span&gt;;\\n}\\nfunction IconBtn({ children, onClick }) {\\n  const [h, setH] = useState(false);\\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ width: 26, height: 26, borderRadius: 6, border: \\\"none\\\", cursor: \\\"pointer\\\", background: h ? T.surface2 : \\\"transparent\\\", color: h ? T.ink : T.faint, display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\" }}&gt;{children}&lt;\\/button&gt;;\\n}\\n\\n/* ============ KPIs ============ */\\nconst KPIS = [\\n  { label: \\\"Total Assets\\\", value: 84355, delta: \\\"12.4%\\\", up: true },\\n  { label: \\\"Cloud Coverage\\\", value: 96.2, suffix: \\\"%\\\", delta: \\\"2.1%\\\", up: true },\\n  { label: \\\"Open Vulnerabilities\\\", value: 382, delta: \\\"8.0%\\\", up: false },\\n  { label: \\\"Unmanaged Devices\\\", value: 1204, delta: \\\"3.2%\\\", up: false },\\n];\\nfunction useCountUp(target, dur = 950) {\\n  const [v, setV] = useState(0);\\n  useEffect(() =&gt; {\\n    let raf; const start = performance.now();\\n    const tick = (now) =&gt; { const p = Math.min(1, (now - start) / dur); setV(target * (1 - Math.pow(1 - p, 3))); if (p &lt; 1) raf = requestAnimationFrame(tick); };\\n    raf = requestAnimationFrame(tick); return () =&gt; cancelAnimationFrame(raf);\\n  }, [target]);\\n  return v;\\n}\\nfunction KpiValue({ value, suffix }) {\\n  const v = useCountUp(value);\\n  const text = suffix === \\\"%\\\" ? v.toFixed(1) : fmt(Math.round(v));\\n  return {text}{suffix || \\\"\\\"}&lt;\\/span&gt;;\\n}\\nfunction KpiRow() {\\n  return (\\n    \n\\n      {KPIS.map((k, i) =&gt; (\\n        \n\\n          \n{k.label}&lt;\\/div&gt;\\n          \n\\n            \\n            {k.delta}&lt;\\/Delta&gt;\\n          &lt;\\/div&gt;\\n        &lt;\\/div&gt;\\n      ))}\\n    &lt;\\/div&gt;\\n  );\\n}\\n\\n/* ============ chart bodies ============ */\\nconst PIE = [\\n  { c: \\\"green\\\", label: \\\"Windows Assets\\\", val: 1236 }, { c: \\\"greenDeep\\\", label: \\\"Active Directory\\\", val: 411 },\\n  { c: \\\"mint\\\", label: \\\"SCCM Managed\\\", val: 198 }, { c: \\\"lilac\\\", label: \\\"Intune Managed\\\", val: 89 }, { c: \\\"lilacPale\\\", label: \\\"Unmanaged\\\", val: 43 },\\n];\\nfunction DonutBody() {\\n  const [hi, setHi] = useState(null);\\n  const [tip, setTip] = useState(null);\\n  const [off, setOff] = useState(() =&gt; new Set());\\n  const [drawn, setDrawn] = useState(false);\\n  useEffect(() =&gt; { const id = setTimeout(() =&gt; setDrawn(true), 60); return () =&gt; clearTimeout(id); }, []);\\n  const r = 46, sw = 14, C = 2 * Math.PI * r, gap = 5;\\n  const toggle = (i) =&gt; setOff(s =&gt; { const n = new Set(s); n.has(i) ? n.delete(i) : n.add(i); return n; });\\n  const visTotal = PIE.reduce((a, p, i) =&gt; a + (off.has(i) ? 0 : p.val), 0) || 1;\\n  let acc = 0;\\n  const segs = PIE.map((p, i) =&gt; {\\n    if (off.has(i)) return null;\\n    const len = (p.val / visTotal) * C;\\n    const seg = Math.max(1, len - gap);\\n    const active = hi === i, dim = hi !== null &amp;&amp; !off.has(hi) &amp;&amp; !active;\\n    const node = (\\n       { setHi(i); setTip({ i, x: e.clientX, y: e.clientY }); }} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; { setHi(null); setTip(null); }} onClick={() =&gt; toggle(i)}\\n        style={{ opacity: dim ? 0.35 : 1, cursor: \\\"pointer\\\", transition: \\\"stroke-dasharray .8s cubic-bezier(.22,1,.36,1), stroke-width .18s ease, opacity .18s ease\\\" }} /&gt;\\n    );\\n    acc += len; return node;\\n  });\\n  const liveHi = hi !== null &amp;&amp; !off.has(hi);\\n  const center = liveHi ? { big: ((PIE[hi].val / visTotal) * 100).toFixed(1) + \\\"%\\\", small: PIE[hi].label } : { big: fmt(visTotal), small: \\\"Total Assets\\\" };\\n  return (\\n    \n\\n      \n\\n        \\n          \\n          {segs}\\n        &lt;\\/svg&gt;\\n        \n\\n          {center.big}&lt;\\/span&gt;\\n          {center.small}&lt;\\/span&gt;\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n      \n\\n        {PIE.map((p, i) =&gt; {\\n          const isOff = off.has(i);\\n          return (\\n            \n { setHi(i); if (!isOff) setTip({ i, x: e.clientX, y: e.clientY }); }} onMouseMove={(e) =&gt; !isOff &amp;&amp; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; { setHi(null); setTip(null); }} onClick={() =&gt; toggle(i)}\\n              title={isOff ? \\\"Click to show\\\" : \\\"Click to hide\\\"}\\n              style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 9, padding: \\\"5px 6px\\\", borderRadius: 6, cursor: \\\"pointer\\\", background: hi === i &amp;&amp; !isOff ? T.canvas : \\\"transparent\\\", transition: \\\"background .12s\\\" }}&gt;\\n              \\n              {p.label}&lt;\\/span&gt;\\n              {isOff ? \\\"Hidden\\\" : (hi === i ? fmt(p.val) : ((p.val / visTotal) * 100).toFixed(1) + \\\"%\\\")}&lt;\\/span&gt;\\n            &lt;\\/div&gt;\\n          );\\n        })}\\n      &lt;\\/div&gt;\\n      {tip !== null &amp;&amp; !off.has(tip.i) &amp;&amp; \\n        \n{PIE[tip.i].label}&lt;\\/div&gt;\\n        \n{fmt(PIE[tip.i].val)}&lt;\\/div&gt;\\n        \n{(PIE[tip.i].val / visTotal * 100).toFixed(1)}% of assets&lt;\\/div&gt;\\n      &lt;\\/FloatTip&gt;}\\n    &lt;\\/div&gt;\\n  );\\n}\\nconst LINE_LABELS = [\\\"W1\\\", \\\"W2\\\", \\\"W3\\\", \\\"W4\\\", \\\"W5\\\", \\\"W6\\\", \\\"W7\\\", \\\"W8\\\", \\\"W9\\\", \\\"W10\\\", \\\"W11\\\", \\\"W12\\\"];\\nconst LINE_SERIES = [\\n  { key: \\\"all\\\", label: \\\"All Devices\\\", color: T.viz.green, pts: [38000, 41200, 44500, 47800, 51000, 55300, 59800, 63200, 68500, 72100, 78400, 84355] },\\n  { key: \\\"managed\\\", label: \\\"Managed\\\", color: T.viz.lilac, pts: [29000, 31000, 33500, 35800, 38000, 41000, 44500, 47200, 50500, 54100, 58400, 61200] },\\n  { key: \\\"cloud\\\", label: \\\"Cloud\\\", color: T.viz.orange, pts: [8000, 9200, 10500, 11800, 13000, 14300, 15800, 17200, 18500, 20100, 21400, 22097] },\\n  { key: \\\"unmanaged\\\", label: \\\"Unmanaged\\\", color: T.viz.greenDeep, pts: [3200, 3100, 3300, 3000, 3500, 3300, 3100, 2900, 2700, 2500, 2300, 2100] },\\n];\\nfunction LineBody() {\\n  const [off, setOff] = useState(() =&gt; new Set());\\n  const [hov, setHov] = useState(null);\\n  const w = 680, h = 196, padT = 12, padB = 12, padL = 8, padR = 8, n = LINE_LABELS.length, max = 90000;\\n  const yAxisW = 40;\\n  const X = (i) =&gt; padL + (i / (n - 1)) * (w - padL - padR);\\n  const Y = (v) =&gt; padT + (1 - v / max) * (h - padT - padB);\\n  const smooth = (pts) =&gt; { let d = `M ${X(0)} ${Y(pts[0])}`; for (let i = 1; i &lt; n; i++) { const cx = (X(i - 1) + X(i)) / 2; d += ` C ${cx} ${Y(pts[i - 1])}, ${cx} ${Y(pts[i])}, ${X(i)} ${Y(pts[i])}`; } return d; };\\n  const toggle = (k) =&gt; setOff(s =&gt; { const x = new Set(s); x.has(k) ? x.delete(k) : x.add(k); return x; });\\n  const visible = LINE_SERIES.filter(s =&gt; !off.has(s.key));\\n  const xPct = (i) =&gt; (X(i) / w) * 100, yPct = (v) =&gt; (Y(v) / h) * 100;\\n  const yTicks = [90000, 60000, 30000, 0];\\n  return (\\n    \n\\n      \n\\n        {/* Y-axis labels */}\\n        \n\\n          {yTicks.map((v, i) =&gt; (\\n            {v === 0 ? \\\"0\\\" : (v / 1000) + \\\"K\\\"}&lt;\\/span&gt;\\n          ))}\\n        &lt;\\/div&gt;\\n        {/* Chart area */}\\n        \n setHov(null)}&gt;\\n          \\n            {yTicks.map((v, i) =&gt; )}\\n            {hov &amp;&amp; }\\n            {visible.map(s =&gt; )}\\n          &lt;\\/svg&gt;\\n          {visible.map(s =&gt; s.pts.map((v, i) =&gt; {\\n            const isHov = hov &amp;&amp; hov.s.key === s.key &amp;&amp; hov.i === i, dim = hov &amp;&amp; !isHov;\\n            return (\\n              \n setHov({ s, i })}\\n                style={{ position: \\\"absolute\\\", left: `${xPct(i)}%`, top: `${yPct(v)}%`, transform: \\\"translate(-50%, -50%)\\\", width: 20, height: 20, display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\", cursor: \\\"pointer\\\", zIndex: isHov ? 4 : 2 }}&gt;\\n                \\n              &lt;\\/div&gt;\\n            );\\n          }))}\\n          {hov &amp;&amp; (\\n            \n n - 4 ? \\\"calc(-100% - 12px)\\\" : hov.i &lt; 3 ? \\\"12px\\\" : \\\"-50%\\\"}, calc(-100% - 14px))`, background: T.surface, border: `1px solid ${T.line}`, borderRadius: 10, boxShadow: T.shadow, padding: \\\"9px 12px\\\", whiteSpace: \\\"nowrap\\\", pointerEvents: \\\"none\\\", zIndex: 6 }}&gt;\\n              \n{hov.s.label}&lt;\\/div&gt;\\n              \n{fmt(hov.s.pts[hov.i])}&lt;\\/div&gt;\\n              {hov.i &gt; 0 &amp;&amp; (() =&gt; { const pct = (hov.s.pts[hov.i] - hov.s.pts[hov.i - 1]) / hov.s.pts[hov.i - 1] * 100; const up = pct &gt;= 0; return \n{up ?  : }{up ? \\\"+\\\" : \\\"\\\"}{pct.toFixed(1)}% from prev&lt;\\/div&gt;; })()}\\n              \n{LINE_LABELS[hov.i]}&lt;\\/div&gt;\\n            &lt;\\/div&gt;\\n          )}\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n      {/* X-axis labels */}\\n      \n\\n        {LINE_LABELS.map((label, i) =&gt; (\\n          \n{i % 3 === 0 ? label : \\\"\\\"}&lt;\\/div&gt;\\n        ))}\\n      &lt;\\/div&gt;\\n      \n\\n        {LINE_SERIES.map(s =&gt; {\\n          const isOff = off.has(s.key);\\n          return (\\n             toggle(s.key)} title={isOff ? \\\"Show series\\\" : \\\"Hide series\\\"} className=\\\"ax-press\\\"\\n              style={{ display: \\\"inline-flex\\\", alignItems: \\\"center\\\", gap: 6, padding: \\\"3px 9px\\\", borderRadius: 999, border: `1px solid ${isOff ? T.lineSoft : T.line}`, background: isOff ? \\\"transparent\\\" : T.canvas, cursor: \\\"pointer\\\", fontFamily: T.font, fontSize: 11.5, fontWeight: 500, color: isOff ? T.faint : T.body, transition: \\\"all .14s\\\" }}&gt;\\n              \\n              {s.label}&lt;\\/span&gt;\\n            &lt;\\/button&gt;\\n          );\\n        })}\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\nconst STACK_DATA = [[\\\"Jan\\\", 40, 25, 20], [\\\"Feb\\\", 35, 30, 15], [\\\"Mar\\\", 52, 22, 26], [\\\"Apr\\\", 30, 35, 18], [\\\"May\\\", 48, 28, 24], [\\\"Jun\\\", 58, 32, 28]];\\nconst STACK_SERIES = [\\n  { key: \\\"cloud\\\", label: \\\"Cloud\\\", color: T.viz.green },\\n  { key: \\\"onprem\\\", label: \\\"On-prem\\\", color: T.viz.mint },\\n  { key: \\\"saas\\\", label: \\\"SaaS\\\", color: T.viz.lilac },\\n];\\nfunction StackedBody() {\\n  const [off, setOff] = useState(() =&gt; new Set());\\n  const [segHov, setSegHov] = useState(null);\\n  const [tip, setTip] = useState(null);\\n  const toggle = (key) =&gt; setOff(s =&gt; { const n = new Set(s); n.has(key) ? n.delete(key) : n.add(key); return n; });\\n  const visSeries = STACK_SERIES.filter(s =&gt; !off.has(s.key));\\n  const yAxisW = 34;\\n  const allTotals = STACK_DATA.map(row =&gt; visSeries.reduce((sum, s) =&gt; sum + row[STACK_SERIES.findIndex(s2 =&gt; s2.key === s.key) + 1], 0));\\n  const rawMax = Math.max(...allTotals, 1);\\n  const yMax = Math.ceil(rawMax / 20) * 20;\\n  const yTicks = [yMax, yMax * 0.75, yMax * 0.5, yMax * 0.25, 0];\\n  const tipContent = tip &amp;&amp; segHov ? (() =&gt; {\\n    const row = STACK_DATA[segHov.col];\\n    const s = STACK_SERIES.find(s =&gt; s.key === segHov.key);\\n    const idx = STACK_SERIES.findIndex(s2 =&gt; s2.key === segHov.key);\\n    const val = row[idx + 1] * 86;\\n    const totalVis = visSeries.reduce((sum, ss) =&gt; sum + row[STACK_SERIES.findIndex(s2 =&gt; s2.key === ss.key) + 1], 0);\\n    const pct = (row[idx + 1] / (totalVis || 1) * 100).toFixed(1);\\n    return { label: s.label, color: s.color, val, pct, month: row[0] };\\n  })() : null;\\n  return (\\n    \n\\n      {tip &amp;&amp; tipContent &amp;&amp; \\n        \n{tipContent.month}&lt;\\/div&gt;\\n        \n{tipContent.label}&lt;\\/div&gt;\\n        \n{fmt(tipContent.val)}&lt;\\/div&gt;\\n        \n{tipContent.pct}% of total&lt;\\/div&gt;\\n      &lt;\\/FloatTip&gt;}\\n      \n\\n        {/* Y-axis */}\\n        \n\\n          {yTicks.map((v, i) =&gt; (\\n            {v === 0 ? \\\"0\\\" : v + \\\"K\\\"}&lt;\\/span&gt;\\n          ))}\\n        &lt;\\/div&gt;\\n        {/* Bars */}\\n        \n\\n          \n\\n            {yTicks.map((v, i) =&gt; (\\n              \n\\n            ))}\\n            {STACK_DATA.map((row, ci) =&gt; {\\n              const total = visSeries.reduce((sum, s) =&gt; sum + row[STACK_SERIES.findIndex(s2 =&gt; s2.key === s.key) + 1], 0);\\n              const colHov = segHov?.col === ci;\\n              const dim = segHov &amp;&amp; !colHov;\\n              return (\\n                \n\\n                  \n\\n                    {visSeries.map((s, si) =&gt; {\\n                      const val = row[STACK_SERIES.findIndex(s2 =&gt; s2.key === s.key) + 1];\\n                      const isFirst = si === 0, isLast = si === visSeries.length - 1;\\n                      const isHov = segHov?.col === ci &amp;&amp; segHov?.key === s.key;\\n                      return (\\n                        \n { setSegHov({ col: ci, key: s.key }); setTip({ x: e.clientX, y: e.clientY }); }}\\n                          onMouseMove={(e) =&gt; setTip({ x: e.clientX, y: e.clientY })}\\n                          onMouseLeave={() =&gt; { setSegHov(null); setTip(null); }}\\n                          style={{ flex: val, background: s.color, borderRadius: isFirst ? \\\"6px 6px 0 0\\\" : isLast ? \\\"0 0 6px 6px\\\" : 0, filter: isHov ? \\\"brightness(1.18)\\\" : \\\"none\\\", transition: \\\"filter .15s\\\", cursor: \\\"pointer\\\" }} /&gt;\\n                      );\\n                    })}\\n                  &lt;\\/div&gt;\\n                  {row[0]}&lt;\\/span&gt;\\n                &lt;\\/div&gt;\\n              );\\n            })}\\n          &lt;\\/div&gt;\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n      {/* Clickable legend */}\\n      \n\\n        {STACK_SERIES.map(s =&gt; {\\n          const isOff = off.has(s.key);\\n          return (\\n             toggle(s.key)} className=\\\"ax-press\\\"\\n              style={{ display: \\\"inline-flex\\\", alignItems: \\\"center\\\", gap: 6, padding: \\\"3px 9px\\\", borderRadius: 999, border: `1px solid ${isOff ? T.lineSoft : T.line}`, background: isOff ? \\\"transparent\\\" : T.canvas, cursor: \\\"pointer\\\", fontFamily: T.font, fontSize: 11.5, fontWeight: 500, color: isOff ? T.faint : T.body, transition: \\\"all .14s\\\" }}&gt;\\n              \\n              {s.label}&lt;\\/span&gt;\\n            &lt;\\/button&gt;\\n          );\\n        })}\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\nconst SEV = [[\\\"Critical\\\", 142, 100, SEVC.critical], [\\\"High\\\", 98, 70, SEVC.high], [\\\"Medium\\\", 76, 54, SEVC.medium], [\\\"Low\\\", 45, 32, SEVC.low], [\\\"Info\\\", 21, 15, SEVC.info]];\\nconst SEV_ASSETS = {\\n  Critical: [[\\\"PC-CURTIS-WILLIAMS\\\", \\\"CVE-2024-21412 \\u00b7 SmartScreen bypass\\\"], [\\\"srv-db-fin-04\\\", \\\"CVE-2024-3094 \\u00b7 xz-utils backdoor\\\"], [\\\"esx-infranginx-5567897\\\", \\\"CVE-2023-46604 \\u00b7 ActiveMQ RCE\\\"], [\\\"WIN-RUTHD\\\", \\\"CVE-2024-21413 \\u00b7 Outlook RCE\\\"]],\\n  High: [[\\\"macbook-pro-jdoe\\\", \\\"CVE-2024-23222 \\u00b7 WebKit type confusion\\\"], [\\\"azure-infra9274676\\\", \\\"CVE-2024-21401 \\u00b7 Entra ID elevation\\\"], [\\\"lablb-2918146-beta\\\", \\\"CVE-2024-1709 \\u00b7 ScreenConnect auth bypass\\\"]],\\n  Medium: [[\\\"iphone-asmith\\\", \\\"CVE-2024-23225 \\u00b7 kernel memory\\\"], [\\\"sepio-external3026786\\\", \\\"CVE-2024-0519 \\u00b7 V8 out-of-bounds\\\"]],\\n  Low: [[\\\"android-pixel-7\\\", \\\"CVE-2024-0039 \\u00b7 System component\\\"]],\\n  Info: [[\\\"win-marychasse\\\", \\\"Informational \\u00b7 TLS 1.0 enabled\\\"]],\\n};\\nfunction SeverityDrawer({ sev, close }) {\\n  const list = SEV_ASSETS[sev[0]] || [];\\n  return createPortal(&lt;&gt;\\n    \n\\n    \n\\n      \n\\n        \\n        \n\\n          \n{sev[0]} severity&lt;\\/div&gt;\\n          \n{sev[1]} open vulnerabilities \\u00b7 {list.length} assets shown&lt;\\/div&gt;\\n        &lt;\\/div&gt;\\n        &lt;\\/IconBtn&gt;\\n      &lt;\\/div&gt;\\n      \n\\n        {list.map(([host, cve], i) =&gt; (\\n          \n\\n            \n\\n              {host}&lt;\\/span&gt;\\n              {sev[0]}&lt;\\/span&gt;\\n            &lt;\\/div&gt;\\n            {cve}&lt;\\/span&gt;\\n          &lt;\\/div&gt;\\n        ))}\\n      &lt;\\/div&gt;\\n      \n\\n        View all {sev[1]} in Inventory&lt;\\/button&gt;\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  &lt;\\/&gt;, document.body);\\n}\\nfunction SeverityBody() {\\n  const [hi, setHi] = useState(null);\\n  const [drill, setDrill] = useState(null);\\n  const [tip, setTip] = useState(null);\\n  const sevTotal = SEV.reduce((a, b) =&gt; a + b[1], 0);\\n  return (&lt;&gt;\\n    \n\\n      {SEV.map((b, i) =&gt; {\\n        const active = hi === i, dim = hi !== null &amp;&amp; !active;\\n        return (\\n          \n setDrill(b)} onMouseEnter={(e) =&gt; { setHi(i); setTip({ i, x: e.clientX, y: e.clientY }); }} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; { setHi(null); setTip(null); }}\\n            style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 12, opacity: dim ? 0.5 : 1, transition: \\\"opacity .15s\\\", cursor: \\\"pointer\\\" }}&gt;\\n            {b[0]}&lt;\\/span&gt;\\n            \n\n&lt;\\/div&gt;\\n            {active ? b[1] + \\\" open\\\" : b[1]}&lt;\\/span&gt;\\n          &lt;\\/div&gt;\\n        );\\n      })}\\n    &lt;\\/div&gt;\\n    {tip &amp;&amp; \n{SEV[tip.i][0]}&lt;\\/div&gt;\n{fmt(SEV[tip.i][1])}&lt;\\/div&gt;\n{Math.round(SEV[tip.i][1] / sevTotal * 100)}% of open findings&lt;\\/div&gt;&lt;\\/FloatTip&gt;}\\n    {drill &amp;&amp;  setDrill(null)} /&gt;}\\n  &lt;\\/&gt;);\\n}\\nconst ST_COLOR = { ok: T.viz.green, warn: T.viz.amber, err: T.red };\\n\\n/* ===== System Lifecycle (discovery cycle) ===== */\\nconst LIFECYCLE = [\\n  { name: \\\"Fetch\\\", pct: 100 }, { name: \\\"Clean\\\", pct: 100 }, { name: \\\"Correlate\\\", pct: 100 },\\n  { name: \\\"Enrich\\\", pct: 78 }, { name: \\\"Calculate\\\", pct: 0 },\\n];\\nfunction LifecycleBody() {\\n  const [tip, setTip] = useState(null);\\n  const done = LIFECYCLE.filter(s =&gt; s.pct === 100).length, total = LIFECYCLE.length;\\n  const overall = Math.round(LIFECYCLE.reduce((a, s) =&gt; a + s.pct, 0) / total);\\n  const r = 42, sw = 11, C = 2 * Math.PI * r, dash = (overall / 100) * C;\\n  return (\\n    \n\\n      {tip &amp;&amp; \n{LIFECYCLE[tip.i].name} stage&lt;\\/div&gt;\n{LIFECYCLE[tip.i].pct &gt; 0 ? LIFECYCLE[tip.i].pct + \\\"% complete\\\" : \\\"Not started\\\"}&lt;\\/div&gt;&lt;\\/FloatTip&gt;}\\n      \n\\n        \n\\n          \\n            \\n            \\n          &lt;\\/svg&gt;\\n          \n\\n            {done}/{total}&lt;\\/span&gt;\\n            Stages&lt;\\/span&gt;\\n          &lt;\\/div&gt;\\n        &lt;\\/div&gt;\\n        \n\\n          {LIFECYCLE.map((s, i) =&gt; {\\n            const c = s.pct === 100 ? T.viz.green : s.pct &gt; 0 ? T.blue : T.bg40;\\n            return (\\n              \n setTip({ i, x: e.clientX, y: e.clientY })} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; setTip(null)} style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 10, cursor: \\\"default\\\" }}&gt;\\n                {s.name}&lt;\\/span&gt;\\n                \n\\n                  \n\\n                &lt;\\/div&gt;\\n                 0 ? T.blue : T.bg40, ...tnum }}&gt;{s.pct &gt; 0 ? s.pct + \\\"%\\\" : \\\"\\u2014\\\"}&lt;\\/span&gt;\\n              &lt;\\/div&gt;\\n            );\\n          })}\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n      \n\\n        {[[\\\"Cycle started\\\", \\\"09:00:04\\\"], [\\\"Duration\\\", \\\"00:42:18\\\"], [\\\"Next cycle\\\", \\\"13:17:42\\\"]].map(([k, v], i) =&gt; (\\n          \n\\n            \n{k}&lt;\\/div&gt;\\n            \n{v}&lt;\\/div&gt;\\n          &lt;\\/div&gt;\\n        ))}\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\n\\n/* ===== Discovery Log ===== */\\nconst DISC_PHASES = [[\\\"Fetch\\\", T.viz.green], [\\\"Clean\\\", T.viz.mint], [\\\"Correlate\\\", T.viz.lilac], [\\\"Enrich\\\", T.viz.lilacPale], [\\\"Calculate\\\", T.viz.amber], [\\\"Save\\\", T.viz.orange]];\\nconst DISCOVERY = [\\n  { started: \\\"Jun 15, 09:00\\\", completed: \\\"Jun 15, 09:35\\\", duration: \\\"35min 22sec\\\", ph: [40, 12, 18, 10, 12, 8] },\\n  { started: \\\"Jun 14, 09:00\\\", completed: \\\"Jun 14, 09:35\\\", duration: \\\"35min 59sec\\\", ph: [38, 14, 17, 11, 12, 8] },\\n  { started: \\\"Jun 13, 09:00\\\", completed: \\\"Jun 13, 09:35\\\", duration: \\\"35min 29sec\\\", ph: [41, 11, 18, 10, 12, 8] },\\n  { started: \\\"Jun 12, 09:00\\\", completed: \\\"Jun 12, 09:35\\\", duration: \\\"35min 11sec\\\", ph: [39, 13, 17, 11, 12, 8] },\\n  { started: \\\"Jun 11, 09:00\\\", completed: \\\"Jun 11, 09:35\\\", duration: \\\"35min 58sec\\\", ph: [44, 12, 16, 9, 11, 8] },\\n  { started: \\\"Jun 10, 09:00\\\", completed: \\\"Jun 10, 09:30\\\", duration: \\\"30min 54sec\\\", ph: [36, 12, 18, 12, 14, 8] },\\n  { started: \\\"Jun 9, 09:00\\\", completed: \\\"Jun 9, 09:34\\\", duration: \\\"34min 02sec\\\", ph: [37, 13, 17, 11, 13, 9] },\\n  { started: \\\"Jun 8, 09:00\\\", completed: \\\"Jun 8, 09:31\\\", duration: \\\"31min 38sec\\\", ph: [40, 12, 17, 10, 13, 8] },\\n];\\nfunction DiscoveryBody() {\\n  const [hi, setHi] = useState(null);\\n  const [tip, setTip] = useState(null);\\n  const cols = \\\"minmax(70px, 1.6fr) 104px 92px\\\";\\n  const durToSec = (s) =&gt; { let t = 0; const m = s.match(/(\\\\d+)\\\\s*min/), sec = s.match(/(\\\\d+)\\\\s*sec/); if (m) t += +m[1] * 60; if (sec) t += +sec[1]; return t; };\\n  const fmtDur = (x) =&gt; { x = Math.round(x); const m = Math.floor(x / 60), s = x % 60; return m &gt; 0 ? `${m}min ${s}sec` : `${s}sec`; };\\n  return (\\n    \n\\n      \n\\n        {[\\\"Latest Discoveries\\\", \\\"Started\\\", \\\"Duration\\\"].map((c, i) =&gt; (\\n          {c}&lt;\\/span&gt;\\n        ))}\\n      &lt;\\/div&gt;\\n      \n\\n        {DISCOVERY.map((d, i) =&gt; (\\n          \n setHi(i)} onMouseLeave={() =&gt; { setHi(null); setTip(null); }}\\n            style={{ display: \\\"grid\\\", gridTemplateColumns: cols, gap: 12, alignItems: \\\"center\\\", padding: \\\"7px 6px\\\", borderBottom: i &lt; DISCOVERY.length - 1 ? `1px solid ${T.hair}` : \\\"none\\\", background: hi === i ? T.canvas : \\\"transparent\\\", borderRadius: 6, transition: \\\"background .12s\\\" }}&gt;\\n            \n\\n              {d.ph.map((w, j) =&gt;  setTip({ d, j, x: e.clientX, y: e.clientY })} onMouseMove={(e) =&gt; setTip({ d, j, x: e.clientX, y: e.clientY })}\\n                style={{ width: `${w}%`, height: \\\"100%\\\", background: DISC_PHASES[j][1], cursor: \\\"pointer\\\" }} /&gt;)}\\n            &lt;\\/div&gt;\\n            {d.started}&lt;\\/span&gt;\\n            {d.duration}&lt;\\/span&gt;\\n          &lt;\\/div&gt;\\n        ))}\\n      &lt;\\/div&gt;\\n      {tip &amp;&amp; \\n        \n{DISC_PHASES[tip.j][0]}&lt;\\/div&gt;\\n        \n{fmtDur(durToSec(tip.d.duration) * tip.d.ph[tip.j] / 100)}&lt;\\/div&gt;\\n        \n{tip.d.ph[tip.j]}% of cycle&lt;\\/div&gt;\\n      &lt;\\/FloatTip&gt;}\\n    &lt;\\/div&gt;\\n  );\\n}\\n\\n/* ===== Adapter Connections (status + logo coin + preview) ===== */\\nconst ADAPTER_CONN = [\\n  { brand: \\\"crowdstrike\\\", name: \\\"CrowdStrike\\\", st: \\\"ok\\\", desc: \\\"9,120 devices \\u00b7 synced 4m ago\\\" },\\n  { brand: \\\"aws\\\", name: \\\"Amazon Web Services\\\", st: \\\"ok\\\", desc: \\\"12,400 assets \\u00b7 synced 6m ago\\\" },\\n  { brand: \\\"azure\\\", name: \\\"Microsoft Azure\\\", st: \\\"ok\\\", desc: \\\"22,097 assets \\u00b7 synced 5m ago\\\" },\\n  { brand: \\\"okta\\\", name: \\\"Okta\\\", st: \\\"ok\\\", desc: \\\"9,870 users \\u00b7 synced 8m ago\\\" },\\n  { short: \\\"Jm\\\", color: \\\"#3B3B3B\\\", name: \\\"Jamf Pro\\\", st: \\\"err\\\", desc: \\\"Connection timeout \\u2014 check credentials\\\" },\\n  { short: \\\"now\\\", color: \\\"#2E8B57\\\", name: \\\"ServiceNow\\\", st: \\\"warn\\\", desc: \\\"Rate limited \\u00b7 retrying\\\" },\\n  { brand: \\\"googlecloud\\\", name: \\\"Google Cloud\\\", st: \\\"ok\\\", desc: \\\"9,055 assets \\u00b7 synced 7m ago\\\" },\\n  { brand: \\\"vmware\\\", name: \\\"VMware vCenter\\\", st: \\\"ok\\\", desc: \\\"4,310 VMs \\u00b7 synced 11m ago\\\" },\\n];\\nconst ST_LABEL = { ok: \\\"Connected\\\", warn: \\\"Degraded\\\", err: \\\"Error\\\" };\\nfunction AdapterCoin({ a }) {\\n  if (a.brand) return ;\\n  return {a.short}&lt;\\/span&gt;;\\n}\\nfunction AdaptersBody() {\\n  const connected = ADAPTER_CONN.filter(a =&gt; a.st === \\\"ok\\\").length;\\n  const attention = ADAPTER_CONN.length - connected;\\n  return (\\n    \n\\n      \n\\n        {connected}&lt;\\/span&gt;\\n        connected sources&lt;\\/span&gt;\\n        {attention &gt; 0 &amp;&amp; {attention} need attention&lt;\\/span&gt;}\\n      &lt;\\/div&gt;\\n      \n\\n        {ADAPTER_CONN.map((a, i) =&gt; {\\n          const ring = ST_COLOR[a.st];\\n          return (\\n            \n\\n              \\n              \n\\n                \n{a.name}&lt;\\/div&gt;\\n                \n\\n                  \\n                  {a.desc}&lt;\\/span&gt;\\n                &lt;\\/div&gt;\\n              &lt;\\/div&gt;\\n            &lt;\\/div&gt;\\n          );\\n        })}\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\nconst HEALTH_OK_BRANDS = [\\\"crowdstrike\\\", \\\"aws\\\", \\\"azure\\\", \\\"okta\\\", \\\"googlecloud\\\", \\\"vmware\\\"];\\nfunction HealthOkBody() {\\n  return (\\n    \n\\n      \n\\n        33&lt;\\/span&gt;\\n        adapters syncing successfully&lt;\\/span&gt;\\n      &lt;\\/div&gt;\\n      \n\\n        {HEALTH_OK_BRANDS.map((b, i) =&gt; )}\\n        +27&lt;\\/span&gt;\\n      &lt;\\/div&gt;\\n      \n\\n         100% healthy \\u00b7 last full sync 4m ago\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\nconst HEALTH_FAIL = [\\n  { short: \\\"Jm\\\", color: \\\"#3B3B3B\\\", name: \\\"Jamf Pro\\\", reason: \\\"Connection timeout \\u2014 check credentials\\\" },\\n  { short: \\\"now\\\", color: \\\"#2E8B57\\\", name: \\\"ServiceNow\\\", reason: \\\"Rate limited \\u00b7 retrying\\\" },\\n];\\nfunction HealthFailBody() {\\n  return (\\n    \n\\n      \n\\n        {HEALTH_FAIL.length}&lt;\\/span&gt;\\n        adapters need attention&lt;\\/span&gt;\\n      &lt;\\/div&gt;\\n      \n\\n        {HEALTH_FAIL.map((a, i) =&gt; (\\n          \n\\n            {a.short}&lt;\\/span&gt;\\n            \n\\n              \n{a.name}&lt;\\/div&gt;\\n              \n{a.reason}&lt;\\/div&gt;\\n            &lt;\\/div&gt;\\n            Fix&lt;\\/button&gt;\\n          &lt;\\/div&gt;\\n        ))}\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\n/* ===== Cost Optimization dashboard ===== */\\nconst fmtMoney = (n) =&gt; n.toLocaleString(\\\"en-US\\\");\\nfunction CostKPI({ value, unit }) {\\n  return (\\n    \n\\n      {value}&lt;\\/span&gt;\\n      {unit &amp;&amp; {unit}&lt;\\/span&gt;}\\n    &lt;\\/div&gt;\\n  );\\n}\\nfunction HBarList({ rows, accent, prefix, avatar, appLogo }) {\\n  const max = Math.max(...rows.map(r =&gt; r[1]), 1);\\n  const totalVal = rows.reduce((a, r) =&gt; a + r[1], 0) || 1;\\n  const [tip, setTip] = useState(null);\\n  return (\\n    \n\\n      {rows.map(([label, val], i) =&gt; {\\n        const pct = Math.max(4, (val / max) * 100), inside = pct &gt; 24;\\n        return (\\n          \n setTip({ i, x: e.clientX, y: e.clientY })} onMouseMove={(e) =&gt; setTip({ i, x: e.clientX, y: e.clientY })} onMouseLeave={() =&gt; setTip(null)}\\n            style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 12, cursor: \\\"default\\\" }}&gt;\\n            {avatar &amp;&amp; }{appLogo &amp;&amp; }{label}&lt;\\/span&gt;&lt;\\/span&gt;\\n            \n\\n              \n\\n                {inside &amp;&amp; {prefix || \\\"\\\"}{fmtMoney(val)}&lt;\\/span&gt;}\\n              &lt;\\/div&gt;\\n              {!inside &amp;&amp; {prefix || \\\"\\\"}{fmtMoney(val)}&lt;\\/span&gt;}\\n            &lt;\\/div&gt;\\n          &lt;\\/div&gt;\\n        );\\n      })}\\n      {tip &amp;&amp; \\n        \n{rows[tip.i][0]}&lt;\\/div&gt;\\n        \n{prefix || \\\"\\\"}{fmtMoney(rows[tip.i][1])}&lt;\\/div&gt;\\n        \n{(rows[tip.i][1] / totalVal * 100).toFixed(1)}% of shown total&lt;\\/div&gt;\\n      &lt;\\/FloatTip&gt;}\\n    &lt;\\/div&gt;\\n  );\\n}\\nconst COST_CATEGORY = [[\\\"Productivity\\\", 141993], [\\\"Video Conference\\\", 55928], [\\\"File Sharing\\\", 52943], [\\\"Authentication\\\", 11440], [\\\"CRM\\\", 9870]];\\nconst COST_APP = [[\\\"Zoom\\\", 55928], [\\\"Miro\\\", 52885], [\\\"Dropbox\\\", 50431], [\\\"Salesforce\\\", 43176], [\\\"Slack\\\", 38420]];\\nconst COST_TOPLIC = [[\\\"Zoom One Pro\\\", 70800], [\\\"Google WS Ent. Starter\\\", 27450], [\\\"Google WS Ent. Standard\\\", 12985], [\\\"Google WS Business\\\", 8640], [\\\"Microsoft 365 G3 GCC\\\", 1930]];\\nconst COST_USAGE = [[\\\"aaron.church@demo.local\\\", 29], [\\\"aaron.daniels@demo.local\\\", 29], [\\\"ada.pires@demo.local\\\", 29], [\\\"adelaide.gercak@demo.local\\\", 29], [\\\"adrian.williams@demo.local\\\", 29]];\\nconst COST_RENEWALS = [\\n  { app: \\\"Office365\\\", name: \\\"Microsoft 365 E5\\\", date: \\\"2026-07-06\\\", cost: \\\"3,175.50\\\", term: \\\"Yearly\\\", unit: \\\"54.75\\\" },\\n  { app: \\\"Office365\\\", name: \\\"Microsoft Power Aut\\u2026\\\", date: \\\"2026-08-07\\\", cost: \\\"6,518.75\\\", term: \\\"Yearly\\\", unit: \\\"37.25\\\" },\\n];\\nfunction CostExpAllBody() { return ; }\\nfunction CostLicAllBody() { return ; }\\nfunction CostExp2024Body() { return ; }\\nfunction CostLicTotalBody() { return ; }\\nfunction CostCategoryBody() { return ; }\\nfunction CostAppBody() { return ; }\\nfunction CostTopLicBody() { return ; }\\nfunction CostUsageBody() { return ; }\\nfunction CostRenewalsBody() {\\n  const cols = [\\n    { label: \\\"Application\\\", render: r =&gt; {r.app}&lt;\\/span&gt;&lt;\\/span&gt; },\\n    { label: \\\"Name\\\", render: r =&gt; {r.name}&lt;\\/span&gt; },\\n    { label: \\\"Renewal Date\\\", render: r =&gt; {r.date}&lt;\\/span&gt; },\\n    { label: \\\"Total Cost\\\", align: \\\"right\\\", render: r =&gt; ${r.cost}&lt;\\/span&gt; },\\n    { label: \\\"Term\\\", render: r =&gt; {r.term}&lt;\\/span&gt; },\\n    { label: \\\"Unit\\\", align: \\\"right\\\", render: r =&gt; ${r.unit}&lt;\\/span&gt; },\\n  ];\\n  return (\\n    \n\\n      \n\\n        \\n          \\n            {cols.map((c, i) =&gt; {c.label}&lt;\\/th&gt;)}\\n          &lt;\\/tr&gt;\\n        &lt;\\/thead&gt;\\n        \\n          {COST_RENEWALS.map((r, ri) =&gt; (\\n            \\n              {cols.map((c, i) =&gt; {c.render(r)}&lt;\\/td&gt;)}\\n            &lt;\\/tr&gt;\\n          ))}\\n        &lt;\\/tbody&gt;\\n      &lt;\\/table&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\nfunction ResetViewBtn({ disabled, onReset }) {\\n  const [h, setH] = useState(false);\\n  return (\\n     setH(true)} onMouseLeave={() =&gt; setH(false)}\\n      title={disabled ? \\\"Layout is at its default\\\" : \\\"Restore the default tile layout\\\"}\\n      style={{ display: \\\"inline-flex\\\", alignItems: \\\"center\\\", gap: 6, height: 30, padding: \\\"0 13px\\\", borderRadius: 999, fontFamily: T.font, fontSize: 13, fontWeight: 600, cursor: disabled ? \\\"default\\\" : \\\"pointer\\\", border: `1px solid ${disabled ? T.lineSoft : h ? T.lineStrong : T.line}`, background: disabled ? \\\"transparent\\\" : h ? T.surface2 : T.control, color: disabled ? T.faint : T.body, transition: \\\"all .14s\\\" }}&gt;\\n       Reset view\\n    &lt;\\/button&gt;\\n  );\\n}\\n\\nconst TILE_META = {\\n  line: { eyebrow: \\\"Activity\\\", title: \\\"Device Discovery Over Time\\\", Body: LineBody },\\n  donut: { eyebrow: \\\"Composition\\\", title: \\\"Windows Distribution\\\", Body: DonutBody },\\n  lifecycle: { eyebrow: \\\"Pipeline\\\", title: \\\"System Lifecycle\\\", Body: LifecycleBody },\\n  discovery: { eyebrow: \\\"Activity\\\", title: \\\"Discovery Log\\\", Body: DiscoveryBody },\\n  adapters: { eyebrow: \\\"Connections\\\", title: \\\"Adapter Connections\\\", Body: AdaptersBody },\\n  stacked: { eyebrow: \\\"Trend\\\", title: \\\"Asset Growth by Category\\\", Body: StackedBody, footer: 12.4%&lt;\\/Delta&gt; },\\n  severity: { eyebrow: \\\"Risk\\\", title: \\\"Vulnerabilities by Severity\\\", Body: SeverityBody, footer: 18 resolved&lt;\\/Delta&gt; },\\n  healthOk: { eyebrow: \\\"Adapters\\\", title: \\\"Adapter Health \\u00b7 Successful\\\", Body: HealthOkBody },\\n  healthFail: { eyebrow: \\\"Adapters\\\", title: \\\"Adapter Health \\u00b7 Attention\\\", Body: HealthFailBody },\\n  costExpAll: { eyebrow: \\\"Spend\\\", title: \\\"Total Expenses (All Time)\\\", Body: CostExpAllBody },\\n  costExp2024: { eyebrow: \\\"Spend\\\", title: \\\"Total Expenses (2024)\\\", Body: CostExp2024Body },\\n  costLicAll: { eyebrow: \\\"Licenses\\\", title: \\\"Total License Cost (All Time)\\\", Body: CostLicAllBody },\\n  costLicTotal: { eyebrow: \\\"Licenses\\\", title: \\\"Total License Cost\\\", Body: CostLicTotalBody },\\n  costRenewals: { eyebrow: \\\"Renewals\\\", title: \\\"Upcoming Renewals (next 90 days)\\\", Body: CostRenewalsBody, footer: View all results&lt;\\/a&gt;, noPad: true },\\n  costCategory: { eyebrow: \\\"Spend\\\", title: \\\"Expenses by Category (2024)\\\", Body: CostCategoryBody },\\n  costApp: { eyebrow: \\\"Spend\\\", title: \\\"Expenses by App (2024)\\\", Body: CostAppBody },\\n  costTopLic: { eyebrow: \\\"Licenses\\\", title: \\\"Most Expensive Licenses (2024)\\\", Body: CostTopLicBody },\\n  costUsage: { eyebrow: \\\"Usage\\\", title: \\\"Azure AD Logons \\u00b7 last 30 days\\\", Body: CostUsageBody },\\n};\\n\\n/* ============ resizable grid (corner drag, neighbors reflow) ============ */\\nconst GRID_COLS = 12, ROW_UNIT = 40, GAP = 16;\\nconst INITIAL_TILES = [\\n  { id: \\\"line\\\", w: 8, h: 7 }, { id: \\\"donut\\\", w: 4, h: 7 },\\n  { id: \\\"lifecycle\\\", w: 5, h: 7 }, { id: \\\"discovery\\\", w: 7, h: 7 },\\n  { id: \\\"adapters\\\", w: 7, h: 6 }, { id: \\\"severity\\\", w: 5, h: 6 },\\n  { id: \\\"healthOk\\\", w: 6, h: 5 }, { id: \\\"healthFail\\\", w: 6, h: 5 },\\n  { id: \\\"stacked\\\", w: 12, h: 5 },\\n];\\nconst COST_TILES = [\\n  { id: \\\"costExpAll\\\", w: 3, h: 4 }, { id: \\\"costExp2024\\\", w: 3, h: 4 }, { id: \\\"costLicAll\\\", w: 3, h: 4 }, { id: \\\"costLicTotal\\\", w: 3, h: 4 },\\n  { id: \\\"costRenewals\\\", w: 12, h: 6 },\\n  { id: \\\"costCategory\\\", w: 6, h: 6 }, { id: \\\"costApp\\\", w: 6, h: 6 },\\n  { id: \\\"costTopLic\\\", w: 6, h: 6 }, { id: \\\"costUsage\\\", w: 6, h: 6 },\\n];\\nconst DASH_TILESETS = { \\\"Cost Optimization\\\": COST_TILES };\\nfunction DashboardGrid({ tileSet = INITIAL_TILES }) {\\n  const [tiles, setTiles] = useState(tileSet);\\n  const [hoverId, setHoverId] = useState(null);\\n  const [resizingId, setResizingId] = useState(null);\\n  const [drag, setDrag] = useState(null);\\n  const dragId = drag ? drag.id : null;\\n  const ref = useRef(null);\\n  const tileEls = useRef({});\\n  const justDragged = useRef(false);\\n\\n  const startDrag = (e, id, immediate) =&gt; {\\n    if (e.button || (e.target.closest &amp;&amp; (e.target.closest(\\\"[data-resize]\\\") || e.target.closest(\\\"button\\\")))) return;\\n    const startX = e.clientX, startY = e.clientY;\\n    let dragging = false;\\n    const begin = (cx, cy) =&gt; {\\n      const el = tileEls.current[id]; if (!el) return;\\n      const rect = el.getBoundingClientRect();\\n      dragging = true;\\n      setDrag({ id, x: cx, y: cy, ox: cx - rect.left, oy: cy - rect.top, w: rect.width, h: rect.height });\\n      document.body.style.userSelect = \\\"none\\\";\\n    };\\n    const timer = immediate ? null : setTimeout(() =&gt; begin(startX, startY), 300);\\n    const onMove = (ev) =&gt; {\\n      if (!dragging) {\\n        const moved = Math.abs(ev.clientX - startX) &gt; (immediate ? 4 : 8) || Math.abs(ev.clientY - startY) &gt; (immediate ? 4 : 8);\\n        if (!moved) return;\\n        if (immediate) begin(ev.clientX, ev.clientY); else { end(); return; }\\n        if (!dragging) return;\\n      }\\n      setDrag(d =&gt; d ? { ...d, x: ev.clientX, y: ev.clientY } : d);\\n      for (const tid in tileEls.current) {\\n        const el = tileEls.current[tid];\\n        if (!el || tid === id) continue;\\n        const r = el.getBoundingClientRect();\\n        if (ev.clientX &gt;= r.left &amp;&amp; ev.clientX &lt;= r.right &amp;&amp; ev.clientY &gt;= r.top &amp;&amp; ev.clientY &lt;= r.bottom) {\\n          setTiles(ts =&gt; { const from = ts.findIndex(x =&gt; x.id === id), to = ts.findIndex(x =&gt; x.id === tid); if (from &lt; 0 || to &lt; 0 || from === to) return ts; const n = ts.slice(); const [mv] = n.splice(from, 1); n.splice(to, 0, mv); return n; });\\n          break;\\n        }\\n      }\\n    };\\n    const end = () =&gt; { clearTimeout(timer); if (dragging) { justDragged.current = true; setTimeout(() =&gt; { justDragged.current = false; }, 60); } dragging = false; setDrag(null); document.body.style.userSelect = \\\"\\\"; window.removeEventListener(\\\"pointermove\\\", onMove); window.removeEventListener(\\\"pointerup\\\", end); };\\n    window.addEventListener(\\\"pointermove\\\", onMove); window.addEventListener(\\\"pointerup\\\", end);\\n  };\\n\\n  const startResize = (e, id) =&gt; {\\n    e.preventDefault(); e.stopPropagation();\\n    setResizingId(id);\\n    const rect = ref.current.getBoundingClientRect();\\n    const colW = (rect.width - GAP * (GRID_COLS - 1)) / GRID_COLS;\\n    const t = tiles.find(x =&gt; x.id === id);\\n    const startWpx = t.w * colW + (t.w - 1) * GAP;\\n    const startHpx = t.h * ROW_UNIT + (t.h - 1) * GAP;\\n    const sx = e.clientX, sy = e.clientY;\\n    const onMove = (ev) =&gt; {\\n      let w = Math.round((startWpx + (ev.clientX - sx) + GAP) / (colW + GAP));\\n      let h = Math.round((startHpx + (ev.clientY - sy) + GAP) / (ROW_UNIT + GAP));\\n      w = Math.max(3, Math.min(GRID_COLS, w));\\n      h = Math.max(4, Math.min(14, h));\\n      setTiles(ts =&gt; ts.map(x =&gt; x.id === id ? { ...x, w, h } : x));\\n    };\\n    const onUp = () =&gt; { setResizingId(null); document.body.style.cursor = \\\"\\\"; window.removeEventListener(\\\"mousemove\\\", onMove); window.removeEventListener(\\\"mouseup\\\", onUp); };\\n    document.body.style.cursor = \\\"nwse-resize\\\";\\n    window.addEventListener(\\\"mousemove\\\", onMove); window.addEventListener(\\\"mouseup\\\", onUp);\\n  };\\n\\n  const isDefault = JSON.stringify(tiles) === JSON.stringify(tileSet);\\n  return (\\n    &lt;&gt;\\n      \n\\n         setTiles(tileSet)} /&gt;\\n      &lt;\\/div&gt;\\n    \n\\n      {tiles.map((t, ti) =&gt; {\\n        const m = TILE_META[t.id];\\n        const isHover = hoverId === t.id, isResizing = resizingId === t.id, isDragging = dragId === t.id, anyDrag = dragId !== null;\\n        return (\\n          \n (tileEls.current[t.id] = el)}\\n            onPointerDown={(e) =&gt; startDrag(e, t.id)}\\n            onClickCapture={(e) =&gt; { if (justDragged.current) { e.stopPropagation(); justDragged.current = false; } }}\\n            onMouseEnter={() =&gt; setHoverId(t.id)} onMouseLeave={() =&gt; setHoverId(null)}\\n            style={{ gridColumn: `span ${t.w}`, gridRow: `span ${t.h}`, position: \\\"relative\\\", minWidth: 0, zIndex: 1 }}&gt;\\n            {isDragging ? (\\n              \n\\n            ) : (&lt;&gt;\\n            \n\\n              \n { e.stopPropagation(); startDrag(e, t.id, true); }} title=\\\"Drag to move\\\" style={{ padding: \\\"13px 20px 12px\\\", borderBottom: `1px solid ${T.hair}`, display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 8, cursor: \\\"grab\\\" }}&gt;\\n                \n\\n                  \n{m.eyebrow}&lt;\\/div&gt;\\n                  \n{m.title}&lt;\\/div&gt;\\n                &lt;\\/div&gt;\\n                &lt;\\/IconBtn&gt;\\n              &lt;\\/div&gt;\\n              \n&lt;\\/div&gt;\\n              {m.footer &amp;&amp; \n{m.footer}&lt;\\/div&gt;}\\n            &lt;\\/div&gt;\\n            \n startResize(e, t.id)} data-resize title=\\\"Drag to resize\\\"\\n              style={{ position: \\\"absolute\\\", right: 0, bottom: 0, width: 20, height: 20, cursor: \\\"nwse-resize\\\", display: \\\"flex\\\", alignItems: \\\"flex-end\\\", justifyContent: \\\"flex-end\\\", padding: 4, opacity: isHover || isResizing ? 1 : 0, transition: \\\"opacity .15s\\\" }}&gt;\\n              &lt;\\/svg&gt;\\n            &lt;\\/div&gt;\\n            &lt;\\/&gt;)}\\n          &lt;\\/div&gt;\\n        );\\n      })}\\n    &lt;\\/div&gt;\\n    {drag &amp;&amp; (() =&gt; { const m = TILE_META[drag.id]; return createPortal(\\n      \n\\n        \n\\n          \n\\n            \n\\n              \n{m.eyebrow}&lt;\\/div&gt;\\n              \n{m.title}&lt;\\/div&gt;\\n            &lt;\\/div&gt;\\n            &lt;\\/span&gt;\\n          &lt;\\/div&gt;\\n          \nDrop to reorder&lt;\\/div&gt;\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;, document.body); })()}\\n    &lt;\\/&gt;\\n  );\\n}\\n\\n/* ============ Assets table view (real device schema) ============ */\\nconst ADAPTERS = {\\n  aws_adapter: { brand: \\\"aws\\\" }, active_directory_adapter: { brand: \\\"active_directory\\\" },\\n  crowd_strike_adapter: { brand: \\\"crowdstrike\\\" }, google_mdm_adapter: { brand: \\\"googlecloud\\\" },\\n  esx_adapter: { brand: \\\"vmware\\\" }, sentinelone_adapter: { brand: \\\"sentinelone\\\" },\\n  service_now_adapter: { brand: \\\"service_now\\\" }, epo_adapter: { brand: \\\"epo\\\" },\\n  paloalto_panorama_adapter: { brand: \\\"paloalto\\\" }, cisco_meraki_adapter: { brand: \\\"cisco_meraki\\\" },\\n  cisco_ise_adapter: { brand: \\\"cisco_ise\\\" }, cisco_adapter: { brand: \\\"cisco\\\" },\\n  tanium_adapter: { brand: \\\"tanium\\\" }, tanium_asset_adapter: { brand: \\\"tanium\\\" },\\n  claroty_adapter: { brand: \\\"claroty\\\" }, counter_act_adapter: { brand: \\\"forescout\\\" },\\n  tenable_security_center_adapter: { brand: \\\"tenable\\\" }, zoom_adapter: { brand: \\\"zoom\\\" },\\n  checkpoint_r80_adapter: { brand: \\\"checkpoint\\\" }, cylance_adapter: { brand: \\\"cylance\\\" },\\n  chef_adapter: { brand: \\\"chef\\\" }, axonius_network_inspector_adapter: { short: \\\"NP\\\", color: \\\"#1C1D1F\\\" },\\n};\\nfunction AdapterAvatar({ k, size = 32 }) {\\n  const a = ADAPTERS[k] || { short: k.slice(0, 2).toUpperCase(), color: \\\"#939598\\\" };\\n  if (a.brand) return ;\\n  return \n 28 ? 11 : 9, fontWeight: 700, color: a.color }}&gt;{a.short}&lt;\\/div&gt;;\\n}\\nfunction AdapterStack({ list }) {\\n  const shown = list.slice(0, 3), extra = list.length - shown.length;\\n  return (\\n    \\n      \\n      {shown.map((k, i) =&gt; &lt;\\/span&gt;)}\\n      {extra &gt; 0 &amp;&amp; +{extra}&lt;\\/span&gt;}\\n    &lt;\\/span&gt;\\n  );\\n}\\n/* OS category icons */\\nfunction OsIcon({ os }) {\\n  const c = { Windows: \\\"#0078D4\\\", Linux: \\\"#1C1D1F\\\", \\\"OS X\\\": \\\"#555\\\", iOS: \\\"#111\\\", Android: \\\"#3DDC84\\\", VMWare: \\\"#607078\\\" }[os] || T.faint;\\n  const mc = T.isLight ? \\\"#1B2030\\\" : \\\"#D6DAE6\\\"; // monochrome marks adapt to theme\\n  const g = {\\n    Windows: &lt;\\/svg&gt;,\\n    \\\"OS X\\\": &lt;\\/svg&gt;,\\n    iOS: &lt;\\/svg&gt;,\\n    Android: &lt;\\/svg&gt;,\\n    Linux: &lt;\\/svg&gt;,\\n    VMWare: vm&lt;\\/span&gt;,\\n  }[os];\\n  if (!os) return \\u2014&lt;\\/span&gt;;\\n  return {g || }&lt;\\/span&gt;{os}&lt;\\/span&gt;;\\n}\\nconst DEVICES = [\\n  { name: \\\"PC-CURTIS-WILLIAMS\\\", host: \\\"PC-CURTIS-WILLIAMS.demo.local\\\", os: \\\"Windows\\\", ip: \\\"10.0.49.148\\\", mac: \\\"88:53:2E:12:45:C4\\\", seen: \\\"2026-06-08 09:34\\\", tags: [\\\"Corporate\\\", \\\"Managed\\\"], adapters: [\\\"active_directory_adapter\\\", \\\"crowd_strike_adapter\\\", \\\"epo_adapter\\\", \\\"google_mdm_adapter\\\", \\\"tanium_adapter\\\", \\\"sentinelone_adapter\\\", \\\"cisco_ise_adapter\\\"] },\\n  { name: \\\"infranginx-5567897-stg\\\", host: \\\"esx-infranginx-5567897-stg.demo.local\\\", os: \\\"Linux\\\", ip: \\\"10.0.63.107\\\", mac: \\\"00:0C:29:12:55:38\\\", seen: \\\"2026-06-08 11:43\\\", tags: [\\\"Staging\\\", \\\"Cloud\\\"], adapters: [\\\"cisco_ise_adapter\\\", \\\"claroty_adapter\\\", \\\"counter_act_adapter\\\", \\\"epo_adapter\\\", \\\"tanium_adapter\\\", \\\"esx_adapter\\\", \\\"aws_adapter\\\"] },\\n  { name: \\\"WIN-RUTHD\\\", host: \\\"WIN-RUTHD.demo.local\\\", os: \\\"Windows\\\", ip: \\\"10.0.48.107\\\", mac: \\\"88:53:2E:12:44:9B\\\", seen: \\\"2026-06-08 13:18\\\", tags: [\\\"Corporate\\\"], adapters: [\\\"active_directory_adapter\\\", \\\"cisco_adapter\\\", \\\"crowd_strike_adapter\\\", \\\"cylance_adapter\\\", \\\"epo_adapter\\\", \\\"tanium_adapter\\\"] },\\n  { name: \\\"external3026786-prd\\\", host: \\\"sepio-external3026786-prd.demo.local\\\", os: \\\"Linux\\\", ip: \\\"10.0.64.36\\\", mac: \\\"88:53:2E:12:56:12\\\", seen: \\\"2026-06-08 05:54\\\", tags: [\\\"Production\\\", \\\"Internet-facing\\\"], adapters: [\\\"checkpoint_r80_adapter\\\", \\\"chef_adapter\\\", \\\"epo_adapter\\\", \\\"paloalto_panorama_adapter\\\", \\\"axonius_network_inspector_adapter\\\", \\\"claroty_adapter\\\", \\\"tenable_security_center_adapter\\\"] },\\n  { name: \\\"macbook-pro-jdoe\\\", host: \\\"macbook-pro-jdoe.demo.local\\\", os: \\\"OS X\\\", ip: \\\"10.0.51.22\\\", mac: \\\"A4:83:E7:9C:11:04\\\", seen: \\\"2026-06-08 12:02\\\", tags: [\\\"Endpoint\\\", \\\"BYOD\\\"], adapters: [\\\"google_mdm_adapter\\\", \\\"crowd_strike_adapter\\\", \\\"sentinelone_adapter\\\"] },\\n  { name: \\\"lablb-2918146-beta\\\", host: \\\"esx-lablb-2918146-beta.manufacturing.com\\\", os: \\\"Linux\\\", ip: \\\"10.0.56.90\\\", mac: \\\"00:0C:29:12:4C:BF\\\", seen: \\\"2026-06-08 11:30\\\", tags: [\\\"Lab\\\"], adapters: [\\\"cisco_meraki_adapter\\\", \\\"claroty_adapter\\\", \\\"epo_adapter\\\", \\\"esx_adapter\\\", \\\"tanium_asset_adapter\\\", \\\"counter_act_adapter\\\", \\\"service_now_adapter\\\"] },\\n  { name: \\\"iphone-asmith\\\", host: \\\"\\u2014\\\", os: \\\"iOS\\\", ip: \\\"10.0.77.51\\\", mac: \\\"F0:18:98:22:7D:AA\\\", seen: \\\"2026-06-08 11:58\\\", tags: [\\\"Mobile\\\", \\\"BYOD\\\"], adapters: [\\\"google_mdm_adapter\\\", \\\"zoom_adapter\\\"] },\\n  { name: \\\"srv-db-fin-04\\\", host: \\\"srv-db-fin-04.healthcare-subsidiary.com\\\", os: \\\"Linux\\\", ip: \\\"10.0.40.12\\\", mac: \\\"00:50:56:9A:3C:11\\\", seen: \\\"2026-06-08 07:12\\\", tags: [\\\"Production\\\", \\\"Database\\\", \\\"PCI\\\"], adapters: [\\\"service_now_adapter\\\", \\\"tenable_security_center_adapter\\\", \\\"tanium_adapter\\\", \\\"epo_adapter\\\", \\\"aws_adapter\\\", \\\"claroty_adapter\\\"] },\\n  { name: \\\"azure-infra9274676-prd\\\", host: \\\"azure-infra9274676-prd.demo.local\\\", os: \\\"Windows\\\", ip: \\\"10.0.61.5\\\", mac: \\\"00:0D:3A:1F:8E:22\\\", seen: \\\"2026-06-08 10:47\\\", tags: [\\\"Production\\\", \\\"Cloud\\\"], adapters: [\\\"active_directory_adapter\\\", \\\"aws_adapter\\\", \\\"sentinelone_adapter\\\", \\\"service_now_adapter\\\"] },\\n  { name: \\\"android-pixel-7\\\", host: \\\"\\u2014\\\", os: \\\"Android\\\", ip: \\\"10.0.78.130\\\", mac: \\\"3C:28:6D:55:01:9F\\\", seen: \\\"2026-06-08 09:05\\\", tags: [\\\"Mobile\\\"], adapters: [\\\"google_mdm_adapter\\\"] },\\n  { name: \\\"Win-MaryChasse\\\", host: \\\"WIN-MARYCHASSE.demo.local\\\", os: \\\"Windows\\\", ip: \\\"10.0.49.201\\\", mac: \\\"88:53:2E:12:48:7E\\\", seen: \\\"2026-06-07 22:41\\\", tags: [\\\"Corporate\\\"], adapters: [\\\"active_directory_adapter\\\", \\\"epo_adapter\\\", \\\"cisco_meraki_adapter\\\"] },\\n  { name: \\\"esx-mail-2231-prd\\\", host: \\\"esx-mail-2231-prd.manufacturing.com\\\", os: \\\"VMWare\\\", ip: \\\"10.0.62.18\\\", mac: \\\"00:0C:29:44:1A:E0\\\", seen: \\\"2026-06-08 06:33\\\", tags: [\\\"Production\\\"], adapters: [\\\"esx_adapter\\\", \\\"tenable_security_center_adapter\\\", \\\"paloalto_panorama_adapter\\\"] },\\n  { name: \\\"PC-Doris9920\\\", host: \\\"PC-DORIS9920.demo.local\\\", os: \\\"Windows\\\", ip: \\\"10.0.50.66\\\", mac: \\\"88:53:2E:12:51:C9\\\", seen: \\\"2026-06-08 08:59\\\", tags: [\\\"Corporate\\\", \\\"Managed\\\"], adapters: [\\\"active_directory_adapter\\\", \\\"crowd_strike_adapter\\\", \\\"tanium_adapter\\\", \\\"google_mdm_adapter\\\"] },\\n  { name: \\\"kiosk-lobby-03\\\", host: \\\"kiosk-lobby-03.demo.local\\\", os: \\\"Linux\\\", ip: \\\"10.0.44.7\\\", mac: \\\"B8:27:EB:0C:5A:31\\\", seen: \\\"2026-06-07 19:20\\\", tags: [\\\"IoT\\\", \\\"Unmanaged\\\"], adapters: [\\\"counter_act_adapter\\\", \\\"claroty_adapter\\\"] },\\n];\\n\\nconst INIT_COLS = [\\n  { key: \\\"adapters\\\", label: \\\"Adapter Connections\\\", w: 230, pinned: false },\\n  { key: \\\"name\\\", label: \\\"Asset Name\\\", w: 230, pinned: false },\\n  { key: \\\"host\\\", label: \\\"Host Name\\\", w: 300, pinned: false },\\n  { key: \\\"os\\\", label: \\\"OS Type\\\", w: 140, pinned: false },\\n  { key: \\\"ip\\\", label: \\\"IP Address\\\", w: 140, pinned: false },\\n  { key: \\\"mac\\\", label: \\\"MAC Address\\\", w: 160, pinned: false },\\n  { key: \\\"seen\\\", label: \\\"Last Seen (UTC)\\\", w: 170, pinned: false },\\n  { key: \\\"tags\\\", label: \\\"Tags\\\", w: 220, pinned: false },\\n];\\nconst CB_W = 46;\\nconst mono = { fontFamily: \\\"ui-monospace, 'SF Mono', monospace\\\" };\\nfunction cellContent(key, r) {\\n  switch (key) {\\n    case \\\"adapters\\\": return ;\\n    case \\\"name\\\": return {r.name}&lt;\\/span&gt;;\\n    case \\\"host\\\": return {r.host}&lt;\\/span&gt;;\\n    case \\\"os\\\": return ;\\n    case \\\"ip\\\": return {r.ip}&lt;\\/span&gt;;\\n    case \\\"mac\\\": return {r.mac}&lt;\\/span&gt;;\\n    case \\\"seen\\\": return {r.seen}&lt;\\/span&gt;;\\n    case \\\"tags\\\": return {r.tags.slice(0, 2).map((t, j) =&gt; )}{r.tags.length &gt; 2 &amp;&amp; +{r.tags.length - 2}&lt;\\/span&gt;}&lt;\\/span&gt;;\\n    default: return null;\\n  }\\n}\\n\\nfunction HeaderCell({ col, left, isLastPinned, onResize, onPin, onDragStart, regRef, dragging }) {\\n  const [h, setH] = useState(false);\\n  const sticky = col.pinned;\\n  return (\\n    \n regRef(col.key, el)} onPointerDown={(e) =&gt; onDragStart(e, col.key)} onMouseEnter={() =&gt; setH(true)} onMouseLeave={() =&gt; setH(false)}\\n      style={{ width: col.w, flexShrink: 0, position: sticky ? \\\"sticky\\\" : \\\"relative\\\", left: sticky ? left : undefined, zIndex: sticky ? 4 : 1, background: T.canvas, height: 40, display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 6, padding: \\\"0 12px\\\", boxShadow: isLastPinned ? \\\"2px 0 5px rgba(27,32,70,0.06)\\\" : \\\"none\\\", cursor: \\\"grab\\\", opacity: dragging ? 0.4 : 1 }}&gt;\\n      {col.label}&lt;\\/span&gt;\\n      {(h || col.pinned) &amp;&amp; (\\n         onPin(col.key)} title={col.pinned ? \\\"Unpin column\\\" : \\\"Pin column\\\"}\\n          style={{ width: 24, height: 24, borderRadius: 6, border: \\\"none\\\", cursor: \\\"pointer\\\", background: \\\"transparent\\\", color: col.pinned ? T.blue : T.faint, display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\", transform: col.pinned ? \\\"none\\\" : \\\"rotate(45deg)\\\", flexShrink: 0 }}&gt;\\n          \\n        &lt;\\/button&gt;\\n      )}\\n      \n onResize(e, col.key)} data-colresize title=\\\"Drag to resize\\\"\\n        style={{ position: \\\"absolute\\\", right: -3, top: 8, width: 6, height: 24, cursor: \\\"col-resize\\\", display: \\\"flex\\\", justifyContent: \\\"center\\\", zIndex: 5 }}&gt;\\n        \\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\n\\nfunction AssetsTable() {\\n  const [columns, setColumns] = useState(INIT_COLS);\\n  const [hoverRow, setHoverRow] = useState(null);\\n  const [perPage, setPerPage] = useState(20);\\n  const [dragCol, setDragCol] = useState(null);\\n  const colEls = useRef({});\\n  const regRef = (k, el) =&gt; { colEls.current[k] = el; };\\n\\n  const startColDrag = (e, key) =&gt; {\\n    if (e.button || (e.target.closest &amp;&amp; (e.target.closest(\\\"[data-colresize]\\\") || e.target.closest(\\\"button\\\")))) return;\\n    const startX = e.clientX; let dragging = false;\\n    const onMove = (ev) =&gt; {\\n      if (!dragging) { if (Math.abs(ev.clientX - startX) &gt; 6) { dragging = true; setDragCol(key); document.body.style.userSelect = \\\"none\\\"; } else return; }\\n      for (const k in colEls.current) {\\n        const el = colEls.current[k]; if (!el || k === key) continue;\\n        const r = el.getBoundingClientRect();\\n        if (ev.clientX &gt;= r.left &amp;&amp; ev.clientX &lt;= r.right) {\\n          setColumns(cs =&gt; { const from = cs.findIndex(c =&gt; c.key === key), to = cs.findIndex(c =&gt; c.key === k); if (from &lt; 0 || to &lt; 0 || from === to) return cs; const n = cs.slice(); const [m] = n.splice(from, 1); n.splice(to, 0, m); return n; });\\n          break;\\n        }\\n      }\\n    };\\n    const onUp = () =&gt; { dragging = false; setDragCol(null); document.body.style.userSelect = \\\"\\\"; window.removeEventListener(\\\"pointermove\\\", onMove); window.removeEventListener(\\\"pointerup\\\", onUp); };\\n    window.addEventListener(\\\"pointermove\\\", onMove); window.addEventListener(\\\"pointerup\\\", onUp);\\n  };\\n\\n  const startColResize = (e, key) =&gt; {\\n    e.preventDefault(); e.stopPropagation();\\n    const sx = e.clientX, startW = columns.find(c =&gt; c.key === key).w;\\n    const onMove = (ev) =&gt; { const w = Math.max(90, startW + (ev.clientX - sx)); setColumns(cs =&gt; cs.map(c =&gt; c.key === key ? { ...c, w } : c)); };\\n    const onUp = () =&gt; { document.body.style.cursor = \\\"\\\"; window.removeEventListener(\\\"mousemove\\\", onMove); window.removeEventListener(\\\"mouseup\\\", onUp); };\\n    document.body.style.cursor = \\\"col-resize\\\";\\n    window.addEventListener(\\\"mousemove\\\", onMove); window.addEventListener(\\\"mouseup\\\", onUp);\\n  };\\n  const togglePin = (key) =&gt; setColumns(cs =&gt; cs.map(c =&gt; c.key === key ? { ...c, pinned: !c.pinned } : c));\\n\\n  const pinned = columns.filter(c =&gt; c.pinned), unpinned = columns.filter(c =&gt; !c.pinned);\\n  const ordered = [...pinned, ...unpinned];\\n  const leftMap = {}; let acc = CB_W;\\n  pinned.forEach(c =&gt; { leftMap[c.key] = acc; acc += c.w; });\\n  const lastPinned = pinned.length ? pinned[pinned.length - 1].key : null;\\n  const totalW = CB_W + columns.reduce((a, c) =&gt; a + c.w, 0);\\n\\n  return (\\n    \n\\n      \n\\n        \n\\n          {/* header */}\\n          \n\\n            \n\\n              \\n            &lt;\\/div&gt;\\n            {ordered.map(c =&gt; )}\\n            \n\\n          &lt;\\/div&gt;\\n          {/* rows */}\\n          {DEVICES.map((r, i) =&gt; {\\n            const rowBg = hoverRow === i ? T.surface2 : T.surface;\\n            return (\\n              \n setHoverRow(i)} onMouseLeave={() =&gt; setHoverRow(null)}\\n                style={{ display: \\\"flex\\\", height: 52, borderBottom: i &lt; DEVICES.length - 1 ? `1px solid ${T.hair}` : \\\"none\\\", background: rowBg }}&gt;\\n                \n\\n                  {hoverRow === i ?  : {i + 1}&lt;\\/span&gt;}\\n                &lt;\\/div&gt;\\n                {ordered.map(c =&gt; {\\n                  const sticky = c.pinned;\\n                  return (\\n                    \n\\n                      {cellContent(c.key, r)}\\n                    &lt;\\/div&gt;\\n                  );\\n                })}\\n                \n\\n              &lt;\\/div&gt;\\n            );\\n          })}\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n      {/* footer */}\\n      \n\\n        \n\\n          Rows per page:&lt;\\/span&gt;\\n           setPerPage(Number(e.target.value))}\\n            style={{ height: 30, padding: \\\"0 28px 0 10px\\\", borderRadius: 999, border: `1px solid ${T.line}`, background: T.surface, color: T.ink, fontSize: 13, fontWeight: 500, fontFamily: T.font, cursor: \\\"pointer\\\", appearance: \\\"none\\\", WebkitAppearance: \\\"none\\\", backgroundImage: `url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238494B5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E\\\")`, backgroundRepeat: \\\"no-repeat\\\", backgroundPosition: \\\"right 8px center\\\", outline: \\\"none\\\" }}&gt;\\n            {[20, 50, 100].map(n =&gt; {n}&lt;\\/option&gt;)}\\n          &lt;\\/select&gt;\\n        &lt;\\/div&gt;\\n        \n\\n          1\\u2013{perPage} of 12,409&lt;\\/span&gt;\\n          \n\\n            &lt;\\/PageBtn&gt;&lt;\\/PageBtn&gt;\\n            1&lt;\\/PageBtn&gt;2&lt;\\/PageBtn&gt;3&lt;\\/PageBtn&gt;4&lt;\\/PageBtn&gt;\\n            \\u2026&lt;\\/span&gt;621&lt;\\/PageBtn&gt;\\n            &lt;\\/PageBtn&gt;&lt;\\/PageBtn&gt;\\n          &lt;\\/div&gt;\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\n\\nfunction QueryPill({ children, primary, active, onClick }) {\\n  const [h, setH] = useState(false);\\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ display: \\\"inline-flex\\\", alignItems: \\\"center\\\", gap: 6, height: 32, padding: \\\"0 14px\\\", borderRadius: 999, cursor: \\\"pointer\\\", fontFamily: T.font, fontSize: 13.5, fontWeight: 600, border: primary ? \\\"none\\\" : `1px solid ${active || h ? T.lineStrong : T.line}`, background: primary ? T.blue : active || h ? T.surface2 : T.control, color: primary ? T.onAccent : T.body }}&gt;{children}&lt;\\/button&gt;;\\n}\\nfunction ToolLink({ icon: Icon, children }) {\\n  const [h, setH] = useState(false);\\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ display: \\\"inline-flex\\\", alignItems: \\\"center\\\", gap: 6, height: 30, padding: \\\"0 10px\\\", border: \\\"none\\\", borderRadius: 999, background: h ? T.surface2 : \\\"transparent\\\", color: T.body, fontSize: 13.5, fontWeight: 600, cursor: \\\"pointer\\\", fontFamily: T.font }}&gt;{Icon &amp;&amp; }{children}&lt;\\/button&gt;;\\n}\\nfunction SegTool({ icon: Icon, title, first }) {\\n  const [h, setH] = useState(false);\\n  return (\\n     setH(true)} onMouseLeave={() =&gt; setH(false)}&gt;\\n      &lt;\\/button&gt;\\n      {h &amp;&amp; {title}&lt;\\/span&gt;}\\n    &lt;\\/span&gt;\\n  );\\n}\\nfunction IconTool({ icon: Icon, title }) {\\n  const [h, setH] = useState(false);\\n  return (\\n     setH(true)} onMouseLeave={() =&gt; setH(false)}&gt;\\n      &lt;\\/button&gt;\\n      {h &amp;&amp; {title}&lt;\\/span&gt;}\\n    &lt;\\/span&gt;\\n  );\\n}\\nfunction Segmented({ options, value, onChange }) {\\n  const idx = Math.max(0, options.indexOf(value));\\n  const wpct = 100 / options.length;\\n  return (\\n    \n\\n      \\n      {options.map(o =&gt; (\\n         onChange(o)} style={{ position: \\\"relative\\\", zIndex: 1, minWidth: 62, padding: \\\"0 12px\\\", border: \\\"none\\\", background: \\\"transparent\\\", color: value === o ? T.onAccent : T.body, fontSize: 13.5, fontWeight: value === o ? 600 : 500, cursor: \\\"pointer\\\", fontFamily: T.font, transition: \\\"color .2s\\\" }}&gt;{o}&lt;\\/button&gt;\\n      ))}\\n    &lt;\\/div&gt;\\n  );\\n}\\n\\nfunction QueriesPanel({ close }) {\\n  const recent = [\\n    { nm: \\\"FH: 1.4 Asset Context.Business Importance\\\", sub: \\\"Shared Queries\\\" },\\n    { nm: \\\"low Risk Score_2025-12-24T11-53\\\", sub: \\\"Public Queries / Predefined Queries\\\" },\\n    { nm: \\\"Unmanaged endpoints seen &lt; 7d\\\", sub: \\\"Shared Queries\\\" },\\n    { nm: \\\"Critical CVEs on internet-facing\\\", sub: \\\"Public Queries / Predefined Queries\\\" },\\n  ];\\n  return createPortal(&lt;&gt;\\n    \n\\n    \n\\n      \n\\n        Queries&lt;\\/span&gt;\\n        &lt;\\/IconBtn&gt;\\n        &lt;\\/IconBtn&gt;\\n        &lt;\\/IconBtn&gt;\\n      &lt;\\/div&gt;\\n      \n\\n        \n\\n          \\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n      \n\\n        \nFavorites&lt;\\/span&gt;&lt;\\/div&gt;\\n        \nRecently Used Saved Queries&lt;\\/span&gt;&lt;\\/div&gt;\\n        {recent.map((q, i) =&gt; (\\n           (e.currentTarget.style.background = T.surface2)} onMouseLeave={(e) =&gt; (e.currentTarget.style.background = \\\"transparent\\\")}\\n            style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 11, width: \\\"100%\\\", border: \\\"none\\\", background: \\\"transparent\\\", borderRadius: 10, cursor: \\\"pointer\\\", padding: \\\"9px\\\", textAlign: \\\"left\\\", fontFamily: T.font }}&gt;\\n            &lt;\\/span&gt;\\n            \\n              {q.nm}&lt;\\/span&gt;\\n              {q.sub}&lt;\\/span&gt;\\n            &lt;\\/span&gt;\\n          &lt;\\/button&gt;\\n        ))}\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  &lt;\\/&gt;, document.body);\\n}\\nfunction AssetsView() {\\n  const [mode, setMode] = useState(\\\"Wizard\\\");\\n  const [enrichOpen, setEnrichOpen] = useState(false);\\n  const [queriesOpen, setQueriesOpen] = useState(false);\\n  return (\\n    \n\\n      \n\\n      {/* breadcrumb + title + module actions */}\\n      \n\\n        \n\\n          \nInventory /&lt;\\/span&gt; Assets&lt;\\/div&gt;\\n          \nDevices&lt;\\/h1&gt;\\n        &lt;\\/div&gt;\\n        \n\\n          \n\\n             setEnrichOpen(o =&gt; !o)}&gt;Enrichment &amp; Investigation &lt;\\/QueryPill&gt;\\n            {enrichOpen &amp;&amp; (&lt;&gt;\\n              \n setEnrichOpen(false)} style={{ position: \\\"fixed\\\", inset: 0, zIndex: 40 }} /&gt;\\n              \n\\n                {[\\\"Business Data Enrichment\\\", \\\"Device Inventory Classification\\\", \\\"Asset Investigation\\\"].map(o =&gt; (\\n                   setEnrichOpen(false)} onMouseEnter={(e) =&gt; (e.currentTarget.style.background = T.surface2)} onMouseLeave={(e) =&gt; (e.currentTarget.style.background = \\\"transparent\\\")}\\n                    style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"space-between\\\", gap: 10, width: \\\"100%\\\", border: \\\"none\\\", background: \\\"transparent\\\", borderRadius: 8, cursor: \\\"pointer\\\", padding: \\\"9px 11px\\\", fontSize: 13, fontWeight: 500, fontFamily: T.font, color: T.body, textAlign: \\\"left\\\" }}&gt;\\n                    {o} \\n                  &lt;\\/button&gt;\\n                ))}\\n              &lt;\\/div&gt;\\n            &lt;\\/&gt;)}\\n          &lt;\\/div&gt;\\n          &lt;\\/IconBtn&gt;\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n      {/* query toolbar */}\\n      \n\\n        New Query&lt;\\/ToolLink&gt;\\n        Save As&lt;\\/ToolLink&gt;\\n        Reset&lt;\\/ToolLink&gt;\\n        Copy Query&lt;\\/ToolLink&gt;\\n        \n\\n        Display by Date&lt;\\/ToolLink&gt;\\n        \n\\n         setQueriesOpen(o =&gt; !o)}&gt;{queriesOpen ?  : &lt;&gt; Queries&lt;\\/&gt;}&lt;\\/QueryPill&gt;\\n        \\n      &lt;\\/div&gt;\\n      {/* search + wizard / basic filters */}\\n      {mode === \\\"Wizard\\\" ? (\\n        \n\\n          \n\\n            \\n            \\n          &lt;\\/div&gt;\\n          Query Wizard&lt;\\/button&gt;\\n        &lt;\\/div&gt;\\n      ) : (\\n        \n\\n          \\n          \\n          \nLast Seen&lt;\\/span&gt;&lt;\\/div&gt;\\n          \nTags&lt;\\/span&gt;&lt;\\/div&gt;\\n           Filter&lt;\\/button&gt;\\n        &lt;\\/div&gt;\\n      )}\\n      {/* stats toolbar */}\\n      \n\\n        Total 12,409&lt;\\/span&gt;&lt;\\/span&gt;\\n         Last updated: 2026-06-08 17:07:59&lt;\\/span&gt;&lt;\\/span&gt;\\n        \n\\n        \n\\n          \n\\n            \\n            \\n            \\n          &lt;\\/div&gt;\\n           New Asset&lt;\\/button&gt;\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n      &lt;\\/div&gt;{/* end flexShrink header */}\\n      \n\\n        \\n      &lt;\\/div&gt;\\n      {queriesOpen &amp;&amp;  setQueriesOpen(false)} /&gt;}\\n    &lt;\\/div&gt;\\n  );\\n}\\nfunction PageBtn({ children, active, disabled, wide }) {\\n  const [h, setH] = useState(false);\\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ minWidth: wide ? \\\"auto\\\" : 30, height: 30, padding: wide ? \\\"0 10px\\\" : 0, borderRadius: 999, border: active ? \\\"none\\\" : `1px solid ${h &amp;&amp; !disabled ? T.lineStrong : \\\"transparent\\\"}`, background: active ? T.blue : h &amp;&amp; !disabled ? T.surface2 : \\\"transparent\\\", color: active ? T.onAccent : disabled ? T.faint : T.body, fontSize: 13, fontWeight: 500, cursor: disabled ? \\\"default\\\" : \\\"pointer\\\", display: \\\"inline-flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\", fontFamily: T.font, ...tnum }}&gt;{children}&lt;\\/button&gt;;\\n}\\n\\n/* ============ Inventory tree panel (assets view) ============ */\\nconst INV_GROUPS_INIT = [\\n  { name: \\\"Compute\\\", icon: Server, open: true, items: [\\n    { icon: Server, label: \\\"Corporate Devices\\\", count: \\\"8,204\\\", fav: true },\\n    { icon: ShieldAlert, label: \\\"Internet-facing Assets\\\", count: \\\"312\\\", fav: true },\\n    { folder: \\\"Endpoint\\\", open: true, items: [\\n      { icon: Server, label: \\\"Devices\\\", count: \\\"12,409\\\", active: true },\\n      { icon: Workflow, label: \\\"Processes\\\", count: \\\"0\\\" },\\n    ]},\\n    { folder: \\\"Infrastructure\\\", open: false, items: [\\n      { icon: Boxes, label: \\\"Compute Services\\\", count: \\\"14\\\" },\\n      { icon: Cable, label: \\\"Databases\\\", count: \\\"36\\\" },\\n      { icon: Boxes, label: \\\"Containers\\\", count: \\\"258\\\" },\\n      { icon: Cable, label: \\\"Serverless Functions\\\", count: \\\"103\\\" },\\n      { icon: Boxes, label: \\\"Compute Images\\\", count: \\\"25\\\" },\\n    ]},\\n    { icon: Settings, label: \\\"Configurations\\\", count: \\\"0\\\" },\\n    { icon: Clock, label: \\\"Latest Devices\\\", count: \\\"12,409\\\" },\\n  ] },\\n  { name: \\\"Identity\\\", icon: Users, open: false, items: [\\n    { folder: \\\"Directory\\\", open: false, items: [\\n      { icon: Users, label: \\\"Users\\\", count: \\\"4,821\\\" },\\n      { icon: Users, label: \\\"Groups\\\", count: \\\"312\\\" },\\n    ]},\\n    { icon: ShieldAlert, label: \\\"Service Accounts\\\", count: \\\"87\\\" },\\n  ] },\\n  { name: \\\"Applications\\\", icon: Layers, open: false, items: [\\n    { icon: Layers, label: \\\"SaaS Apps\\\", count: \\\"143\\\" },\\n    { icon: Layers, label: \\\"Installed Software\\\", count: \\\"2,904\\\" },\\n  ] },\\n  { name: \\\"Tickets\\\", icon: Bell, open: false, items: [\\n    { icon: Bell, label: \\\"Open Tickets\\\", count: \\\"48\\\" },\\n    { icon: Bell, label: \\\"Resolved\\\", count: \\\"203\\\" },\\n  ] },\\n];\\nfunction InventoryPanel({ collapsed, setCollapsed }) {\\n  const [groups, setGroups] = useState(INV_GROUPS_INIT);\\n  const [favOpen, setFavOpen] = useState(true);\\n\\n  const collectItems = (items) =&gt; items.flatMap(it =&gt; it.folder ? collectItems(it.items) : [it]);\\n  const favItems = groups.flatMap(g =&gt; collectItems(g.items)).filter(it =&gt; it.fav);\\n\\n  const toggleFavInItems = (items, label) =&gt; items.map(it =&gt;\\n    it.folder ? { ...it, items: toggleFavInItems(it.items, label) }\\n              : it.label === label ? { ...it, fav: !it.fav } : it\\n  );\\n  const toggleFav = (label) =&gt; setGroups(gs =&gt; gs.map(g =&gt; ({ ...g, items: toggleFavInItems(g.items, label) })));\\n  const compute = groups.find(g =&gt; g.name === \\\"Compute\\\");\\n  const computeLeafItems = compute ? compute.items.filter(it =&gt; !it.folder) : [];\\n  return (\\n    \n\\n       setCollapsed(!collapsed)} title={collapsed ? \\\"Expand inventory\\\" : \\\"Collapse panel\\\"} className=\\\"ax-edge-collapse\\\"\\n        style={{ position: \\\"absolute\\\", top: 16, right: -14, zIndex: 6, width: 28, height: 28, borderRadius: \\\"50%\\\", border: `1px solid ${T.line}`, background: T.surface, color: T.muted, cursor: \\\"pointer\\\", display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\", boxShadow: T.shadow }}&gt;\\n        {collapsed ?  : }\\n      &lt;\\/button&gt;\\n      \n\\n        {collapsed ? (\\n          \n\\n            \n\\n              \\n            &lt;\\/div&gt;\\n            \n\\n            {computeLeafItems.map((it, i) =&gt; {\\n              const Icon = it.icon;\\n              return (\\n                \n\\n                  \\n                &lt;\\/div&gt;\\n              );\\n            })}\\n          &lt;\\/div&gt;\\n        ) : (\\n          &lt;&gt;\\n            \n\\n              \n\\n                \\n              &lt;\\/div&gt;\\n            &lt;\\/div&gt;\\n            \n\\n              \n\\n                \n setFavOpen(o =&gt; !o)} style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 9, padding: \\\"9px 8px\\\", cursor: \\\"pointer\\\", borderRadius: 8, color: T.body }}&gt;\\n                  \\n                  \\n                  Favorites&lt;\\/span&gt;\\n                  {favItems.length}&lt;\\/span&gt;\\n                &lt;\\/div&gt;\\n                {favOpen &amp;&amp; favItems.map((it, ii) =&gt; )}\\n              &lt;\\/div&gt;\\n              {groups.map((g, gi) =&gt; { const Icon = g.icon; return (\\n                \n\\n                  \n setGroups(gs =&gt; gs.map((x, i) =&gt; i === gi ? { ...x, open: !x.open } : x))}\\n                    style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 9, padding: \\\"9px 8px\\\", cursor: \\\"pointer\\\", borderRadius: 8, color: g.open ? T.accentText : T.body }}&gt;\\n                    \\n                    \\n                    {g.name}&lt;\\/span&gt;\\n                  &lt;\\/div&gt;\\n                  {g.open &amp;&amp; g.items.map((it, ii) =&gt; it.folder ?  : )}\\n                &lt;\\/div&gt;\\n              ); })}\\n            &lt;\\/div&gt;\\n          &lt;\\/&gt;\\n        )}\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\nfunction InvFolder({ folder, toggleFav }) {\\n  const [open, setOpen] = useState(folder.open);\\n  const [h, setH] = useState(false);\\n  const FIcon = open ? FolderOpen : Folder;\\n  return (\\n    \n\\n      \n setH(true)} onMouseLeave={() =&gt; setH(false)} onClick={() =&gt; setOpen(o =&gt; !o)}\\n        style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 8, height: 34, padding: \\\"0 8px 0 22px\\\", borderRadius: 8, cursor: \\\"pointer\\\", background: h ? T.surface2 : \\\"transparent\\\", transition: \\\"background .12s\\\" }}&gt;\\n        \\n        \\n        {folder.folder}&lt;\\/span&gt;\\n      &lt;\\/div&gt;\\n      {open &amp;&amp; folder.items.map((it, i) =&gt; )}\\n    &lt;\\/div&gt;\\n  );\\n}\\nfunction InvRow({ icon: Icon, label, count, active, fav, indent, toggleFav }) {\\n  const [h, setH] = useState(false);\\n  const left = indent || 28;\\n  return (\\n    \n setH(true)} onMouseLeave={() =&gt; setH(false)}\\n      style={{ position: \\\"relative\\\", display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 11, height: 36, margin: \\\"1px 0\\\", padding: `0 8px 0 ${left}px`, borderRadius: 8, cursor: \\\"pointer\\\", background: active ? T.accentSoft : h ? T.surface2 : \\\"transparent\\\", transition: \\\"background .14s\\\" }}&gt;\\n      \\n      {label}&lt;\\/span&gt;\\n      {(h || fav) &amp;&amp; toggleFav &amp;&amp; (\\n         { e.stopPropagation(); toggleFav(label); }} title={fav ? \\\"Remove from favorites\\\" : \\\"Add to favorites\\\"} className=\\\"ax-star\\\"\\n          style={{ width: 22, height: 22, borderRadius: 6, border: \\\"none\\\", background: \\\"transparent\\\", cursor: \\\"pointer\\\", display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\", padding: 0, flexShrink: 0 }}&gt;\\n          \\n        &lt;\\/button&gt;\\n      )}\\n      {!h &amp;&amp; !fav &amp;&amp; {count}&lt;\\/span&gt;}\\n    &lt;\\/div&gt;\\n  );\\n}\\n\\n/* ============ chrome ============ */\\nfunction AppHeader({ theme, setTheme }) {\\n  return (\\n    \n\\n      \n\\n        \\n      &lt;\\/div&gt;\\n      \n\\n        \n\\n          Search Axonius&lt;\\/span&gt;\\n          \\u2318K&lt;\\/span&gt;\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n      \n\\n        New navigation BETA&lt;\\/span&gt;&lt;\\/button&gt;\\n         setTheme(theme === \\\"dark\\\" ? \\\"light\\\" : \\\"dark\\\")} title=\\\"Toggle light / dark\\\"&gt;{theme === \\\"dark\\\" ?  : }&lt;\\/HBtn&gt;\\n        &lt;\\/HBtn&gt;\\n        \nSB&lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\nfunction HBtn({ children, onClick, title }) {\\n  const [h, setH] = useState(false);\\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ width: 32, height: 32, borderRadius: 8, border: \\\"none\\\", cursor: \\\"pointer\\\", background: h ? T.surface2 : \\\"transparent\\\", color: h ? T.ink : T.bg80, display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\" }}&gt;{children}&lt;\\/button&gt;;\\n}\\n\\nconst HICONS = {\\n  dashboard: '',\\n  inventory: '',\\n  shield: '',\\n  bolt: '',\\n  link: '',\\n  chart: '',\\n  cog: '',\\n};\\nfunction HIcon({ name, size = 20, color = \\\"currentColor\\\", sw = 1.6, className }) {\\n  return ${HICONS[name] || \\\"\\\"}&lt;\\/svg&gt;` }} /&gt;;\\n}\\nconst RAIL = [\\n  { key: \\\"dashboard\\\", hi: \\\"dashboard\\\", label: \\\"Dashboard\\\" }, { key: \\\"assets\\\", hi: \\\"inventory\\\", label: \\\"Inventory\\\" },\\n  { key: \\\"exposures\\\", hi: \\\"shield\\\", label: \\\"Exposures\\\" }, { key: \\\"action\\\", hi: \\\"bolt\\\", label: \\\"Action Center\\\" },\\n  { key: \\\"adapters\\\", hi: \\\"link\\\", label: \\\"Adapters\\\" }, { key: \\\"analysis\\\", hi: \\\"chart\\\", label: \\\"Analysis\\\" },\\n];\\nfunction IconRail({ view, setView }) {\\n  return (\\n    \n\\n      {RAIL.map(r =&gt;  setView(r.key)} /&gt;)}\\n      \n\\n      \n\\n    &lt;\\/div&gt;\\n  );\\n}\\nfunction RailGlyph({ hi, label, active, onClick }) {\\n  const [h, setH] = useState(false);\\n  return (\\n    \n setH(true)} onMouseLeave={() =&gt; setH(false)} title={label} className=\\\"ax-rail ax-press\\\"\\n      style={{ position: \\\"relative\\\", width: 44, height: 44, borderRadius: 14, cursor: \\\"pointer\\\", display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\", background: active ? T.accentSoft : h ? T.surface2 : \\\"transparent\\\", transition: \\\"background .15s\\\" }}&gt;\\n      \\n    &lt;\\/div&gt;\\n  );\\n}\\n\\nconst DASH_TREE_INIT = [\\n  { g: \\\"Favorites\\\", open: true, items: [\\n    { nm: \\\"My Dashboard\\\", fav: true }, { nm: \\\"Asset Profile - Copy_2024-06-09\\\", fav: true },\\n    { nm: \\\"Axonius Dashboard\\\", fav: true, active: true, def: true }, { nm: \\\"Cost Optimization\\\", fav: true }, { nm: \\\"Cloud Compliance\\\", fav: true },\\n  ] },\\n  { g: \\\"Public\\\", open: false, items: [\\n    { folder: \\\"Security\\\", open: false, items: [{ nm: \\\"SecOps Overview\\\" }, { nm: \\\"Threat Intelligence\\\" }] },\\n    { folder: \\\"Executive\\\", open: false, items: [{ nm: \\\"Executive Summary\\\" }, { nm: \\\"Board Report\\\" }] },\\n    { nm: \\\"Asset Inventory V 1.0\\\" }, { nm: \\\"Active Directory Insights\\\" },\\n  ] },\\n  { g: \\\"Shared\\\", open: false, items: [\\n    { folder: \\\"Team SOC\\\", open: false, items: [{ nm: \\\"Vulnerability Posture\\\" }, { nm: \\\"Incident Response\\\" }] },\\n    { nm: \\\"Cloud Inventory\\\" }, { nm: \\\"Compliance Overview\\\" },\\n  ] },\\n  { g: \\\"Private\\\", open: false, items: [{ nm: \\\"My Drafts\\\" }, { nm: \\\"Work in Progress\\\" }] },\\n  { g: \\\"Managed by Axonius\\\", open: false, items: [{ nm: \\\"Device Overview\\\" }, { nm: \\\"User Overview\\\" }, { nm: \\\"Adapters Health\\\" }, { nm: \\\"Coverage &amp; Gaps\\\" }] },\\n];\\nfunction PanelBtn({ primary, filled, icon: Icon, children, onClick }) {\\n  const [h, setH] = useState(false);\\n  return (\\n     setH(true)} onMouseLeave={() =&gt; setH(false)} className={filled ? \\\"ax-primary\\\" : \\\"ax-press\\\"}\\n      style={{ height: 38, borderRadius: 999, border: filled ? \\\"none\\\" : primary ? `1.5px solid ${T.accentText}` : `1px solid ${h ? T.lineStrong : T.line}`, cursor: \\\"pointer\\\", width: \\\"100%\\\", background: filled ? (h ? T.blueDeep : T.blue) : primary ? (h ? T.accentSoft : \\\"transparent\\\") : h ? T.surface2 : \\\"transparent\\\", color: filled ? T.onAccent : primary ? T.accentText : T.body, fontSize: 13, fontWeight: 600, fontFamily: T.font, display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\", gap: 7, boxShadow: \\\"none\\\", transition: \\\"background .14s ease, border-color .14s ease\\\" }}&gt;\\n       {children}\\n    &lt;\\/button&gt;\\n  );\\n}\\nfunction CreateDashModal({ onCreate, close }) {\\n  const [name, setName] = useState(\\\"\\\");\\n  const [tpl, setTpl] = useState(\\\"blank\\\");\\n  const tpls = [{ k: \\\"blank\\\", t: \\\"Blank dashboard\\\", d: \\\"Start from an empty canvas\\\" }, { k: \\\"template\\\", t: \\\"From a template\\\", d: \\\"Prebuilt charts to tweak\\\" }];\\n  return createPortal(\\n    \n\\n      \n e.stopPropagation()} style={{ width: 480, maxWidth: \\\"92vw\\\", background: T.canvas, border: `1px solid ${T.line}`, borderRadius: 14, boxShadow: \\\"0 30px 80px rgba(0,0,0,.55)\\\", overflow: \\\"hidden\\\", animation: \\\"axRise .26s cubic-bezier(.22,1,.36,1) both\\\" }}&gt;\\n        \n\\n          Create dashboard&lt;\\/span&gt;\\n          &lt;\\/IconBtn&gt;\\n        &lt;\\/div&gt;\\n        \n\\n          \n\\n            Dashboard name&lt;\\/label&gt;\\n             setName(e.target.value)} placeholder=\\\"e.g. Security Posture\\\" style={{ width: \\\"100%\\\", height: 40, padding: \\\"0 14px\\\", border: `1px solid ${T.line}`, borderRadius: 8, background: T.control, color: T.ink, fontFamily: T.font, fontSize: 14, outline: \\\"none\\\", boxSizing: \\\"border-box\\\" }} /&gt;\\n          &lt;\\/div&gt;\\n          \n\\n            Starting point&lt;\\/label&gt;\\n            \n\\n              {tpls.map(o =&gt; (\\n                 setTpl(o.k)} style={{ flex: 1, textAlign: \\\"left\\\", padding: \\\"12px 13px\\\", borderRadius: 10, border: `1.5px solid ${tpl === o.k ? T.accentText : T.line}`, background: tpl === o.k ? T.accentSoft : \\\"transparent\\\", cursor: \\\"pointer\\\", fontFamily: T.font }}&gt;\\n                  \n{o.t}&lt;\\/div&gt;\\n                  \n{o.d}&lt;\\/div&gt;\\n                &lt;\\/button&gt;\\n              ))}\\n            &lt;\\/div&gt;\\n          &lt;\\/div&gt;\\n        &lt;\\/div&gt;\\n        \n\\n          Cancel&lt;\\/button&gt;\\n           name.trim() &amp;&amp; onCreate(name.trim())} className=\\\"ax-press\\\" style={{ height: 38, padding: \\\"0 18px\\\", borderRadius: 999, border: \\\"none\\\", background: name.trim() ? T.blue : T.surface2, color: name.trim() ? T.onAccent : T.faint, fontSize: 13.5, fontWeight: 600, cursor: name.trim() ? \\\"pointer\\\" : \\\"default\\\", fontFamily: T.font }}&gt;Create dashboard&lt;\\/button&gt;\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;, document.body);\\n}\\nfunction SidePanel({ collapsed, setCollapsed, activeDash, setActiveDash }) {\\n  const [tree, setTree] = useState(DASH_TREE_INIT);\\n  const [menu, setMenu] = useState(null);\\n  const [editing, setEditing] = useState(null);\\n  const [createOpen, setCreateOpen] = useState(false);\\n\\n  const mut = (fn) =&gt; setTree(t =&gt; fn(t.map(g =&gt; ({ ...g, items: g.items.map(it =&gt; ({ ...it })) }))));\\n  const toggleGroup = (gi) =&gt; setTree(t =&gt; t.map((g, i) =&gt; i === gi ? { ...g, open: !g.open } : g));\\n  const setActive = (gi, ii) =&gt; { mut(t =&gt; { t.forEach(g =&gt; g.items.forEach(it =&gt; it.active = false)); t[gi].items[ii].active = true; return t; }); if (setActiveDash) setActiveDash(tree[gi].items[ii].nm); };\\n  const toggleFav = (gi, ii) =&gt; mut(t =&gt; { t[gi].items[ii].fav = !t[gi].items[ii].fav; return t; });\\n  const setDefault = (gi, ii) =&gt; mut(t =&gt; { t.forEach(g =&gt; g.items.forEach(it =&gt; it.def = false)); t[gi].items[ii].def = true; return t; });\\n  const duplicate = (gi, ii) =&gt; mut(t =&gt; { t[gi].items.splice(ii + 1, 0, { nm: t[gi].items[ii].nm + \\\" (copy)\\\" }); return t; });\\n  const rename = (gi, ii, nm) =&gt; mut(t =&gt; { t[gi].items[ii].nm = nm || t[gi].items[ii].nm; return t; });\\n  const remove = (gi, ii) =&gt; mut(t =&gt; { t[gi].items.splice(ii, 1); return t; });\\n  const createDash = (nm) =&gt; mut(t =&gt; { const p = t.find(g =&gt; g.g === \\\"Private\\\"); p.open = true; p.items.push({ nm: nm || \\\"Untitled dashboard\\\" }); return t; });\\n  const openMenu = (gi, ii, e) =&gt; { const r = e.currentTarget.getBoundingClientRect(); setMenu({ gi, ii, top: r.bottom + 6, left: Math.max(8, r.right - 196) }); };\\n\\n  if (collapsed) {\\n    const favItems = tree.flatMap(g =&gt; g.items).filter(it =&gt; it.fav || it.active);\\n    return (\\n      \n\\n         setCollapsed(false)} title=\\\"Expand dashboards\\\" className=\\\"ax-edge-collapse\\\"\\n          style={{ position: \\\"absolute\\\", top: 16, right: -14, zIndex: 6, width: 28, height: 28, borderRadius: \\\"50%\\\", border: `1px solid ${T.line}`, background: T.surface, color: T.muted, cursor: \\\"pointer\\\", display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\", boxShadow: T.shadow }}&gt;\\n          \\n        &lt;\\/button&gt;\\n         setCreateOpen(true)} style={{ width: 38, height: 38, borderRadius: 8, border: `1.5px solid ${T.accentText}`, background: \\\"transparent\\\", cursor: \\\"pointer\\\", display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\", color: T.accentText }}&gt;\\n          \\n        &lt;\\/button&gt;\\n        \n\\n        {favItems.map((s, i) =&gt; (\\n          \n\\n            \\n            {s.fav &amp;&amp; }\\n          &lt;\\/div&gt;\\n        ))}\\n        {createOpen &amp;&amp;  { createDash(nm); setCreateOpen(false); }} close={() =&gt; setCreateOpen(false)} /&gt;}\\n      &lt;\\/div&gt;\\n    );\\n  }\\n  return (\\n    \n\\n       setCollapsed(true)} title=\\\"Collapse panel\\\" className=\\\"ax-edge-collapse\\\"\\n        style={{ position: \\\"absolute\\\", top: 16, right: -14, zIndex: 6, width: 28, height: 28, borderRadius: \\\"50%\\\", border: `1px solid ${T.line}`, background: T.surface, color: T.muted, cursor: \\\"pointer\\\", display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\", boxShadow: T.shadow }}&gt;\\n        \\n      &lt;\\/button&gt;\\n      \n\\n         setCreateOpen(true)}&gt;Create Dashboard&lt;\\/PanelBtn&gt;\\n        Manage Dashboards&lt;\\/PanelBtn&gt;\\n      &lt;\\/div&gt;\\n      \n\\n        \n\\n          \\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n      \n\\n        {tree.map((g, gi) =&gt; (\\n          \\n        ))}\\n      &lt;\\/div&gt;\\n      {menu &amp;&amp;  setMenu(null)}\\n        actions={{ rename: () =&gt; setEditing({ gi: menu.gi, ii: menu.ii }), duplicate, toggleFav, setDefault, remove }} /&gt;}\\n      {createOpen &amp;&amp;  { createDash(nm); setCreateOpen(false); }} close={() =&gt; setCreateOpen(false)} /&gt;}\\n    &lt;\\/div&gt;\\n  );\\n}\\nconst DASH_CAT_ICON = { Favorites: Star, Public: Globe, Shared: Users, Private: Lock, \\\"Managed by Axonius\\\": ShieldCheck };\\nfunction DashGroup({ group, gi, toggleGroup, setActive, toggleFav, openMenu, editing, setEditing, rename }) {\\n  const Icon = DASH_CAT_ICON[group.g] || LayoutGrid;\\n  return (\\n    \n\\n       toggleGroup(gi)} className=\\\"ax-catrow\\\"\\n        style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 9, width: \\\"100%\\\", border: \\\"none\\\", background: \\\"transparent\\\", cursor: \\\"pointer\\\", padding: \\\"8px 8px\\\", borderRadius: 8, fontFamily: T.font }}&gt;\\n        \\n        \\n        {group.g}&lt;\\/span&gt;\\n        {group.g === \\\"Favorites\\\" ? group.items.filter(it =&gt; it.fav !== false).length : group.items.length}&lt;\\/span&gt;\\n      &lt;\\/button&gt;\\n      {group.open &amp;&amp; group.items\\n        .filter(it =&gt; group.g !== \\\"Favorites\\\" || it.fav !== false)\\n        .map((it, ii) =&gt;\\n          it.folder\\n            ? \\n            : \\n        )}\\n    &lt;\\/div&gt;\\n  );\\n}\\nfunction DashFolder({ folder, indent, onToggle }) {\\n  const [h, setH] = useState(false);\\n  const [open, setOpen] = useState(folder.open);\\n  const toggle = () =&gt; { setOpen(o =&gt; !o); if (onToggle) onToggle(!open); };\\n  const FIcon = open ? FolderOpen : Folder;\\n  return (\\n    \n\\n      \n setH(true)} onMouseLeave={() =&gt; setH(false)} onClick={toggle}\\n        style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 8, height: 34, padding: `0 8px 0 ${indent || 22}px`, borderRadius: 8, cursor: \\\"pointer\\\", background: h ? T.surface2 : \\\"transparent\\\", transition: \\\"background .12s\\\" }}&gt;\\n        \\n        \\n        {folder.folder}&lt;\\/span&gt;\\n      &lt;\\/div&gt;\\n      {open &amp;&amp; folder.items.map((it, i) =&gt; (\\n        \n e.currentTarget.style.background = T.surface2} onMouseLeave={(e) =&gt; e.currentTarget.style.background = \\\"transparent\\\"}&gt;\\n          \\n          {it.nm}&lt;\\/span&gt;\\n        &lt;\\/div&gt;\\n      ))}\\n    &lt;\\/div&gt;\\n  );\\n}\\nfunction DashItem({ item, gi, ii, setActive, toggleFav, openMenu, editing, setEditing, rename }) {\\n  const [h, setH] = useState(false);\\n  return (\\n    \n setH(true)} onMouseLeave={() =&gt; setH(false)} onClick={() =&gt; !editing &amp;&amp; setActive(gi, ii)} className=\\\"ax-press\\\"\\n      style={{ position: \\\"relative\\\", display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 9, height: 36, padding: \\\"0 8px 0 28px\\\", margin: \\\"1px 0\\\", cursor: \\\"pointer\\\", borderRadius: 8, border: \\\"none\\\", background: item.active ? T.accentSoft : h ? T.surface2 : \\\"transparent\\\", transition: \\\"background .14s\\\" }}&gt;\\n      \\n      {editing ? (\\n         e.stopPropagation()}\\n          onBlur={(e) =&gt; { rename(gi, ii, e.target.value.trim()); setEditing(null); }}\\n          onKeyDown={(e) =&gt; { if (e.key === \\\"Enter\\\") { rename(gi, ii, e.target.value.trim()); setEditing(null); } if (e.key === \\\"Escape\\\") setEditing(null); }}\\n          style={{ flex: 1, minWidth: 0, border: `1px solid ${T.blue}`, borderRadius: 6, padding: \\\"2px 6px\\\", fontSize: 13.5, fontFamily: T.font, color: T.ink, outline: \\\"none\\\", background: T.surface }} /&gt;\\n      ) : (\\n        {item.nm}&lt;\\/span&gt;\\n      )}\\n      {(h || item.fav) &amp;&amp; !editing &amp;&amp; (\\n         { e.stopPropagation(); toggleFav(gi, ii); }} title={item.fav ? \\\"Remove from favorites\\\" : \\\"Add to favorites\\\"} className=\\\"ax-star\\\"\\n          style={{ width: 22, height: 22, borderRadius: 6, border: \\\"none\\\", background: \\\"transparent\\\", cursor: \\\"pointer\\\", display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\", padding: 0, flexShrink: 0 }}&gt;\\n          \\n        &lt;\\/button&gt;\\n      )}\\n      {h &amp;&amp; !editing &amp;&amp; (\\n         { e.stopPropagation(); openMenu(gi, ii, e); }} title=\\\"More actions\\\"\\n          style={{ width: 22, height: 22, borderRadius: 6, border: \\\"none\\\", background: \\\"transparent\\\", cursor: \\\"pointer\\\", display: \\\"flex\\\", alignItems: \\\"center\\\", justifyContent: \\\"center\\\", padding: 0, flexShrink: 0, color: T.muted }}&gt;\\n          \\n        &lt;\\/button&gt;\\n      )}\\n    &lt;\\/div&gt;\\n  );\\n}\\nfunction RowMenu({ menu, tree, close, actions }) {\\n  const it = tree[menu.gi]?.items?.[menu.ii] || {};\\n  const rows = [\\n    { ic: Pencil, l: \\\"Rename\\\", fn: () =&gt; actions.rename() },\\n    { ic: Copy, l: \\\"Duplicate\\\", fn: () =&gt; actions.duplicate(menu.gi, menu.ii) },\\n    { ic: Star, l: it.fav ? \\\"Remove from favorites\\\" : \\\"Add to favorites\\\", fn: () =&gt; actions.toggleFav(menu.gi, menu.ii) },\\n    { ic: Check, l: it.def ? \\\"Default dashboard\\\" : \\\"Set as default\\\", fn: () =&gt; actions.setDefault(menu.gi, menu.ii) },\\n    { ic: Download, l: \\\"Export\\\", fn: () =&gt; {} },\\n    { sep: true },\\n    { ic: Trash2, l: \\\"Delete\\\", danger: true, fn: () =&gt; actions.remove(menu.gi, menu.ii) },\\n  ];\\n  return (\\n    &lt;&gt;\\n      \n\\n      \n\\n        {rows.map((a, i) =&gt; a.sep\\n          ? \n\\n          :  { a.fn(); close(); }}&gt;{a.l}&lt;\\/MenuRow&gt;)}\\n      &lt;\\/div&gt;\\n    &lt;\\/&gt;\\n  );\\n}\\nfunction MenuRow({ icon: Icon, danger, children, onClick }) {\\n  const [h, setH] = useState(false);\\n  return (\\n     setH(true)} onMouseLeave={() =&gt; setH(false)}\\n      style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 9, width: \\\"100%\\\", border: \\\"none\\\", borderRadius: 8, cursor: \\\"pointer\\\", padding: \\\"7px 9px\\\", fontSize: 13, fontFamily: T.font, fontWeight: 500, textAlign: \\\"left\\\", color: danger ? T.red : T.body, background: h ? (danger ? `${T.red}10` : T.canvas) : \\\"transparent\\\" }}&gt;\\n       {children}\\n    &lt;\\/button&gt;\\n  );\\n}\\n\\nfunction ModuleHeader({ view, activeDash }) {\\n  const isDash = view === \\\"dashboard\\\";\\n  return (\\n    \n\\n      \n{isDash ? \\\"Dashboards / Favorites\\\" : \\\"Assets / All Devices\\\"}&lt;\\/span&gt;&lt;\\/div&gt;\\n      \n\\n        \n\\n          \n{isDash ? activeDash : \\\"Assets\\\"}&lt;\\/h1&gt;\\n          {isDash &amp;&amp; }\\n        &lt;\\/div&gt;\\n        \n\\n          {isDash ? &lt;&gt;\\n             Updated 2m ago&lt;\\/span&gt;\\n            Add Chart&lt;\\/HdrBtn&gt;\\n          &lt;\\/&gt; : &lt;&gt;\\n            Export&lt;\\/HdrBtn&gt;\\n            New Query&lt;\\/HdrBtn&gt;\\n          &lt;\\/&gt;}\\n          &lt;\\/IconBtn&gt;\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\nfunction HdrBtn({ icon: Icon, children, primary, filled }) {\\n  const [h, setH] = useState(false);\\n  return  setH(true)} onMouseLeave={() =&gt; setH(false)} style={{ display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 6, height: 34, padding: \\\"0 14px\\\", borderRadius: 999, cursor: \\\"pointer\\\", fontFamily: T.font, fontSize: 13.5, fontWeight: 600, border: filled ? \\\"none\\\" : (primary ? `1.5px solid ${T.accentText}` : `1px solid ${h ? T.lineStrong : T.line}`), background: filled ? (h ? T.blueDeep : T.blue) : (primary ? (h ? T.accentSoft : \\\"transparent\\\") : (h ? T.surface2 : T.control)), color: filled ? T.onAccent : (primary ? T.accentText : T.body) }}&gt;{children}&lt;\\/button&gt;;\\n}\\n\\nfunction AxoniusApp() {\\n  const [view, setView] = useState(\\\"dashboard\\\");\\n  const [collapsed, setCollapsed] = useState(false);\\n  const [invCollapsed, setInvCollapsed] = useState(false);\\n  const [theme, setTheme] = useState(\\\"dark\\\");\\n  const [activeDash, setActiveDash] = useState(\\\"Axonius Dashboard\\\");\\n  T = THEMES[theme];\\n  useEffect(() =&gt; {\\n    document.body.style.background = THEMES[theme].shell;\\n    const el = document.documentElement;\\n    el.classList.add(\\\"theming\\\");\\n    const id = setTimeout(() =&gt; el.classList.remove(\\\"theming\\\"), 450);\\n    return () =&gt; clearTimeout(id);\\n  }, [theme]);\\n  return (\\n    \n\\n      {`@import url('https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;500;600;700&amp;family=Schibsted+Grotesk:wght@500;600;700&amp;display=swap'); * { box-sizing: border-box; } .theming, .theming * { transition: background-color .4s ease, border-color .4s ease, color .35s ease, fill .3s ease, stroke .3s ease !important; } *::-webkit-scrollbar { width: 9px; height: 9px; } *::-webkit-scrollbar-thumb { background: ${T.bg40}; border-radius: 5px; } *::-webkit-scrollbar-track { background: transparent; }\\n        .ax-tile *::-webkit-scrollbar-thumb { background: transparent; transition: background .2s ease; }\\n        .ax-tile:hover *::-webkit-scrollbar-thumb { background: ${T.bg40}; }\\n        .ax-tbl::-webkit-scrollbar-thumb { background: transparent; } .ax-tbl:hover::-webkit-scrollbar-thumb { background: ${T.bg40}; } .ax-tbl::-webkit-scrollbar-corner { background: transparent; }\\n        input::placeholder { color: ${T.muted}; opacity: 1; }\\n        .ax-catrow:hover { background: ${T.surface2}; }\\n        .ax-catrow:hover .ax-favbtn { opacity: 1 !important; }\\n        .ax-edge-collapse { opacity: 0; transform: scale(.8); transition: opacity .15s ease, transform .15s ease; }\\n        .ax-sidepanel:hover .ax-edge-collapse { opacity: 1; transform: scale(1); }\\n        button, [role=\\\"button\\\"] { transition: transform .14s cubic-bezier(.34,1.56,.64,1), background-color .15s ease, box-shadow .18s ease, border-color .15s ease, color .12s ease; }\\n        button:not(:disabled):active { transform: scale(.92); }\\n        .ax-press { transition: transform .14s cubic-bezier(.34,1.56,.64,1), background-color .14s ease; }\\n        .ax-press:active { transform: scale(.95); }\\n        .ax-card { transition: transform .2s cubic-bezier(.34,1.56,.64,1), box-shadow .2s ease, border-color .15s ease; }\\n        .ax-card:hover { border-color: ${T.lineStrong} !important; box-shadow: ${T.shadow} !important; }\\n        .ax-primary:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(37,99,235,.4) !important; }\\n        .ax-primary:active { transform: translateY(0) scale(.96); }\\n        @keyframes axRise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }\\n        .ax-rise { animation: axRise .45s cubic-bezier(.22,1,.36,1) both; }\\n        @keyframes axJiggle { 0%, 100% { transform: rotate(-0.5deg); } 50% { transform: rotate(0.5deg); } }\\n        .ax-jiggle { animation: axJiggle .32s ease-in-out infinite; }\\n        @keyframes axPop { 0% { transform: scale(1); } 45% { transform: scale(1.25) rotate(-8deg); } 100% { transform: scale(1); } }\\n        .ax-star:hover { animation: axPop .4s ease; }\\n        @keyframes axSpin { to { transform: rotate(360deg); } }\\n        .ax-spin:hover { animation: axSpin .6s ease; }\\n        button:not(:disabled):hover { transform: translateY(-1px); }\\n        @keyframes axGrow { from { transform: scaleX(0); } to { transform: scaleX(1); } }\\n        @keyframes axGrowY { from { transform: scaleY(0); } to { transform: scaleY(1); } }\\n        @keyframes axDraw { to { stroke-dashoffset: 0; } }\\n        @keyframes axFade { from { opacity: 0; } to { opacity: 1; } }\\n        @keyframes axSlideIn { from { transform: translateX(100%); } to { transform: translateX(0); } }\\n        @keyframes axBounce { 0% { transform: translateY(0) scale(1); } 35% { transform: translateY(-4px) scale(1.14); } 70% { transform: translateY(0) scale(1); } 100% { transform: translateY(0) scale(1); } }\\n        .ax-rail:hover .ax-railicon { animation: axBounce .5s ease; }\\n        .ax-flat:hover { transform: none !important; }`}&lt;\\/style&gt;\\n      \\n      \n\\n        \\n        \n\\n          {view === \\\"dashboard\\\" &amp;&amp; }\\n          {view === \\\"assets\\\" &amp;&amp; }\\n          \n\\n            {view === \\\"dashboard\\\" &amp;&amp; }\\n            {view === \\\"dashboard\\\" ? (\\n              \n\\n                {DASH_TILESETS[activeDash]\\n                  ? \\n                  : &lt;&gt;&lt;\\/&gt;}\\n              &lt;\\/div&gt;\\n            ) : view === \\\"assets\\\" ? (\\n              \\n            ) : (\\n              \n\\n                {RAIL.find(r =&gt; r.key === view)?.label} view \\u2014 coming soon\\n              &lt;\\/div&gt;\\n            )}\\n          &lt;\\/div&gt;\\n        &lt;\\/div&gt;\\n      &lt;\\/div&gt;\\n    &lt;\\/div&gt;\\n  );\\n}\\n\\ncreateRoot(document.getElementById(\\\"root\\\")).render();\\n    &lt;\\/script&gt;\\n  \\n    fetch('/.inspector/overlay.js')\\n      .then(r =&gt; r.text())\\n      .then(code =&gt; { const s = document.createElement('script'); s.textContent = code; document.head.appendChild(s); })\\n      .catch(() =&gt; {});\\n  &lt;\\/script&gt;\\n  &lt;\\/body&gt;\\n&lt;\\/html&gt;\\n\";\n\n    let editor, updateTimer, blobUrl;\n\n    function updatePreview(src) {\n      document.getElementById('preview-dot').className = 'loading';\n      if (blobUrl) URL.revokeObjectURL(blobUrl);\n      blobUrl = URL.createObjectURL(new Blob([src], { type: 'text\\/html' }));\n      const f = document.getElementById('preview');\n      f.onload = () =&gt; { document.getElementById('preview-dot').className = ''; };\n      f.src = blobUrl;\n    }\n\n    function downloadFile() {\n      const src = editor ? editor.getValue() : INITIAL_SOURCE;\n      const a = document.createElement('a');\n      a.href = URL.createObjectURL(new Blob([src], { type: 'text\\/html' }));\n      a.download = 'design-sandbox3.html'; a.click();\n    }\n\n    function resetSource() {\n      if (editor) editor.setValue(INITIAL_SOURCE);\n      updatePreview(INITIAL_SOURCE);\n    }\n\n    async function copySource() {\n      const src = editor ? editor.getValue() : INITIAL_SOURCE;\n      await navigator.clipboard.writeText(src);\n      const btn = document.getElementById('copy-btn');\n      btn.textContent = '&#10003; Copied!';\n      setTimeout(() =&gt; { btn.innerHTML = '&#11096; Copy HTML'; }, 2000);\n    }\n\n    // Resizable divider\n    const divider = document.getElementById('divider');\n    const edPane = document.getElementById('editor-pane');\n    let drag = false, sx, sw;\n    divider.addEventListener('mousedown', e =&gt; { drag = true; sx = e.clientX; sw = edPane.offsetWidth; divider.classList.add('dragging'); e.preventDefault(); });\n    document.addEventListener('mousemove', e =&gt; { if (!drag) return; edPane.style.width = Math.max(280, Math.min(sw + e.clientX - sx, window.innerWidth - 280)) + 'px'; editor &amp;&amp; editor.layout(); });\n    document.addEventListener('mouseup', () =&gt; { drag = false; divider.classList.remove('dragging'); });\n\n    require.config({ paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs' } });\n    require(['vs\\/editor\\/editor.main'], function() {\n      editor = monaco.editor.create(document.getElementById('monaco-container'), {\n        value: INITIAL_SOURCE,\n        language: 'html',\n        theme: 'vs-dark',\n        fontSize: 12.5,\n        lineHeight: 20,\n        minimap: { enabled: true },\n        wordWrap: 'off',\n        scrollBeyondLastLine: false,\n        automaticLayout: true,\n        folding: true,\n        bracketPairColorization: { enabled: true },\n      });\n      updatePreview(INITIAL_SOURCE);\n      editor.onDidChangeModelContent(() =&gt; {\n        const st = document.getElementById('status');\n        st.textContent = 'editing\u2026'; st.className = 'saving';\n        clearTimeout(updateTimer);\n        updateTimer = setTimeout(() =&gt; {\n          const v = editor.getValue();\n          updatePreview(v);\n          st.textContent = (v.length / 1024).toFixed(0) + ' KB';\n          st.className = 'idle';\n        }, 1000);\n      });\n    });\n  \n\n", "creation_timestamp": "2026-06-29T18:55:05.874572Z"}]}