@lifeart/async-dom 2.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +623 -0
- package/dist/base.d.cts +398 -0
- package/dist/base.d.cts.map +1 -0
- package/dist/base.d.ts +398 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/cli.cjs +528 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +493 -0
- package/dist/cli.js.map +1 -0
- package/dist/debug.d.cts +145 -0
- package/dist/debug.d.cts.map +1 -0
- package/dist/debug.d.ts +145 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/index.cjs +26 -0
- package/dist/index.d.cts +560 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +560 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index2.d.cts +5 -0
- package/dist/index2.d.ts +5 -0
- package/dist/index3.d.cts +882 -0
- package/dist/index3.d.cts.map +1 -0
- package/dist/index3.d.ts +882 -0
- package/dist/index3.d.ts.map +1 -0
- package/dist/main-thread.cjs +5459 -0
- package/dist/main-thread.cjs.map +1 -0
- package/dist/main-thread.js +5429 -0
- package/dist/main-thread.js.map +1 -0
- package/dist/react.cjs +116 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +91 -0
- package/dist/react.d.cts.map +1 -0
- package/dist/react.d.ts +91 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +113 -0
- package/dist/react.js.map +1 -0
- package/dist/resolve-debug.cjs +24 -0
- package/dist/resolve-debug.cjs.map +1 -0
- package/dist/resolve-debug.js +19 -0
- package/dist/resolve-debug.js.map +1 -0
- package/dist/server.cjs +250 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +127 -0
- package/dist/server.d.cts.map +1 -0
- package/dist/server.d.ts +127 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +245 -0
- package/dist/server.js.map +1 -0
- package/dist/svelte.cjs +48 -0
- package/dist/svelte.cjs.map +1 -0
- package/dist/svelte.d.cts +38 -0
- package/dist/svelte.d.cts.map +1 -0
- package/dist/svelte.d.ts +38 -0
- package/dist/svelte.d.ts.map +1 -0
- package/dist/svelte.js +47 -0
- package/dist/svelte.js.map +1 -0
- package/dist/sync-channel.cjs +532 -0
- package/dist/sync-channel.cjs.map +1 -0
- package/dist/sync-channel.js +425 -0
- package/dist/sync-channel.js.map +1 -0
- package/dist/transport.cjs +213 -0
- package/dist/transport.cjs.map +1 -0
- package/dist/transport.d.cts +79 -0
- package/dist/transport.d.cts.map +1 -0
- package/dist/transport.d.ts +79 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +202 -0
- package/dist/transport.js.map +1 -0
- package/dist/vite-plugin.cjs +112 -0
- package/dist/vite-plugin.cjs.map +1 -0
- package/dist/vite-plugin.d.cts +39 -0
- package/dist/vite-plugin.d.cts.map +1 -0
- package/dist/vite-plugin.d.ts +39 -0
- package/dist/vite-plugin.d.ts.map +1 -0
- package/dist/vite-plugin.js +107 -0
- package/dist/vite-plugin.js.map +1 -0
- package/dist/vue.cjs +123 -0
- package/dist/vue.cjs.map +1 -0
- package/dist/vue.d.cts +126 -0
- package/dist/vue.d.cts.map +1 -0
- package/dist/vue.d.ts +126 -0
- package/dist/vue.d.ts.map +1 -0
- package/dist/vue.js +120 -0
- package/dist/vue.js.map +1 -0
- package/dist/worker-thread.cjs +2751 -0
- package/dist/worker-thread.cjs.map +1 -0
- package/dist/worker-thread.js +2692 -0
- package/dist/worker-thread.js.map +1 -0
- package/dist/worker-transport.cjs +136 -0
- package/dist/worker-transport.cjs.map +1 -0
- package/dist/worker-transport.d.cts +162 -0
- package/dist/worker-transport.d.cts.map +1 -0
- package/dist/worker-transport.d.ts +162 -0
- package/dist/worker-transport.d.ts.map +1 -0
- package/dist/worker-transport.js +125 -0
- package/dist/worker-transport.js.map +1 -0
- package/dist/worker.cjs +12 -0
- package/dist/worker.d.cts +2 -0
- package/dist/worker.d.ts +2 -0
- package/dist/worker.js +2 -0
- package/dist/ws-server-transport.cjs +147 -0
- package/dist/ws-server-transport.cjs.map +1 -0
- package/dist/ws-server-transport.d.cts +64 -0
- package/dist/ws-server-transport.d.cts.map +1 -0
- package/dist/ws-server-transport.d.ts +64 -0
- package/dist/ws-server-transport.d.ts.map +1 -0
- package/dist/ws-server-transport.js +142 -0
- package/dist/ws-server-transport.js.map +1 -0
- package/dist/ws-transport.cjs +954 -0
- package/dist/ws-transport.cjs.map +1 -0
- package/dist/ws-transport.js +913 -0
- package/dist/ws-transport.js.map +1 -0
- package/package.json +145 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-thread.js","names":["isDangerousURI"],"sources":["../src/core/html-sanitizer.ts","../src/core/node-cache.ts","../src/core/scheduler.ts","../src/debug/causality-graph.ts","../src/debug/format-helpers.ts","../src/debug/replay.ts","../src/debug/session-export.ts","../src/debug/stats-helpers.ts","../src/debug/tree-diff.ts","../src/debug/devtools-panel.ts","../src/main-thread/event-bridge.ts","../src/main-thread/renderer.ts","../src/main-thread/thread-manager.ts","../src/main-thread/index.ts"],"sourcesContent":["/**\n * Lightweight HTML sanitizer for async-dom.\n *\n * Strips dangerous tags and attributes to prevent XSS when\n * worker-provided HTML is injected via innerHTML or insertAdjacentHTML.\n */\n\nconst DANGEROUS_TAGS = new Set([\n\t\"script\",\n\t\"iframe\",\n\t\"object\",\n\t\"embed\",\n\t\"form\",\n\t\"base\",\n\t\"meta\",\n\t\"link\",\n\t\"style\",\n]);\n\nconst DANGEROUS_ATTR_PATTERN = /^on/i;\n\nconst DANGEROUS_URI_ATTRS = new Set([\"href\", \"src\", \"data\", \"action\", \"formaction\", \"xlink:href\"]);\n\nconst DANGEROUS_ATTRS = new Set([\"srcdoc\", \"formaction\"]);\n\n/**\n * Returns true if the given URI string starts with `javascript:` (ignoring whitespace and case).\n */\nfunction isDangerousURI(value: string): boolean {\n\tconst trimmed = value.trim().toLowerCase();\n\treturn (\n\t\t/^\\s*javascript\\s*:/i.test(trimmed) ||\n\t\t/^\\s*vbscript\\s*:/i.test(trimmed) ||\n\t\t/^\\s*data\\s*:\\s*text\\/html/i.test(trimmed)\n\t);\n}\n\n/**\n * Sanitize an HTML string by removing dangerous tags and attributes.\n *\n * Uses the browser's DOMParser to parse the HTML, walks the resulting tree,\n * and removes any elements/attributes that could execute scripts or load\n * external resources in a dangerous way.\n */\nexport function sanitizeHTML(html: string): string {\n\tconst parser = new DOMParser();\n\tconst doc = parser.parseFromString(`<body>${html}</body>`, \"text/html\");\n\tconst body = doc.body;\n\n\tsanitizeNode(body);\n\n\treturn body.innerHTML;\n}\n\nfunction sanitizeNode(node: Node): void {\n\t// Collect children first since we may remove nodes during iteration\n\tconst children = Array.from(node.childNodes);\n\n\tfor (const child of children) {\n\t\tif (child.nodeType === Node.ELEMENT_NODE) {\n\t\t\tconst el = child as Element;\n\t\t\tconst tagName = el.tagName.toLowerCase();\n\n\t\t\tif (DANGEROUS_TAGS.has(tagName)) {\n\t\t\t\tel.remove();\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Remove dangerous attributes\n\t\t\tconst attrsToRemove: string[] = [];\n\t\t\tfor (let i = 0; i < el.attributes.length; i++) {\n\t\t\t\tconst attr = el.attributes[i];\n\t\t\t\tconst name = attr.name.toLowerCase();\n\n\t\t\t\tif (DANGEROUS_ATTR_PATTERN.test(name)) {\n\t\t\t\t\tattrsToRemove.push(attr.name);\n\t\t\t\t} else if (DANGEROUS_ATTRS.has(name)) {\n\t\t\t\t\tattrsToRemove.push(attr.name);\n\t\t\t\t} else if (DANGEROUS_URI_ATTRS.has(name) && isDangerousURI(attr.value)) {\n\t\t\t\t\tattrsToRemove.push(attr.name);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const attrName of attrsToRemove) {\n\t\t\t\tel.removeAttribute(attrName);\n\t\t\t}\n\n\t\t\t// Recurse into children\n\t\t\tsanitizeNode(el);\n\t\t}\n\t}\n}\n","import type { NodeId } from \"./protocol.ts\";\nimport { DOCUMENT_NODE_ID } from \"./protocol.ts\";\n\n/**\n * Cache for mapping NodeIds to real DOM nodes on the main thread.\n * Supports both forward (NodeId → Node) and reverse (Node → NodeId) lookups.\n */\nexport class NodeCache {\n\tprivate cache = new Map<NodeId, Node>();\n\tprivate reverseCache = new WeakMap<Node, NodeId>();\n\n\tget(id: NodeId): Node | null {\n\t\tif (id === DOCUMENT_NODE_ID) return document as unknown as Node;\n\n\t\treturn this.cache.get(id) ?? null;\n\t}\n\n\t/** Reverse lookup: get the NodeId for a real DOM node. */\n\tgetId(node: Node): NodeId | null {\n\t\treturn this.reverseCache.get(node) ?? null;\n\t}\n\n\tset(id: NodeId, node: Node): void {\n\t\tthis.cache.set(id, node);\n\t\tthis.reverseCache.set(node, id);\n\t}\n\n\tdelete(id: NodeId): void {\n\t\tconst node = this.cache.get(id);\n\t\tif (node) {\n\t\t\tthis.reverseCache.delete(node);\n\t\t}\n\t\tthis.cache.delete(id);\n\t}\n\n\tclear(): void {\n\t\tthis.cache.clear();\n\t\t// WeakMap entries are GC'd automatically when nodes are collected\n\t}\n\n\thas(id: NodeId): boolean {\n\t\treturn this.cache.has(id);\n\t}\n}\n","import {\n\tCRITICAL_QUEUE_SIZE,\n\tDEFAULT_FRAME_BUDGET_MS,\n\tFLUSH_BATCH_SIZE,\n\tMAX_QUEUE_BEFORE_FLUSH,\n\tVIEWPORT_CACHE_FRAMES,\n} from \"./constants.ts\";\nimport type { AppId, DomMutation, Priority } from \"./protocol.ts\";\n\n/** Configuration for the FrameScheduler. All fields are optional with sensible defaults. */\nexport interface SchedulerConfig {\n\t/** Maximum milliseconds to spend processing mutations per frame (default: 16ms for 60fps). */\n\tframeBudgetMs?: number;\n\t/** Whether to skip off-screen style mutations (default: true). */\n\tenableViewportCulling?: boolean;\n\t/** Whether to drop optional mutations under frame pressure (default: true). */\n\tenablePrioritySkipping?: boolean;\n}\n\n/** Diagnostic record for a single frame, used by devtools flamechart visualization. */\nexport interface FrameLogEntry {\n\t/** Monotonically increasing frame counter. */\n\tframeId: number;\n\t/** Wall-clock time spent in this frame's tick(), in milliseconds. */\n\ttotalMs: number;\n\t/** Number of mutations applied during this frame. */\n\tactionCount: number;\n\t/** Cumulative time per mutation action type (e.g., \"setAttribute\" -> 1.2ms). */\n\ttimingBreakdown: Map<string, number>;\n\t/** Per-app mutation counts and deferred counts per frame (multi-app mode). */\n\tperApp?: Map<string, { mutations: number; deferred: number }>;\n}\n\nconst MAX_FRAME_LOG = 30;\n\n/** Internal wrapper that tags each mutation with scheduling metadata. */\ninterface PrioritizedMutation {\n\tmutation: DomMutation;\n\tpriority: Priority;\n\t/** Monotonic insertion order, used as a tiebreaker in priority sorting. */\n\tuid: number;\n\tappId: AppId;\n\t/** UID of the MutationMessage batch this mutation came from. */\n\tbatchUid?: number;\n}\n\n/** Callback that applies a single mutation to the real DOM (typically DomRenderer.apply). */\nexport type MutationApplier = (mutation: DomMutation, appId: AppId, batchUid?: number) => void;\n\n/**\n * Frame-budget scheduler that processes DOM mutations within requestAnimationFrame\n * callbacks, respecting a configurable time budget per frame.\n *\n * Key features preserved from the original vm.js:\n * - Adaptive batch sizing based on measured action execution times\n * - Priority sorting (high > normal > low, non-optional before optional)\n * - Viewport culling for optional style mutations\n * - Graceful degradation: skip optional mutations under pressure\n */\nexport class FrameScheduler {\n\t/** Priority-sorted queue of pending mutations awaiting application. */\n\tprivate queue: PrioritizedMutation[] = [];\n\t/** Most recent execution time per action type, used for adaptive batch sizing. */\n\tprivate actionTimes = new Map<string, number>();\n\tprivate frameId = 0;\n\tprivate running = false;\n\tprivate rafId = 0;\n\tprivate uidCounter = 0;\n\n\tprivate timePerLastFrame = 0;\n\tprivate totalActionsLastFrame = 0;\n\t/** True while the user is scrolling; triggers skipping of optional mutations. */\n\tprivate isScrolling = false;\n\tprivate scrollTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate scrollAbort: AbortController | null = null;\n\n\tprivate viewportHeight = 0;\n\tprivate viewportWidth = 0;\n\t/** Cache of element-id -> in-viewport results to avoid repeated getBoundingClientRect. */\n\tprivate boundingRectCache = new Map<string, boolean>();\n\t/** Frame number when each viewport cache entry was last computed. */\n\tprivate boundingRectCacheFrame = new Map<string, number>();\n\n\tprivate readonly frameBudgetMs: number;\n\tprivate readonly enableViewportCulling: boolean;\n\tprivate readonly enablePrioritySkipping: boolean;\n\n\tprivate applier: MutationApplier | null = null;\n\n\t/** Number of active apps; enables per-app fairness budget splitting when > 1. */\n\tprivate appCount = 0;\n\t/** Per-app mutation count within the current frame, reset each tick. */\n\tprivate appBudgets = new Map<AppId, number>();\n\n\tprivate lastTickTime = 0;\n\tprivate healthCheckTimer: ReturnType<typeof setTimeout> | null = null;\n\tprivate queueOverflowWarned = false;\n\n\tprivate lastEnqueueTime = 0;\n\n\t/** Count of frames where processing time exceeded the frame budget. */\n\tprivate droppedFrameCount = 0;\n\n\tprivate lastWorkerToMainLatencyMs = 0;\n\n\t/** Rolling log of the last MAX_FRAME_LOG frames for devtools inspection. */\n\tprivate frameLog: FrameLogEntry[] = [];\n\n\tconstructor(config: SchedulerConfig = {}) {\n\t\tthis.frameBudgetMs = config.frameBudgetMs ?? DEFAULT_FRAME_BUDGET_MS;\n\t\tthis.enableViewportCulling = config.enableViewportCulling ?? true;\n\t\tthis.enablePrioritySkipping = config.enablePrioritySkipping ?? true;\n\t}\n\n\t/** Set the function that applies each mutation to the real DOM. */\n\tsetApplier(applier: MutationApplier): void {\n\t\tthis.applier = applier;\n\t}\n\n\t/** Update the number of active apps for per-app fairness budgeting. */\n\tsetAppCount(count: number): void {\n\t\tthis.appCount = count;\n\t}\n\n\t/**\n\t * Add mutations to the scheduling queue.\n\t * Mutations are not applied immediately; they wait for the next frame tick.\n\t * Emits a warning if the queue exceeds 10,000 items (indicates a processing bottleneck).\n\t *\n\t * @param mutations - Array of DOM mutations to schedule\n\t * @param appId - Owning app, used for per-app fairness\n\t * @param priority - Scheduling priority (default: \"normal\")\n\t * @param batchUid - Optional batch identifier for grouping\n\t */\n\tenqueue(\n\t\tmutations: DomMutation[],\n\t\tappId: AppId,\n\t\tpriority: Priority = \"normal\",\n\t\tbatchUid?: number,\n\t): void {\n\t\tthis.lastEnqueueTime = performance.now();\n\t\tfor (const mutation of mutations) {\n\t\t\tthis.uidCounter++;\n\t\t\tthis.queue.push({ mutation, priority, uid: this.uidCounter, appId, batchUid });\n\t\t}\n\n\t\t// Always warn on queue overflow — this is always a bug\n\t\tif (this.queue.length > 10_000 && !this.queueOverflowWarned) {\n\t\t\tthis.queueOverflowWarned = true;\n\t\t\tconsole.warn(\n\t\t\t\t`[async-dom] Scheduler queue overflow: ${this.queue.length} pending mutations. ` +\n\t\t\t\t\t\"Possible causes: tab hidden, applier not set, or mutations arriving faster than processing.\",\n\t\t\t);\n\t\t}\n\t\tif (this.queue.length <= 10_000) {\n\t\t\tthis.queueOverflowWarned = false;\n\t\t}\n\t}\n\n\t/** Start the rAF loop. Sets up scroll detection and a 1-second health check. */\n\tstart(): void {\n\t\tif (this.running) return;\n\t\tthis.running = true;\n\t\tthis.lastTickTime = 0;\n\t\tthis.setupScrollListener();\n\t\tthis.scheduleFrame();\n\n\t\t// Health check: warn if tick doesn't fire within 1 second\n\t\tthis.healthCheckTimer = setTimeout(() => {\n\t\t\tif (this.running && this.lastTickTime === 0) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t\"[async-dom] Scheduler started but tick() has not fired after 1 second. \" +\n\t\t\t\t\t\t\"This usually means the tab is hidden (rAF does not fire in background tabs). \" +\n\t\t\t\t\t\t`Queue has ${this.queue.length} pending mutations.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}, 1000);\n\n\t\tconsole.debug(\"[async-dom] Scheduler started\");\n\t}\n\n\tprivate scheduleFrame(): void {\n\t\tif (!this.running) return;\n\t\tif (typeof document !== \"undefined\" && document.hidden) {\n\t\t\t// Tab is hidden — rAF won't fire. Use setTimeout fallback.\n\t\t\tsetTimeout(() => this.tick(performance.now()), this.frameBudgetMs);\n\t\t} else {\n\t\t\tthis.rafId = requestAnimationFrame((ts) => this.tick(ts));\n\t\t}\n\t}\n\n\t/** Stop the rAF loop, cancel pending frames, and tear down scroll listeners. */\n\tstop(): void {\n\t\tthis.running = false;\n\t\tif (this.healthCheckTimer) {\n\t\t\tclearTimeout(this.healthCheckTimer);\n\t\t\tthis.healthCheckTimer = null;\n\t\t}\n\t\tif (this.rafId) {\n\t\t\tcancelAnimationFrame(this.rafId);\n\t\t\tthis.rafId = 0;\n\t\t}\n\t\tif (this.scrollAbort) {\n\t\t\tthis.scrollAbort.abort();\n\t\t\tthis.scrollAbort = null;\n\t\t}\n\t\tthis.clearViewportCache();\n\t}\n\n\tclearViewportCache(): void {\n\t\tthis.boundingRectCache.clear();\n\t\tthis.boundingRectCacheFrame.clear();\n\t}\n\n\t/** Synchronously apply all queued mutations, bypassing frame budget. Used for teardown. */\n\tflush(): void {\n\t\tconst applier = this.applier;\n\t\tif (!applier) return;\n\t\tthis.queue.sort(prioritySort);\n\t\tfor (const item of this.queue) {\n\t\t\tapplier(item.mutation, item.appId, item.batchUid);\n\t\t}\n\t\tthis.queue.length = 0;\n\t}\n\n\t/** Number of mutations waiting to be applied. */\n\tget pendingCount(): number {\n\t\treturn this.queue.length;\n\t}\n\n\t/** Record the cross-thread latency from a worker MutationMessage.sentAt */\n\trecordWorkerLatency(sentAt: number): void {\n\t\tthis.lastWorkerToMainLatencyMs = Math.max(0, Date.now() - sentAt);\n\t}\n\n\t/** Return a snapshot of scheduler metrics for devtools and diagnostics. */\n\tgetStats(): {\n\t\tpending: number;\n\t\tframeId: number;\n\t\tlastFrameTimeMs: number;\n\t\tlastFrameActions: number;\n\t\tisRunning: boolean;\n\t\tlastTickTime: number;\n\t\tenqueueToApplyMs: number;\n\t\tdroppedFrameCount: number;\n\t\tworkerToMainLatencyMs: number;\n\t} {\n\t\treturn {\n\t\t\tpending: this.queue.length,\n\t\t\tframeId: this.frameId,\n\t\t\tlastFrameTimeMs: this.timePerLastFrame,\n\t\t\tlastFrameActions: this.totalActionsLastFrame,\n\t\t\tisRunning: this.running,\n\t\t\tlastTickTime: this.lastTickTime,\n\t\t\tenqueueToApplyMs:\n\t\t\t\tthis.lastTickTime > 0 && this.lastEnqueueTime > 0\n\t\t\t\t\t? Math.max(0, this.lastTickTime - this.lastEnqueueTime)\n\t\t\t\t\t: 0,\n\t\t\tdroppedFrameCount: this.droppedFrameCount,\n\t\t\tworkerToMainLatencyMs: this.lastWorkerToMainLatencyMs,\n\t\t};\n\t}\n\n\t/** Return a copy of the rolling frame log (last 30 frames). */\n\tgetFrameLog(): FrameLogEntry[] {\n\t\treturn this.frameLog.slice();\n\t}\n\n\t/**\n\t * Core frame loop. Processes as many queued mutations as the frame budget allows.\n\t *\n\t * Algorithm:\n\t * 1. Sort queue by priority (high > normal > low), then optional last, then FIFO\n\t * 2. Compute maxActions via getActionsForFrame() (adaptive batch sizing)\n\t * 3. Iterate queue, skipping optional mutations under pressure (shouldSkip)\n\t * 4. In multi-app mode, enforce per-app fairness caps (maxActions / appCount)\n\t * 5. Break if elapsed time exceeds frameBudgetMs (unless queue is critically large)\n\t * 6. Re-enqueue deferred items for the next frame\n\t */\n\tprivate tick(_timestamp: number): void {\n\t\tif (!this.running) return;\n\n\t\tthis.lastTickTime = performance.now();\n\t\tconst start = performance.now();\n\t\tthis.frameId++;\n\t\tthis.calcViewportSize();\n\n\t\t// Sort by priority\n\t\tthis.queue.sort(prioritySort);\n\n\t\tconst applier = this.applier;\n\t\tif (!applier) {\n\t\t\tthis.scheduleNext(start);\n\t\t\treturn;\n\t\t}\n\n\t\tlet processed = 0;\n\t\tconst maxActions = this.getActionsForFrame();\n\t\tconst deferred: PrioritizedMutation[] = [];\n\t\tconst frameTimingBreakdown = new Map<string, number>();\n\n\t\t// Feature 18: per-app mutation/deferred counts for this frame\n\t\tconst perAppMutations = new Map<string, number>();\n\t\tconst perAppDeferred = new Map<string, number>();\n\n\t\t// Reset per-app budgets at the start of each frame when multi-app\n\t\tif (this.appCount > 1) {\n\t\t\tthis.appBudgets.clear();\n\t\t}\n\n\t\tlet cursor = 0;\n\t\twhile (cursor < this.queue.length && processed < maxActions) {\n\t\t\tconst elapsed = performance.now() - start;\n\n\t\t\t// Under normal load, respect frame budget\n\t\t\tif (this.queue.length < MAX_QUEUE_BEFORE_FLUSH && elapsed >= this.frameBudgetMs) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst item = this.queue[cursor];\n\t\t\tcursor++;\n\n\t\t\tif (this.shouldSkip(item)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Per-app fairness: soft cap each app's share when multi-app\n\t\t\tif (this.appCount > 1) {\n\t\t\t\tconst appBudget = this.appBudgets.get(item.appId) ?? 0;\n\t\t\t\tconst maxPerApp = Math.ceil(maxActions / this.appCount);\n\t\t\t\tif (appBudget >= maxPerApp) {\n\t\t\t\t\tdeferred.push(item);\n\t\t\t\t\t// Feature 18: track deferred count per app\n\t\t\t\t\tconst appKey = String(item.appId);\n\t\t\t\t\tperAppDeferred.set(appKey, (perAppDeferred.get(appKey) ?? 0) + 1);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis.appBudgets.set(item.appId, appBudget + 1);\n\t\t\t}\n\n\t\t\tconst actionStart = performance.now();\n\t\t\tapplier(item.mutation, item.appId, item.batchUid);\n\t\t\tconst actionTime = performance.now() - actionStart;\n\n\t\t\t// Feature 18: track mutation count per app\n\t\t\t{\n\t\t\t\tconst appKey = String(item.appId);\n\t\t\t\tperAppMutations.set(appKey, (perAppMutations.get(appKey) ?? 0) + 1);\n\t\t\t}\n\t\t\tthis.recordTiming(item.mutation.action, actionTime);\n\t\t\tframeTimingBreakdown.set(\n\t\t\t\titem.mutation.action,\n\t\t\t\t(frameTimingBreakdown.get(item.mutation.action) ?? 0) + actionTime,\n\t\t\t);\n\t\t\tprocessed++;\n\t\t}\n\n\t\t// Remove processed items efficiently\n\t\tif (cursor === this.queue.length) {\n\t\t\tthis.queue.length = 0;\n\t\t} else if (cursor > 0) {\n\t\t\tthis.queue = this.queue.slice(cursor);\n\t\t}\n\n\t\t// Re-enqueue deferred items for next frame\n\t\tif (deferred.length > 0) {\n\t\t\tthis.queue = deferred.concat(this.queue);\n\t\t}\n\n\t\tconst delta = performance.now() - start;\n\t\tif (processed > 0) {\n\t\t\tif (delta > this.frameBudgetMs) {\n\t\t\t\tthis.droppedFrameCount++;\n\t\t\t}\n\t\t\tthis.timePerLastFrame = delta;\n\t\t\tthis.totalActionsLastFrame = processed;\n\n\t\t\t// Feature 18: build per-app breakdown\n\t\t\tlet perApp: Map<string, { mutations: number; deferred: number }> | undefined;\n\t\t\tif (perAppMutations.size > 0 || perAppDeferred.size > 0) {\n\t\t\t\tperApp = new Map();\n\t\t\t\tconst allApps = new Set([...perAppMutations.keys(), ...perAppDeferred.keys()]);\n\t\t\t\tfor (const appKey of allApps) {\n\t\t\t\t\tperApp.set(appKey, {\n\t\t\t\t\t\tmutations: perAppMutations.get(appKey) ?? 0,\n\t\t\t\t\t\tdeferred: perAppDeferred.get(appKey) ?? 0,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.frameLog.push({\n\t\t\t\tframeId: this.frameId,\n\t\t\t\ttotalMs: delta,\n\t\t\t\tactionCount: processed,\n\t\t\t\ttimingBreakdown: frameTimingBreakdown,\n\t\t\t\tperApp,\n\t\t\t});\n\t\t\tif (this.frameLog.length > MAX_FRAME_LOG) {\n\t\t\t\tthis.frameLog.shift();\n\t\t\t}\n\t\t}\n\n\t\tthis.scheduleNext(start);\n\t}\n\n\t/** Schedule the next tick, delaying if the frame finished early to avoid busy-spinning. */\n\tprivate scheduleNext(frameStart: number): void {\n\t\tconst elapsed = performance.now() - frameStart;\n\t\tif (elapsed + 1 >= this.frameBudgetMs) {\n\t\t\tthis.scheduleFrame();\n\t\t} else {\n\t\t\t// Frame finished early — delay next tick to avoid burning CPU\n\t\t\tsetTimeout(() => {\n\t\t\t\tthis.scheduleFrame();\n\t\t\t}, this.frameBudgetMs - elapsed);\n\t\t}\n\t}\n\n\t/**\n\t * Determine how many mutations to attempt this frame using adaptive batch sizing.\n\t *\n\t * Strategy (escalating by queue pressure):\n\t * - Queue > 25k: emergency flush — process everything in one frame\n\t * - Queue >= MAX_QUEUE_BEFORE_FLUSH (3000): process FLUSH_BATCH_SIZE (500)\n\t * - Queue > CRITICAL_QUEUE_SIZE (1500): process up to CRITICAL_QUEUE_SIZE\n\t * - Otherwise: use the measured average action time to estimate how many\n\t * actions fit in 3x the frame budget (the 3x multiplier allows the time-\n\t * based break in tick() to be the real limiter, while ensuring enough\n\t * work is attempted). Falls back to 2000 when no timing data exists yet.\n\t */\n\tprivate getActionsForFrame(): number {\n\t\tconst queueLen = this.queue.length;\n\n\t\tif (queueLen > 25000) {\n\t\t\treturn queueLen;\n\t\t}\n\t\tif (queueLen >= MAX_QUEUE_BEFORE_FLUSH) {\n\t\t\treturn FLUSH_BATCH_SIZE;\n\t\t}\n\t\tif (queueLen > CRITICAL_QUEUE_SIZE) {\n\t\t\treturn CRITICAL_QUEUE_SIZE;\n\t\t}\n\n\t\t// Adaptive: estimate how many actions we can fit in the frame budget\n\t\tconst avgTime = this.getAvgActionTime();\n\t\tif (avgTime > 0) {\n\t\t\treturn Math.max(1, Math.floor((this.frameBudgetMs * 3) / avgTime));\n\t\t}\n\n\t\treturn 2000;\n\t}\n\n\t/**\n\t * Decide whether to skip an optional mutation to preserve frame budget.\n\t * Non-optional mutations are never skipped. Optional mutations are skipped when:\n\t * - User is actively scrolling (visual updates would be wasted)\n\t * - Queue is large (> half of CRITICAL_QUEUE_SIZE), indicating backpressure\n\t * - Previous frame exceeded budget (prevent cascading frame drops)\n\t */\n\tprivate shouldSkip(item: PrioritizedMutation): boolean {\n\t\tif (!this.enablePrioritySkipping) return false;\n\n\t\tconst mutation = item.mutation;\n\t\tconst isOptional = \"optional\" in mutation && mutation.optional;\n\t\tif (!isOptional) return false;\n\n\t\t// Skip optional during scroll or when hidden\n\t\tif (this.isScrolling) return true;\n\n\t\t// Skip optional when queue is large\n\t\tif (this.queue.length > CRITICAL_QUEUE_SIZE / 2) return true;\n\n\t\t// Skip optional if last frame exceeded budget\n\t\tif (this.timePerLastFrame > this.frameBudgetMs + 0.2) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Viewport culling for style mutations\n\t\tif (this.enableViewportCulling && mutation.action === \"setStyle\") {\n\t\t\t// Viewport culling would check if node is visible\n\t\t\t// This is a placeholder — actual check requires DOM access via renderer\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/** Record the execution time for an action type. The 0.02ms bias prevents zero-time entries from skewing averages. */\n\tprivate recordTiming(action: string, ms: number): void {\n\t\tif (ms > 0) {\n\t\t\tthis.actionTimes.set(action, ms + 0.02);\n\t\t}\n\t}\n\n\tprivate getAvgActionTime(): number {\n\t\tif (this.totalActionsLastFrame === 0) return 0;\n\t\treturn this.timePerLastFrame / this.totalActionsLastFrame;\n\t}\n\n\tprivate calcViewportSize(): void {\n\t\tthis.viewportHeight = window.innerHeight || document.documentElement.clientHeight;\n\t\tthis.viewportWidth = window.innerWidth || document.documentElement.clientWidth;\n\t}\n\n\t/**\n\t * Check if an element is within the viewport, using a per-frame cache to\n\t * avoid repeated getBoundingClientRect calls. Cache entries expire after\n\t * VIEWPORT_CACHE_FRAMES (60) frames.\n\t */\n\tisInViewport(elem: Element): boolean {\n\t\tconst id = elem.id;\n\t\tif (!id) return true;\n\n\t\tconst cachedFrame = this.boundingRectCacheFrame.get(id);\n\t\tif (cachedFrame !== undefined && cachedFrame + VIEWPORT_CACHE_FRAMES > this.frameId) {\n\t\t\treturn this.boundingRectCache.get(id) ?? true;\n\t\t}\n\n\t\tconst rect = elem.getBoundingClientRect();\n\t\tconst result =\n\t\t\trect.top >= 0 &&\n\t\t\trect.left >= 0 &&\n\t\t\trect.bottom <= this.viewportHeight &&\n\t\t\trect.right <= this.viewportWidth;\n\n\t\tthis.boundingRectCache.set(id, result);\n\t\tthis.boundingRectCacheFrame.set(id, this.frameId);\n\t\treturn result;\n\t}\n\n\tprivate setupScrollListener(): void {\n\t\tif (this.scrollAbort) {\n\t\t\tthis.scrollAbort.abort();\n\t\t}\n\t\tthis.scrollAbort = new AbortController();\n\n\t\twindow.addEventListener(\n\t\t\t\"scroll\",\n\t\t\t() => {\n\t\t\t\tthis.isScrolling = true;\n\t\t\t\tif (this.scrollTimer !== null) {\n\t\t\t\t\tclearTimeout(this.scrollTimer);\n\t\t\t\t}\n\t\t\t\tthis.scrollTimer = setTimeout(() => {\n\t\t\t\t\tthis.isScrolling = false;\n\t\t\t\t}, 66);\n\t\t\t},\n\t\t\t{ passive: true, signal: this.scrollAbort.signal },\n\t\t);\n\t}\n}\n\n/**\n * Sort comparator: high priority first, then non-optional before optional,\n * then by insertion order (uid) for FIFO stability within the same level.\n */\nfunction prioritySort(a: PrioritizedMutation, b: PrioritizedMutation): number {\n\tconst priorityOrder: Record<Priority, number> = { high: 0, normal: 1, low: 2 };\n\tconst pa = priorityOrder[a.priority];\n\tconst pb = priorityOrder[b.priority];\n\tif (pa !== pb) return pa - pb;\n\n\t// Non-optional before optional\n\tconst aOpt = \"optional\" in a.mutation && a.mutation.optional ? 1 : 0;\n\tconst bOpt = \"optional\" in b.mutation && b.mutation.optional ? 1 : 0;\n\tif (aOpt !== bOpt) return aOpt - bOpt;\n\n\treturn a.uid - b.uid;\n}\n","/**\n * Causality Graph — Feature 15\n *\n * Builds a DAG: Event -> MutationBatch -> Affected Nodes\n * from logged mutations and events. Each mutation batch is\n * tagged with its causal event (click, input, timer, etc.).\n */\n\nexport interface CausalEvent {\n\teventType: string;\n\tlistenerId: string;\n\ttimestamp: number;\n}\n\nexport interface CausalBatch {\n\tbatchUid: number;\n\tcausalEvent: CausalEvent | null;\n\tnodeIds: Set<number>;\n\tmutationCount: number;\n\ttimestamp: number;\n}\n\nexport interface CausalityNode {\n\ttype: \"event\" | \"batch\" | \"node\";\n\tid: string;\n\tlabel: string;\n\tchildren: string[];\n}\n\nexport interface CausalityGraph {\n\tnodes: Map<string, CausalityNode>;\n\troots: string[];\n}\n\n/**\n * Build a causality DAG from batch records.\n */\nexport function buildCausalityGraph(batches: CausalBatch[]): CausalityGraph {\n\tconst nodes = new Map<string, CausalityNode>();\n\tconst roots: string[] = [];\n\n\t// Group batches by their causal event\n\tconst eventMap = new Map<string, CausalBatch[]>();\n\tconst orphanBatches: CausalBatch[] = [];\n\n\tfor (const batch of batches) {\n\t\tif (batch.causalEvent) {\n\t\t\tconst eventKey = `event:${batch.causalEvent.eventType}:${batch.causalEvent.listenerId}:${batch.causalEvent.timestamp}`;\n\t\t\tif (!eventMap.has(eventKey)) {\n\t\t\t\teventMap.set(eventKey, []);\n\t\t\t}\n\t\t\teventMap.get(eventKey)?.push(batch);\n\t\t} else {\n\t\t\torphanBatches.push(batch);\n\t\t}\n\t}\n\n\t// Create event nodes\n\tfor (const [eventKey, eventBatches] of eventMap) {\n\t\tconst firstBatch = eventBatches[0];\n\t\tconst evt = firstBatch.causalEvent!;\n\t\tconst eventNode: CausalityNode = {\n\t\t\ttype: \"event\",\n\t\t\tid: eventKey,\n\t\t\tlabel: `${evt.eventType} (${evt.listenerId})`,\n\t\t\tchildren: [],\n\t\t};\n\n\t\tfor (const batch of eventBatches) {\n\t\t\tconst batchKey = `batch:${batch.batchUid}`;\n\t\t\tconst batchNode: CausalityNode = {\n\t\t\t\ttype: \"batch\",\n\t\t\t\tid: batchKey,\n\t\t\t\tlabel: `Batch #${batch.batchUid} (${batch.mutationCount} muts)`,\n\t\t\t\tchildren: [],\n\t\t\t};\n\n\t\t\tfor (const nodeId of batch.nodeIds) {\n\t\t\t\tconst nodeKey = `node:${nodeId}`;\n\t\t\t\tif (!nodes.has(nodeKey)) {\n\t\t\t\t\tnodes.set(nodeKey, {\n\t\t\t\t\t\ttype: \"node\",\n\t\t\t\t\t\tid: nodeKey,\n\t\t\t\t\t\tlabel: `#${nodeId}`,\n\t\t\t\t\t\tchildren: [],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbatchNode.children.push(nodeKey);\n\t\t\t}\n\n\t\t\tnodes.set(batchKey, batchNode);\n\t\t\teventNode.children.push(batchKey);\n\t\t}\n\n\t\tnodes.set(eventKey, eventNode);\n\t\troots.push(eventKey);\n\t}\n\n\t// Orphan batches (no causal event)\n\tfor (const batch of orphanBatches) {\n\t\tconst batchKey = `batch:${batch.batchUid}`;\n\t\tconst batchNode: CausalityNode = {\n\t\t\ttype: \"batch\",\n\t\t\tid: batchKey,\n\t\t\tlabel: `Batch #${batch.batchUid} (${batch.mutationCount} muts, no event)`,\n\t\t\tchildren: [],\n\t\t};\n\n\t\tfor (const nodeId of batch.nodeIds) {\n\t\t\tconst nodeKey = `node:${nodeId}`;\n\t\t\tif (!nodes.has(nodeKey)) {\n\t\t\t\tnodes.set(nodeKey, {\n\t\t\t\t\ttype: \"node\",\n\t\t\t\t\tid: nodeKey,\n\t\t\t\t\tlabel: `#${nodeId}`,\n\t\t\t\t\tchildren: [],\n\t\t\t\t});\n\t\t\t}\n\t\t\tbatchNode.children.push(nodeKey);\n\t\t}\n\n\t\tnodes.set(batchKey, batchNode);\n\t\troots.push(batchKey);\n\t}\n\n\treturn { nodes, roots };\n}\n\n/**\n * Storage for causal batch records, maintained on the main thread.\n */\nexport class CausalityTracker {\n\tprivate batches: CausalBatch[] = [];\n\tprivate maxBatches = 100;\n\n\t/** Record a batch with its causal event */\n\trecordBatch(\n\t\tbatchUid: number,\n\t\tnodeIds: number[],\n\t\tmutationCount: number,\n\t\tcausalEvent: CausalEvent | null,\n\t): void {\n\t\tthis.batches.push({\n\t\t\tbatchUid,\n\t\t\tcausalEvent,\n\t\t\tnodeIds: new Set(nodeIds),\n\t\t\tmutationCount,\n\t\t\ttimestamp: Date.now(),\n\t\t});\n\t\tif (this.batches.length > this.maxBatches) {\n\t\t\tthis.batches.shift();\n\t\t}\n\t}\n\n\t/** Get all recorded batches */\n\tgetBatches(): CausalBatch[] {\n\t\treturn this.batches.slice();\n\t}\n\n\t/** Build the DAG from recorded batches */\n\tbuildGraph(): CausalityGraph {\n\t\treturn buildCausalityGraph(this.batches);\n\t}\n\n\t/** Find batches that affected a given nodeId */\n\tfindBatchesForNode(nodeId: number): CausalBatch[] {\n\t\treturn this.batches.filter((b) => b.nodeIds.has(nodeId));\n\t}\n\n\t/** Clear all records */\n\tclear(): void {\n\t\tthis.batches.length = 0;\n\t}\n}\n","/**\n * Format a byte count into a human-readable string (B, KB, MB).\n */\nexport function formatBytes(bytes: number): string {\n\tif (bytes === 0) return \"0 B\";\n\tif (bytes < 1024) return `${bytes} B`;\n\tif (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n\treturn `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n","import type { MutationLogEntry } from \"../core/debug.ts\";\n\nexport interface ReplayState {\n\tentries: MutationLogEntry[];\n\tcurrentIndex: number;\n\tisPlaying: boolean;\n}\n\nexport function createReplayState(entries: MutationLogEntry[]): ReplayState {\n\treturn { entries: [...entries], currentIndex: 0, isPlaying: false };\n}\n\nexport function replayStep(state: ReplayState): MutationLogEntry | null {\n\tif (state.currentIndex >= state.entries.length) return null;\n\treturn state.entries[state.currentIndex++];\n}\n\nexport function replaySeek(state: ReplayState, index: number): void {\n\tstate.currentIndex = Math.max(0, Math.min(index, state.entries.length));\n}\n\nexport function replayReset(state: ReplayState): void {\n\tstate.currentIndex = 0;\n\tstate.isPlaying = false;\n}\n","import type {\n\tEventLogEntry,\n\tMutationLogEntry,\n\tSyncReadLogEntry,\n\tWarningLogEntry,\n} from \"../core/debug.ts\";\n\nexport interface DebugSession {\n\tversion: 1;\n\texportedAt: string;\n\tmutationLog: MutationLogEntry[];\n\twarningLog: WarningLogEntry[];\n\teventLog: EventLogEntry[];\n\tsyncReadLog: SyncReadLogEntry[];\n\tschedulerStats: Record<string, unknown>;\n\ttree?: unknown;\n\tappData?: Record<string, unknown>;\n}\n\nexport function exportSession(data: {\n\tmutationLog: MutationLogEntry[];\n\twarningLog: WarningLogEntry[];\n\teventLog: EventLogEntry[];\n\tsyncReadLog: SyncReadLogEntry[];\n\tschedulerStats: Record<string, unknown>;\n\ttree?: unknown;\n\tappData?: Record<string, unknown>;\n}): string {\n\tconst session: DebugSession = {\n\t\tversion: 1,\n\t\texportedAt: new Date().toISOString(),\n\t\t...data,\n\t};\n\treturn JSON.stringify(session, replacer, 2);\n}\n\nfunction replacer(_key: string, value: unknown): unknown {\n\tif (value instanceof Map) return Object.fromEntries(value);\n\treturn value;\n}\n\nexport function importSession(json: string): DebugSession {\n\tconst raw = JSON.parse(json);\n\tif (!raw || typeof raw !== \"object\") throw new Error(\"Invalid session: not an object\");\n\tif (raw.version !== 1) throw new Error(`Unsupported session version: ${raw.version}`);\n\tif (!Array.isArray(raw.mutationLog))\n\t\tthrow new Error(\"Invalid session: mutationLog must be an array\");\n\tif (!Array.isArray(raw.warningLog))\n\t\tthrow new Error(\"Invalid session: warningLog must be an array\");\n\tif (!Array.isArray(raw.eventLog)) throw new Error(\"Invalid session: eventLog must be an array\");\n\tif (!Array.isArray(raw.syncReadLog))\n\t\tthrow new Error(\"Invalid session: syncReadLog must be an array\");\n\t// Cap array sizes to prevent OOM\n\tconst MAX_ENTRIES = 10_000;\n\tif (raw.mutationLog.length > MAX_ENTRIES) raw.mutationLog = raw.mutationLog.slice(-MAX_ENTRIES);\n\tif (raw.warningLog.length > MAX_ENTRIES) raw.warningLog = raw.warningLog.slice(-MAX_ENTRIES);\n\tif (raw.eventLog.length > MAX_ENTRIES) raw.eventLog = raw.eventLog.slice(-MAX_ENTRIES);\n\tif (raw.syncReadLog.length > MAX_ENTRIES) raw.syncReadLog = raw.syncReadLog.slice(-MAX_ENTRIES);\n\treturn raw as DebugSession;\n}\n\nexport function downloadJson(content: string, filename: string): void {\n\tconst blob = new Blob([content], { type: \"application/json\" });\n\tconst url = URL.createObjectURL(blob);\n\tconst a = document.createElement(\"a\");\n\ta.href = url;\n\ta.download = filename;\n\ta.click();\n\tURL.revokeObjectURL(url);\n}\n","/**\n * Shared helper functions for devtools statistics computation.\n * Extracted to a separate module for testability.\n */\n\n/** Compute the value at a given percentile from a sorted array. */\nexport function percentile(sorted: number[], p: number): number {\n\tif (sorted.length === 0) return 0;\n\tconst idx = Math.ceil((p / 100) * sorted.length) - 1;\n\treturn sorted[Math.max(0, idx)];\n}\n\n/** Compute P50, P95, P99 from an unsorted data array. */\nexport function computePercentiles(data: number[]): { p50: number; p95: number; p99: number } {\n\tif (data.length === 0) return { p50: 0, p95: 0, p99: 0 };\n\tconst sorted = [...data].sort((a, b) => a - b);\n\treturn {\n\t\tp50: percentile(sorted, 50),\n\t\tp95: percentile(sorted, 95),\n\t\tp99: percentile(sorted, 99),\n\t};\n}\n\n/** Color class for latency values: green/yellow/red. */\nexport function latencyColorClass(ms: number): string {\n\tif (ms > 16) return \"red\";\n\tif (ms > 5) return \"yellow\";\n\treturn \"green\";\n}\n\n/** Color class for sync read latency values: green/yellow/red. */\nexport function syncReadColorClass(ms: number): string {\n\tif (ms > 50) return \"red\";\n\tif (ms > 5) return \"yellow\";\n\treturn \"green\";\n}\n","/**\n * Tree Diff — Feature 17\n *\n * Compares two virtual DOM tree snapshots and produces a diff\n * showing added, removed, and changed nodes.\n */\n\nexport interface TreeSnapshot {\n\ttype: \"element\" | \"text\" | \"comment\";\n\ttag?: string;\n\tid?: number;\n\tclassName?: string;\n\tattributes?: Record<string, string>;\n\ttext?: string;\n\tchildren?: TreeSnapshot[];\n}\n\nexport type DiffType = \"added\" | \"removed\" | \"changed\" | \"unchanged\";\n\nexport interface TreeDiffNode {\n\tdiffType: DiffType;\n\tnode: TreeSnapshot;\n\t/** For 'changed' nodes, which fields changed */\n\tchanges?: string[];\n\tchildren?: TreeDiffNode[];\n}\n\n/**\n * Deep-clone a tree snapshot for immutable storage.\n */\nexport function cloneSnapshot(node: TreeSnapshot): TreeSnapshot {\n\tconst clone: TreeSnapshot = { type: node.type };\n\tif (node.tag !== undefined) clone.tag = node.tag;\n\tif (node.id !== undefined) clone.id = node.id;\n\tif (node.className !== undefined) clone.className = node.className;\n\tif (node.text !== undefined) clone.text = node.text;\n\tif (node.attributes) {\n\t\tclone.attributes = { ...node.attributes };\n\t}\n\tif (node.children) {\n\t\tclone.children = node.children.map(cloneSnapshot);\n\t}\n\treturn clone;\n}\n\n/**\n * Compare two tree snapshots and produce a diff tree.\n */\nexport function diffTrees(\n\toldTree: TreeSnapshot | null,\n\tnewTree: TreeSnapshot | null,\n): TreeDiffNode | null {\n\tif (!oldTree && !newTree) return null;\n\n\tif (!oldTree && newTree) {\n\t\treturn markAdded(newTree);\n\t}\n\n\tif (oldTree && !newTree) {\n\t\treturn markRemoved(oldTree);\n\t}\n\n\t// Both exist — compare\n\treturn compareNodes(oldTree!, newTree!);\n}\n\nfunction markAdded(node: TreeSnapshot): TreeDiffNode {\n\tconst result: TreeDiffNode = {\n\t\tdiffType: \"added\",\n\t\tnode,\n\t};\n\tif (node.children) {\n\t\tresult.children = node.children.map(markAdded);\n\t}\n\treturn result;\n}\n\nfunction markRemoved(node: TreeSnapshot): TreeDiffNode {\n\tconst result: TreeDiffNode = {\n\t\tdiffType: \"removed\",\n\t\tnode,\n\t};\n\tif (node.children) {\n\t\tresult.children = node.children.map(markRemoved);\n\t}\n\treturn result;\n}\n\nfunction compareNodes(oldNode: TreeSnapshot, newNode: TreeSnapshot): TreeDiffNode {\n\tconst changes: string[] = [];\n\n\t// Check type/tag mismatch — treat as remove + add\n\tif (oldNode.type !== newNode.type || oldNode.tag !== newNode.tag) {\n\t\t// Different node type — this subtree was replaced\n\t\treturn {\n\t\t\tdiffType: \"changed\",\n\t\t\tnode: newNode,\n\t\t\tchanges: [\"replaced\"],\n\t\t\tchildren: [markRemoved(oldNode), markAdded(newNode)],\n\t\t};\n\t}\n\n\t// Compare attributes\n\tif (oldNode.type === \"element\" && newNode.type === \"element\") {\n\t\tconst oldAttrs = oldNode.attributes ?? {};\n\t\tconst newAttrs = newNode.attributes ?? {};\n\t\tconst allKeys = new Set([...Object.keys(oldAttrs), ...Object.keys(newAttrs)]);\n\t\tfor (const key of allKeys) {\n\t\t\tif (oldAttrs[key] !== newAttrs[key]) {\n\t\t\t\tchanges.push(`attr:${key}`);\n\t\t\t}\n\t\t}\n\t\tif (oldNode.className !== newNode.className) {\n\t\t\tchanges.push(\"className\");\n\t\t}\n\t}\n\n\t// Compare text\n\tif (oldNode.text !== newNode.text) {\n\t\tchanges.push(\"text\");\n\t}\n\n\t// Compare children\n\tconst oldChildren = oldNode.children ?? [];\n\tconst newChildren = newNode.children ?? [];\n\tconst diffChildren = diffChildArrays(oldChildren, newChildren);\n\n\tconst diffType = changes.length > 0 ? \"changed\" : \"unchanged\";\n\n\tconst result: TreeDiffNode = {\n\t\tdiffType,\n\t\tnode: newNode,\n\t};\n\tif (changes.length > 0) {\n\t\tresult.changes = changes;\n\t}\n\tif (diffChildren.length > 0) {\n\t\tresult.children = diffChildren;\n\t}\n\treturn result;\n}\n\n/**\n * Diff two child arrays using node IDs for matching where possible.\n */\nfunction diffChildArrays(oldChildren: TreeSnapshot[], newChildren: TreeSnapshot[]): TreeDiffNode[] {\n\tconst result: TreeDiffNode[] = [];\n\n\t// Build index of old children by id for matching\n\tconst oldById = new Map<number, { node: TreeSnapshot; used: boolean }>();\n\tconst oldNoId: TreeSnapshot[] = [];\n\tfor (const child of oldChildren) {\n\t\tif (child.id != null) {\n\t\t\toldById.set(child.id, { node: child, used: false });\n\t\t} else {\n\t\t\toldNoId.push(child);\n\t\t}\n\t}\n\n\tlet noIdCursor = 0;\n\n\tfor (const newChild of newChildren) {\n\t\tif (newChild.id != null) {\n\t\t\tconst oldEntry = oldById.get(newChild.id);\n\t\t\tif (oldEntry) {\n\t\t\t\toldEntry.used = true;\n\t\t\t\tresult.push(compareNodes(oldEntry.node, newChild));\n\t\t\t} else {\n\t\t\t\tresult.push(markAdded(newChild));\n\t\t\t}\n\t\t} else {\n\t\t\t// Try to match positionally with non-id old children\n\t\t\tif (noIdCursor < oldNoId.length) {\n\t\t\t\tresult.push(compareNodes(oldNoId[noIdCursor], newChild));\n\t\t\t\tnoIdCursor++;\n\t\t\t} else {\n\t\t\t\tresult.push(markAdded(newChild));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Old children with IDs that weren't matched\n\tfor (const [, entry] of oldById) {\n\t\tif (!entry.used) {\n\t\t\tresult.push(markRemoved(entry.node));\n\t\t}\n\t}\n\n\t// Remaining old non-id children\n\tfor (let i = noIdCursor; i < oldNoId.length; i++) {\n\t\tresult.push(markRemoved(oldNoId[i]));\n\t}\n\n\treturn result;\n}\n\n/**\n * Check if a diff tree has any actual changes.\n */\nexport function hasChanges(diff: TreeDiffNode): boolean {\n\tif (diff.diffType !== \"unchanged\") return true;\n\tif (diff.children) {\n\t\treturn diff.children.some(hasChanges);\n\t}\n\treturn false;\n}\n","import type {\n\tEventLogEntry,\n\tMutationEventCorrelation,\n\tMutationLogEntry,\n\tSyncReadLogEntry,\n\tWarningLogEntry,\n} from \"../core/debug.ts\";\nimport { WarningDescriptions } from \"../core/debug.ts\";\nimport type { PerfEntryData } from \"../core/protocol.ts\";\nimport type { CausalityGraph, CausalityTracker } from \"./causality-graph.ts\";\nimport { formatBytes } from \"./format-helpers.ts\";\nimport {\n\tcreateReplayState,\n\ttype ReplayState,\n\treplayReset,\n\treplaySeek,\n\treplayStep,\n} from \"./replay.ts\";\nimport { type DebugSession, downloadJson, exportSession, importSession } from \"./session-export.ts\";\nimport { computePercentiles, latencyColorClass, syncReadColorClass } from \"./stats-helpers.ts\";\nimport {\n\tcloneSnapshot,\n\tdiffTrees,\n\thasChanges,\n\ttype TreeDiffNode,\n\ttype TreeSnapshot,\n} from \"./tree-diff.ts\";\n\n/**\n * The shape of __ASYNC_DOM_DEVTOOLS__ exposed on globalThis (main thread).\n */\ninterface FrameLogEntry {\n\tframeId: number;\n\ttotalMs: number;\n\tactionCount: number;\n\ttimingBreakdown: Map<string, number>;\n\t/** Feature 18: per-app mutation counts and deferred counts per frame */\n\tperApp?: Map<string, { mutations: number; deferred: number }>;\n}\n\ninterface EventTraceEntry {\n\teventType: string;\n\tserializeMs: number;\n\ttimestamp: number;\n\ttransportMs?: number;\n\tdispatchMs?: number;\n\tmutationCount?: number;\n}\n\ninterface DevtoolsAPI {\n\tscheduler: {\n\t\tpending: () => number;\n\t\tstats: () => {\n\t\t\tpending: number;\n\t\t\tframeId: number;\n\t\t\tlastFrameTimeMs: number;\n\t\t\tlastFrameActions: number;\n\t\t\tisRunning: boolean;\n\t\t\tlastTickTime: number;\n\t\t\tenqueueToApplyMs: number;\n\t\t\tdroppedFrameCount: number;\n\t\t\tworkerToMainLatencyMs: number;\n\t\t};\n\t\tframeLog: () => FrameLogEntry[];\n\t\tflush: () => void;\n\t\tstop: () => void;\n\t\tstart: () => void;\n\t};\n\tdebugStats: () => Record<string, number>;\n\tgetEventTraces: () => EventTraceEntry[];\n\tgetListenersForNode: (nodeId: number) => Array<{ listenerId: string; eventName: string }>;\n\tenableHighlightUpdates: (enabled: boolean) => void;\n\tfindRealNode: (nodeId: number) => Node | null;\n\tapps: () => string[];\n\trenderers: () => Record<string, { root: unknown }>;\n\trefreshDebugData: () => void;\n\tgetAppData: (appId: string) => AppDebugData | undefined;\n\tgetAllAppsData: () => Record<string, AppDebugData>;\n\tgetTransportStats: () => Record<\n\t\tstring,\n\t\t{\n\t\t\tmessageCount: number;\n\t\t\ttotalBytes: number;\n\t\t\tlargestMessageBytes: number;\n\t\t\tlastMessageBytes: number;\n\t\t} | null\n\t>;\n\treplayMutation: (mutation: import(\"../core/protocol.ts\").DomMutation, appId: string) => void;\n\tclearAndReapply: (\n\t\tmutations: Array<{ mutation: import(\"../core/protocol.ts\").DomMutation; batchUid?: number }>,\n\t\tupToIndex: number,\n\t\tappId?: string,\n\t) => void;\n\t/** Feature 15: Causality graph tracker */\n\tgetCausalityTracker: () => CausalityTracker;\n\t/** Feature 16: Worker CPU profiler entries */\n\tgetWorkerPerfEntries: () => Record<string, PerfEntryData[]>;\n\t/** Feature 19: Mutation-to-event correlation */\n\tgetMutationCorrelation: () => MutationEventCorrelation;\n}\n\ninterface AppDebugData {\n\ttree: unknown;\n\tworkerStats: unknown;\n\tperTypeCoalesced: unknown;\n\tcoalescedLog: unknown;\n}\n\ninterface TreeNode {\n\ttype: \"element\" | \"text\" | \"comment\";\n\ttag?: string;\n\tid?: number;\n\tclassName?: string;\n\tattributes?: Record<string, string>;\n\ttext?: string;\n\tchildren?: TreeNode[];\n}\n\nconst MAX_LOG_ENTRIES = 200;\nconst MAX_WARNING_ENTRIES = 200;\nconst MAX_EVENT_LOG_ENTRIES = 200;\nconst MAX_SYNC_READ_LOG_ENTRIES = 200;\n\n// ---- Mutation / Warning / Event / SyncRead capture ----\n\nconst mutationLog: MutationLogEntry[] = [];\nconst warningLog: WarningLogEntry[] = [];\nconst eventLog: EventLogEntry[] = [];\nconst syncReadLog: SyncReadLogEntry[] = [];\nlet warningBadgeCount = 0;\nlet onWarningBadgeUpdate: (() => void) | null = null;\nlet logPaused = false;\nlet isReplaying = false;\n\nexport function captureMutation(entry: MutationLogEntry): void {\n\tif (logPaused || isReplaying) return;\n\tmutationLog.push(entry);\n\tif (mutationLog.length > MAX_LOG_ENTRIES) mutationLog.shift();\n}\n\nexport function captureEvent(entry: EventLogEntry): void {\n\tif (logPaused) return;\n\teventLog.push(entry);\n\tif (eventLog.length > MAX_EVENT_LOG_ENTRIES) eventLog.shift();\n}\n\nexport function captureSyncRead(entry: SyncReadLogEntry): void {\n\tif (logPaused) return;\n\tsyncReadLog.push(entry);\n\tif (syncReadLog.length > MAX_SYNC_READ_LOG_ENTRIES) syncReadLog.shift();\n}\n\nexport function captureWarning(entry: WarningLogEntry): void {\n\tif (logPaused) {\n\t\twarningBadgeCount++;\n\t\tonWarningBadgeUpdate?.();\n\t\treturn;\n\t}\n\twarningLog.push(entry);\n\tif (warningLog.length > MAX_WARNING_ENTRIES) warningLog.shift();\n\twarningBadgeCount++;\n\tonWarningBadgeUpdate?.();\n}\n\n/**\n * Reset module-level capture state. Used by destroy() and tests.\n */\nexport function resetDevtoolsState(): void {\n\tmutationLog.length = 0;\n\twarningLog.length = 0;\n\teventLog.length = 0;\n\tsyncReadLog.length = 0;\n\twarningBadgeCount = 0;\n\tlogPaused = false;\n\tisReplaying = false;\n}\n\n/**\n * Set the logPaused flag. Exposed for testing.\n */\nexport function setLogPaused(value: boolean): void {\n\tlogPaused = value;\n}\n\n/**\n * Set the isReplaying flag. Exposed for testing.\n */\nexport function setIsReplaying(value: boolean): void {\n\tisReplaying = value;\n}\n\n/**\n * Get current values of module-level flags. Exposed for testing.\n */\nexport function getDevtoolsFlags(): { logPaused: boolean; isReplaying: boolean } {\n\treturn { logPaused, isReplaying };\n}\n\n// ---- CSS ----\n\nconst PANEL_CSS = `\n:host {\n all: initial;\n font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Consolas', monospace;\n font-size: 12px;\n color: #d4d4d4;\n line-height: 1.4;\n}\n\n*, *::before, *::after {\n box-sizing: border-box;\n}\n\n.panel {\n position: fixed;\n bottom: 8px;\n right: 8px;\n z-index: 2147483647;\n background: #1e1e1e;\n border: 1px solid #3c3c3c;\n border-radius: 6px;\n box-shadow: 0 4px 24px rgba(0,0,0,0.5);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n width: 450px;\n height: 400px;\n resize: both;\n min-width: 300px;\n min-height: 200px;\n transition: width 0.15s, height 0.15s;\n}\n\n.panel.collapsed {\n width: auto !important;\n height: auto !important;\n min-width: 0;\n min-height: 0;\n resize: none;\n border-radius: 4px;\n}\n\n.toggle-tab {\n display: none;\n padding: 4px 12px;\n cursor: pointer;\n background: #2d2d2d;\n color: #d4d4d4;\n border: none;\n font-family: inherit;\n font-size: 11px;\n white-space: nowrap;\n user-select: none;\n}\n\n.panel.collapsed .toggle-tab {\n display: block;\n}\n\n.panel.collapsed .app-bar,\n.panel.collapsed .tab-bar,\n.panel.collapsed .tab-content,\n.panel.collapsed .header-bar {\n display: none;\n}\n\n.header-bar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0 8px;\n height: 28px;\n background: #2d2d2d;\n border-bottom: 1px solid #3c3c3c;\n flex-shrink: 0;\n}\n\n.header-title {\n font-size: 11px;\n font-weight: 600;\n color: #cccccc;\n}\n\n.header-actions {\n display: flex;\n gap: 4px;\n align-items: center;\n}\n\n.header-btn {\n background: none;\n border: none;\n color: #808080;\n cursor: pointer;\n font-size: 12px;\n padding: 0 4px;\n font-family: inherit;\n}\n.header-btn:hover { color: #d4d4d4; }\n\n/* ---- App bar (multi-app) ---- */\n\n.app-bar {\n display: none;\n background: #252526;\n border-bottom: 1px solid #3c3c3c;\n flex-shrink: 0;\n padding: 0 4px;\n gap: 2px;\n align-items: center;\n height: 24px;\n overflow-x: auto;\n}\n.app-bar.visible { display: flex; }\n\n.app-btn {\n padding: 2px 8px;\n background: none;\n border: 1px solid transparent;\n border-radius: 3px;\n color: #808080;\n cursor: pointer;\n font-family: inherit;\n font-size: 10px;\n white-space: nowrap;\n}\n.app-btn:hover { color: #cccccc; }\n.app-btn.active {\n color: #d4d4d4;\n background: #37373d;\n border-color: #007acc;\n}\n\n.app-label {\n color: #555;\n font-size: 10px;\n margin-right: 4px;\n flex-shrink: 0;\n}\n\n/* ---- Tab bar ---- */\n\n.tab-bar {\n display: flex;\n background: #252526;\n border-bottom: 1px solid #3c3c3c;\n flex-shrink: 0;\n}\n\n.tab-btn {\n padding: 4px 12px;\n background: none;\n border: none;\n border-bottom: 2px solid transparent;\n color: #808080;\n cursor: pointer;\n font-family: inherit;\n font-size: 11px;\n white-space: nowrap;\n}\n.tab-btn:hover { color: #cccccc; }\n.tab-btn.active {\n color: #d4d4d4;\n border-bottom-color: #007acc;\n}\n\n.tab-badge {\n display: inline-block;\n background: #f44747;\n color: #fff;\n font-size: 9px;\n padding: 0 4px;\n border-radius: 8px;\n margin-left: 4px;\n min-width: 14px;\n text-align: center;\n vertical-align: middle;\n}\n\n.tab-content {\n flex: 1;\n overflow: auto;\n padding: 6px 8px;\n display: none;\n}\n.tab-content.active { display: block; }\n\n/* ---- Tree tab ---- */\n\n.tree-refresh-bar {\n display: flex;\n align-items: center;\n gap: 6px;\n padding-bottom: 4px;\n border-bottom: 1px solid #2d2d2d;\n margin-bottom: 4px;\n}\n\n.tree-refresh-btn {\n background: #3c3c3c;\n border: 1px solid #555;\n color: #d4d4d4;\n padding: 2px 8px;\n cursor: pointer;\n font-family: inherit;\n font-size: 11px;\n border-radius: 3px;\n}\n.tree-refresh-btn:hover { background: #505050; }\n\n.tree-status {\n color: #555;\n font-size: 10px;\n}\n\n.tree-node { padding-left: 14px; }\n.tree-line {\n display: flex;\n align-items: baseline;\n gap: 3px;\n padding: 1px 0;\n cursor: pointer;\n white-space: nowrap;\n}\n.tree-line:hover { background: #2a2d2e; }\n\n.tree-toggle {\n width: 12px;\n text-align: center;\n color: #808080;\n flex-shrink: 0;\n font-size: 9px;\n}\n\n.tree-tag { color: #569cd6; }\n.tree-attr-name { color: #9cdcfe; }\n.tree-attr-value { color: #ce9178; }\n.tree-text-node { color: #6a9955; font-style: italic; }\n.tree-comment { color: #6a9955; font-style: italic; }\n.tree-nodeid { color: #555; font-size: 10px; margin-left: 4px; }\n\n.tree-children { display: none; }\n.tree-node.expanded > .tree-children { display: block; }\n\n.tree-empty { color: #808080; padding: 16px; text-align: center; }\n\n/* ---- Performance tab ---- */\n\n.perf-section-title {\n color: #007acc;\n font-size: 11px;\n font-weight: 600;\n padding: 6px 0 3px;\n border-bottom: 1px solid #2d2d2d;\n margin-bottom: 2px;\n}\n.perf-section-title:first-child { padding-top: 0; }\n\n.perf-row {\n display: flex;\n justify-content: space-between;\n padding: 3px 0;\n border-bottom: 1px solid #2d2d2d;\n}\n.perf-label { color: #808080; }\n.perf-value { color: #d4d4d4; font-weight: 600; }\n.perf-value.red { color: #f44747; }\n.perf-value.yellow { color: #d7ba7d; }\n.perf-value.green { color: #4ec9b0; }\n\n.perf-sparkline {\n color: #555;\n font-size: 10px;\n letter-spacing: 1px;\n}\n\n/* ---- Log tab ---- */\n\n.log-toolbar {\n display: flex;\n gap: 6px;\n align-items: center;\n padding-bottom: 4px;\n border-bottom: 1px solid #2d2d2d;\n margin-bottom: 4px;\n}\n\n.log-filter {\n flex: 1;\n background: #3c3c3c;\n border: 1px solid #555;\n color: #d4d4d4;\n padding: 2px 6px;\n font-family: inherit;\n font-size: 11px;\n border-radius: 3px;\n outline: none;\n}\n.log-filter:focus { border-color: #007acc; }\n\n.log-btn {\n background: #3c3c3c;\n border: 1px solid #555;\n color: #d4d4d4;\n padding: 2px 8px;\n cursor: pointer;\n font-family: inherit;\n font-size: 11px;\n border-radius: 3px;\n white-space: nowrap;\n}\n.log-btn:hover { background: #505050; }\n.log-btn.active { background: #007acc; border-color: #007acc; }\n\n.log-count {\n color: #555;\n font-size: 10px;\n flex-shrink: 0;\n}\n\n.log-list {\n overflow-y: auto;\n max-height: calc(100% - 32px);\n}\n\n.log-entry {\n display: flex;\n gap: 6px;\n padding: 2px 0;\n border-bottom: 1px solid #2a2a2a;\n font-size: 11px;\n}\n.log-time { color: #555; flex-shrink: 0; width: 80px; }\n.log-action { color: #569cd6; flex-shrink: 0; width: 120px; overflow: hidden; text-overflow: ellipsis; }\n.log-detail { color: #808080; overflow: hidden; text-overflow: ellipsis; }\n\n.log-empty { color: #808080; padding: 16px; text-align: center; }\n\n/* ---- Warnings tab ---- */\n\n.warn-entry {\n padding: 4px 0;\n border-bottom: 1px solid #2a2a2a;\n font-size: 11px;\n}\n.warn-time { color: #555; margin-right: 6px; }\n.warn-code {\n font-weight: 600;\n margin-right: 6px;\n}\n.warn-code.ASYNC_DOM_MISSING_NODE { color: #f44747; }\n.warn-code.ASYNC_DOM_SYNC_TIMEOUT { color: #f44747; }\n.warn-code.ASYNC_DOM_LISTENER_NOT_FOUND { color: #d7ba7d; }\n.warn-code.ASYNC_DOM_EVENT_ATTACH_FAILED { color: #d7ba7d; }\n.warn-code.ASYNC_DOM_TRANSPORT_NOT_OPEN { color: #d7ba7d; }\n.warn-code.ASYNC_DOM_BLOCKED_PROPERTY { color: #d7ba7d; }\n\n.warn-msg { color: #d4d4d4; }\n.warn-stack {\n margin: 4px 0 0 0; padding: 8px; background: #1a1a1a; border: 1px solid #333;\n border-radius: 3px; font-size: 11px; color: #ce9178; white-space: pre-wrap;\n word-break: break-all; max-height: 200px; overflow-y: auto; line-height: 1.4;\n}\n.warn-code.WORKER_ERROR, .warn-code.WORKER_UNHANDLED_REJECTION { color: #f44747; }\n.warn-empty { color: #808080; padding: 16px; text-align: center; }\n\n/* Grouped Warnings */\n.warn-group { margin: 4px 0; border: 1px solid #2d2d2d; border-radius: 3px; }\n.warn-group-header { display: flex; align-items: center; gap: 6px; padding: 4px 6px; background: #252526; cursor: pointer; font-size: 11px; user-select: none; }\n.warn-group-header:hover { background: #2a2d2e; }\n.warn-group-toggle { color: #808080; font-size: 9px; width: 12px; text-align: center; flex-shrink: 0; }\n.warn-group-code { font-weight: 600; }\n.warn-group-count { color: #808080; font-size: 10px; }\n.warn-group-entries { display: none; padding: 0 6px 4px 18px; }\n.warn-group.expanded .warn-group-entries { display: block; }\n.warn-group-doc { padding: 4px 6px; background: #1a1a1a; border-bottom: 1px solid #2d2d2d; font-size: 10px; }\n.warn-group-desc { color: #9cdcfe; }\n.warn-group-suggestion { color: #4ec9b0; margin-top: 2px; }\n.warn-suppress-btn { background: #3c3c3c; border: 1px solid #555; color: #808080; padding: 1px 6px; cursor: pointer; font-family: inherit; font-size: 10px; border-radius: 3px; margin-left: auto; }\n.warn-suppress-btn:hover { color: #d4d4d4; background: #505050; }\n.warn-suppressed-note { color: #555; font-size: 10px; padding: 4px; text-align: center; font-style: italic; }\n.warn-view-toggle { font-size: 10px; }\n\n/* ---- Frame flamechart ---- */\n\n.frame-section-title {\n color: #007acc;\n font-size: 11px;\n font-weight: 600;\n padding: 6px 0 3px;\n border-bottom: 1px solid #2d2d2d;\n margin-bottom: 4px;\n}\n\n.frame-bar-row {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 2px 0;\n border-bottom: 1px solid #2a2a2a;\n font-size: 11px;\n cursor: pointer;\n}\n.frame-bar-row:hover { background: #2a2d2e; }\n\n.frame-label {\n color: #808080;\n flex-shrink: 0;\n width: 70px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.frame-bar-track {\n flex: 1;\n height: 14px;\n background: #2d2d2d;\n border-radius: 2px;\n overflow: hidden;\n position: relative;\n}\n\n.frame-bar-fill {\n height: 100%;\n border-radius: 2px;\n transition: width 0.15s;\n}\n.frame-bar-fill.green { background: #4ec9b0; }\n.frame-bar-fill.yellow { background: #d7ba7d; }\n.frame-bar-fill.red { background: #f44747; }\n\n.frame-info {\n color: #808080;\n flex-shrink: 0;\n width: 130px;\n text-align: right;\n font-size: 10px;\n white-space: nowrap;\n}\n\n.frame-detail {\n padding: 4px 8px;\n background: #1a1a1a;\n border: 1px solid #333;\n border-radius: 3px;\n margin: 2px 0 4px 0;\n font-size: 10px;\n color: #d4d4d4;\n}\n\n.frame-detail-row {\n display: flex;\n justify-content: space-between;\n padding: 1px 0;\n}\n.frame-detail-action { color: #569cd6; }\n.frame-detail-time { color: #d4d4d4; }\n\n/* ---- Event tracer ---- */\n\n.event-trace-section {\n margin-top: 8px;\n border-top: 1px solid #2d2d2d;\n padding-top: 4px;\n}\n\n.event-trace-title {\n color: #007acc;\n font-size: 11px;\n font-weight: 600;\n padding: 2px 0 3px;\n}\n\n.event-trace-entry {\n font-size: 11px;\n padding: 2px 0;\n border-bottom: 1px solid #2a2a2a;\n color: #808080;\n}\n.event-trace-type { color: #569cd6; font-weight: 600; }\n.event-trace-time { color: #d7ba7d; }\n\n.event-timeline { display: flex; align-items: center; gap: 2px; height: 16px; margin: 2px 0; cursor: pointer; }\n.event-timeline:hover { background: #2a2d2e; }\n.event-phase { height: 12px; border-radius: 2px; min-width: 4px; position: relative; }\n.event-phase.serialize { background: #569cd6; }\n.event-phase.transport { background: #d7ba7d; }\n.event-phase.dispatch { background: #4ec9b0; }\n.event-phase-label { font-size: 9px; color: #808080; white-space: nowrap; }\n.event-mutation-count { color: #ce9178; font-weight: 600; font-size: 10px; }\n.event-timeline-detail {\n padding: 4px 8px; background: #1a1a1a; border: 1px solid #333;\n border-radius: 3px; margin: 2px 0 4px 0; font-size: 10px; color: #d4d4d4; display: none;\n}\n.event-timeline-detail.visible { display: block; }\n\n.sidebar-listener {\n padding: 2px 0;\n border-bottom: 1px solid #2a2a2a;\n font-size: 10px;\n}\n.sidebar-listener-event { color: #d7ba7d; font-weight: 600; }\n.sidebar-listener-id { color: #555; margin-left: 4px; }\n.sidebar-computed-val { color: #b5cea8; }\n\n/* ---- Node Inspector Sidebar ---- */\n\n.tree-with-sidebar {\n display: flex;\n height: 100%;\n}\n\n.tree-main {\n flex: 1;\n overflow: auto;\n min-width: 0;\n}\n\n.node-sidebar {\n width: 200px;\n flex-shrink: 0;\n border-left: 1px solid #3c3c3c;\n overflow-y: auto;\n padding: 6px;\n background: #1e1e1e;\n font-size: 11px;\n display: none;\n}\n.node-sidebar.visible { display: block; }\n\n.sidebar-title {\n color: #007acc;\n font-size: 11px;\n font-weight: 600;\n padding: 4px 0 2px;\n border-bottom: 1px solid #2d2d2d;\n margin-bottom: 2px;\n}\n.sidebar-title:first-child { padding-top: 0; }\n\n.sidebar-row {\n display: flex;\n justify-content: space-between;\n padding: 1px 0;\n gap: 4px;\n}\n.sidebar-key { color: #9cdcfe; word-break: break-all; }\n.sidebar-val { color: #ce9178; word-break: break-all; text-align: right; max-width: 120px; overflow: hidden; text-overflow: ellipsis; }\n\n.sidebar-empty { color: #555; font-style: italic; padding: 2px 0; }\n\n.sidebar-mutation {\n padding: 2px 0;\n border-bottom: 1px solid #2a2a2a;\n font-size: 10px;\n}\n.sidebar-mut-action { color: #569cd6; }\n.sidebar-mut-time { color: #555; }\n\n.tree-line.selected { background: #094771; }\n\n/* ---- Batch Diff View (Log tab) ---- */\n\n.batch-group {\n margin: 2px 0;\n border: 1px solid #2d2d2d;\n border-radius: 3px;\n}\n\n.batch-header {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 3px 6px;\n background: #252526;\n cursor: pointer;\n font-size: 11px;\n user-select: none;\n}\n.batch-header:hover { background: #2a2d2e; }\n\n.batch-toggle {\n color: #808080;\n font-size: 9px;\n width: 12px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.batch-uid { color: #569cd6; font-weight: 600; }\n.batch-count { color: #808080; }\n\n.batch-entries {\n display: none;\n padding: 0 4px 2px 18px;\n}\n.batch-group.expanded .batch-entries { display: block; }\n\n.log-entry.color-green .log-action { color: #4ec9b0; }\n.log-entry.color-blue .log-action { color: #569cd6; }\n.log-entry.color-red .log-action { color: #f44747; }\n\n/* ---- Mutation Type Chart (Performance tab) ---- */\n\n.chart-bar-row {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 2px 0;\n font-size: 11px;\n}\n\n.chart-bar-label {\n color: #808080;\n flex-shrink: 0;\n width: 120px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chart-bar-track {\n flex: 1;\n height: 12px;\n background: #2d2d2d;\n border-radius: 2px;\n overflow: hidden;\n}\n\n.chart-bar-fill {\n height: 100%;\n border-radius: 2px;\n background: #569cd6;\n transition: width 0.15s;\n}\n\n.chart-bar-value {\n color: #d4d4d4;\n flex-shrink: 0;\n width: 50px;\n text-align: right;\n font-size: 10px;\n}\n\n/* ---- Coalescing Visualizer (Performance tab) ---- */\n\n.coalesce-row {\n display: flex;\n justify-content: space-between;\n padding: 2px 0;\n border-bottom: 1px solid #2a2a2a;\n font-size: 11px;\n}\n.coalesce-action { color: #569cd6; width: 120px; flex-shrink: 0; }\n.coalesce-detail { color: #808080; flex: 1; }\n.coalesce-pct { color: #d7ba7d; flex-shrink: 0; width: 60px; text-align: right; }\n\n/* ---- Flush button ---- */\n\n.flush-btn {\n background: #3c3c3c;\n border: 1px solid #555;\n color: #d4d4d4;\n padding: 1px 6px;\n cursor: pointer;\n font-family: inherit;\n font-size: 10px;\n border-radius: 3px;\n white-space: nowrap;\n margin-left: 6px;\n}\n.flush-btn:hover { background: #505050; }\n\n/* ---- Coalesced log (dimmed/strikethrough) ---- */\n\n.coalesced-entry {\n display: flex;\n gap: 6px;\n padding: 2px 0;\n border-bottom: 1px solid #2a2a2a;\n font-size: 11px;\n opacity: 0.5;\n text-decoration: line-through;\n}\n.coalesced-entry .log-action { color: #808080; }\n\n.coalesced-toggle {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 0;\n font-size: 11px;\n color: #808080;\n}\n.coalesced-toggle input { margin: 0; }\n.coalesced-toggle label { cursor: pointer; }\n\n/* ---- Event / Sync Read log entries ---- */\n\n.log-section-title {\n color: #007acc;\n font-size: 11px;\n font-weight: 600;\n padding: 6px 0 3px;\n border-top: 1px solid #2d2d2d;\n margin-top: 4px;\n}\n\n.log-entry.event-entry .log-action { color: #d7ba7d; }\n.log-entry.syncread-entry .log-action { color: #c586c0; }\n\n/* Sync Read Heatmap */\n.heatmap-container { display: flex; flex-wrap: wrap; gap: 2px; padding: 4px 0; }\n.heatmap-block { width: 14px; height: 14px; border-radius: 2px; cursor: pointer; position: relative; }\n.heatmap-block.green { background: #4ec9b0; }\n.heatmap-block.yellow { background: #d7ba7d; }\n.heatmap-block.red { background: #f44747; }\n.heatmap-tooltip { position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background: #1a1a1a; border: 1px solid #555; padding: 2px 6px; border-radius: 3px; font-size: 10px; white-space: nowrap; z-index: 10; color: #d4d4d4; pointer-events: none; }\n\n/* Latency sparkline color coding */\n.perf-latency-val.green { color: #4ec9b0; }\n.perf-latency-val.yellow { color: #d7ba7d; }\n.perf-latency-val.red { color: #f44747; }\n\n/* Threshold line on sparkline */\n.sparkline-with-threshold { position: relative; display: inline-block; }\n.sparkline-threshold { position: absolute; bottom: 50%; left: 0; right: 0; border-top: 1px dashed #f44747; opacity: 0.5; pointer-events: none; }\n.transport-warn { color: #f44747; font-size: 10px; margin-left: 4px; }\n\n/* ---- Replay bar ---- */\n\n.replay-bar { display: flex; align-items: center; gap: 4px; padding: 4px 0; border-bottom: 1px solid #2d2d2d; margin-bottom: 4px; background: #1a1a1a; }\n.replay-btn { background: #3c3c3c; border: 1px solid #555; color: #d4d4d4; padding: 2px 6px; cursor: pointer; font-family: inherit; font-size: 11px; border-radius: 3px; }\n.replay-btn:hover { background: #505050; }\n.replay-btn.active { background: #007acc; border-color: #007acc; }\n.replay-slider { flex: 1; height: 4px; accent-color: #007acc; }\n.replay-position { color: #808080; font-size: 10px; flex-shrink: 0; min-width: 60px; text-align: center; }\n.replay-exit { color: #f44747; border-color: #f44747; }\n.replay-exit:hover { background: #f44747; color: #fff; }\n.replay-highlight { background: #094771 !important; }\n\n/* ---- Import indicator ---- */\n\n.import-indicator { color: #d7ba7d; font-size: 10px; margin-left: 6px; }\n/* ---- Feature 15: Causality Graph tab ---- */\n\n.graph-container {\n padding: 4px;\n}\n\n.graph-node {\n display: flex;\n align-items: flex-start;\n margin: 2px 0;\n padding: 3px 6px;\n border-left: 2px solid #3c3c3c;\n font-size: 11px;\n}\n.graph-node.event-node { border-left-color: #d7ba7d; }\n.graph-node.batch-node { border-left-color: #569cd6; }\n.graph-node.dom-node { border-left-color: #4ec9b0; }\n\n.graph-node-label {\n color: #d4d4d4;\n cursor: pointer;\n}\n.graph-node-label:hover { text-decoration: underline; }\n\n.graph-node-type {\n font-weight: 600;\n margin-right: 6px;\n font-size: 9px;\n text-transform: uppercase;\n flex-shrink: 0;\n width: 40px;\n}\n.graph-node-type.event { color: #d7ba7d; }\n.graph-node-type.batch { color: #569cd6; }\n.graph-node-type.node { color: #4ec9b0; }\n\n.graph-children {\n padding-left: 16px;\n}\n\n.graph-empty {\n color: #808080;\n padding: 16px;\n text-align: center;\n}\n\n/* ---- Feature 16: Worker CPU Profiler ---- */\n\n.worker-perf-section {\n margin-top: 8px;\n}\n\n.worker-perf-bar {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 1px 0;\n font-size: 10px;\n}\n\n.worker-perf-name {\n color: #808080;\n flex-shrink: 0;\n width: 180px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.worker-perf-duration {\n color: #d4d4d4;\n flex-shrink: 0;\n width: 60px;\n text-align: right;\n}\n\n.worker-perf-track {\n flex: 1;\n height: 10px;\n background: #2d2d2d;\n border-radius: 2px;\n overflow: hidden;\n}\n\n.worker-perf-fill {\n height: 100%;\n border-radius: 2px;\n background: #c586c0;\n}\n\n.worker-util {\n font-size: 11px;\n padding: 2px 0;\n}\n.worker-util-label { color: #808080; }\n.worker-util-value { color: #d4d4d4; font-weight: 600; }\n\n/* ---- Feature 17: Tree Diff ---- */\n\n.snapshot-bar {\n display: flex;\n gap: 6px;\n align-items: center;\n padding-bottom: 4px;\n flex-wrap: wrap;\n}\n\n.snapshot-btn {\n background: #3c3c3c;\n border: 1px solid #555;\n color: #d4d4d4;\n padding: 2px 8px;\n cursor: pointer;\n font-family: inherit;\n font-size: 11px;\n border-radius: 3px;\n}\n.snapshot-btn:hover { background: #505050; }\n.snapshot-btn:disabled { opacity: 0.4; cursor: default; }\n\n.snapshot-info {\n color: #555;\n font-size: 10px;\n}\n\n.diff-marker {\n display: inline-block;\n font-size: 9px;\n padding: 0 3px;\n border-radius: 2px;\n margin-left: 4px;\n font-weight: 600;\n}\n.diff-marker.added { background: #2ea04333; color: #4ec9b0; }\n.diff-marker.removed { background: #f4474733; color: #f44747; }\n.diff-marker.changed { background: #d7ba7d33; color: #d7ba7d; }\n\n.tree-line.diff-added { background: #2ea04315; }\n.tree-line.diff-removed { background: #f4474715; text-decoration: line-through; opacity: 0.7; }\n.tree-line.diff-changed { background: #d7ba7d15; }\n\n/* ---- Feature 18: Multi-App Interleaving ---- */\n\n.multiapp-frame {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 2px 0;\n border-bottom: 1px solid #2a2a2a;\n font-size: 10px;\n}\n\n.multiapp-frame-label {\n color: #808080;\n flex-shrink: 0;\n width: 50px;\n}\n\n.multiapp-stacked-bar {\n flex: 1;\n height: 14px;\n display: flex;\n border-radius: 2px;\n overflow: hidden;\n background: #2d2d2d;\n}\n\n.multiapp-segment {\n height: 100%;\n min-width: 1px;\n}\n\n.multiapp-info {\n color: #808080;\n flex-shrink: 0;\n font-size: 10px;\n white-space: nowrap;\n width: 100px;\n text-align: right;\n}\n\n.multiapp-legend {\n display: flex;\n gap: 8px;\n padding: 2px 0;\n font-size: 10px;\n flex-wrap: wrap;\n}\n\n.multiapp-legend-item {\n display: flex;\n align-items: center;\n gap: 3px;\n}\n\n.multiapp-legend-dot {\n display: inline-block;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n}\n\n/* ---- Feature 19: Why Updated? ---- */\n\n.why-updated-section {\n margin-top: 4px;\n}\n\n.why-updated-title {\n color: #c586c0;\n font-size: 11px;\n font-weight: 600;\n padding: 4px 0 2px;\n border-bottom: 1px solid #2d2d2d;\n margin-bottom: 2px;\n}\n\n.why-updated-chain {\n padding: 2px 0;\n font-size: 10px;\n border-bottom: 1px solid #2a2a2a;\n}\n\n.why-chain-mutation { color: #569cd6; }\n.why-chain-arrow { color: #555; margin: 0 3px; }\n.why-chain-batch { color: #d7ba7d; }\n.why-chain-event { color: #4ec9b0; }\n.why-chain-none { color: #555; font-style: italic; }\n\n/* Responsive / mobile-friendly */\n@media (max-width: 600px) {\n .panel { width: calc(100vw - 16px) !important; height: 50vh !important; left: 8px; right: 8px; bottom: 8px; }\n .panel.collapsed { width: auto; height: auto; }\n .tab-bar button { padding: 4px 8px; font-size: 10px; }\n .header-bar { padding: 2px 8px; }\n .tree-tag, .log-action { font-size: 11px; }\n .stat-row { font-size: 11px; }\n}\n@media (max-width: 400px) {\n .panel { width: calc(100vw - 8px) !important; left: 4px; right: 4px; }\n .tab-bar button { padding: 3px 6px; font-size: 9px; }\n}\n`;\n\n// ---- Helpers ----\n\nfunction escapeHtml(str: string): string {\n\treturn str\n\t\t.replace(/&/g, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/\"/g, \""\");\n}\n\nfunction formatTime(ts: number): string {\n\tconst d = new Date(ts);\n\tif (Number.isNaN(d.getTime())) {\n\t\tconst now = new Date();\n\t\tconst h = String(now.getHours()).padStart(2, \"0\");\n\t\tconst m = String(now.getMinutes()).padStart(2, \"0\");\n\t\tconst s = String(now.getSeconds()).padStart(2, \"0\");\n\t\treturn `${h}:${m}:${s}`;\n\t}\n\tconst h = String(d.getHours()).padStart(2, \"0\");\n\tconst m = String(d.getMinutes()).padStart(2, \"0\");\n\tconst s = String(d.getSeconds()).padStart(2, \"0\");\n\tconst ms = String(d.getMilliseconds()).padStart(3, \"0\");\n\treturn `${h}:${m}:${s}.${ms}`;\n}\n\nfunction truncate(str: string, max: number): string {\n\treturn str.length > max ? `${str.slice(0, max)}...` : str;\n}\n\n// ASCII sparkline from an array of numbers\nfunction sparkline(data: number[]): string {\n\tif (data.length === 0) return \"\";\n\tconst chars = \"\\u2581\\u2582\\u2583\\u2584\\u2585\\u2586\\u2587\\u2588\";\n\tconst max = Math.max(...data);\n\tconst min = Math.min(...data);\n\tconst range = max - min || 1;\n\treturn data.map((v) => chars[Math.min(Math.floor(((v - min) / range) * 7), 7)]).join(\"\");\n}\n\n// ---- Panel creation ----\n\nexport function createDevtoolsPanel(): { destroy: () => void } {\n\tconst host = document.createElement(\"div\");\n\thost.id = \"__async-dom-devtools__\";\n\tconst shadow = host.attachShadow({ mode: \"open\" });\n\n\tconst style = document.createElement(\"style\");\n\tstyle.textContent = PANEL_CSS;\n\tshadow.appendChild(style);\n\n\tconst panel = document.createElement(\"div\");\n\tpanel.className = \"panel collapsed\";\n\n\t// Collapsed toggle tab\n\tconst toggleTab = document.createElement(\"button\");\n\ttoggleTab.className = \"toggle-tab\";\n\n\tconst healthDot = document.createElement(\"span\");\n\thealthDot.style.cssText =\n\t\t\"display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px;background-color:#4ec9b0;vertical-align:middle;\";\n\ttoggleTab.appendChild(healthDot);\n\n\tconst toggleTabText = document.createElement(\"span\");\n\ttoggleTabText.textContent = \"async-dom \\u25B2\";\n\ttoggleTab.appendChild(toggleTabText);\n\n\tpanel.appendChild(toggleTab);\n\n\t// Header bar\n\tconst headerBar = document.createElement(\"div\");\n\theaderBar.className = \"header-bar\";\n\n\tconst headerTitle = document.createElement(\"span\");\n\theaderTitle.className = \"header-title\";\n\theaderTitle.textContent = \"async-dom devtools\";\n\n\tconst importIndicator = document.createElement(\"span\");\n\timportIndicator.className = \"import-indicator\";\n\timportIndicator.style.display = \"none\";\n\theaderTitle.appendChild(importIndicator);\n\n\theaderBar.appendChild(headerTitle);\n\n\tconst headerActions = document.createElement(\"div\");\n\theaderActions.className = \"header-actions\";\n\n\tconst highlightBtn = document.createElement(\"button\");\n\thighlightBtn.className = \"header-btn\";\n\thighlightBtn.textContent = \"\\u2B24\";\n\thighlightBtn.title = \"Highlight DOM updates\";\n\thighlightBtn.style.fontSize = \"8px\";\n\thighlightBtn.style.color = \"#808080\";\n\thighlightBtn.addEventListener(\"click\", () => {\n\t\thighlightUpdatesEnabled = !highlightUpdatesEnabled;\n\t\thighlightBtn.style.color = highlightUpdatesEnabled ? \"#4ec9b0\" : \"#808080\";\n\t\tconst dt = getDevtools();\n\t\tif (dt) dt.enableHighlightUpdates(highlightUpdatesEnabled);\n\t});\n\theaderActions.appendChild(highlightBtn);\n\n\tconst exportBtn = document.createElement(\"button\");\n\texportBtn.className = \"header-btn\";\n\texportBtn.textContent = \"\\u2193\";\n\texportBtn.title = \"Export debug session\";\n\theaderActions.appendChild(exportBtn);\n\n\tconst importBtn = document.createElement(\"button\");\n\timportBtn.className = \"header-btn\";\n\timportBtn.textContent = \"\\u2191\";\n\timportBtn.title = \"Import debug session\";\n\theaderActions.appendChild(importBtn);\n\n\tconst refreshBtn = document.createElement(\"button\");\n\trefreshBtn.className = \"header-btn\";\n\trefreshBtn.textContent = \"\\u21BB\";\n\trefreshBtn.title = \"Refresh data from workers\";\n\theaderActions.appendChild(refreshBtn);\n\n\tconst closeBtn = document.createElement(\"button\");\n\tcloseBtn.className = \"header-btn\";\n\tcloseBtn.textContent = \"\\u25BC\";\n\tcloseBtn.title = \"Collapse\";\n\theaderActions.appendChild(closeBtn);\n\n\theaderBar.appendChild(headerActions);\n\tpanel.appendChild(headerBar);\n\n\t// App bar (multi-app support)\n\tconst appBar = document.createElement(\"div\");\n\tappBar.className = \"app-bar\";\n\tpanel.appendChild(appBar);\n\n\tlet selectedAppId: string | null = null;\n\n\t// Tab bar\n\tconst tabBar = document.createElement(\"div\");\n\ttabBar.className = \"tab-bar\";\n\n\tconst tabs = [\"Tree\", \"Performance\", \"Log\", \"Warnings\", \"Graph\"] as const;\n\ttype TabName = (typeof tabs)[number];\n\tconst tabBtns: Record<string, HTMLButtonElement> = {};\n\tconst tabPanels: Record<string, HTMLDivElement> = {};\n\n\tfor (const tabName of tabs) {\n\t\tconst btn = document.createElement(\"button\");\n\t\tbtn.className = `tab-btn${tabName === \"Tree\" ? \" active\" : \"\"}`;\n\t\tbtn.textContent = tabName;\n\t\tbtn.dataset.tab = tabName;\n\t\ttabBar.appendChild(btn);\n\t\ttabBtns[tabName] = btn;\n\t}\n\tpanel.appendChild(tabBar);\n\n\t// Warning badge\n\tconst warningBadge = document.createElement(\"span\");\n\twarningBadge.className = \"tab-badge\";\n\twarningBadge.style.display = \"none\";\n\n\t// Tab contents\n\tlet activeTab: TabName = \"Tree\";\n\n\tfunction switchTab(name: TabName): void {\n\t\tactiveTab = name;\n\t\tfor (const t of tabs) {\n\t\t\ttabBtns[t].classList.toggle(\"active\", t === name);\n\t\t\ttabPanels[t].classList.toggle(\"active\", t === name);\n\t\t}\n\t\tif (name === \"Warnings\") {\n\t\t\twarningBadgeCount = 0;\n\t\t\tupdateWarningBadge();\n\t\t}\n\t\trenderActiveTab();\n\t}\n\n\tfor (const tabName of tabs) {\n\t\ttabBtns[tabName].addEventListener(\"click\", () => switchTab(tabName));\n\t}\n\n\t// ---- Tree content ----\n\tconst treeContent = document.createElement(\"div\");\n\ttreeContent.className = \"tab-content active\";\n\ttreeContent.innerHTML =\n\t\t'<div class=\"tree-empty\">Click refresh to load virtual DOM tree from worker.</div>';\n\ttabPanels.Tree = treeContent as HTMLDivElement;\n\tpanel.appendChild(treeContent);\n\n\t// ---- Performance content ----\n\tconst perfContent = document.createElement(\"div\");\n\tperfContent.className = \"tab-content\";\n\tperfContent.innerHTML = '<div class=\"perf-row\"><span class=\"perf-label\">Loading...</span></div>';\n\ttabPanels.Performance = perfContent as HTMLDivElement;\n\tpanel.appendChild(perfContent);\n\n\t// ---- Log content ----\n\tconst logContent = document.createElement(\"div\");\n\tlogContent.className = \"tab-content\";\n\n\tconst logToolbar = document.createElement(\"div\");\n\tlogToolbar.className = \"log-toolbar\";\n\n\tconst logFilter = document.createElement(\"input\");\n\tlogFilter.className = \"log-filter\";\n\tlogFilter.placeholder = \"Filter...\";\n\tlogFilter.type = \"text\";\n\tlogToolbar.appendChild(logFilter);\n\n\tconst logCountSpan = document.createElement(\"span\");\n\tlogCountSpan.className = \"log-count\";\n\tlogCountSpan.textContent = \"0\";\n\tlogToolbar.appendChild(logCountSpan);\n\n\tconst logPauseBtn = document.createElement(\"button\");\n\tlogPauseBtn.className = \"log-btn\";\n\tlogPauseBtn.textContent = \"Pause\";\n\tlogToolbar.appendChild(logPauseBtn);\n\n\tconst logAutoScrollBtn = document.createElement(\"button\");\n\tlogAutoScrollBtn.className = \"log-btn active\";\n\tlogAutoScrollBtn.textContent = \"Auto-scroll\";\n\tlogToolbar.appendChild(logAutoScrollBtn);\n\n\tconst logClearBtn = document.createElement(\"button\");\n\tlogClearBtn.className = \"log-btn\";\n\tlogClearBtn.textContent = \"Clear\";\n\tlogToolbar.appendChild(logClearBtn);\n\n\tconst logReplayBtn = document.createElement(\"button\");\n\tlogReplayBtn.className = \"log-btn\";\n\tlogReplayBtn.textContent = \"Replay\";\n\tlogToolbar.appendChild(logReplayBtn);\n\n\tlogContent.appendChild(logToolbar);\n\n\t// Replay bar (hidden by default)\n\tconst replayBar = document.createElement(\"div\");\n\treplayBar.className = \"replay-bar\";\n\treplayBar.style.display = \"none\";\n\n\tconst replayFirstBtn = document.createElement(\"button\");\n\treplayFirstBtn.className = \"replay-btn\";\n\treplayFirstBtn.textContent = \"\\u23EE\";\n\treplayBar.appendChild(replayFirstBtn);\n\n\tconst replayPrevBtn = document.createElement(\"button\");\n\treplayPrevBtn.className = \"replay-btn\";\n\treplayPrevBtn.textContent = \"\\u25C0\";\n\treplayBar.appendChild(replayPrevBtn);\n\n\tconst replayPlayBtn = document.createElement(\"button\");\n\treplayPlayBtn.className = \"replay-btn\";\n\treplayPlayBtn.textContent = \"\\u25B6\";\n\treplayBar.appendChild(replayPlayBtn);\n\n\tconst replayStepFwdBtn = document.createElement(\"button\");\n\treplayStepFwdBtn.className = \"replay-btn\";\n\treplayStepFwdBtn.textContent = \"\\u25B6\\u2758\";\n\treplayStepFwdBtn.title = \"Step forward one entry\";\n\treplayBar.appendChild(replayStepFwdBtn);\n\n\tconst replayNextBtn = document.createElement(\"button\");\n\treplayNextBtn.className = \"replay-btn\";\n\treplayNextBtn.textContent = \"\\u23ED\";\n\treplayNextBtn.title = \"Skip to end\";\n\treplayBar.appendChild(replayNextBtn);\n\n\tconst replaySlider = document.createElement(\"input\");\n\treplaySlider.type = \"range\";\n\treplaySlider.className = \"replay-slider\";\n\treplaySlider.min = \"0\";\n\treplaySlider.max = \"0\";\n\treplaySlider.value = \"0\";\n\treplayBar.appendChild(replaySlider);\n\n\tconst replayPosition = document.createElement(\"span\");\n\treplayPosition.className = \"replay-position\";\n\treplayPosition.textContent = \"0 / 0\";\n\treplayBar.appendChild(replayPosition);\n\n\tconst replaySpeedBtn = document.createElement(\"button\");\n\treplaySpeedBtn.className = \"replay-btn\";\n\treplaySpeedBtn.textContent = \"1x\";\n\treplayBar.appendChild(replaySpeedBtn);\n\n\tconst replayExitBtn = document.createElement(\"button\");\n\treplayExitBtn.className = \"replay-btn replay-exit\";\n\treplayExitBtn.textContent = \"\\u2715 Exit\";\n\treplayBar.appendChild(replayExitBtn);\n\n\tconst logList = document.createElement(\"div\");\n\tlogList.className = \"log-list\";\n\tlogList.innerHTML = '<div class=\"log-empty\">No mutations captured yet.</div>';\n\tlogContent.appendChild(logList);\n\n\t// Insert replay bar before logList (must be after both are created)\n\tlogContent.insertBefore(replayBar, logList);\n\n\ttabPanels.Log = logContent as HTMLDivElement;\n\tpanel.appendChild(logContent);\n\n\t// ---- Warnings content ----\n\tconst warnContent = document.createElement(\"div\");\n\twarnContent.className = \"tab-content\";\n\n\tconst warnToolbar = document.createElement(\"div\");\n\twarnToolbar.className = \"log-toolbar\";\n\n\tconst warnFilter = document.createElement(\"input\");\n\twarnFilter.className = \"log-filter\";\n\twarnFilter.placeholder = \"Filter warnings...\";\n\twarnFilter.type = \"text\";\n\twarnToolbar.appendChild(warnFilter);\n\n\tconst warnViewToggle = document.createElement(\"button\");\n\twarnViewToggle.className = \"log-btn warn-view-toggle\";\n\twarnViewToggle.textContent = \"Chronological\";\n\twarnToolbar.appendChild(warnViewToggle);\n\n\tconst warnClearBtn = document.createElement(\"button\");\n\twarnClearBtn.className = \"log-btn\";\n\twarnClearBtn.textContent = \"Clear\";\n\twarnToolbar.appendChild(warnClearBtn);\n\twarnContent.appendChild(warnToolbar);\n\n\tconst warnList = document.createElement(\"div\");\n\twarnList.className = \"log-list\";\n\twarnList.innerHTML = '<div class=\"warn-empty\">No warnings captured yet.</div>';\n\twarnContent.appendChild(warnList);\n\n\ttabPanels.Warnings = warnContent as HTMLDivElement;\n\tpanel.appendChild(warnContent);\n\n\t// ---- Graph content (Feature 15: Causality Graph) ----\n\tconst graphContent = document.createElement(\"div\");\n\tgraphContent.className = \"tab-content\";\n\tgraphContent.innerHTML =\n\t\t'<div class=\"graph-empty\">No causality data yet. Interact with the app to generate event-mutation data.</div>';\n\ttabPanels.Graph = graphContent as HTMLDivElement;\n\tpanel.appendChild(graphContent);\n\n\t// Attach badge to Warnings tab button\n\ttabBtns.Warnings.appendChild(warningBadge);\n\n\tshadow.appendChild(panel);\n\tdocument.body.appendChild(host);\n\n\t// ---- State ----\n\tlet treePollTimer: ReturnType<typeof setInterval> | null = null;\n\tlet perfPollTimer: ReturnType<typeof setInterval> | null = null;\n\tlet logRenderTimer: ReturnType<typeof setInterval> | null = null;\n\tlet autoScroll = true;\n\tconst queueHistory: number[] = [];\n\tconst MAX_HISTORY = 30;\n\tlet highlightUpdatesEnabled = false;\n\tlet selectedNodeForSidebar: TreeNode | null = null;\n\t/** Tracks which node IDs are expanded in the tree view. Empty means \"first render\". */\n\tconst expandedNodeIds = new Set<number>();\n\t/** Whether the tree has been rendered at least once (to distinguish first render). */\n\tlet hasRenderedTree = false;\n\tlet expandedFrameId: number | null = null;\n\n\t// Feature 3: Latency history tracking\n\tconst latencyHistory: number[] = [];\n\t// Guards to prevent duplicate sparkline data on manual refresh\n\tlet lastQueuePushFrameId = -1;\n\tlet lastLatencyPushFrameId = -1;\n\tconst MAX_LATENCY_HISTORY = 60;\n\n\t// Track pending setTimeout IDs so destroy() can cancel them\n\tlet treeRefreshTimeout: ReturnType<typeof setTimeout> | null = null;\n\tlet perfRefreshTimeout: ReturnType<typeof setTimeout> | null = null;\n\tlet manualRefreshTimeout: ReturnType<typeof setTimeout> | null = null;\n\n\t// Replay state (Feature 8)\n\tlet replayState: ReplayState | null = null;\n\tlet replayTimer: ReturnType<typeof setInterval> | null = null;\n\tlet replaySpeedMultiplier = 1;\n\tconst REPLAY_SPEEDS = [1, 2, 5];\n\n\t// Import state (Feature 14)\n\tlet importedSession: DebugSession | null = null;\n\n\t// Feature 17: Tree snapshots for diffing\n\tlet snapshot1: TreeSnapshot | null = null;\n\tlet snapshot2: TreeSnapshot | null = null;\n\tlet showDiff = false;\n\tlet currentDiff: TreeDiffNode | null = null;\n\n\t// ---- Feature 8: Replay controls ----\n\n\tfunction updateReplayUI(): void {\n\t\tif (!replayState) return;\n\t\treplaySlider.max = String(replayState.entries.length);\n\t\treplaySlider.value = String(replayState.currentIndex);\n\t\treplayPosition.textContent = `${replayState.currentIndex} / ${replayState.entries.length}`;\n\t\treplayPlayBtn.textContent = replayState.isPlaying ? \"\\u23F8\" : \"\\u25B6\";\n\t\treplayPlayBtn.classList.toggle(\"active\", replayState.isPlaying);\n\t}\n\n\tfunction enterReplayMode(): void {\n\t\tif (importedSession) return; // no replay in imported mode\n\t\tconst dt = getDevtools();\n\t\t// Pause the scheduler so live mutations don't interfere with replay\n\t\tdt?.scheduler.stop();\n\t\tisReplaying = true;\n\t\treplayState = createReplayState(mutationLog);\n\t\treplayBar.style.display = \"flex\";\n\t\tlogReplayBtn.classList.add(\"active\");\n\t\tupdateReplayUI();\n\t\trenderLogTab();\n\t}\n\n\tfunction exitReplayMode(): void {\n\t\tif (replayTimer) {\n\t\t\tclearInterval(replayTimer);\n\t\t\treplayTimer = null;\n\t\t}\n\t\tconst dt = getDevtools();\n\t\ttry {\n\t\t\tif (replayState) {\n\t\t\t\treplayState.isPlaying = false;\n\t\t\t\t// Restore DOM to latest state by re-applying the full mutation log\n\t\t\t\tconst appId = selectedAppId ?? dt?.apps()[0];\n\t\t\t\tif (dt?.clearAndReapply && appId) {\n\t\t\t\t\tdt.clearAndReapply(mutationLog, mutationLog.length, appId);\n\t\t\t\t}\n\t\t\t\treplayState = null;\n\t\t\t}\n\t\t\tisReplaying = false;\n\t\t} finally {\n\t\t\t// Resume the scheduler so live mutations flow again — even if replay restoration throws\n\t\t\tdt?.scheduler.start();\n\t\t}\n\t\treplayBar.style.display = \"none\";\n\t\tlogReplayBtn.classList.remove(\"active\");\n\t\trenderLogTab();\n\t}\n\n\tfunction applyReplayMutation(entry: MutationLogEntry): void {\n\t\tconst dt = getDevtools();\n\t\tif (!dt?.replayMutation) return;\n\t\tconst appId = selectedAppId ?? dt.apps()[0];\n\t\tif (appId) {\n\t\t\ttry {\n\t\t\t\tdt.replayMutation(entry.mutation, appId);\n\t\t\t} catch (e) {\n\t\t\t\tconsole.error(\"[async-dom devtools] replayMutation failed\", e);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction clearAndReapplyUpTo(index: number): void {\n\t\tif (!replayState) return;\n\t\tconst dt = getDevtools();\n\t\tif (!dt?.clearAndReapply) return;\n\t\tconst appId = selectedAppId ?? dt.apps()[0];\n\t\ttry {\n\t\t\tdt.clearAndReapply(replayState.entries, index, appId);\n\t\t} catch (e) {\n\t\t\tconsole.error(\"[async-dom devtools] clearAndReapply failed\", e);\n\t\t}\n\t}\n\n\tfunction replayStepForwardOne(): void {\n\t\tif (!replayState) return;\n\t\tconst entry = replayStep(replayState);\n\t\tif (entry) applyReplayMutation(entry);\n\t\tupdateReplayUI();\n\t\trenderLogTab();\n\t}\n\n\tfunction replayStepBackward(): void {\n\t\tif (!replayState) return;\n\t\tif (replayState.currentIndex > 0) {\n\t\t\treplaySeek(replayState, replayState.currentIndex - 1);\n\t\t\t// Backward requires clearing and re-applying from scratch\n\t\t\tclearAndReapplyUpTo(replayState.currentIndex);\n\t\t}\n\t\tupdateReplayUI();\n\t\trenderLogTab();\n\t}\n\n\tfunction replayGoToStart(): void {\n\t\tif (!replayState) return;\n\t\treplayReset(replayState);\n\t\t// Clear DOM — nothing to re-apply at index 0\n\t\tclearAndReapplyUpTo(0);\n\t\tupdateReplayUI();\n\t\trenderLogTab();\n\t}\n\n\tfunction replayGoToEnd(): void {\n\t\tif (!replayState) return;\n\t\treplaySeek(replayState, replayState.entries.length);\n\t\t// Re-apply all mutations\n\t\tclearAndReapplyUpTo(replayState.entries.length);\n\t\tupdateReplayUI();\n\t\trenderLogTab();\n\t}\n\n\tfunction toggleReplayPlay(): void {\n\t\tif (!replayState) return;\n\t\treplayState.isPlaying = !replayState.isPlaying;\n\t\tif (replayState.isPlaying) {\n\t\t\tconst intervalMs = Math.max(50, 500 / replaySpeedMultiplier);\n\t\t\treplayTimer = setInterval(() => {\n\t\t\t\tif (!replayState || replayState.currentIndex >= replayState.entries.length) {\n\t\t\t\t\tif (replayState) replayState.isPlaying = false;\n\t\t\t\t\tif (replayTimer) {\n\t\t\t\t\t\tclearInterval(replayTimer);\n\t\t\t\t\t\treplayTimer = null;\n\t\t\t\t\t}\n\t\t\t\t\tupdateReplayUI();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst entry = replayStep(replayState);\n\t\t\t\tif (entry) applyReplayMutation(entry);\n\t\t\t\tupdateReplayUI();\n\t\t\t\trenderLogTab();\n\t\t\t}, intervalMs);\n\t\t} else {\n\t\t\tif (replayTimer) {\n\t\t\t\tclearInterval(replayTimer);\n\t\t\t\treplayTimer = null;\n\t\t\t}\n\t\t}\n\t\tupdateReplayUI();\n\t}\n\n\tfunction cycleReplaySpeed(): void {\n\t\tconst idx = REPLAY_SPEEDS.indexOf(replaySpeedMultiplier);\n\t\treplaySpeedMultiplier = REPLAY_SPEEDS[(idx + 1) % REPLAY_SPEEDS.length];\n\t\treplaySpeedBtn.textContent = `${replaySpeedMultiplier}x`;\n\t\t// Restart play interval if playing\n\t\tif (replayState?.isPlaying) {\n\t\t\tif (replayTimer) {\n\t\t\t\tclearInterval(replayTimer);\n\t\t\t\treplayTimer = null;\n\t\t\t}\n\t\t\treplayState.isPlaying = false;\n\t\t\ttoggleReplayPlay();\n\t\t}\n\t}\n\n\tlogReplayBtn.addEventListener(\"click\", () => {\n\t\tif (replayState) exitReplayMode();\n\t\telse enterReplayMode();\n\t});\n\treplayFirstBtn.addEventListener(\"click\", replayGoToStart);\n\treplayPrevBtn.addEventListener(\"click\", replayStepBackward);\n\treplayPlayBtn.addEventListener(\"click\", toggleReplayPlay);\n\treplayStepFwdBtn.addEventListener(\"click\", replayStepForwardOne);\n\treplayNextBtn.addEventListener(\"click\", replayGoToEnd);\n\treplaySlider.addEventListener(\"input\", () => {\n\t\tif (!replayState) return;\n\t\tconst target = Number(replaySlider.value);\n\t\treplaySeek(replayState, target);\n\t\t// Re-apply mutations up to the new position\n\t\tclearAndReapplyUpTo(replayState.currentIndex);\n\t\tupdateReplayUI();\n\t\trenderLogTab();\n\t});\n\treplaySpeedBtn.addEventListener(\"click\", cycleReplaySpeed);\n\treplayExitBtn.addEventListener(\"click\", exitReplayMode);\n\n\t// ---- Feature 14: Export / Import ----\n\n\texportBtn.addEventListener(\"click\", () => {\n\t\tconst dt = getDevtools();\n\t\tconst schedulerStats = dt?.scheduler?.stats() ?? {};\n\t\tconst allData = dt?.getAllAppsData() ?? {};\n\t\tconst firstAppData = Object.values(allData)[0];\n\n\t\tconst json = exportSession({\n\t\t\tmutationLog: importedSession ? importedSession.mutationLog : [...mutationLog],\n\t\t\twarningLog: importedSession ? importedSession.warningLog : [...warningLog],\n\t\t\teventLog: importedSession ? importedSession.eventLog : [...eventLog],\n\t\t\tsyncReadLog: importedSession ? importedSession.syncReadLog : [...syncReadLog],\n\t\t\tschedulerStats: schedulerStats as Record<string, unknown>,\n\t\t\ttree: firstAppData?.tree,\n\t\t\tappData: allData as Record<string, unknown>,\n\t\t});\n\n\t\tconst timestamp = new Date().toISOString().replace(/[:.]/g, \"-\").slice(0, 19);\n\t\tdownloadJson(json, `async-dom-session-${timestamp}.json`);\n\t});\n\n\timportBtn.addEventListener(\"click\", () => {\n\t\tconst input = document.createElement(\"input\");\n\t\tinput.type = \"file\";\n\t\tinput.accept = \".json\";\n\t\tinput.addEventListener(\"change\", () => {\n\t\t\tconst file = input.files?.[0];\n\t\t\tif (!file) return;\n\t\t\tconst reader = new FileReader();\n\t\t\treader.onload = () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst session = importSession(reader.result as string);\n\t\t\t\t\tenterImportMode(session);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error(\"[async-dom devtools] Import failed:\", err);\n\t\t\t\t}\n\t\t\t};\n\t\t\treader.readAsText(file);\n\t\t});\n\t\tinput.click();\n\t});\n\n\tfunction setImportControlsDisabled(disabled: boolean): void {\n\t\t// Log tab controls\n\t\tlogClearBtn.disabled = disabled;\n\t\tlogPauseBtn.disabled = disabled;\n\t\tlogAutoScrollBtn.disabled = disabled;\n\t\tlogReplayBtn.disabled = disabled;\n\t\t// Warnings tab controls\n\t\twarnClearBtn.disabled = disabled;\n\n\t\tconst grayedStyle = disabled ? \"0.4\" : \"1\";\n\t\tlogClearBtn.style.opacity = grayedStyle;\n\t\tlogPauseBtn.style.opacity = grayedStyle;\n\t\tlogAutoScrollBtn.style.opacity = grayedStyle;\n\t\tlogReplayBtn.style.opacity = grayedStyle;\n\t\twarnClearBtn.style.opacity = grayedStyle;\n\n\t\tif (disabled) {\n\t\t\tlogClearBtn.style.pointerEvents = \"none\";\n\t\t\tlogPauseBtn.style.pointerEvents = \"none\";\n\t\t\tlogAutoScrollBtn.style.pointerEvents = \"none\";\n\t\t\tlogReplayBtn.style.pointerEvents = \"none\";\n\t\t\twarnClearBtn.style.pointerEvents = \"none\";\n\t\t} else {\n\t\t\tlogClearBtn.style.pointerEvents = \"\";\n\t\t\tlogPauseBtn.style.pointerEvents = \"\";\n\t\t\tlogAutoScrollBtn.style.pointerEvents = \"\";\n\t\t\tlogReplayBtn.style.pointerEvents = \"\";\n\t\t\twarnClearBtn.style.pointerEvents = \"\";\n\t\t}\n\t}\n\n\tfunction enterImportMode(session: DebugSession): void {\n\t\timportedSession = session;\n\t\t// Pause live capture so incoming mutations don't overwrite the ring buffer\n\t\tlogPaused = true;\n\t\tlogPauseBtn.textContent = \"Resume\";\n\t\tlogPauseBtn.classList.add(\"active\");\n\t\t// Exit replay if active\n\t\tif (replayState) exitReplayMode();\n\n\t\timportIndicator.textContent = \"[IMPORTED]\";\n\t\timportIndicator.style.display = \"inline\";\n\n\t\t// Disable irrelevant controls\n\t\tsetImportControlsDisabled(true);\n\n\t\t// Add a close-import button if not already present\n\t\tlet closeImportBtn = headerActions.querySelector(\n\t\t\t\".close-import-btn\",\n\t\t) as HTMLButtonElement | null;\n\t\tif (!closeImportBtn) {\n\t\t\tcloseImportBtn = document.createElement(\"button\");\n\t\t\tcloseImportBtn.className = \"header-btn close-import-btn\";\n\t\t\tcloseImportBtn.textContent = \"\\u2715\";\n\t\t\tcloseImportBtn.title = \"Close imported session\";\n\t\t\tcloseImportBtn.style.color = \"#d7ba7d\";\n\t\t\tcloseImportBtn.addEventListener(\"click\", exitImportMode);\n\t\t\theaderActions.insertBefore(closeImportBtn, headerActions.firstChild);\n\t\t}\n\n\t\trenderActiveTab();\n\t}\n\n\tfunction exitImportMode(): void {\n\t\timportedSession = null;\n\t\timportIndicator.style.display = \"none\";\n\t\timportIndicator.textContent = \"\";\n\n\t\t// Resume live capture\n\t\tlogPaused = false;\n\t\tlogPauseBtn.textContent = \"Pause\";\n\t\tlogPauseBtn.classList.remove(\"active\");\n\n\t\t// Re-enable controls\n\t\tsetImportControlsDisabled(false);\n\n\t\tconst closeImportBtn = headerActions.querySelector(\".close-import-btn\");\n\t\tif (closeImportBtn) closeImportBtn.remove();\n\n\t\trenderActiveTab();\n\t}\n\n\t// ---- Feature 1: Queue pressure health dot (polls even when collapsed) ----\n\tfunction updateHealthDot(): void {\n\t\tconst dt = getDevtools();\n\t\tif (!dt?.scheduler?.stats) return;\n\t\tconst stats = dt.scheduler.stats();\n\t\tconst pending = stats.pending;\n\t\tif (pending > 1000 || !stats.isRunning || stats.lastFrameTimeMs > 16) {\n\t\t\thealthDot.style.backgroundColor = \"#f44747\"; // red\n\t\t} else if (pending > 100 || stats.lastFrameTimeMs > 12) {\n\t\t\thealthDot.style.backgroundColor = \"#d7ba7d\"; // yellow\n\t\t} else {\n\t\t\thealthDot.style.backgroundColor = \"#4ec9b0\"; // green\n\t\t}\n\t}\n\n\tconst healthDotTimer = setInterval(updateHealthDot, 2000);\n\n\tfunction getDevtools(): DevtoolsAPI | null {\n\t\treturn (globalThis as Record<string, unknown>).__ASYNC_DOM_DEVTOOLS__ as DevtoolsAPI | null;\n\t}\n\n\t// ---- Toggle expand / collapse ----\n\n\tfunction expand(): void {\n\t\tpanel.classList.remove(\"collapsed\");\n\t\trequestTreeRefresh();\n\t\tstartPolling();\n\t}\n\n\tfunction collapse(): void {\n\t\tpanel.classList.add(\"collapsed\");\n\t\tstopPolling();\n\t\t// Stop replay playback to prevent invisible DOM mutations while collapsed\n\t\tif (replayTimer) {\n\t\t\tclearInterval(replayTimer);\n\t\t\treplayTimer = null;\n\t\t}\n\t\tif (replayState?.isPlaying) {\n\t\t\treplayState.isPlaying = false;\n\t\t\tupdateReplayUI();\n\t\t}\n\t}\n\n\ttoggleTab.addEventListener(\"click\", expand);\n\tcloseBtn.addEventListener(\"click\", collapse);\n\n\t// ---- Refresh: request data from workers ----\n\n\tfunction requestTreeRefresh(): void {\n\t\tconst dt = getDevtools();\n\t\tif (!dt) return;\n\t\tdt.refreshDebugData();\n\t\t// Render after a short delay to let the response arrive\n\t\tmanualRefreshTimeout = setTimeout(() => {\n\t\t\tmanualRefreshTimeout = null;\n\t\t\tupdateAppBar();\n\t\t\trenderActiveTab();\n\t\t}, 250);\n\t}\n\n\trefreshBtn.addEventListener(\"click\", requestTreeRefresh);\n\n\t// ---- App bar ----\n\n\t/** Reset UI state that is specific to a particular app when switching apps. */\n\tfunction resetPerAppState(): void {\n\t\t// Tree tab: clear snapshots and diff state\n\t\tsnapshot1 = null;\n\t\tsnapshot2 = null;\n\t\tshowDiff = false;\n\t\tcurrentDiff = null;\n\t\tselectedNodeForSidebar = null;\n\t\texpandedNodeIds.clear();\n\t\thasRenderedTree = false;\n\n\t\t// Log tab: reset coalesced view and log render position\n\t\tshowCoalesced = false;\n\t\tlastRenderedLogLength = 0;\n\t\tlastRenderedFilterText = \"\";\n\t\tlastRenderedEventLogLength = 0;\n\t\tlastRenderedSyncReadLogLength = 0;\n\n\t\t// Replay: exit replay mode if active\n\t\tif (replayState) {\n\t\t\texitReplayMode();\n\t\t}\n\n\t\t// Performance: reset expanded frame\n\t\texpandedFrameId = null;\n\t}\n\n\tfunction updateAppBar(): void {\n\t\tconst dt = getDevtools();\n\t\tif (!dt) return;\n\t\tconst apps = dt.apps();\n\t\tif (apps.length <= 1) {\n\t\t\tappBar.classList.remove(\"visible\");\n\t\t\tselectedAppId = apps[0] ?? null;\n\t\t\treturn;\n\t\t}\n\t\tappBar.classList.add(\"visible\");\n\t\tappBar.innerHTML = \"\";\n\n\t\tconst label = document.createElement(\"span\");\n\t\tlabel.className = \"app-label\";\n\t\tlabel.textContent = \"Apps:\";\n\t\tappBar.appendChild(label);\n\n\t\tif (selectedAppId === null || !apps.includes(selectedAppId)) {\n\t\t\tconst previousAppId = selectedAppId;\n\t\t\tselectedAppId = apps[0];\n\t\t\tif (previousAppId !== null && previousAppId !== selectedAppId) {\n\t\t\t\tresetPerAppState();\n\t\t\t}\n\t\t}\n\n\t\tfor (const id of apps) {\n\t\t\tconst btn = document.createElement(\"button\");\n\t\t\tbtn.className = `app-btn${id === selectedAppId ? \" active\" : \"\"}`;\n\t\t\tbtn.textContent = id;\n\t\t\tbtn.addEventListener(\"click\", () => {\n\t\t\t\tif (selectedAppId !== id) {\n\t\t\t\t\tselectedAppId = id;\n\t\t\t\t\tresetPerAppState();\n\t\t\t\t}\n\t\t\t\tupdateAppBar();\n\t\t\t\trenderActiveTab();\n\t\t\t});\n\t\t\tappBar.appendChild(btn);\n\t\t}\n\t}\n\n\tfunction renderActiveTab(): void {\n\t\tif (activeTab === \"Tree\") renderTreeTab();\n\t\telse if (activeTab === \"Performance\") renderPerfTab();\n\t\telse if (activeTab === \"Log\") renderLogTab();\n\t\telse if (activeTab === \"Warnings\") renderWarningsTab();\n\t\telse if (activeTab === \"Graph\") renderGraphTab();\n\t}\n\n\t// ---- Tree rendering (VIRTUAL DOM from worker) ----\n\n\tfunction renderNodeSidebar(sidebar: HTMLDivElement, node: TreeNode): void {\n\t\tsidebar.innerHTML = \"\";\n\n\t\t// Node ID\n\t\tif (node.id != null) {\n\t\t\tconst title0 = document.createElement(\"div\");\n\t\t\ttitle0.className = \"sidebar-title\";\n\t\t\ttitle0.textContent = \"Node\";\n\t\t\tsidebar.appendChild(title0);\n\n\t\t\tconst row0 = document.createElement(\"div\");\n\t\t\trow0.className = \"sidebar-row\";\n\t\t\trow0.innerHTML = `<span class=\"sidebar-key\">_nodeId</span><span class=\"sidebar-val\">${node.id}</span>`;\n\t\t\tsidebar.appendChild(row0);\n\t\t}\n\n\t\t// Type + tag\n\t\tconst typeRow = document.createElement(\"div\");\n\t\ttypeRow.className = \"sidebar-row\";\n\t\ttypeRow.innerHTML = `<span class=\"sidebar-key\">type</span><span class=\"sidebar-val\">${escapeHtml(node.type)}</span>`;\n\t\tsidebar.appendChild(typeRow);\n\n\t\tif (node.tag) {\n\t\t\tconst tagRow = document.createElement(\"div\");\n\t\t\ttagRow.className = \"sidebar-row\";\n\t\t\ttagRow.innerHTML = `<span class=\"sidebar-key\">tag</span><span class=\"sidebar-val\">${escapeHtml(node.tag)}</span>`;\n\t\t\tsidebar.appendChild(tagRow);\n\t\t}\n\n\t\t// Children count\n\t\tconst childCount = node.children?.length ?? 0;\n\t\tconst childRow = document.createElement(\"div\");\n\t\tchildRow.className = \"sidebar-row\";\n\t\tchildRow.innerHTML = `<span class=\"sidebar-key\">children</span><span class=\"sidebar-val\">${childCount}</span>`;\n\t\tsidebar.appendChild(childRow);\n\n\t\t// isConnected (check via findRealNode)\n\t\tconst dt = getDevtools();\n\t\tif (dt && node.id != null) {\n\t\t\tconst realNode = dt.findRealNode(node.id);\n\t\t\tconst connected = realNode ? (realNode as Element).isConnected : false;\n\t\t\tconst connRow = document.createElement(\"div\");\n\t\t\tconnRow.className = \"sidebar-row\";\n\t\t\tconnRow.innerHTML = `<span class=\"sidebar-key\">isConnected</span><span class=\"sidebar-val\">${connected}</span>`;\n\t\t\tsidebar.appendChild(connRow);\n\t\t}\n\n\t\t// Attributes\n\t\tconst attrs = node.attributes ?? {};\n\t\tconst attrKeys = Object.keys(attrs);\n\t\tif (attrKeys.length > 0) {\n\t\t\tconst attrTitle = document.createElement(\"div\");\n\t\t\tattrTitle.className = \"sidebar-title\";\n\t\t\tattrTitle.textContent = \"Attributes\";\n\t\t\tsidebar.appendChild(attrTitle);\n\n\t\t\tfor (const key of attrKeys) {\n\t\t\t\tconst row = document.createElement(\"div\");\n\t\t\t\trow.className = \"sidebar-row\";\n\t\t\t\trow.innerHTML = `<span class=\"sidebar-key\">${escapeHtml(key)}</span><span class=\"sidebar-val\" title=\"${escapeHtml(attrs[key])}\">${escapeHtml(truncate(attrs[key], 30))}</span>`;\n\t\t\t\tsidebar.appendChild(row);\n\t\t\t}\n\t\t} else if (node.type === \"element\") {\n\t\t\tconst attrTitle = document.createElement(\"div\");\n\t\t\tattrTitle.className = \"sidebar-title\";\n\t\t\tattrTitle.textContent = \"Attributes\";\n\t\t\tsidebar.appendChild(attrTitle);\n\t\t\tconst emptyAttr = document.createElement(\"div\");\n\t\t\temptyAttr.className = \"sidebar-empty\";\n\t\t\temptyAttr.textContent = \"none\";\n\t\t\tsidebar.appendChild(emptyAttr);\n\t\t}\n\n\t\t// Event Listeners\n\t\tif (dt && node.id != null) {\n\t\t\tconst listeners = dt.getListenersForNode(node.id);\n\t\t\tconst listenerTitle = document.createElement(\"div\");\n\t\t\tlistenerTitle.className = \"sidebar-title\";\n\t\t\tlistenerTitle.textContent = `Event Listeners (${listeners.length})`;\n\t\t\tsidebar.appendChild(listenerTitle);\n\n\t\t\tif (listeners.length === 0) {\n\t\t\t\tconst emptyListeners = document.createElement(\"div\");\n\t\t\t\temptyListeners.className = \"sidebar-empty\";\n\t\t\t\temptyListeners.textContent = \"none\";\n\t\t\t\tsidebar.appendChild(emptyListeners);\n\t\t\t} else {\n\t\t\t\tfor (const listener of listeners) {\n\t\t\t\t\tconst listenerDiv = document.createElement(\"div\");\n\t\t\t\t\tlistenerDiv.className = \"sidebar-listener\";\n\t\t\t\t\tlistenerDiv.innerHTML =\n\t\t\t\t\t\t`<span class=\"sidebar-listener-event\">${escapeHtml(listener.eventName)}</span>` +\n\t\t\t\t\t\t`<span class=\"sidebar-listener-id\">${escapeHtml(listener.listenerId)}</span>`;\n\t\t\t\t\tsidebar.appendChild(listenerDiv);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Inline styles (from style attribute)\n\t\tif (attrs.style) {\n\t\t\tconst styleTitle = document.createElement(\"div\");\n\t\t\tstyleTitle.className = \"sidebar-title\";\n\t\t\tstyleTitle.textContent = \"Inline Styles\";\n\t\t\tsidebar.appendChild(styleTitle);\n\n\t\t\tconst parts = attrs.style.split(\";\").filter((s) => s.trim());\n\t\t\tfor (const part of parts) {\n\t\t\t\tconst colonIdx = part.indexOf(\":\");\n\t\t\t\tif (colonIdx === -1) continue;\n\t\t\t\tconst prop = part.slice(0, colonIdx).trim();\n\t\t\t\tconst val = part.slice(colonIdx + 1).trim();\n\t\t\t\tconst row = document.createElement(\"div\");\n\t\t\t\trow.className = \"sidebar-row\";\n\t\t\t\trow.innerHTML = `<span class=\"sidebar-key\">${escapeHtml(prop)}</span><span class=\"sidebar-val\">${escapeHtml(val)}</span>`;\n\t\t\t\tsidebar.appendChild(row);\n\t\t\t}\n\t\t}\n\n\t\t// Computed Styles (from real DOM node)\n\t\tif (dt && node.id != null) {\n\t\t\tconst realNode = dt.findRealNode(node.id) as HTMLElement | null;\n\t\t\tif (realNode && realNode.nodeType === 1 && typeof getComputedStyle === \"function\") {\n\t\t\t\tconst computed = getComputedStyle(realNode);\n\t\t\t\tconst keyProps = [\n\t\t\t\t\t\"display\",\n\t\t\t\t\t\"position\",\n\t\t\t\t\t\"width\",\n\t\t\t\t\t\"height\",\n\t\t\t\t\t\"margin\",\n\t\t\t\t\t\"padding\",\n\t\t\t\t\t\"color\",\n\t\t\t\t\t\"backgroundColor\",\n\t\t\t\t\t\"fontSize\",\n\t\t\t\t\t\"fontFamily\",\n\t\t\t\t\t\"overflow\",\n\t\t\t\t\t\"visibility\",\n\t\t\t\t\t\"opacity\",\n\t\t\t\t\t\"zIndex\",\n\t\t\t\t];\n\t\t\t\tconst styleTitle = document.createElement(\"div\");\n\t\t\t\tstyleTitle.className = \"sidebar-title\";\n\t\t\t\tstyleTitle.textContent = \"Computed Styles\";\n\t\t\t\tsidebar.appendChild(styleTitle);\n\n\t\t\t\tfor (const prop of keyProps) {\n\t\t\t\t\tconst val = computed.getPropertyValue(prop.replace(/([A-Z])/g, \"-$1\").toLowerCase());\n\t\t\t\t\tif (val) {\n\t\t\t\t\t\tconst row = document.createElement(\"div\");\n\t\t\t\t\t\trow.className = \"sidebar-row\";\n\t\t\t\t\t\trow.innerHTML =\n\t\t\t\t\t\t\t`<span class=\"sidebar-key\">${escapeHtml(prop)}</span>` +\n\t\t\t\t\t\t\t`<span class=\"sidebar-val sidebar-computed-val\">${escapeHtml(truncate(val, 24))}</span>`;\n\t\t\t\t\t\tsidebar.appendChild(row);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Recent mutations targeting this node (with action details)\n\t\tif (node.id != null) {\n\t\t\tconst nodeId = node.id;\n\t\t\tconst recentMuts = mutationLog.filter((entry) => {\n\t\t\t\tconst m = entry.mutation as Record<string, unknown>;\n\t\t\t\treturn m.id === nodeId;\n\t\t\t});\n\t\t\tconst mutTitle = document.createElement(\"div\");\n\t\t\tmutTitle.className = \"sidebar-title\";\n\t\t\tmutTitle.textContent = `Mutation History (${recentMuts.length})`;\n\t\t\tsidebar.appendChild(mutTitle);\n\n\t\t\tif (recentMuts.length === 0) {\n\t\t\t\tconst emptyMut = document.createElement(\"div\");\n\t\t\t\temptyMut.className = \"sidebar-empty\";\n\t\t\t\temptyMut.textContent = \"none captured\";\n\t\t\t\tsidebar.appendChild(emptyMut);\n\t\t\t} else {\n\t\t\t\tconst last10 = recentMuts.slice(-10);\n\t\t\t\tfor (const entry of last10) {\n\t\t\t\t\tconst m = entry.mutation as Record<string, unknown>;\n\t\t\t\t\tlet detail = \"\";\n\t\t\t\t\tif (m.name) detail += ` ${m.name}`;\n\t\t\t\t\tif (m.property) detail += ` .${m.property}`;\n\t\t\t\t\tif (m.value !== undefined) detail += `=\"${truncate(String(m.value), 20)}\"`;\n\t\t\t\t\tif (m.tag) detail += ` <${m.tag}>`;\n\t\t\t\t\tif (m.textContent !== undefined) detail += ` \"${truncate(String(m.textContent), 20)}\"`;\n\t\t\t\t\tif (m.childId !== undefined) detail += ` child:${m.childId}`;\n\n\t\t\t\t\tconst div = document.createElement(\"div\");\n\t\t\t\t\tdiv.className = \"sidebar-mutation\";\n\t\t\t\t\tdiv.innerHTML =\n\t\t\t\t\t\t`<span class=\"sidebar-mut-time\">${formatTime(entry.timestamp)}</span> ` +\n\t\t\t\t\t\t`<span class=\"sidebar-mut-action\">${escapeHtml(entry.action)}</span>` +\n\t\t\t\t\t\t(detail\n\t\t\t\t\t\t\t? `<br><span style=\"color:#808080;font-size:9px;padding-left:4px\">${escapeHtml(detail.trim())}</span>`\n\t\t\t\t\t\t\t: \"\");\n\t\t\t\t\tsidebar.appendChild(div);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Feature 19: \"Why Was This Node Updated?\" section\n\t\tif (node.id != null) {\n\t\t\tconst nodeId = node.id;\n\t\t\tconst dt2 = getDevtools();\n\t\t\tif (dt2?.getMutationCorrelation) {\n\t\t\t\tconst correlation = dt2.getMutationCorrelation();\n\t\t\t\tconst whyEntries = correlation.getWhyUpdated(nodeId);\n\n\t\t\t\tconst whyTitle = document.createElement(\"div\");\n\t\t\t\twhyTitle.className = \"why-updated-title\";\n\t\t\t\twhyTitle.textContent = `Why Updated? (${whyEntries.length})`;\n\t\t\t\tsidebar.appendChild(whyTitle);\n\n\t\t\t\tif (whyEntries.length === 0) {\n\t\t\t\t\tconst emptyWhy = document.createElement(\"div\");\n\t\t\t\t\temptyWhy.className = \"sidebar-empty\";\n\t\t\t\t\temptyWhy.textContent = \"no correlation data\";\n\t\t\t\t\tsidebar.appendChild(emptyWhy);\n\t\t\t\t} else {\n\t\t\t\t\tconst recentWhy = whyEntries.slice(-8);\n\t\t\t\t\tfor (const entry of recentWhy) {\n\t\t\t\t\t\tconst chain = document.createElement(\"div\");\n\t\t\t\t\t\tchain.className = \"why-updated-chain\";\n\n\t\t\t\t\t\t// mutation action\n\t\t\t\t\t\tlet html = `<span class=\"why-chain-mutation\">${escapeHtml(entry.action)}</span>`;\n\n\t\t\t\t\t\t// batch\n\t\t\t\t\t\tif (entry.batchUid != null) {\n\t\t\t\t\t\t\thtml += `<span class=\"why-chain-arrow\">\\u2192</span>`;\n\t\t\t\t\t\t\thtml += `<span class=\"why-chain-batch\">Batch #${entry.batchUid}</span>`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// causal event\n\t\t\t\t\t\tif (entry.causalEvent) {\n\t\t\t\t\t\t\thtml += `<span class=\"why-chain-arrow\">\\u2192</span>`;\n\t\t\t\t\t\t\thtml += `<span class=\"why-chain-event\">${escapeHtml(entry.causalEvent.eventType)}</span>`;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\thtml += `<span class=\"why-chain-arrow\">\\u2192</span>`;\n\t\t\t\t\t\t\thtml += `<span class=\"why-chain-none\">no event</span>`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tchain.innerHTML = html;\n\t\t\t\t\t\tsidebar.appendChild(chain);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsidebar.classList.add(\"visible\");\n\t}\n\n\tfunction renderTreeTab(): void {\n\t\t// Imported session: show tree if available\n\t\tif (importedSession) {\n\t\t\tif (importedSession.tree) {\n\t\t\t\tconst tree = importedSession.tree as TreeNode;\n\t\t\t\tconst layout = document.createElement(\"div\");\n\t\t\t\tlayout.className = \"tree-with-sidebar\";\n\t\t\t\tconst treeMain = document.createElement(\"div\");\n\t\t\t\ttreeMain.className = \"tree-main\";\n\t\t\t\tconst statusLine = document.createElement(\"div\");\n\t\t\t\tstatusLine.className = \"tree-refresh-bar\";\n\t\t\t\tconst statusText = document.createElement(\"span\");\n\t\t\t\tstatusText.className = \"tree-status\";\n\t\t\t\tstatusText.textContent = \"Imported session tree (read-only)\";\n\t\t\t\tstatusLine.appendChild(statusText);\n\t\t\t\ttreeMain.appendChild(statusLine);\n\t\t\t\tconst sidebar = document.createElement(\"div\") as HTMLDivElement;\n\t\t\t\tsidebar.className = \"node-sidebar\";\n\t\t\t\tconst fakeDt = getDevtools();\n\t\t\t\tif (fakeDt) {\n\t\t\t\t\tbuildTreeDOM(treeMain, tree, 0, true, fakeDt, sidebar);\n\t\t\t\t}\n\t\t\t\tlayout.appendChild(treeMain);\n\t\t\t\tlayout.appendChild(sidebar);\n\t\t\t\ttreeContent.innerHTML = \"\";\n\t\t\t\ttreeContent.appendChild(layout);\n\t\t\t} else {\n\t\t\t\ttreeContent.innerHTML = '<div class=\"tree-empty\">Imported session has no tree data.</div>';\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst dt = getDevtools();\n\t\tif (!dt) {\n\t\t\ttreeContent.innerHTML = '<div class=\"tree-empty\">Devtools API not available.</div>';\n\t\t\treturn;\n\t\t}\n\n\t\tconst allData = dt.getAllAppsData();\n\t\tconst appIds = Object.keys(allData);\n\n\t\tif (appIds.length === 0) {\n\t\t\ttreeContent.innerHTML =\n\t\t\t\t'<div class=\"tree-empty\">No apps registered. Click \\u21BB to refresh.</div>';\n\t\t\treturn;\n\t\t}\n\n\t\t// If multi-app, show selected app; if single, show only one\n\t\tconst targetAppId = selectedAppId && allData[selectedAppId] ? selectedAppId : appIds[0];\n\t\tconst data = allData[targetAppId];\n\n\t\tif (!data || !data.tree) {\n\t\t\ttreeContent.innerHTML =\n\t\t\t\t'<div class=\"tree-empty\">No virtual DOM tree received yet. Click \\u21BB to refresh.</div>';\n\t\t\treturn;\n\t\t}\n\n\t\tconst tree = data.tree as TreeNode;\n\n\t\t// Layout: tree + sidebar\n\t\tconst layout = document.createElement(\"div\");\n\t\tlayout.className = \"tree-with-sidebar\";\n\n\t\tconst treeMain = document.createElement(\"div\");\n\t\ttreeMain.className = \"tree-main\";\n\n\t\t// Feature 17: Snapshot/Diff bar\n\t\tconst snapshotBar = document.createElement(\"div\");\n\t\tsnapshotBar.className = \"snapshot-bar\";\n\n\t\tconst snapshotBtn = document.createElement(\"button\");\n\t\tsnapshotBtn.className = \"snapshot-btn\";\n\t\tsnapshotBtn.textContent = snapshot1\n\t\t\t? snapshot2\n\t\t\t\t? \"Reset Snapshots\"\n\t\t\t\t: \"Snapshot B\"\n\t\t\t: \"Snapshot A\";\n\t\tsnapshotBtn.addEventListener(\"click\", () => {\n\t\t\tif (snapshot1 && snapshot2) {\n\t\t\t\t// Reset\n\t\t\t\tsnapshot1 = null;\n\t\t\t\tsnapshot2 = null;\n\t\t\t\tshowDiff = false;\n\t\t\t\tcurrentDiff = null;\n\t\t\t} else if (!snapshot1) {\n\t\t\t\tsnapshot1 = cloneSnapshot(tree as unknown as TreeSnapshot);\n\t\t\t} else {\n\t\t\t\tsnapshot2 = cloneSnapshot(tree as unknown as TreeSnapshot);\n\t\t\t}\n\t\t\trenderTreeTab();\n\t\t});\n\t\tsnapshotBar.appendChild(snapshotBtn);\n\n\t\tif (snapshot1 && snapshot2) {\n\t\t\tconst diffBtn = document.createElement(\"button\");\n\t\t\tdiffBtn.className = \"snapshot-btn\";\n\t\t\tdiffBtn.textContent = showDiff ? \"Hide Diff\" : \"Show Diff\";\n\t\t\tdiffBtn.addEventListener(\"click\", () => {\n\t\t\t\tshowDiff = !showDiff;\n\t\t\t\tif (showDiff) {\n\t\t\t\t\tcurrentDiff = diffTrees(snapshot1, snapshot2);\n\t\t\t\t} else {\n\t\t\t\t\tcurrentDiff = null;\n\t\t\t\t}\n\t\t\t\trenderTreeTab();\n\t\t\t});\n\t\t\tsnapshotBar.appendChild(diffBtn);\n\t\t}\n\n\t\tconst snapshotInfo = document.createElement(\"span\");\n\t\tsnapshotInfo.className = \"snapshot-info\";\n\t\tif (snapshot1 && snapshot2) {\n\t\t\tsnapshotInfo.textContent = \"2 snapshots captured\";\n\t\t\tif (showDiff && currentDiff) {\n\t\t\t\tsnapshotInfo.textContent += hasChanges(currentDiff) ? \" (changes found)\" : \" (no changes)\";\n\t\t\t}\n\t\t} else if (snapshot1) {\n\t\t\tsnapshotInfo.textContent = \"1 snapshot captured\";\n\t\t}\n\t\tsnapshotBar.appendChild(snapshotInfo);\n\n\t\ttreeMain.appendChild(snapshotBar);\n\n\t\t// Status line\n\t\tconst statusLine = document.createElement(\"div\");\n\t\tstatusLine.className = \"tree-refresh-bar\";\n\t\tconst statusText = document.createElement(\"span\");\n\t\tstatusText.className = \"tree-status\";\n\t\tstatusText.textContent = `Virtual DOM for app: ${targetAppId}`;\n\t\tstatusLine.appendChild(statusText);\n\t\ttreeMain.appendChild(statusLine);\n\n\t\tconst sidebar = document.createElement(\"div\") as HTMLDivElement;\n\t\tsidebar.className = \"node-sidebar\";\n\n\t\t// Feature 17: if showing diff, render diff tree; otherwise normal tree\n\t\tif (showDiff && currentDiff) {\n\t\t\tbuildDiffTreeDOM(treeMain, currentDiff, 0, true, dt, sidebar);\n\t\t} else {\n\t\t\tbuildTreeDOM(treeMain, tree, 0, true, dt, sidebar);\n\t\t}\n\n\t\tlayout.appendChild(treeMain);\n\t\tlayout.appendChild(sidebar);\n\n\t\ttreeContent.innerHTML = \"\";\n\t\ttreeContent.appendChild(layout);\n\n\t\t// Mark that the tree has been rendered at least once so subsequent\n\t\t// rebuilds use expandedNodeIds instead of the depth-based default.\n\t\thasRenderedTree = true;\n\n\t\t// Refresh selectedNodeForSidebar to point at the new tree's node\n\t\t// so the sidebar shows up-to-date metadata after a rebuild.\n\t\tif (selectedNodeForSidebar && selectedNodeForSidebar.id != null) {\n\t\t\tconst freshNode = findTreeNodeById(tree, selectedNodeForSidebar.id);\n\t\t\tif (freshNode) {\n\t\t\t\tselectedNodeForSidebar = freshNode;\n\t\t\t}\n\t\t}\n\n\t\t// If we had a selected node, try to render sidebar for it\n\t\tif (selectedNodeForSidebar) {\n\t\t\trenderNodeSidebar(sidebar, selectedNodeForSidebar);\n\t\t}\n\t}\n\n\t/** Recursively find a TreeNode by its numeric id. */\n\tfunction findTreeNodeById(root: TreeNode, targetId: number): TreeNode | null {\n\t\tif (root.id === targetId) return root;\n\t\tfor (const child of root.children ?? []) {\n\t\t\tconst found = findTreeNodeById(child, targetId);\n\t\t\tif (found) return found;\n\t\t}\n\t\treturn null;\n\t}\n\n\tfunction buildTreeDOM(\n\t\tparent: HTMLElement,\n\t\tnode: TreeNode,\n\t\tdepth: number,\n\t\texpanded: boolean,\n\t\tdt: DevtoolsAPI,\n\t\tsidebar: HTMLDivElement,\n\t): void {\n\t\tconst wrapper = document.createElement(\"div\");\n\t\twrapper.className = `tree-node${expanded ? \" expanded\" : \"\"}`;\n\n\t\tconst line = document.createElement(\"div\");\n\t\tline.className = \"tree-line\";\n\t\tline.style.paddingLeft = `${depth * 14}px`;\n\n\t\t// Helper to select node in sidebar\n\t\tfunction selectForSidebar(): void {\n\t\t\t// Remove previous selection highlight\n\t\t\tconst prev = parent.closest(\".tree-with-sidebar\")?.querySelector(\".tree-line.selected\");\n\t\t\tif (prev) prev.classList.remove(\"selected\");\n\t\t\tline.classList.add(\"selected\");\n\n\t\t\tselectedNodeForSidebar = node;\n\t\t\trenderNodeSidebar(sidebar, node);\n\t\t}\n\n\t\tif (node.type === \"text\") {\n\t\t\tconst toggle = document.createElement(\"span\");\n\t\t\ttoggle.className = \"tree-toggle\";\n\t\t\tline.appendChild(toggle);\n\n\t\t\tconst textSpan = document.createElement(\"span\");\n\t\t\ttextSpan.className = \"tree-text-node\";\n\t\t\ttextSpan.textContent = `\"${truncate((node.text ?? \"\").trim(), 50)}\"`;\n\t\t\tline.appendChild(textSpan);\n\n\t\t\tif (node.id != null) {\n\t\t\t\tconst idSpan = document.createElement(\"span\");\n\t\t\t\tidSpan.className = \"tree-nodeid\";\n\t\t\t\tidSpan.textContent = `_${node.id}`;\n\t\t\t\tline.appendChild(idSpan);\n\t\t\t}\n\n\t\t\tline.addEventListener(\"click\", selectForSidebar);\n\t\t\twrapper.appendChild(line);\n\t\t\tparent.appendChild(wrapper);\n\t\t\treturn;\n\t\t}\n\n\t\tif (node.type === \"comment\") {\n\t\t\tconst toggle = document.createElement(\"span\");\n\t\t\ttoggle.className = \"tree-toggle\";\n\t\t\tline.appendChild(toggle);\n\n\t\t\tconst commentSpan = document.createElement(\"span\");\n\t\t\tcommentSpan.className = \"tree-comment\";\n\t\t\tcommentSpan.textContent = `<!-- ${truncate(node.text ?? \"\", 40)} -->`;\n\t\t\tline.appendChild(commentSpan);\n\n\t\t\tline.addEventListener(\"click\", selectForSidebar);\n\t\t\twrapper.appendChild(line);\n\t\t\tparent.appendChild(wrapper);\n\t\t\treturn;\n\t\t}\n\n\t\t// Element node\n\t\tconst children = node.children ?? [];\n\t\tconst hasChildren = children.length > 0;\n\n\t\t// Determine expanded state from expandedNodeIds (or default on first render)\n\t\tlet isExpanded: boolean;\n\t\tif (node.id != null && hasRenderedTree) {\n\t\t\tisExpanded = expandedNodeIds.has(node.id);\n\t\t} else {\n\t\t\t// First render or node without id: use the depth-based default\n\t\t\tisExpanded = expanded;\n\t\t\tif (node.id != null && isExpanded) {\n\t\t\t\texpandedNodeIds.add(node.id);\n\t\t\t}\n\t\t}\n\t\t// Update wrapper class to reflect computed expanded state\n\t\twrapper.className = `tree-node${isExpanded ? \" expanded\" : \"\"}`;\n\n\t\tconst toggleEl = document.createElement(\"span\");\n\t\ttoggleEl.className = \"tree-toggle\";\n\t\ttoggleEl.textContent = hasChildren ? (isExpanded ? \"\\u25BC\" : \"\\u25B6\") : \" \";\n\t\tline.appendChild(toggleEl);\n\n\t\t// Build tag string: <tag .className #id>\n\t\tconst tag = (node.tag ?? \"???\").toLowerCase();\n\t\tconst tagSpan = document.createElement(\"span\");\n\t\tlet html = `<span class=\"tree-tag\"><${escapeHtml(tag)}</span>`;\n\n\t\tconst attrs = node.attributes ?? {};\n\t\tif (attrs.id) {\n\t\t\thtml += ` <span class=\"tree-attr-name\">id</span>=<span class=\"tree-attr-value\">\"${escapeHtml(attrs.id)}\"</span>`;\n\t\t}\n\t\tif (node.className) {\n\t\t\tconst cls = truncate(node.className, 30);\n\t\t\thtml += ` <span class=\"tree-attr-name\">class</span>=<span class=\"tree-attr-value\">\"${escapeHtml(cls)}\"</span>`;\n\t\t}\n\n\t\t// Show up to 2 extra attributes\n\t\tlet shownAttrs = 0;\n\t\tfor (const attrName in attrs) {\n\t\t\tif (attrName === \"id\" || attrName === \"class\") continue;\n\t\t\tif (shownAttrs >= 2) break;\n\t\t\thtml += ` <span class=\"tree-attr-name\">${escapeHtml(attrName)}</span>=<span class=\"tree-attr-value\">\"${escapeHtml(truncate(attrs[attrName], 20))}\"</span>`;\n\t\t\tshownAttrs++;\n\t\t}\n\n\t\thtml += `<span class=\"tree-tag\">></span>`;\n\t\ttagSpan.innerHTML = html;\n\t\tline.appendChild(tagSpan);\n\n\t\tif (node.id != null) {\n\t\t\tconst nidSpan = document.createElement(\"span\");\n\t\t\tnidSpan.className = \"tree-nodeid\";\n\t\t\tnidSpan.textContent = `_${node.id}`;\n\t\t\tline.appendChild(nidSpan);\n\t\t}\n\n\t\t// Click: toggle children, select for sidebar, or highlight real DOM node\n\t\tline.addEventListener(\"click\", (e: MouseEvent) => {\n\t\t\tif (hasChildren && e.target === toggleEl) {\n\t\t\t\twrapper.classList.toggle(\"expanded\");\n\t\t\t\tconst nowExpanded = wrapper.classList.contains(\"expanded\");\n\t\t\t\ttoggleEl.textContent = nowExpanded ? \"\\u25BC\" : \"\\u25B6\";\n\t\t\t\t// Track expand/collapse state so it survives tree rebuilds\n\t\t\t\tif (node.id != null) {\n\t\t\t\t\tif (nowExpanded) {\n\t\t\t\t\t\texpandedNodeIds.add(node.id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\texpandedNodeIds.delete(node.id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Select for sidebar inspection\n\t\t\tselectForSidebar();\n\t\t\t// Also highlight real DOM node via findRealNode\n\t\t\tif (node.id != null) {\n\t\t\t\tconst realNode = dt.findRealNode(node.id) as HTMLElement | null;\n\t\t\t\tif (realNode && \"scrollIntoView\" in realNode) {\n\t\t\t\t\trealNode.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n\t\t\t\t\tconst prev = realNode.style.outline;\n\t\t\t\t\tconst prevOffset = realNode.style.outlineOffset;\n\t\t\t\t\trealNode.style.outline = \"3px solid #007acc\";\n\t\t\t\t\trealNode.style.outlineOffset = \"2px\";\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\trealNode.style.outline = prev;\n\t\t\t\t\t\trealNode.style.outlineOffset = prevOffset;\n\t\t\t\t\t}, 1500);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\twrapper.appendChild(line);\n\n\t\tif (hasChildren) {\n\t\t\tconst childrenDiv = document.createElement(\"div\");\n\t\t\tchildrenDiv.className = \"tree-children\";\n\t\t\tfor (const child of children) {\n\t\t\t\tbuildTreeDOM(childrenDiv, child, depth + 1, depth < 2, dt, sidebar);\n\t\t\t}\n\t\t\twrapper.appendChild(childrenDiv);\n\t\t}\n\n\t\tparent.appendChild(wrapper);\n\t}\n\n\t// ---- Feature 17: Diff tree rendering ----\n\n\tfunction buildDiffTreeDOM(\n\t\tparent: HTMLElement,\n\t\tdiff: TreeDiffNode,\n\t\tdepth: number,\n\t\texpanded: boolean,\n\t\tdt: DevtoolsAPI,\n\t\tsidebar: HTMLDivElement,\n\t): void {\n\t\tconst node = diff.node;\n\t\tconst wrapper = document.createElement(\"div\");\n\t\twrapper.className = `tree-node${expanded ? \" expanded\" : \"\"}`;\n\n\t\tconst line = document.createElement(\"div\");\n\t\tline.className = \"tree-line\";\n\t\tline.style.paddingLeft = `${depth * 14}px`;\n\n\t\t// Apply diff styling\n\t\tif (diff.diffType === \"added\") line.classList.add(\"diff-added\");\n\t\telse if (diff.diffType === \"removed\") line.classList.add(\"diff-removed\");\n\t\telse if (diff.diffType === \"changed\") line.classList.add(\"diff-changed\");\n\n\t\tconst children = diff.children ?? [];\n\t\tconst hasChildren = children.length > 0;\n\n\t\tif (node.type === \"text\") {\n\t\t\tconst toggle = document.createElement(\"span\");\n\t\t\ttoggle.className = \"tree-toggle\";\n\t\t\tline.appendChild(toggle);\n\n\t\t\tconst textSpan = document.createElement(\"span\");\n\t\t\ttextSpan.className = \"tree-text-node\";\n\t\t\ttextSpan.textContent = `\"${truncate((node.text ?? \"\").trim(), 50)}\"`;\n\t\t\tline.appendChild(textSpan);\n\n\t\t\tappendDiffMarker(line, diff);\n\t\t\twrapper.appendChild(line);\n\t\t\tparent.appendChild(wrapper);\n\t\t\treturn;\n\t\t}\n\n\t\tif (node.type === \"comment\") {\n\t\t\tconst toggle = document.createElement(\"span\");\n\t\t\ttoggle.className = \"tree-toggle\";\n\t\t\tline.appendChild(toggle);\n\n\t\t\tconst commentSpan = document.createElement(\"span\");\n\t\t\tcommentSpan.className = \"tree-comment\";\n\t\t\tcommentSpan.textContent = `<!-- ${truncate(node.text ?? \"\", 40)} -->`;\n\t\t\tline.appendChild(commentSpan);\n\n\t\t\tappendDiffMarker(line, diff);\n\t\t\twrapper.appendChild(line);\n\t\t\tparent.appendChild(wrapper);\n\t\t\treturn;\n\t\t}\n\n\t\t// Element node\n\t\t// Determine expanded state from expandedNodeIds (or default on first render)\n\t\tlet isExpanded: boolean;\n\t\tif (node.id != null && hasRenderedTree) {\n\t\t\tisExpanded = expandedNodeIds.has(node.id);\n\t\t} else {\n\t\t\tisExpanded = expanded;\n\t\t\tif (node.id != null && isExpanded) {\n\t\t\t\texpandedNodeIds.add(node.id);\n\t\t\t}\n\t\t}\n\t\twrapper.className = `tree-node${isExpanded ? \" expanded\" : \"\"}`;\n\n\t\tconst toggleEl = document.createElement(\"span\");\n\t\ttoggleEl.className = \"tree-toggle\";\n\t\ttoggleEl.textContent = hasChildren ? (isExpanded ? \"\\u25BC\" : \"\\u25B6\") : \" \";\n\t\tline.appendChild(toggleEl);\n\n\t\tconst tag = (node.tag ?? \"???\").toLowerCase();\n\t\tconst tagSpan = document.createElement(\"span\");\n\t\tlet html = `<span class=\"tree-tag\"><${escapeHtml(tag)}</span>`;\n\t\tconst attrs = node.attributes ?? {};\n\t\tif (attrs.id) {\n\t\t\thtml += ` <span class=\"tree-attr-name\">id</span>=<span class=\"tree-attr-value\">\"${escapeHtml(attrs.id)}\"</span>`;\n\t\t}\n\t\tif (node.className) {\n\t\t\thtml += ` <span class=\"tree-attr-name\">class</span>=<span class=\"tree-attr-value\">\"${escapeHtml(truncate(node.className, 30))}\"</span>`;\n\t\t}\n\t\thtml += `<span class=\"tree-tag\">></span>`;\n\t\ttagSpan.innerHTML = html;\n\t\tline.appendChild(tagSpan);\n\n\t\tif (node.id != null) {\n\t\t\tconst nidSpan = document.createElement(\"span\");\n\t\t\tnidSpan.className = \"tree-nodeid\";\n\t\t\tnidSpan.textContent = `_${node.id}`;\n\t\t\tline.appendChild(nidSpan);\n\t\t}\n\n\t\tappendDiffMarker(line, diff);\n\n\t\tif (hasChildren) {\n\t\t\ttoggleEl.addEventListener(\"click\", (e) => {\n\t\t\t\te.stopPropagation();\n\t\t\t\twrapper.classList.toggle(\"expanded\");\n\t\t\t\tconst nowExpanded = wrapper.classList.contains(\"expanded\");\n\t\t\t\ttoggleEl.textContent = nowExpanded ? \"\\u25BC\" : \"\\u25B6\";\n\t\t\t\tif (node.id != null) {\n\t\t\t\t\tif (nowExpanded) {\n\t\t\t\t\t\texpandedNodeIds.add(node.id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\texpandedNodeIds.delete(node.id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\twrapper.appendChild(line);\n\n\t\tif (hasChildren) {\n\t\t\tconst childrenDiv = document.createElement(\"div\");\n\t\t\tchildrenDiv.className = \"tree-children\";\n\t\t\tfor (const child of children) {\n\t\t\t\tbuildDiffTreeDOM(childrenDiv, child, depth + 1, depth < 2, dt, sidebar);\n\t\t\t}\n\t\t\twrapper.appendChild(childrenDiv);\n\t\t}\n\n\t\tparent.appendChild(wrapper);\n\t}\n\n\tfunction appendDiffMarker(line: HTMLElement, diff: TreeDiffNode): void {\n\t\tif (diff.diffType === \"unchanged\") return;\n\t\tconst marker = document.createElement(\"span\");\n\t\tmarker.className = `diff-marker ${diff.diffType}`;\n\t\tif (diff.diffType === \"added\") marker.textContent = \"+ADD\";\n\t\telse if (diff.diffType === \"removed\") marker.textContent = \"-DEL\";\n\t\telse if (diff.diffType === \"changed\") {\n\t\t\tmarker.textContent = `~${(diff.changes ?? []).join(\",\")}`;\n\t\t}\n\t\tline.appendChild(marker);\n\t}\n\n\t// ---- Performance rendering ----\n\n\tfunction renderPerfTab(): void {\n\t\t// Imported session: show read-only scheduler stats\n\t\tif (importedSession) {\n\t\t\tconst ss = importedSession.schedulerStats;\n\t\t\tlet html = '<div class=\"perf-section-title\">Imported Session (read-only)</div>';\n\t\t\tfor (const [key, val] of Object.entries(ss)) {\n\t\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">${escapeHtml(String(key))}</span><span class=\"perf-value\">${escapeHtml(String(val))}</span></div>`;\n\t\t\t}\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Exported At</span><span class=\"perf-value\">${escapeHtml(importedSession.exportedAt)}</span></div>`;\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Mutations</span><span class=\"perf-value\">${importedSession.mutationLog.length}</span></div>`;\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Warnings</span><span class=\"perf-value\">${importedSession.warningLog.length}</span></div>`;\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Events</span><span class=\"perf-value\">${importedSession.eventLog.length}</span></div>`;\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Sync Reads</span><span class=\"perf-value\">${importedSession.syncReadLog.length}</span></div>`;\n\t\t\tperfContent.innerHTML = html;\n\t\t\treturn;\n\t\t}\n\n\t\tconst dt = getDevtools();\n\t\tif (!dt) {\n\t\t\tperfContent.innerHTML =\n\t\t\t\t'<div class=\"perf-row\"><span class=\"perf-label\">Devtools API not available.</span></div>';\n\t\t\treturn;\n\t\t}\n\n\t\tconst stats = dt.scheduler.stats();\n\t\tconst pending = stats.pending;\n\n\t\t// Track queue depth history (guard against duplicate pushes on manual refresh)\n\t\tif (stats.frameId !== lastQueuePushFrameId) {\n\t\t\tqueueHistory.push(pending);\n\t\t\tif (queueHistory.length > MAX_HISTORY) queueHistory.shift();\n\t\t\tlastQueuePushFrameId = stats.frameId;\n\t\t}\n\n\t\tlet html = \"\";\n\n\t\t// Scheduler section with Flush button\n\t\thtml +=\n\t\t\t'<div class=\"perf-section-title\">Scheduler<button class=\"flush-btn\" id=\"flush-btn\">\\u23E9 Flush</button></div>';\n\n\t\tlet pendingClass = \"\";\n\t\tif (pending > 1000) pendingClass = \"red\";\n\t\telse if (pending > 100) pendingClass = \"yellow\";\n\t\telse pendingClass = \"green\";\n\n\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Pending</span><span class=\"perf-value ${pendingClass}\">${pending}</span></div>`;\n\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Frame ID</span><span class=\"perf-value\">${stats.frameId}</span></div>`;\n\n\t\tconst ftClass =\n\t\t\tstats.lastFrameTimeMs > 16 ? \"red\" : stats.lastFrameTimeMs > 12 ? \"yellow\" : \"green\";\n\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Frame Time</span><span class=\"perf-value ${ftClass}\">${stats.lastFrameTimeMs.toFixed(1)}ms</span></div>`;\n\n\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Frame Actions</span><span class=\"perf-value\">${stats.lastFrameActions}</span></div>`;\n\n\t\tconst runClass = stats.isRunning ? \"green\" : \"yellow\";\n\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Running</span><span class=\"perf-value ${runClass}\">${stats.isRunning ? \"Yes\" : \"No\"}</span></div>`;\n\n\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Last Tick</span><span class=\"perf-value\">${stats.lastTickTime > 0 ? `${stats.lastTickTime.toFixed(0)}ms` : \"N/A\"}</span></div>`;\n\n\t\t// Worker-to-main cross-thread latency (real, from Date.now() diff)\n\t\tconst workerLatencyMs = stats.workerToMainLatencyMs;\n\t\tif (workerLatencyMs > 0 && stats.frameId !== lastLatencyPushFrameId) {\n\t\t\tlatencyHistory.push(workerLatencyMs);\n\t\t\tif (latencyHistory.length > MAX_LATENCY_HISTORY) latencyHistory.shift();\n\t\t\tlastLatencyPushFrameId = stats.frameId;\n\t\t}\n\t\tconst workerLatencyClass = latencyColorClass(workerLatencyMs);\n\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Worker\\u2192Main</span><span class=\"perf-value ${workerLatencyClass}\">${workerLatencyMs > 0 ? `${workerLatencyMs.toFixed(1)}ms` : \"N/A\"}</span></div>`;\n\n\t\t// Enqueue-to-apply latency (intra-main-thread)\n\t\tconst enqueueLatencyMs = stats.enqueueToApplyMs;\n\t\tconst enqueueLatencyClass = latencyColorClass(enqueueLatencyMs);\n\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Enqueue\\u2192Apply</span><span class=\"perf-value ${enqueueLatencyClass}\">${enqueueLatencyMs > 0 ? `${enqueueLatencyMs.toFixed(1)}ms` : \"N/A\"}</span></div>`;\n\n\t\t// Latency percentiles\n\t\tif (latencyHistory.length > 0) {\n\t\t\tconst pcts = computePercentiles(latencyHistory);\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Latency P50</span><span class=\"perf-value ${latencyColorClass(pcts.p50)}\">${pcts.p50.toFixed(1)}ms</span></div>`;\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Latency P95</span><span class=\"perf-value ${latencyColorClass(pcts.p95)}\">${pcts.p95.toFixed(1)}ms</span></div>`;\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Latency P99</span><span class=\"perf-value ${latencyColorClass(pcts.p99)}\">${pcts.p99.toFixed(1)}ms</span></div>`;\n\t\t}\n\n\t\t// Latency sparkline\n\t\tif (latencyHistory.length > 1) {\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Latency (${MAX_LATENCY_HISTORY})</span><span class=\"perf-sparkline\">${sparkline(latencyHistory)}</span></div>`;\n\t\t}\n\n\t\t// Dropped frames counter (Feature 7)\n\t\tconst droppedFrames = stats.droppedFrameCount;\n\t\tconst droppedClass = droppedFrames > 0 ? \"red\" : \"green\";\n\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Dropped Frames</span><span class=\"perf-value ${droppedClass}\">${droppedFrames}</span></div>`;\n\n\t\t// Queue depth sparkline with 16ms threshold reference\n\t\tif (queueHistory.length > 1) {\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Queue (${MAX_HISTORY}f)</span><span class=\"sparkline-with-threshold\"><span class=\"perf-sparkline\">${sparkline(queueHistory)}</span><span class=\"sparkline-threshold\"></span></span></div>`;\n\t\t}\n\n\t\t// Apps section\n\t\tconst apps = dt.apps();\n\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Apps</span><span class=\"perf-value\">${apps.length}</span></div>`;\n\n\t\t// Worker stats per app (from cached debug data)\n\t\tconst allData = dt.getAllAppsData();\n\t\tfor (const appId of apps) {\n\t\t\tconst data = allData[appId];\n\t\t\tif (!data?.workerStats) continue;\n\n\t\t\tconst ws = data.workerStats as { added: number; coalesced: number; flushed: number };\n\t\t\thtml += `<div class=\"perf-section-title\">Worker: ${escapeHtml(appId)}</div>`;\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Mutations Added</span><span class=\"perf-value\">${ws.added}</span></div>`;\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Mutations Coalesced</span><span class=\"perf-value\">${ws.coalesced}</span></div>`;\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Mutations Flushed</span><span class=\"perf-value\">${ws.flushed}</span></div>`;\n\n\t\t\tconst coalescingRatio = ws.added > 0 ? ((ws.coalesced / ws.added) * 100).toFixed(1) : \"0.0\";\n\t\t\tconst ratioClass =\n\t\t\t\tNumber.parseFloat(coalescingRatio) > 50\n\t\t\t\t\t? \"green\"\n\t\t\t\t\t: Number.parseFloat(coalescingRatio) > 20\n\t\t\t\t\t\t? \"yellow\"\n\t\t\t\t\t\t: \"\";\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Coalescing Ratio</span><span class=\"perf-value ${ratioClass}\">${coalescingRatio}%</span></div>`;\n\t\t}\n\n\t\t// Main Thread Stats (DebugStats)\n\t\tif (dt.debugStats) {\n\t\t\tconst ds = dt.debugStats();\n\t\t\thtml += '<div class=\"perf-section-title\">Main Thread Stats</div>';\n\t\t\tconst statKeys: Array<[string, string]> = [\n\t\t\t\t[\"mutationsAdded\", \"Mutations Added\"],\n\t\t\t\t[\"mutationsCoalesced\", \"Mutations Coalesced\"],\n\t\t\t\t[\"mutationsFlushed\", \"Mutations Flushed\"],\n\t\t\t\t[\"mutationsApplied\", \"Mutations Applied\"],\n\t\t\t\t[\"eventsForwarded\", \"Events Forwarded\"],\n\t\t\t\t[\"eventsDispatched\", \"Events Dispatched\"],\n\t\t\t\t[\"syncReadRequests\", \"Sync Read Requests\"],\n\t\t\t\t[\"syncReadTimeouts\", \"Sync Read Timeouts\"],\n\t\t\t];\n\t\t\tfor (const [key, label] of statKeys) {\n\t\t\t\tconst val = ds[key] ?? 0;\n\t\t\t\tconst valClass = key === \"syncReadTimeouts\" && val > 0 ? \"red\" : \"\";\n\t\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">${escapeHtml(label)}</span><span class=\"perf-value ${valClass}\">${val}</span></div>`;\n\t\t\t}\n\t\t}\n\n\t\t// Frame budget flamechart\n\t\tconst frameLog = dt.scheduler.frameLog();\n\t\tif (frameLog.length > 0) {\n\t\t\thtml += '<div class=\"frame-section-title\">Frames</div>';\n\t\t\tconst budget = 16;\n\t\t\tfor (const frame of frameLog) {\n\t\t\t\tconst pct = Math.min((frame.totalMs / budget) * 100, 100);\n\t\t\t\tconst ratio = frame.totalMs / budget;\n\t\t\t\tlet colorClass: string;\n\t\t\t\tif (ratio > 1) colorClass = \"red\";\n\t\t\t\telse if (ratio > 0.5) colorClass = \"yellow\";\n\t\t\t\telse colorClass = \"green\";\n\t\t\t\tconst warn = frame.totalMs > budget ? \" !\" : \"\";\n\t\t\t\thtml += `<div class=\"frame-bar-row\" data-frame-id=\"${frame.frameId}\">`;\n\t\t\t\thtml += `<span class=\"frame-label\">#${frame.frameId}</span>`;\n\t\t\t\thtml += `<span class=\"frame-bar-track\"><span class=\"frame-bar-fill ${colorClass}\" style=\"width:${pct.toFixed(1)}%\"></span></span>`;\n\t\t\t\thtml += `<span class=\"frame-info\">${frame.totalMs.toFixed(1)}ms / ${budget}ms (${frame.actionCount})${warn}</span>`;\n\t\t\t\thtml += \"</div>\";\n\t\t\t\tif (expandedFrameId === frame.frameId) {\n\t\t\t\t\thtml += '<div class=\"frame-detail\">';\n\t\t\t\t\tconst entries = [...frame.timingBreakdown.entries()].sort((a, b) => b[1] - a[1]);\n\t\t\t\t\tfor (const [action, ms] of entries) {\n\t\t\t\t\t\thtml += `<div class=\"frame-detail-row\"><span class=\"frame-detail-action\">${escapeHtml(action)}</span><span class=\"frame-detail-time\">${ms.toFixed(2)}ms</span></div>`;\n\t\t\t\t\t}\n\t\t\t\t\thtml += \"</div>\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Coalescing Visualizer: per-type breakdown\n\t\tfor (const appId of apps) {\n\t\t\tconst data = allData[appId];\n\t\t\tif (!data?.perTypeCoalesced) continue;\n\n\t\t\tconst ptc = data.perTypeCoalesced as Record<string, { added: number; coalesced: number }>;\n\t\t\tconst actions = Object.keys(ptc);\n\t\t\tif (actions.length === 0) continue;\n\n\t\t\thtml += `<div class=\"perf-section-title\">Coalescing: ${escapeHtml(appId)}</div>`;\n\t\t\tfor (const action of actions) {\n\t\t\t\tconst c = ptc[action];\n\t\t\t\tconst pct = c.added > 0 ? ((c.coalesced / c.added) * 100).toFixed(0) : \"0\";\n\t\t\t\thtml += `<div class=\"coalesce-row\">`;\n\t\t\t\thtml += `<span class=\"coalesce-action\">${escapeHtml(action)}</span>`;\n\t\t\t\thtml += `<span class=\"coalesce-detail\">${c.added} added, ${c.coalesced} coalesced</span>`;\n\t\t\t\thtml += `<span class=\"coalesce-pct\">(${pct}%)</span>`;\n\t\t\t\thtml += \"</div>\";\n\t\t\t}\n\t\t}\n\n\t\t// Feature 16: Worker CPU Profiler entries\n\t\tif (dt.getWorkerPerfEntries) {\n\t\t\tconst allPerfEntries = dt.getWorkerPerfEntries();\n\t\t\tconst appIds16 = Object.keys(allPerfEntries);\n\t\t\tfor (const appId16 of appIds16) {\n\t\t\t\tconst entries = allPerfEntries[appId16];\n\t\t\t\tif (!entries || entries.length === 0) continue;\n\n\t\t\t\thtml += `<div class=\"perf-section-title\">Worker CPU: ${escapeHtml(appId16)}</div>`;\n\n\t\t\t\t// Compute utilization: total duration vs wall time\n\t\t\t\tconst totalDuration = entries.reduce((s, e) => s + e.duration, 0);\n\t\t\t\tconst maxDuration = Math.max(...entries.map((e) => e.duration));\n\n\t\t\t\t// Group by name prefix (event vs flush)\n\t\t\t\tconst eventEntries = entries.filter((e) => e.name.includes(\":event:\"));\n\t\t\t\tconst flushEntries = entries.filter((e) => e.name.includes(\":flush:\"));\n\t\t\t\tconst eventTotal = eventEntries.reduce((s, e) => s + e.duration, 0);\n\t\t\t\tconst flushTotal = flushEntries.reduce((s, e) => s + e.duration, 0);\n\n\t\t\t\thtml += `<div class=\"worker-util\"><span class=\"worker-util-label\">Total worker time: </span><span class=\"worker-util-value\">${totalDuration.toFixed(1)}ms</span></div>`;\n\t\t\t\thtml += `<div class=\"worker-util\"><span class=\"worker-util-label\">Event handlers: </span><span class=\"worker-util-value\">${eventTotal.toFixed(1)}ms (${eventEntries.length} calls)</span></div>`;\n\t\t\t\thtml += `<div class=\"worker-util\"><span class=\"worker-util-label\">Flush/coalesce: </span><span class=\"worker-util-value\">${flushTotal.toFixed(1)}ms (${flushEntries.length} calls)</span></div>`;\n\n\t\t\t\t// Show top entries by duration\n\t\t\t\tconst topEntries = entries\n\t\t\t\t\t.slice()\n\t\t\t\t\t.sort((a, b) => b.duration - a.duration)\n\t\t\t\t\t.slice(0, 10);\n\t\t\t\tfor (const entry of topEntries) {\n\t\t\t\t\tconst pct = maxDuration > 0 ? Math.max((entry.duration / maxDuration) * 100, 2) : 0;\n\t\t\t\t\tconst shortName = entry.name.replace(\"async-dom:\", \"\");\n\t\t\t\t\thtml += `<div class=\"worker-perf-bar\">`;\n\t\t\t\t\thtml += `<span class=\"worker-perf-name\" title=\"${escapeHtml(entry.name)}\">${escapeHtml(shortName)}</span>`;\n\t\t\t\t\thtml += `<span class=\"worker-perf-track\"><span class=\"worker-perf-fill\" style=\"width:${pct.toFixed(1)}%\"></span></span>`;\n\t\t\t\t\thtml += `<span class=\"worker-perf-duration\">${entry.duration.toFixed(2)}ms</span>`;\n\t\t\t\t\thtml += `</div>`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Feature 18: Multi-App Message Interleaving Timeline\n\t\tif (frameLog.length > 0) {\n\t\t\tconst framesWithPerApp = frameLog.filter((f) => f.perApp && f.perApp.size > 0);\n\t\t\tif (framesWithPerApp.length > 0) {\n\t\t\t\thtml += '<div class=\"perf-section-title\">Multi-App Interleaving</div>';\n\n\t\t\t\t// Collect all app IDs for legend\n\t\t\t\tconst allAppIds18 = new Set<string>();\n\t\t\t\tfor (const frame of framesWithPerApp) {\n\t\t\t\t\tif (frame.perApp) {\n\t\t\t\t\t\tfor (const key of frame.perApp.keys()) {\n\t\t\t\t\t\t\tallAppIds18.add(key);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst appColors18 = new Map<string, string>();\n\t\t\t\tconst palette = [\n\t\t\t\t\t\"#569cd6\",\n\t\t\t\t\t\"#4ec9b0\",\n\t\t\t\t\t\"#d7ba7d\",\n\t\t\t\t\t\"#c586c0\",\n\t\t\t\t\t\"#f44747\",\n\t\t\t\t\t\"#ce9178\",\n\t\t\t\t\t\"#6a9955\",\n\t\t\t\t];\n\t\t\t\tlet colorIdx = 0;\n\t\t\t\tfor (const appKey of allAppIds18) {\n\t\t\t\t\tappColors18.set(appKey, palette[colorIdx % palette.length]);\n\t\t\t\t\tcolorIdx++;\n\t\t\t\t}\n\n\t\t\t\t// Legend\n\t\t\t\thtml += '<div class=\"multiapp-legend\">';\n\t\t\t\tfor (const [appKey, color] of appColors18) {\n\t\t\t\t\thtml += `<span class=\"multiapp-legend-item\"><span class=\"multiapp-legend-dot\" style=\"background:${color}\"></span>${escapeHtml(appKey)}</span>`;\n\t\t\t\t}\n\t\t\t\thtml += \"</div>\";\n\n\t\t\t\t// Stacked bars per frame\n\t\t\t\tfor (const frame of framesWithPerApp.slice(-20)) {\n\t\t\t\t\tconst perApp = frame.perApp!;\n\t\t\t\t\tlet totalMuts = 0;\n\t\t\t\t\tlet totalDeferred = 0;\n\t\t\t\t\tfor (const [, data] of perApp) {\n\t\t\t\t\t\ttotalMuts += data.mutations;\n\t\t\t\t\t\ttotalDeferred += data.deferred;\n\t\t\t\t\t}\n\t\t\t\t\tif (totalMuts === 0) continue;\n\n\t\t\t\t\thtml += `<div class=\"multiapp-frame\">`;\n\t\t\t\t\thtml += `<span class=\"multiapp-frame-label\">#${frame.frameId}</span>`;\n\t\t\t\t\thtml += `<span class=\"multiapp-stacked-bar\">`;\n\t\t\t\t\tfor (const [appKey, data] of perApp) {\n\t\t\t\t\t\tconst pct = (data.mutations / totalMuts) * 100;\n\t\t\t\t\t\tconst color = appColors18.get(appKey) ?? \"#569cd6\";\n\t\t\t\t\t\thtml += `<span class=\"multiapp-segment\" style=\"width:${pct.toFixed(1)}%;background:${color}\" title=\"${escapeHtml(appKey)}: ${data.mutations} muts, ${data.deferred} deferred\"></span>`;\n\t\t\t\t\t}\n\t\t\t\t\thtml += `</span>`;\n\t\t\t\t\thtml += `<span class=\"multiapp-info\">${totalMuts} muts${totalDeferred > 0 ? ` (${totalDeferred} def)` : \"\"}</span>`;\n\t\t\t\t\thtml += `</div>`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Mutation Type Chart: horizontal bar chart from mutation log\n\t\tif (mutationLog.length > 0) {\n\t\t\tconst typeCounts = new Map<string, number>();\n\t\t\tfor (const entry of mutationLog) {\n\t\t\t\ttypeCounts.set(entry.action, (typeCounts.get(entry.action) ?? 0) + 1);\n\t\t\t}\n\t\t\tconst sorted = [...typeCounts.entries()].sort((a, b) => b[1] - a[1]);\n\t\t\tconst maxCount = sorted.length > 0 ? sorted[0][1] : 1;\n\n\t\t\thtml += '<div class=\"perf-section-title\">Mutation Types</div>';\n\t\t\tfor (const [action, count] of sorted) {\n\t\t\t\tconst pct = Math.max((count / maxCount) * 100, 2);\n\t\t\t\thtml += `<div class=\"chart-bar-row\">`;\n\t\t\t\thtml += `<span class=\"chart-bar-label\">${escapeHtml(action)}</span>`;\n\t\t\t\thtml += `<span class=\"chart-bar-track\"><span class=\"chart-bar-fill\" style=\"width:${pct.toFixed(1)}%\"></span></span>`;\n\t\t\t\thtml += `<span class=\"chart-bar-value\">${count}</span>`;\n\t\t\t\thtml += \"</div>\";\n\t\t\t}\n\t\t}\n\n\t\t// Sync Read Heatmap (Feature 12)\n\t\tif (syncReadLog.length > 0) {\n\t\t\tconst totalReads = syncReadLog.length;\n\t\t\tconst timeouts = syncReadLog.filter((e) => e.result === \"timeout\").length;\n\t\t\tconst timeoutRate = totalReads > 0 ? ((timeouts / totalReads) * 100).toFixed(1) : \"0.0\";\n\t\t\tconst syncLatencies = syncReadLog.map((e) => e.latencyMs);\n\t\t\tconst syncPcts = computePercentiles(syncLatencies);\n\n\t\t\thtml += '<div class=\"perf-section-title\">Sync Reads</div>';\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Total</span><span class=\"perf-value\">${totalReads}</span></div>`;\n\t\t\tconst timeoutClass = timeouts > 0 ? \"red\" : \"green\";\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Timeout Rate</span><span class=\"perf-value ${timeoutClass}\">${timeoutRate}% (${timeouts})</span></div>`;\n\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">P95 Latency</span><span class=\"perf-value ${syncReadColorClass(syncPcts.p95)}\">${syncPcts.p95.toFixed(1)}ms</span></div>`;\n\n\t\t\t// Heatmap blocks\n\t\t\thtml += '<div class=\"heatmap-container\">';\n\t\t\tconst recentReads = syncReadLog.slice(-100);\n\t\t\tconst queryNames = [\"boundingRect\", \"computedStyle\", \"nodeProperty\", \"windowProperty\"];\n\t\t\tfor (let i = 0; i < recentReads.length; i++) {\n\t\t\t\tconst entry = recentReads[i];\n\t\t\t\tconst colorCls = syncReadColorClass(entry.latencyMs);\n\t\t\t\tconst queryName = queryNames[entry.queryType] ?? `query:${entry.queryType}`;\n\t\t\t\thtml += `<div class=\"heatmap-block ${colorCls}\" data-sync-read-idx=\"${i}\" title=\"${entry.latencyMs.toFixed(1)}ms ${queryName} node=${entry.nodeId} ${entry.result}\"></div>`;\n\t\t\t}\n\t\t\thtml += \"</div>\";\n\t\t}\n\n\t\t// Transport section\n\t\tif (dt.getTransportStats) {\n\t\t\tconst transportStats = dt.getTransportStats();\n\t\t\tconst appIds = Object.keys(transportStats);\n\t\t\tif (appIds.length > 0) {\n\t\t\t\thtml += '<div class=\"perf-section-title\">Transport</div>';\n\t\t\t\tfor (const appId of appIds) {\n\t\t\t\t\tconst ts = transportStats[appId];\n\t\t\t\t\tif (!ts) continue;\n\t\t\t\t\tif (appIds.length > 1) {\n\t\t\t\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\" style=\"font-weight:600\">App: ${escapeHtml(appId)}</span><span class=\"perf-value\"></span></div>`;\n\t\t\t\t\t}\n\t\t\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Messages Sent</span><span class=\"perf-value\">${ts.messageCount}</span></div>`;\n\t\t\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Total Bytes</span><span class=\"perf-value\">${formatBytes(ts.totalBytes)}</span></div>`;\n\t\t\t\t\tconst avgBytes = ts.messageCount > 0 ? Math.round(ts.totalBytes / ts.messageCount) : 0;\n\t\t\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Avg Message Size</span><span class=\"perf-value\">${formatBytes(avgBytes)}</span></div>`;\n\t\t\t\t\tconst largestClass = ts.largestMessageBytes > 102400 ? \"red\" : \"\";\n\t\t\t\t\tconst largestWarn =\n\t\t\t\t\t\tts.largestMessageBytes > 102400\n\t\t\t\t\t\t\t? '<span class=\"transport-warn\">[!] exceeds 100KB</span>'\n\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Largest Message</span><span class=\"perf-value ${largestClass}\">${formatBytes(ts.largestMessageBytes)}${largestWarn}</span></div>`;\n\t\t\t\t\tconst lastClass = ts.lastMessageBytes > 102400 ? \"red\" : \"\";\n\t\t\t\t\tconst lastWarn =\n\t\t\t\t\t\tts.lastMessageBytes > 102400\n\t\t\t\t\t\t\t? '<span class=\"transport-warn\">[!] exceeds 100KB</span>'\n\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\thtml += `<div class=\"perf-row\"><span class=\"perf-label\">Last Message</span><span class=\"perf-value ${lastClass}\">${formatBytes(ts.lastMessageBytes)}${lastWarn}</span></div>`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tperfContent.innerHTML = html;\n\n\t\t// Wire sync read heatmap block click handlers\n\t\tconst heatmapBlocks = perfContent.querySelectorAll(\".heatmap-block\");\n\t\tconst queryNamesForClick = [\"boundingRect\", \"computedStyle\", \"nodeProperty\", \"windowProperty\"];\n\t\tfor (const block of heatmapBlocks) {\n\t\t\tblock.addEventListener(\"click\", (e) => {\n\t\t\t\tconst el = e.currentTarget as HTMLElement;\n\t\t\t\t// Remove any existing tooltip\n\t\t\t\tconst existing = el.querySelector(\".heatmap-tooltip\");\n\t\t\t\tif (existing) {\n\t\t\t\t\texisting.remove();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Remove tooltips from other blocks\n\t\t\t\tfor (const b of heatmapBlocks) {\n\t\t\t\t\tconst tip = b.querySelector(\".heatmap-tooltip\");\n\t\t\t\t\tif (tip) tip.remove();\n\t\t\t\t}\n\t\t\t\tconst idx = Number(el.dataset.syncReadIdx);\n\t\t\t\tconst recentReads = syncReadLog.slice(-100);\n\t\t\t\tconst entry = recentReads[idx];\n\t\t\t\tif (!entry) return;\n\t\t\t\tconst queryName = queryNamesForClick[entry.queryType] ?? `query:${entry.queryType}`;\n\t\t\t\tconst tooltip = document.createElement(\"div\");\n\t\t\t\ttooltip.className = \"heatmap-tooltip\";\n\t\t\t\ttooltip.textContent = `${queryName} node=${entry.nodeId} ${entry.latencyMs.toFixed(1)}ms ${entry.result}`;\n\t\t\t\tel.appendChild(tooltip);\n\t\t\t});\n\t\t}\n\n\t\t// Wire flush button\n\t\tconst flushBtn = perfContent.querySelector(\"#flush-btn\");\n\t\tif (flushBtn) {\n\t\t\tflushBtn.addEventListener(\"click\", (e) => {\n\t\t\t\te.stopPropagation();\n\t\t\t\tconst dtf = getDevtools();\n\t\t\t\tif (dtf) dtf.scheduler.flush();\n\t\t\t\trenderPerfTab();\n\t\t\t});\n\t\t}\n\n\t\t// Wire click handlers for frame rows\n\t\tconst frameRows = perfContent.querySelectorAll(\".frame-bar-row\");\n\t\tfor (const row of frameRows) {\n\t\t\trow.addEventListener(\"click\", () => {\n\t\t\t\tconst fid = Number((row as HTMLElement).dataset.frameId);\n\t\t\t\texpandedFrameId = expandedFrameId === fid ? null : fid;\n\t\t\t\trenderPerfTab();\n\t\t\t});\n\t\t}\n\t}\n\n\t// ---- Feature 15: Graph tab rendering (Causality DAG) ----\n\n\tfunction renderGraphTab(): void {\n\t\tconst dt = getDevtools();\n\t\tif (!dt?.getCausalityTracker) {\n\t\t\tgraphContent.innerHTML = '<div class=\"graph-empty\">Causality tracker not available.</div>';\n\t\t\treturn;\n\t\t}\n\n\t\tconst tracker = dt.getCausalityTracker();\n\t\tconst graph = tracker.buildGraph();\n\n\t\tif (graph.roots.length === 0) {\n\t\t\tgraphContent.innerHTML =\n\t\t\t\t'<div class=\"graph-empty\">No causality data yet. Interact with the app to generate event-to-mutation data.</div>';\n\t\t\treturn;\n\t\t}\n\n\t\tgraphContent.innerHTML = \"\";\n\n\t\tconst container = document.createElement(\"div\");\n\t\tcontainer.className = \"graph-container\";\n\n\t\t// Render each root and its subtree\n\t\tfor (const rootId of graph.roots) {\n\t\t\trenderGraphNode(container, graph, rootId, 0);\n\t\t}\n\n\t\tgraphContent.appendChild(container);\n\t}\n\n\tfunction renderGraphNode(\n\t\tparent: HTMLElement,\n\t\tgraph: CausalityGraph,\n\t\tnodeId: string,\n\t\tdepth: number,\n\t): void {\n\t\tconst node = graph.nodes.get(nodeId);\n\t\tif (!node) return;\n\n\t\tconst div = document.createElement(\"div\");\n\t\tdiv.style.paddingLeft = `${depth * 16}px`;\n\n\t\tconst line = document.createElement(\"div\");\n\t\tlet cssClass = \"graph-node\";\n\t\tif (node.type === \"event\") cssClass += \" event-node\";\n\t\telse if (node.type === \"batch\") cssClass += \" batch-node\";\n\t\telse cssClass += \" dom-node\";\n\t\tline.className = cssClass;\n\n\t\tconst typeSpan = document.createElement(\"span\");\n\t\ttypeSpan.className = `graph-node-type ${node.type}`;\n\t\ttypeSpan.textContent = node.type === \"event\" ? \"EVT\" : node.type === \"batch\" ? \"BAT\" : \"NOD\";\n\t\tline.appendChild(typeSpan);\n\n\t\tconst labelSpan = document.createElement(\"span\");\n\t\tlabelSpan.className = \"graph-node-label\";\n\t\tlabelSpan.textContent = node.label;\n\t\tline.appendChild(labelSpan);\n\n\t\tdiv.appendChild(line);\n\t\tparent.appendChild(div);\n\n\t\t// Render children\n\t\tif (node.children.length > 0) {\n\t\t\tconst childrenDiv = document.createElement(\"div\");\n\t\t\tchildrenDiv.className = \"graph-children\";\n\t\t\tfor (const childId of node.children) {\n\t\t\t\trenderGraphNode(childrenDiv, graph, childId, depth + 1);\n\t\t\t}\n\t\t\tparent.appendChild(childrenDiv);\n\t\t}\n\t}\n\n\t// ---- Log rendering ----\n\n\tlet lastRenderedLogLength = 0;\n\tlet lastRenderedFilterText = \"\";\n\tlet lastRenderedEventLogLength = 0;\n\tlet lastRenderedSyncReadLogLength = 0;\n\tlet showCoalesced = false;\n\n\tlogPauseBtn.addEventListener(\"click\", () => {\n\t\tlogPaused = !logPaused;\n\t\tlogPauseBtn.textContent = logPaused ? \"Resume\" : \"Pause\";\n\t\tlogPauseBtn.classList.toggle(\"active\", logPaused);\n\t});\n\n\tlogAutoScrollBtn.addEventListener(\"click\", () => {\n\t\tautoScroll = !autoScroll;\n\t\tlogAutoScrollBtn.classList.toggle(\"active\", autoScroll);\n\t});\n\n\tfunction getActionColorClass(action: string): string {\n\t\tswitch (action) {\n\t\t\tcase \"createNode\":\n\t\t\tcase \"createComment\":\n\t\t\tcase \"appendChild\":\n\t\t\tcase \"bodyAppendChild\":\n\t\t\tcase \"headAppendChild\":\n\t\t\tcase \"insertBefore\":\n\t\t\t\treturn \"color-green\";\n\t\t\tcase \"setAttribute\":\n\t\t\tcase \"removeAttribute\":\n\t\t\tcase \"setStyle\":\n\t\t\tcase \"setClassName\":\n\t\t\tcase \"setProperty\":\n\t\t\tcase \"setTextContent\":\n\t\t\tcase \"setHTML\":\n\t\t\tcase \"insertAdjacentHTML\":\n\t\t\t\treturn \"color-blue\";\n\t\t\tcase \"removeNode\":\n\t\t\tcase \"removeChild\":\n\t\t\t\treturn \"color-red\";\n\t\t\tdefault:\n\t\t\t\treturn \"\";\n\t\t}\n\t}\n\n\tfunction buildLogEntryDiv(entry: MutationLogEntry): HTMLDivElement {\n\t\tconst div = document.createElement(\"div\");\n\t\tconst colorClass = getActionColorClass(entry.action);\n\t\tdiv.className = `log-entry${colorClass ? ` ${colorClass}` : \"\"}`;\n\n\t\tconst timeSpan = document.createElement(\"span\");\n\t\ttimeSpan.className = \"log-time\";\n\t\ttimeSpan.textContent = formatTime(entry.timestamp);\n\t\tdiv.appendChild(timeSpan);\n\n\t\tconst actionSpan = document.createElement(\"span\");\n\t\tactionSpan.className = \"log-action\";\n\t\tactionSpan.textContent = entry.action;\n\t\tdiv.appendChild(actionSpan);\n\n\t\tconst detailSpan = document.createElement(\"span\");\n\t\tdetailSpan.className = \"log-detail\";\n\t\tconst nodeId = \"id\" in entry.mutation ? entry.mutation.id : undefined;\n\t\tlet detail = nodeId != null ? `#${nodeId}` : \"\";\n\t\tconst m = entry.mutation as Record<string, unknown>;\n\t\tif (m.tag) detail += ` tag=${m.tag}`;\n\t\tif (m.name && entry.action !== \"addEventListener\") detail += ` ${m.name}`;\n\t\tif (m.property) detail += ` ${m.property}`;\n\t\tdetailSpan.textContent = detail;\n\t\tdiv.appendChild(detailSpan);\n\n\t\treturn div;\n\t}\n\n\tfunction renderLogTab(): void {\n\t\t// Determine the source of mutations based on mode\n\t\tconst activeMutationLog = importedSession ? importedSession.mutationLog : mutationLog;\n\t\tconst activeEventLog = importedSession ? importedSession.eventLog : eventLog;\n\t\tconst activeSyncReadLog = importedSession ? importedSession.syncReadLog : syncReadLog;\n\n\t\t// In replay mode, show only entries up to currentIndex\n\t\tconst displayMutations = replayState\n\t\t\t? replayState.entries.slice(0, replayState.currentIndex)\n\t\t\t: activeMutationLog;\n\n\t\tlogCountSpan.textContent = String(displayMutations.length);\n\n\t\tif (displayMutations.length === 0) {\n\t\t\tif (lastRenderedLogLength !== 0 || replayState) {\n\t\t\t\tconst msg = replayState\n\t\t\t\t\t? \"Replay position: 0. Step forward to see mutations.\"\n\t\t\t\t\t: \"No mutations captured yet.\";\n\t\t\t\tlogList.innerHTML = `<div class=\"log-empty\">${msg}</div>`;\n\t\t\t\tlastRenderedLogLength = 0;\n\t\t\t\tlastRenderedFilterText = \"\";\n\t\t\t\tlastRenderedEventLogLength = 0;\n\t\t\t\tlastRenderedSyncReadLogLength = 0;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst filterText = logFilter.value.toLowerCase().trim();\n\n\t\t// Skip full rebuild if nothing has changed since last render\n\t\tconst needsFullRebuild =\n\t\t\treplayState !== null ||\n\t\t\tfilterText !== lastRenderedFilterText ||\n\t\t\tdisplayMutations.length !== lastRenderedLogLength ||\n\t\t\tactiveEventLog.length !== lastRenderedEventLogLength ||\n\t\t\tactiveSyncReadLog.length !== lastRenderedSyncReadLogLength;\n\n\t\tif (!needsFullRebuild) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst fragment = document.createDocumentFragment();\n\n\t\t// Group mutations by batchUid\n\t\tinterface BatchGroup {\n\t\t\tbatchUid: number | undefined;\n\t\t\tentries: MutationLogEntry[];\n\t\t}\n\t\tconst groups: BatchGroup[] = [];\n\t\tlet currentGroup: BatchGroup | null = null;\n\n\t\tfor (const entry of displayMutations) {\n\t\t\tif (filterText && !entry.action.toLowerCase().includes(filterText)) continue;\n\n\t\t\tconst uid = entry.batchUid;\n\t\t\tif (uid != null && currentGroup !== null && currentGroup.batchUid === uid) {\n\t\t\t\tcurrentGroup.entries.push(entry);\n\t\t\t} else {\n\t\t\t\tcurrentGroup = { batchUid: uid, entries: [entry] };\n\t\t\t\tgroups.push(currentGroup);\n\t\t\t}\n\t\t}\n\n\t\tfor (const group of groups) {\n\t\t\t// If no batchUid or only one entry, render flat\n\t\t\tif (group.batchUid == null || group.entries.length <= 1) {\n\t\t\t\tfor (const entry of group.entries) {\n\t\t\t\t\tfragment.appendChild(buildLogEntryDiv(entry));\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Render as collapsible batch group\n\t\t\tconst batchDiv = document.createElement(\"div\");\n\t\t\tbatchDiv.className = \"batch-group\";\n\n\t\t\tconst header = document.createElement(\"div\");\n\t\t\theader.className = \"batch-header\";\n\n\t\t\tconst toggle = document.createElement(\"span\");\n\t\t\ttoggle.className = \"batch-toggle\";\n\t\t\ttoggle.textContent = \"\\u25B6\";\n\t\t\theader.appendChild(toggle);\n\n\t\t\tconst uidSpan = document.createElement(\"span\");\n\t\t\tuidSpan.className = \"batch-uid\";\n\t\t\tuidSpan.textContent = `Batch #${group.batchUid}`;\n\t\t\theader.appendChild(uidSpan);\n\n\t\t\tconst countSpan = document.createElement(\"span\");\n\t\t\tcountSpan.className = \"batch-count\";\n\t\t\tcountSpan.textContent = `\\u2014 ${group.entries.length} mutations`;\n\t\t\theader.appendChild(countSpan);\n\n\t\t\theader.addEventListener(\"click\", () => {\n\t\t\t\tbatchDiv.classList.toggle(\"expanded\");\n\t\t\t\ttoggle.textContent = batchDiv.classList.contains(\"expanded\") ? \"\\u25BC\" : \"\\u25B6\";\n\t\t\t});\n\n\t\t\tbatchDiv.appendChild(header);\n\n\t\t\tconst entriesDiv = document.createElement(\"div\");\n\t\t\tentriesDiv.className = \"batch-entries\";\n\t\t\tfor (const entry of group.entries) {\n\t\t\t\tentriesDiv.appendChild(buildLogEntryDiv(entry));\n\t\t\t}\n\t\t\tbatchDiv.appendChild(entriesDiv);\n\n\t\t\tfragment.appendChild(batchDiv);\n\t\t}\n\n\t\tlogList.innerHTML = \"\";\n\t\tlogList.appendChild(fragment);\n\n\t\t// Highlight current replay entry\n\t\tif (replayState && replayState.currentIndex > 0) {\n\t\t\tconst allLogEntries = logList.querySelectorAll(\".log-entry\");\n\t\t\tconst targetIdx = replayState.currentIndex - 1;\n\t\t\tif (targetIdx < allLogEntries.length) {\n\t\t\t\tallLogEntries[targetIdx].classList.add(\"replay-highlight\");\n\t\t\t\tallLogEntries[targetIdx].scrollIntoView({ block: \"nearest\" });\n\t\t\t}\n\t\t}\n\n\t\t// Event round-trip tracer section with visual timeline bars\n\t\tconst dt = getDevtools();\n\t\tif (dt) {\n\t\t\tconst traces = dt.getEventTraces();\n\t\t\tif (traces.length > 0) {\n\t\t\t\tconst traceSection = document.createElement(\"div\");\n\t\t\t\ttraceSection.className = \"event-trace-section\";\n\n\t\t\t\tconst traceTitle = document.createElement(\"div\");\n\t\t\t\ttraceTitle.className = \"event-trace-title\";\n\t\t\t\ttraceTitle.textContent = `Event Round-Trips (${traces.length})`;\n\t\t\t\ttraceSection.appendChild(traceTitle);\n\n\t\t\t\tconst recent = traces.slice(-20);\n\n\t\t\t\t// Compute max total time for scaling bars\n\t\t\t\tlet maxTotalMs = 1;\n\t\t\t\tfor (const trace of recent) {\n\t\t\t\t\tconst total = trace.serializeMs + (trace.transportMs ?? 0) + (trace.dispatchMs ?? 0);\n\t\t\t\t\tif (total > maxTotalMs) maxTotalMs = total;\n\t\t\t\t}\n\n\t\t\t\tfor (const trace of recent) {\n\t\t\t\t\tconst serMs = trace.serializeMs;\n\t\t\t\t\tconst trnMs = trace.transportMs ?? 0;\n\t\t\t\t\tconst dspMs = trace.dispatchMs ?? 0;\n\t\t\t\t\tconst mutCount =\n\t\t\t\t\t\ttrace.mutationCount ??\n\t\t\t\t\t\tmutationLog.filter(\n\t\t\t\t\t\t\t(m) => m.timestamp >= trace.timestamp && m.timestamp <= trace.timestamp + 100,\n\t\t\t\t\t\t).length;\n\n\t\t\t\t\tconst totalMs = serMs + trnMs + dspMs;\n\t\t\t\t\tconst scale = 120 / (maxTotalMs || 1); // 120px max bar width\n\n\t\t\t\t\t// Timeline row\n\t\t\t\t\tconst row = document.createElement(\"div\");\n\t\t\t\t\trow.className = \"event-timeline\";\n\n\t\t\t\t\t// Event type label\n\t\t\t\t\tconst typeLabel = document.createElement(\"span\");\n\t\t\t\t\ttypeLabel.className = \"event-trace-type\";\n\t\t\t\t\ttypeLabel.style.cssText =\n\t\t\t\t\t\t\"width:60px;flex-shrink:0;font-size:10px;overflow:hidden;text-overflow:ellipsis;\";\n\t\t\t\t\ttypeLabel.textContent = `[${trace.eventType}]`;\n\t\t\t\t\trow.appendChild(typeLabel);\n\n\t\t\t\t\t// Serialize phase bar\n\t\t\t\t\tconst serBar = document.createElement(\"span\");\n\t\t\t\t\tserBar.className = \"event-phase serialize\";\n\t\t\t\t\tserBar.style.width = `${Math.max(serMs * scale, 4)}px`;\n\t\t\t\t\tserBar.title = `serialize: ${serMs.toFixed(1)}ms`;\n\t\t\t\t\trow.appendChild(serBar);\n\n\t\t\t\t\tconst serLabel = document.createElement(\"span\");\n\t\t\t\t\tserLabel.className = \"event-phase-label\";\n\t\t\t\t\tserLabel.textContent = `${serMs.toFixed(1)}ms`;\n\t\t\t\t\trow.appendChild(serLabel);\n\n\t\t\t\t\t// Arrow\n\t\t\t\t\tconst arrow1 = document.createElement(\"span\");\n\t\t\t\t\tarrow1.className = \"event-phase-label\";\n\t\t\t\t\tarrow1.textContent = \"\\u2192\";\n\t\t\t\t\trow.appendChild(arrow1);\n\n\t\t\t\t\t// Transport phase bar\n\t\t\t\t\tconst trnBar = document.createElement(\"span\");\n\t\t\t\t\ttrnBar.className = \"event-phase transport\";\n\t\t\t\t\ttrnBar.style.width = `${Math.max(trnMs * scale, 4)}px`;\n\t\t\t\t\ttrnBar.title = `transport: ${trnMs.toFixed(1)}ms`;\n\t\t\t\t\trow.appendChild(trnBar);\n\n\t\t\t\t\tconst trnLabel = document.createElement(\"span\");\n\t\t\t\t\ttrnLabel.className = \"event-phase-label\";\n\t\t\t\t\ttrnLabel.textContent = `${trnMs.toFixed(1)}ms`;\n\t\t\t\t\trow.appendChild(trnLabel);\n\n\t\t\t\t\t// Arrow\n\t\t\t\t\tconst arrow2 = document.createElement(\"span\");\n\t\t\t\t\tarrow2.className = \"event-phase-label\";\n\t\t\t\t\tarrow2.textContent = \"\\u2192\";\n\t\t\t\t\trow.appendChild(arrow2);\n\n\t\t\t\t\t// Dispatch phase bar\n\t\t\t\t\tconst dspBar = document.createElement(\"span\");\n\t\t\t\t\tdspBar.className = \"event-phase dispatch\";\n\t\t\t\t\tdspBar.style.width = `${Math.max(dspMs * scale, 4)}px`;\n\t\t\t\t\tdspBar.title = `dispatch: ${dspMs.toFixed(1)}ms`;\n\t\t\t\t\trow.appendChild(dspBar);\n\n\t\t\t\t\tconst dspLabel = document.createElement(\"span\");\n\t\t\t\t\tdspLabel.className = \"event-phase-label\";\n\t\t\t\t\tdspLabel.textContent = `${dspMs.toFixed(1)}ms`;\n\t\t\t\t\trow.appendChild(dspLabel);\n\n\t\t\t\t\t// Arrow + mutation count\n\t\t\t\t\tif (mutCount > 0) {\n\t\t\t\t\t\tconst arrow3 = document.createElement(\"span\");\n\t\t\t\t\t\tarrow3.className = \"event-phase-label\";\n\t\t\t\t\t\tarrow3.textContent = \"\\u2192\";\n\t\t\t\t\t\trow.appendChild(arrow3);\n\n\t\t\t\t\t\tconst mutSpan = document.createElement(\"span\");\n\t\t\t\t\t\tmutSpan.className = \"event-mutation-count\";\n\t\t\t\t\t\tmutSpan.textContent = `${mutCount} mut${mutCount !== 1 ? \"s\" : \"\"}`;\n\t\t\t\t\t\trow.appendChild(mutSpan);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Detail panel (shown on click)\n\t\t\t\t\tconst detail = document.createElement(\"div\");\n\t\t\t\t\tdetail.className = \"event-timeline-detail\";\n\t\t\t\t\tdetail.innerHTML =\n\t\t\t\t\t\t`<div><strong>${escapeHtml(trace.eventType)}</strong> total: ${totalMs.toFixed(1)}ms</div>` +\n\t\t\t\t\t\t`<div>main:serialize ${serMs.toFixed(2)}ms</div>` +\n\t\t\t\t\t\t`<div>transport ${trnMs.toFixed(2)}ms</div>` +\n\t\t\t\t\t\t`<div>worker:dispatch ${dspMs.toFixed(2)}ms</div>` +\n\t\t\t\t\t\t`<div>mutations generated: ${mutCount}</div>`;\n\n\t\t\t\t\trow.addEventListener(\"click\", () => {\n\t\t\t\t\t\tdetail.classList.toggle(\"visible\");\n\t\t\t\t\t});\n\n\t\t\t\t\ttraceSection.appendChild(row);\n\t\t\t\t\ttraceSection.appendChild(detail);\n\t\t\t\t}\n\n\t\t\t\tlogList.appendChild(traceSection);\n\t\t\t}\n\t\t}\n\n\t\t// Events section (Gap 4)\n\t\tif (activeEventLog.length > 0) {\n\t\t\tconst evtSection = document.createElement(\"div\");\n\t\t\tevtSection.className = \"log-section-title\";\n\t\t\tevtSection.textContent = `Events (${activeEventLog.length})`;\n\t\t\tlogList.appendChild(evtSection);\n\n\t\t\tconst recentEvents = activeEventLog.slice(-50);\n\t\t\tfor (const entry of recentEvents) {\n\t\t\t\tconst div = document.createElement(\"div\");\n\t\t\t\tdiv.className = \"log-entry event-entry\";\n\n\t\t\t\tconst timeSpan = document.createElement(\"span\");\n\t\t\t\ttimeSpan.className = \"log-time\";\n\t\t\t\ttimeSpan.textContent = formatTime(entry.timestamp);\n\t\t\t\tdiv.appendChild(timeSpan);\n\n\t\t\t\tconst actionSpan = document.createElement(\"span\");\n\t\t\t\tactionSpan.className = \"log-action\";\n\t\t\t\tactionSpan.textContent = entry.eventType;\n\t\t\t\tdiv.appendChild(actionSpan);\n\n\t\t\t\tconst detailSpan = document.createElement(\"span\");\n\t\t\t\tdetailSpan.className = \"log-detail\";\n\t\t\t\tdetailSpan.textContent = `${entry.phase}\\u2192${entry.phase === \"serialize\" ? \"dispatch\" : \"done\"} targetId=${entry.targetId ?? \"?\"}`;\n\t\t\t\tdiv.appendChild(detailSpan);\n\n\t\t\t\tlogList.appendChild(div);\n\t\t\t}\n\t\t}\n\n\t\t// Sync Reads section (Gap 4)\n\t\tif (activeSyncReadLog.length > 0) {\n\t\t\tconst syncSection = document.createElement(\"div\");\n\t\t\tsyncSection.className = \"log-section-title\";\n\t\t\tsyncSection.textContent = `Sync Reads (${activeSyncReadLog.length})`;\n\t\t\tlogList.appendChild(syncSection);\n\n\t\t\tconst recentReads = activeSyncReadLog.slice(-50);\n\t\t\tfor (const entry of recentReads) {\n\t\t\t\tconst div = document.createElement(\"div\");\n\t\t\t\tdiv.className = \"log-entry syncread-entry\";\n\n\t\t\t\tconst timeSpan = document.createElement(\"span\");\n\t\t\t\ttimeSpan.className = \"log-time\";\n\t\t\t\ttimeSpan.textContent = formatTime(entry.timestamp);\n\t\t\t\tdiv.appendChild(timeSpan);\n\n\t\t\t\tconst actionSpan = document.createElement(\"span\");\n\t\t\t\tactionSpan.className = \"log-action\";\n\t\t\t\tconst queryNames = [\"boundingRect\", \"computedStyle\", \"nodeProperty\", \"windowProperty\"];\n\t\t\t\tactionSpan.textContent = queryNames[entry.queryType] ?? `query:${entry.queryType}`;\n\t\t\t\tdiv.appendChild(actionSpan);\n\n\t\t\t\tconst detailSpan = document.createElement(\"span\");\n\t\t\t\tdetailSpan.className = \"log-detail\";\n\t\t\t\tdetailSpan.textContent = `node=${entry.nodeId} ${entry.latencyMs.toFixed(1)}ms ${entry.result}`;\n\t\t\t\tdiv.appendChild(detailSpan);\n\n\t\t\t\tlogList.appendChild(div);\n\t\t\t}\n\t\t}\n\n\t\t// Coalesced log section (Gap 2)\n\t\t{\n\t\t\tconst coalescedToggleDiv = document.createElement(\"div\");\n\t\t\tcoalescedToggleDiv.className = \"coalesced-toggle\";\n\t\t\tconst checkbox = document.createElement(\"input\");\n\t\t\tcheckbox.type = \"checkbox\";\n\t\t\tcheckbox.id = \"coalesced-toggle-cb\";\n\t\t\tcheckbox.checked = showCoalesced;\n\t\t\tconst label = document.createElement(\"label\");\n\t\t\tlabel.htmlFor = \"coalesced-toggle-cb\";\n\t\t\tlabel.textContent = \"Show coalesced\";\n\t\t\tcoalescedToggleDiv.appendChild(checkbox);\n\t\t\tcoalescedToggleDiv.appendChild(label);\n\t\t\tlogList.appendChild(coalescedToggleDiv);\n\n\t\t\tcheckbox.addEventListener(\"change\", () => {\n\t\t\t\tshowCoalesced = checkbox.checked;\n\t\t\t\trenderLogTab();\n\t\t\t});\n\n\t\t\tif (showCoalesced) {\n\t\t\t\tconst allData = dt ? dt.getAllAppsData() : {};\n\t\t\t\tlet allCoalesced: Array<{ action: string; key: string; timestamp: number }> = [];\n\t\t\t\tfor (const data of Object.values(allData)) {\n\t\t\t\t\tif (data?.coalescedLog && Array.isArray(data.coalescedLog)) {\n\t\t\t\t\t\tallCoalesced = allCoalesced.concat(\n\t\t\t\t\t\t\tdata.coalescedLog as Array<{ action: string; key: string; timestamp: number }>,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tallCoalesced.sort((a, b) => b.timestamp - a.timestamp);\n\t\t\t\tconst last50 = allCoalesced.slice(0, 50);\n\n\t\t\t\tif (last50.length > 0) {\n\t\t\t\t\tconst coalTitle = document.createElement(\"div\");\n\t\t\t\t\tcoalTitle.className = \"log-section-title\";\n\t\t\t\t\tcoalTitle.textContent = `Coalesced (${last50.length} of ${allCoalesced.length})`;\n\t\t\t\t\tlogList.appendChild(coalTitle);\n\n\t\t\t\t\tfor (const entry of last50) {\n\t\t\t\t\t\tconst div = document.createElement(\"div\");\n\t\t\t\t\t\tdiv.className = \"coalesced-entry\";\n\n\t\t\t\t\t\tconst timeSpan = document.createElement(\"span\");\n\t\t\t\t\t\ttimeSpan.className = \"log-time\";\n\t\t\t\t\t\ttimeSpan.textContent = formatTime(entry.timestamp);\n\t\t\t\t\t\tdiv.appendChild(timeSpan);\n\n\t\t\t\t\t\tconst actionSpan = document.createElement(\"span\");\n\t\t\t\t\t\tactionSpan.className = \"log-action\";\n\t\t\t\t\t\tactionSpan.textContent = entry.action;\n\t\t\t\t\t\tdiv.appendChild(actionSpan);\n\n\t\t\t\t\t\tconst detailSpan = document.createElement(\"span\");\n\t\t\t\t\t\tdetailSpan.className = \"log-detail\";\n\t\t\t\t\t\tdetailSpan.textContent = entry.key;\n\t\t\t\t\t\tdiv.appendChild(detailSpan);\n\n\t\t\t\t\t\tlogList.appendChild(div);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (autoScroll && !replayState) {\n\t\t\tlogList.scrollTop = logList.scrollHeight;\n\t\t}\n\t\tlastRenderedLogLength = displayMutations.length;\n\t\tlastRenderedFilterText = filterText;\n\t\tlastRenderedEventLogLength = activeEventLog.length;\n\t\tlastRenderedSyncReadLogLength = activeSyncReadLog.length;\n\t}\n\n\tlogFilter.addEventListener(\"input\", renderLogTab);\n\n\tlogClearBtn.addEventListener(\"click\", () => {\n\t\tmutationLog.length = 0;\n\t\tlastRenderedLogLength = 0;\n\t\tlastRenderedFilterText = \"\";\n\t\tlastRenderedEventLogLength = 0;\n\t\tlastRenderedSyncReadLogLength = 0;\n\t\tlogList.innerHTML = '<div class=\"log-empty\">No mutations captured yet.</div>';\n\t\tlogCountSpan.textContent = \"0\";\n\t});\n\n\t// ---- Warnings rendering ----\n\n\tlet lastRenderedWarningLength = 0;\n\tlet warnViewMode: \"grouped\" | \"chronological\" = \"grouped\";\n\tconst suppressedCodes = new Set<string>();\n\n\twarnViewToggle.addEventListener(\"click\", () => {\n\t\twarnViewMode = warnViewMode === \"grouped\" ? \"chronological\" : \"grouped\";\n\t\twarnViewToggle.textContent = warnViewMode === \"grouped\" ? \"Chronological\" : \"Grouped\";\n\t\twarnViewToggle.classList.toggle(\"active\", warnViewMode === \"chronological\");\n\t\tlastRenderedWarningLength = -1; // force re-render\n\t\trenderWarningsTab();\n\t});\n\n\twarnFilter.addEventListener(\"input\", () => {\n\t\tlastRenderedWarningLength = -1; // force re-render\n\t\trenderWarningsTab();\n\t});\n\n\tfunction buildWarnEntryDiv(entry: WarningLogEntry): HTMLDivElement {\n\t\tconst div = document.createElement(\"div\");\n\t\tdiv.className = \"warn-entry\";\n\n\t\tconst timeSpan = document.createElement(\"span\");\n\t\ttimeSpan.className = \"warn-time\";\n\t\ttimeSpan.textContent = formatTime(entry.timestamp);\n\t\tdiv.appendChild(timeSpan);\n\n\t\tconst codeSpan = document.createElement(\"span\");\n\t\tcodeSpan.className = `warn-code ${entry.code}`;\n\t\tcodeSpan.textContent = entry.code;\n\t\tdiv.appendChild(codeSpan);\n\n\t\tconst msgSpan = document.createElement(\"span\");\n\t\tmsgSpan.className = \"warn-msg\";\n\t\tconst firstLine = entry.message.split(\"\\n\")[0];\n\t\tconst hasStack = entry.message.includes(\"\\n\");\n\t\tmsgSpan.textContent = firstLine;\n\t\tdiv.appendChild(msgSpan);\n\n\t\tif (hasStack) {\n\t\t\tdiv.style.cursor = \"pointer\";\n\t\t\tconst stackPre = document.createElement(\"pre\");\n\t\t\tstackPre.className = \"warn-stack\";\n\t\t\tstackPre.textContent = entry.message;\n\t\t\tstackPre.style.display = \"none\";\n\t\t\tdiv.appendChild(stackPre);\n\t\t\tdiv.addEventListener(\"click\", () => {\n\t\t\t\tstackPre.style.display = stackPre.style.display === \"none\" ? \"block\" : \"none\";\n\t\t\t});\n\t\t}\n\n\t\treturn div;\n\t}\n\n\tfunction renderWarningsTab(): void {\n\t\tconst activeWarningLog = importedSession ? importedSession.warningLog : warningLog;\n\n\t\tif (activeWarningLog.length === 0) {\n\t\t\tif (lastRenderedWarningLength !== 0) {\n\t\t\t\twarnList.innerHTML = '<div class=\"warn-empty\">No warnings captured yet.</div>';\n\t\t\t\tlastRenderedWarningLength = 0;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (activeWarningLog.length === lastRenderedWarningLength) return;\n\n\t\tconst filterText = warnFilter.value.toLowerCase().trim();\n\t\tconst fragment = document.createDocumentFragment();\n\n\t\t// Filter warnings by text\n\t\tconst filtered = filterText\n\t\t\t? activeWarningLog.filter(\n\t\t\t\t\t(e) =>\n\t\t\t\t\t\te.code.toLowerCase().includes(filterText) ||\n\t\t\t\t\t\te.message.toLowerCase().includes(filterText),\n\t\t\t\t)\n\t\t\t: activeWarningLog;\n\n\t\t// Separate visible vs suppressed\n\t\tconst visible = filtered.filter((e) => !suppressedCodes.has(e.code));\n\t\tconst suppressedCount = filtered.length - visible.length;\n\n\t\tif (warnViewMode === \"chronological\") {\n\t\t\t// Flat chronological list (only non-suppressed)\n\t\t\tfor (const entry of visible) {\n\t\t\t\tfragment.appendChild(buildWarnEntryDiv(entry));\n\t\t\t}\n\t\t} else {\n\t\t\t// Grouped view\n\t\t\tconst groups = new Map<string, WarningLogEntry[]>();\n\t\t\tfor (const entry of visible) {\n\t\t\t\tlet arr = groups.get(entry.code);\n\t\t\t\tif (!arr) {\n\t\t\t\t\tarr = [];\n\t\t\t\t\tgroups.set(entry.code, arr);\n\t\t\t\t}\n\t\t\t\tarr.push(entry);\n\t\t\t}\n\n\t\t\tfor (const [code, entries] of groups) {\n\t\t\t\tconst groupDiv = document.createElement(\"div\");\n\t\t\t\tgroupDiv.className = \"warn-group\";\n\n\t\t\t\t// Header\n\t\t\t\tconst header = document.createElement(\"div\");\n\t\t\t\theader.className = \"warn-group-header\";\n\n\t\t\t\tconst toggle = document.createElement(\"span\");\n\t\t\t\ttoggle.className = \"warn-group-toggle\";\n\t\t\t\ttoggle.textContent = \"\\u25B6\";\n\t\t\t\theader.appendChild(toggle);\n\n\t\t\t\tconst codeSpan = document.createElement(\"span\");\n\t\t\t\tcodeSpan.className = `warn-group-code warn-code ${code}`;\n\t\t\t\tcodeSpan.textContent = code;\n\t\t\t\theader.appendChild(codeSpan);\n\n\t\t\t\tconst countSpan = document.createElement(\"span\");\n\t\t\t\tcountSpan.className = \"warn-group-count\";\n\t\t\t\tcountSpan.textContent = `(${entries.length})`;\n\t\t\t\theader.appendChild(countSpan);\n\n\t\t\t\tconst suppressBtn = document.createElement(\"button\");\n\t\t\t\tsuppressBtn.className = \"warn-suppress-btn\";\n\t\t\t\tsuppressBtn.textContent = \"Suppress\";\n\t\t\t\tsuppressBtn.addEventListener(\"click\", (e) => {\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t\tsuppressedCodes.add(code);\n\t\t\t\t\tlastRenderedWarningLength = -1; // force re-render\n\t\t\t\t\trenderWarningsTab();\n\t\t\t\t});\n\t\t\t\theader.appendChild(suppressBtn);\n\n\t\t\t\theader.addEventListener(\"click\", () => {\n\t\t\t\t\tgroupDiv.classList.toggle(\"expanded\");\n\t\t\t\t\ttoggle.textContent = groupDiv.classList.contains(\"expanded\") ? \"\\u25BC\" : \"\\u25B6\";\n\t\t\t\t});\n\n\t\t\t\tgroupDiv.appendChild(header);\n\n\t\t\t\t// Inline documentation\n\t\t\t\tconst desc = WarningDescriptions[code as keyof typeof WarningDescriptions];\n\t\t\t\tif (desc) {\n\t\t\t\t\tconst docDiv = document.createElement(\"div\");\n\t\t\t\t\tdocDiv.className = \"warn-group-doc\";\n\t\t\t\t\tconst descP = document.createElement(\"div\");\n\t\t\t\t\tdescP.className = \"warn-group-desc\";\n\t\t\t\t\tdescP.textContent = desc.description;\n\t\t\t\t\tdocDiv.appendChild(descP);\n\t\t\t\t\tconst sugP = document.createElement(\"div\");\n\t\t\t\t\tsugP.className = \"warn-group-suggestion\";\n\t\t\t\t\tsugP.textContent = `Suggestion: ${desc.suggestion}`;\n\t\t\t\t\tdocDiv.appendChild(sugP);\n\t\t\t\t\tgroupDiv.appendChild(docDiv);\n\t\t\t\t}\n\n\t\t\t\t// Entries\n\t\t\t\tconst entriesDiv = document.createElement(\"div\");\n\t\t\t\tentriesDiv.className = \"warn-group-entries\";\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tentriesDiv.appendChild(buildWarnEntryDiv(entry));\n\t\t\t\t}\n\t\t\t\tgroupDiv.appendChild(entriesDiv);\n\n\t\t\t\tfragment.appendChild(groupDiv);\n\t\t\t}\n\t\t}\n\n\t\twarnList.innerHTML = \"\";\n\t\twarnList.appendChild(fragment);\n\n\t\t// Suppressed note\n\t\tif (suppressedCount > 0) {\n\t\t\tconst note = document.createElement(\"div\");\n\t\t\tnote.className = \"warn-suppressed-note\";\n\t\t\tnote.textContent = `${suppressedCount} suppressed warning${suppressedCount !== 1 ? \"s\" : \"\"} hidden`;\n\t\t\tconst unsuppressBtn = document.createElement(\"button\");\n\t\t\tunsuppressBtn.className = \"warn-suppress-btn\";\n\t\t\tunsuppressBtn.textContent = \"Show all\";\n\t\t\tunsuppressBtn.style.marginLeft = \"8px\";\n\t\t\tunsuppressBtn.addEventListener(\"click\", () => {\n\t\t\t\tsuppressedCodes.clear();\n\t\t\t\tlastRenderedWarningLength = -1;\n\t\t\t\trenderWarningsTab();\n\t\t\t});\n\t\t\tnote.appendChild(unsuppressBtn);\n\t\t\twarnList.appendChild(note);\n\t\t}\n\n\t\twarnList.scrollTop = warnList.scrollHeight;\n\t\tlastRenderedWarningLength = activeWarningLog.length;\n\t}\n\n\twarnClearBtn.addEventListener(\"click\", () => {\n\t\twarningLog.length = 0;\n\t\twarningBadgeCount = 0;\n\t\tlastRenderedWarningLength = 0;\n\t\twarnList.innerHTML = '<div class=\"warn-empty\">No warnings captured yet.</div>';\n\t\tupdateWarningBadge();\n\t});\n\n\t// ---- Warning badge ----\n\n\tfunction updateWarningBadge(): void {\n\t\tif (warningBadgeCount > 0 && activeTab !== \"Warnings\") {\n\t\t\twarningBadge.textContent = String(warningBadgeCount > 99 ? \"99+\" : warningBadgeCount);\n\t\t\twarningBadge.style.display = \"inline-block\";\n\t\t} else {\n\t\t\twarningBadge.style.display = \"none\";\n\t\t}\n\t\t// Update collapsed tab text (preserving the health dot element)\n\t\ttoggleTabText.textContent =\n\t\t\twarningBadgeCount > 0\n\t\t\t\t? `async-dom (${warningBadgeCount > 99 ? \"99+\" : warningBadgeCount}) \\u25B2`\n\t\t\t\t: \"async-dom \\u25B2\";\n\t}\n\n\tonWarningBadgeUpdate = updateWarningBadge;\n\n\t// ---- Polling ----\n\n\tfunction startPolling(): void {\n\t\tstopPolling();\n\n\t\t// Tree: request + render every 2 seconds\n\t\ttreePollTimer = setInterval(() => {\n\t\t\tif (activeTab === \"Tree\") {\n\t\t\t\tconst dt = getDevtools();\n\t\t\t\tif (dt) dt.refreshDebugData();\n\t\t\t\ttreeRefreshTimeout = setTimeout(() => {\n\t\t\t\t\ttreeRefreshTimeout = null;\n\t\t\t\t\trenderTreeTab();\n\t\t\t\t}, 250);\n\t\t\t}\n\t\t}, 2000);\n\n\t\t// Performance: poll every 1 second (also refresh worker stats)\n\t\tperfPollTimer = setInterval(() => {\n\t\t\tif (activeTab === \"Performance\") {\n\t\t\t\tconst dt = getDevtools();\n\t\t\t\tif (dt) dt.refreshDebugData();\n\t\t\t\tperfRefreshTimeout = setTimeout(() => {\n\t\t\t\t\tperfRefreshTimeout = null;\n\t\t\t\t\trenderPerfTab();\n\t\t\t\t}, 250);\n\t\t\t}\n\t\t}, 1000);\n\n\t\t// Log + warnings + graph: poll every 500ms\n\t\tlogRenderTimer = setInterval(() => {\n\t\t\tif (activeTab === \"Log\") renderLogTab();\n\t\t\tif (activeTab === \"Warnings\") renderWarningsTab();\n\t\t\tif (activeTab === \"Graph\") renderGraphTab();\n\t\t}, 500);\n\n\t\t// Render current tab immediately\n\t\trenderActiveTab();\n\t}\n\n\tfunction stopPolling(): void {\n\t\tif (treePollTimer) {\n\t\t\tclearInterval(treePollTimer);\n\t\t\ttreePollTimer = null;\n\t\t}\n\t\tif (perfPollTimer) {\n\t\t\tclearInterval(perfPollTimer);\n\t\t\tperfPollTimer = null;\n\t\t}\n\t\tif (logRenderTimer) {\n\t\t\tclearInterval(logRenderTimer);\n\t\t\tlogRenderTimer = null;\n\t\t}\n\t}\n\n\treturn {\n\t\tdestroy(): void {\n\t\t\tstopPolling();\n\t\t\tif (replayTimer) {\n\t\t\t\tclearInterval(replayTimer);\n\t\t\t\treplayTimer = null;\n\t\t\t}\n\t\t\t// Cancel pending setTimeout callbacks\n\t\t\tif (treeRefreshTimeout) {\n\t\t\t\tclearTimeout(treeRefreshTimeout);\n\t\t\t\ttreeRefreshTimeout = null;\n\t\t\t}\n\t\t\tif (perfRefreshTimeout) {\n\t\t\t\tclearTimeout(perfRefreshTimeout);\n\t\t\t\tperfRefreshTimeout = null;\n\t\t\t}\n\t\t\tif (manualRefreshTimeout) {\n\t\t\t\tclearTimeout(manualRefreshTimeout);\n\t\t\t\tmanualRefreshTimeout = null;\n\t\t\t}\n\t\t\tclearInterval(healthDotTimer);\n\t\t\tonWarningBadgeUpdate = null;\n\t\t\t// Reset module-level state for clean re-creation (e.g., HMR)\n\t\t\tmutationLog.length = 0;\n\t\t\twarningLog.length = 0;\n\t\t\teventLog.length = 0;\n\t\t\tsyncReadLog.length = 0;\n\t\t\twarningBadgeCount = 0;\n\t\t\tlogPaused = false;\n\t\t\tisReplaying = false;\n\t\t\thost.remove();\n\t\t},\n\t};\n}\n","import { NodeCache } from \"../core/node-cache.ts\";\nimport type { AppId, NodeId, SerializedEvent } from \"../core/protocol.ts\";\nimport type { Transport } from \"../transport/base.ts\";\n\n/**\n * Trace record for a single DOM event round-trip, tracking:\n * - serializeMs: time to serialize the DOM event on the main thread\n * - transportMs: estimated message transit time (main -> worker -> main)\n * - dispatchMs: time the worker spent dispatching the event to handlers\n * - mutationCount: number of mutations the event handler produced\n */\nexport interface EventTraceEntry {\n\teventType: string;\n\tlistenerId: string;\n\t/** Time spent serializing the DOM event to a plain object. */\n\tserializeMs: number;\n\t/** performance.now() when the trace was created. */\n\ttimestamp: number;\n\t/** Date.now() when the event was sent, used to compute transportMs on response. */\n\tsentAt: number;\n\t/** Estimated round-trip transport time excluding worker dispatch time. */\n\ttransportMs?: number;\n\t/** Time the worker spent in event handler dispatch. */\n\tdispatchMs?: number;\n\t/** Number of mutations generated by the event handler. */\n\tmutationCount?: number;\n}\n\nconst MAX_EVENT_TRACES = 100;\n\n/**\n * Bridges real DOM events on the main thread to the worker thread.\n * Uses AbortController for clean listener removal.\n */\nexport class EventBridge {\n\t/** Map of listenerId -> AbortController, used for clean listener removal. */\n\tprivate listeners = new Map<\n\t\tstring,\n\t\t{ controller: AbortController; nodeId: NodeId; eventName: string }\n\t>();\n\t/** Per-event configuration (e.g., preventDefault) keyed by \"{nodeId}_{eventName}\". */\n\tprivate eventConfig = new Map<string, { preventDefault: boolean; passive?: boolean }>();\n\tprivate nodeCache: NodeCache;\n\tprivate transport: Transport | null = null;\n\tprivate appId: AppId;\n\t/** Rolling buffer of the last MAX_EVENT_TRACES event traces for diagnostics. */\n\tprivate eventTraces: EventTraceEntry[] = [];\n\tprivate _onTimingResult: ((trace: EventTraceEntry) => void) | null = null;\n\n\tconstructor(appId: AppId, nodeCache?: NodeCache) {\n\t\tthis.appId = appId;\n\t\tthis.nodeCache = nodeCache ?? new NodeCache();\n\t}\n\n\t/**\n\t * Set a callback that is invoked whenever a trace entry is fully\n\t * populated with worker timing data. This allows callers (e.g. the\n\t * devtools debug hooks) to emit EventLogEntry objects.\n\t */\n\tset onTimingResult(cb: ((trace: EventTraceEntry) => void) | null) {\n\t\tthis._onTimingResult = cb;\n\t}\n\n\tsetTransport(transport: Transport): void {\n\t\tthis.transport = transport;\n\t}\n\n\tsetNodeCache(nodeCache: NodeCache): void {\n\t\tthis.nodeCache = nodeCache;\n\t}\n\n\t/**\n\t * Configure event behavior for a specific node/event pair.\n\t * If preventDefault is set on a normally-passive event (e.g., touchstart),\n\t * the listener is detached and re-attached as non-passive so preventDefault works.\n\t */\n\tconfigureEvent(\n\t\tnodeId: NodeId,\n\t\teventName: string,\n\t\tconfig: { preventDefault: boolean; passive?: boolean },\n\t): void {\n\t\tthis.eventConfig.set(`${nodeId}_${eventName}`, config);\n\n\t\t// If setting preventDefault on a passive event, re-attach as non-passive\n\t\tif (config.preventDefault && isPassiveEvent(eventName)) {\n\t\t\tfor (const [listenerId, meta] of this.listeners.entries()) {\n\t\t\t\tif (meta.nodeId === nodeId && meta.eventName === eventName) {\n\t\t\t\t\t// Abort old listener\n\t\t\t\t\tmeta.controller.abort();\n\t\t\t\t\t// Re-attach as non-passive\n\t\t\t\t\tthis.attach(nodeId, eventName, listenerId);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Attach a real DOM event listener that serializes the event and sends it to the worker.\n\t * Uses AbortController for deterministic cleanup. Idempotent: re-attaching the same\n\t * listenerId aborts the previous listener first.\n\t */\n\tattach(nodeId: NodeId, eventName: string, listenerId: string): void {\n\t\tconst node = this.nodeCache.get(nodeId) as EventTarget | null;\n\t\tif (!node) return;\n\n\t\t// Idempotent: if this listener already exists, abort the old one first\n\t\tconst existing = this.listeners.get(listenerId);\n\t\tif (existing) {\n\t\t\texisting.controller.abort();\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tthis.listeners.set(listenerId, { controller, nodeId, eventName });\n\n\t\tconst passive = this._isPassiveForListener(listenerId, eventName);\n\n\t\tnode.addEventListener(\n\t\t\teventName,\n\t\t\t(domEvent: Event) => {\n\t\t\t\tconst configKey = `${nodeId}_${eventName}`;\n\t\t\t\tconst config = this.eventConfig.get(configKey);\n\t\t\t\tif (config?.preventDefault) {\n\t\t\t\t\tdomEvent.preventDefault();\n\t\t\t\t}\n\t\t\t\tconst serializeStart = performance.now();\n\t\t\t\tconst serialized = serializeEvent(domEvent, this.nodeCache);\n\t\t\t\tconst serializeMs = performance.now() - serializeStart;\n\t\t\t\tconst sentAt = Date.now();\n\t\t\t\tthis.eventTraces.push({\n\t\t\t\t\teventType: domEvent.type,\n\t\t\t\t\tlistenerId,\n\t\t\t\t\tserializeMs,\n\t\t\t\t\ttimestamp: performance.now(),\n\t\t\t\t\tsentAt,\n\t\t\t\t});\n\t\t\t\tif (this.eventTraces.length > MAX_EVENT_TRACES) {\n\t\t\t\t\tthis.eventTraces.shift();\n\t\t\t\t}\n\t\t\t\tthis.transport?.send({\n\t\t\t\t\ttype: \"event\",\n\t\t\t\t\tappId: this.appId,\n\t\t\t\t\tlistenerId,\n\t\t\t\t\tevent: serialized,\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ signal: controller.signal, passive },\n\t\t);\n\t}\n\n\t/** Remove a single listener by its ID, aborting the AbortController. */\n\tdetach(listenerId: string): void {\n\t\tconst meta = this.listeners.get(listenerId);\n\t\tif (meta) {\n\t\t\tmeta.controller.abort();\n\t\t\tthis.listeners.delete(listenerId);\n\t\t}\n\t}\n\n\t/** Remove all listeners attached to a specific node (called when a node is removed). */\n\tdetachByNodeId(nodeId: NodeId): void {\n\t\tfor (const [listenerId, meta] of this.listeners) {\n\t\t\tif (meta.nodeId === nodeId) {\n\t\t\t\tmeta.controller.abort();\n\t\t\t\tthis.listeners.delete(listenerId);\n\t\t\t}\n\t\t}\n\t}\n\n\tgetEventTraces(): EventTraceEntry[] {\n\t\treturn this.eventTraces.slice();\n\t}\n\n\t/**\n\t * Update the most recent trace entry for a given listener with\n\t * dispatch and mutation count timing from the worker.\n\t * Transport time is computed on the main thread to avoid cross-origin\n\t * timing issues between main thread and worker `performance.now()`.\n\t */\n\tupdateTraceWithWorkerTiming(listenerId: string, dispatchMs: number, mutationCount: number): void {\n\t\tconst receivedAt = Date.now();\n\t\t// Find the most recent trace that matches by listenerId, walking backwards\n\t\tfor (let i = this.eventTraces.length - 1; i >= 0; i--) {\n\t\t\tconst trace = this.eventTraces[i];\n\t\t\tif (trace.listenerId === listenerId && trace.transportMs === undefined) {\n\t\t\t\ttrace.transportMs = Math.max(0, receivedAt - trace.sentAt - dispatchMs);\n\t\t\t\ttrace.dispatchMs = dispatchMs;\n\t\t\t\ttrace.mutationCount = mutationCount;\n\t\t\t\tthis._onTimingResult?.(trace);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tgetListenersForNode(nodeId: NodeId): Array<{ listenerId: string; eventName: string }> {\n\t\tconst result: Array<{ listenerId: string; eventName: string }> = [];\n\t\tfor (const [listenerId, meta] of this.listeners) {\n\t\t\tif (meta.nodeId === nodeId) {\n\t\t\t\tresult.push({ listenerId, eventName: meta.eventName });\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Remove all listeners across all nodes. Called during teardown. */\n\tdetachAll(): void {\n\t\tfor (const meta of this.listeners.values()) {\n\t\t\tmeta.controller.abort();\n\t\t}\n\t\tthis.listeners.clear();\n\t}\n\n\tprivate _isPassiveForListener(_listenerId: string, eventName: string): boolean {\n\t\t// Check if this event has been configured with preventDefault\n\t\t// If so, it cannot be passive\n\t\tfor (const [key, config] of this.eventConfig.entries()) {\n\t\t\tif (key.endsWith(`_${eventName}`) && config.preventDefault) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn isPassiveEvent(eventName);\n\t}\n}\n\nconst PASSIVE_EVENTS = new Set([\"scroll\", \"touchstart\", \"touchmove\", \"wheel\", \"mousewheel\"]);\n\nfunction isPassiveEvent(name: string): boolean {\n\treturn PASSIVE_EVENTS.has(name);\n}\n\n/** Resolve a DOM element to its string NodeId using the cache, falling back to el.id. */\nfunction getNodeId(el: Element | null, cache?: NodeCache): string | null {\n\tif (!el) return null;\n\tif (cache) {\n\t\tconst id = cache.getId(el);\n\t\tif (id != null) return String(id);\n\t}\n\treturn el.id ?? null;\n}\n\n/**\n * Serialize a DOM event to a plain object that can be transferred via postMessage.\n * Only includes properties relevant to the event type.\n */\nfunction serializeEvent(e: Event, cache?: NodeCache): SerializedEvent {\n\t// Use composedPath()[0] for correct target when events cross shadow boundaries\n\tconst composedTarget = (e.composedPath?.()[0] ?? e.target) as Element;\n\tconst base: SerializedEvent = {\n\t\ttype: e.type,\n\t\ttarget: getNodeId(composedTarget, cache),\n\t\tcurrentTarget: getNodeId(e.currentTarget as Element, cache),\n\t\tbubbles: e.bubbles,\n\t\tcancelable: e.cancelable,\n\t\tcomposed: e.composed,\n\t\teventPhase: e.eventPhase,\n\t\tisTrusted: e.isTrusted,\n\t\ttimeStamp: e.timeStamp,\n\t};\n\n\t// Only preventDefault on click events on anchors\n\tif (e.type === \"click\") {\n\t\tif (e.target instanceof HTMLAnchorElement || e.currentTarget instanceof HTMLAnchorElement) {\n\t\t\te.preventDefault();\n\t\t}\n\t}\n\n\tif (e instanceof MouseEvent) {\n\t\tbase.clientX = e.clientX;\n\t\tbase.clientY = e.clientY;\n\t\tbase.pageX = e.pageX;\n\t\tbase.pageY = e.pageY;\n\t\tbase.screenX = e.screenX;\n\t\tbase.screenY = e.screenY;\n\t\tbase.offsetX = e.offsetX;\n\t\tbase.offsetY = e.offsetY;\n\t\tbase.button = e.button;\n\t\tbase.buttons = e.buttons;\n\t\tbase.altKey = e.altKey;\n\t\tbase.ctrlKey = e.ctrlKey;\n\t\tbase.metaKey = e.metaKey;\n\t\tbase.shiftKey = e.shiftKey;\n\t\tbase.relatedTarget = getNodeId(e.relatedTarget as Element, cache);\n\t\tbase.detail = e.detail;\n\t}\n\n\tif (e instanceof KeyboardEvent) {\n\t\tbase.key = e.key;\n\t\tbase.code = e.code;\n\t\tbase.keyCode = e.keyCode;\n\t\tbase.altKey = e.altKey;\n\t\tbase.ctrlKey = e.ctrlKey;\n\t\tbase.metaKey = e.metaKey;\n\t\tbase.shiftKey = e.shiftKey;\n\t}\n\n\tif (e instanceof InputEvent) {\n\t\tbase.data = e.data ?? undefined;\n\t\tbase.inputType = e.inputType;\n\t}\n\n\t// Serialize input element state for input/change events\n\tconst target = e.target;\n\tif (target instanceof HTMLInputElement) {\n\t\tbase.value = target.value;\n\t\tbase.checked = target.checked;\n\t} else if (target instanceof HTMLTextAreaElement) {\n\t\tbase.value = target.value;\n\t} else if (target instanceof HTMLSelectElement) {\n\t\tbase.value = target.value;\n\t\tbase.selectedIndex = target.selectedIndex;\n\t}\n\n\t// Serialize media element state for media events\n\tconst mediaTarget = e.target;\n\tif (mediaTarget instanceof HTMLMediaElement) {\n\t\tbase.currentTime = mediaTarget.currentTime;\n\t\tbase.duration = Number.isFinite(mediaTarget.duration) ? mediaTarget.duration : 0;\n\t\tbase.paused = mediaTarget.paused;\n\t\tbase.ended = mediaTarget.ended;\n\t\tbase.readyState = mediaTarget.readyState;\n\t}\n\n\tif (e instanceof FocusEvent) {\n\t\tbase.relatedTarget =\n\t\t\te.relatedTarget instanceof Element ? getNodeId(e.relatedTarget, cache) : null;\n\t}\n\n\tif (e instanceof WheelEvent) {\n\t\tObject.assign(base, {\n\t\t\tdeltaX: e.deltaX,\n\t\t\tdeltaY: e.deltaY,\n\t\t\tdeltaZ: e.deltaZ,\n\t\t\tdeltaMode: e.deltaMode,\n\t\t});\n\t}\n\n\treturn base;\n}\n","import type { MutationLogEntry, WarningLogEntry } from \"../core/debug.ts\";\nimport { WarningCode } from \"../core/debug.ts\";\nimport { sanitizeHTML } from \"../core/html-sanitizer.ts\";\nimport { NodeCache } from \"../core/node-cache.ts\";\nimport type { DomMutation, InsertPosition, NodeId } from \"../core/protocol.ts\";\nimport { BODY_NODE_ID, DOCUMENT_NODE_ID, HEAD_NODE_ID, HTML_NODE_ID } from \"../core/protocol.ts\";\n\nconst DANGEROUS_ATTR_NAMES = new Set([\"srcdoc\", \"formaction\"]);\nconst DANGEROUS_URI_ATTR_NAMES = new Set([\"href\", \"src\", \"data\", \"action\", \"xlink:href\"]);\n\nfunction isDangerousURI(value: string): boolean {\n\tconst trimmed = value.trim().toLowerCase();\n\treturn (\n\t\t/^\\s*javascript\\s*:/i.test(trimmed) ||\n\t\t/^\\s*vbscript\\s*:/i.test(trimmed) ||\n\t\t/^\\s*data\\s*:\\s*text\\/html/i.test(trimmed)\n\t);\n}\n\n/**\n * Security permissions controlling which mutation types the renderer will execute.\n * Defaults are restrictive; enable only what the app needs.\n */\nexport interface RendererPermissions {\n\t/** Allow appending nodes directly to <head> (e.g., for injecting styles). */\n\tallowHeadAppend: boolean;\n\t/** Allow appending nodes directly to <body>. */\n\tallowBodyAppend: boolean;\n\t/** Allow history.pushState/replaceState calls. */\n\tallowNavigation: boolean;\n\t/** Allow window.scrollTo calls. */\n\tallowScroll: boolean;\n\t/** Bypass HTML sanitization for innerHTML/insertAdjacentHTML. */\n\tallowUnsafeHTML: boolean;\n\t/** Additional DOM property names allowed for setProperty beyond the built-in list. */\n\tadditionalAllowedProperties?: string[];\n}\n\nconst DEFAULT_PERMISSIONS: RendererPermissions = {\n\tallowHeadAppend: false,\n\tallowBodyAppend: false,\n\tallowNavigation: true,\n\tallowScroll: true,\n\tallowUnsafeHTML: false,\n};\n\nconst ALLOWED_PROPERTIES = new Set([\n\t// Input\n\t\"value\",\n\t\"checked\",\n\t\"disabled\",\n\t\"selectedIndex\",\n\t\"indeterminate\",\n\t\"readOnly\",\n\t\"required\",\n\t\"placeholder\",\n\t\"type\",\n\t\"name\",\n\t// Scroll\n\t\"scrollTop\",\n\t\"scrollLeft\",\n\t// Text\n\t\"textContent\",\n\t\"nodeValue\",\n\t// Media\n\t\"src\",\n\t\"currentTime\",\n\t\"volume\",\n\t\"muted\",\n\t\"controls\",\n\t\"loop\",\n\t\"poster\",\n\t\"autoplay\",\n\t// Misc safe\n\t\"tabIndex\",\n\t\"title\",\n\t\"lang\",\n\t\"dir\",\n\t\"hidden\",\n\t\"draggable\",\n\t\"contentEditable\",\n\t\"htmlFor\",\n\t\"open\",\n\t\"selected\",\n\t\"multiple\",\n\t\"width\",\n\t\"height\",\n\t\"colSpan\",\n\t\"rowSpan\",\n]);\n\nconst ALLOWED_METHODS = new Set([\n\t\"play\",\n\t\"pause\",\n\t\"load\",\n\t\"focus\",\n\t\"blur\",\n\t\"click\",\n\t\"scrollIntoView\",\n\t\"requestFullscreen\",\n\t\"select\",\n\t\"setCustomValidity\",\n\t\"reportValidity\",\n\t\"showModal\",\n\t\"close\",\n]);\n\nconst SVG_TAGS = new Set([\n\t\"svg\",\n\t\"path\",\n\t\"circle\",\n\t\"ellipse\",\n\t\"line\",\n\t\"polygon\",\n\t\"polyline\",\n\t\"rect\",\n\t\"g\",\n\t\"defs\",\n\t\"use\",\n\t\"text\",\n\t\"tspan\",\n\t\"clippath\",\n\t\"mask\",\n\t\"image\",\n\t\"symbol\",\n\t\"marker\",\n\t\"lineargradient\",\n\t\"radialgradient\",\n\t\"stop\",\n\t\"filter\",\n\t\"fegaussianblur\",\n\t\"feoffset\",\n\t\"feblend\",\n\t\"foreignobject\",\n]);\n\nconst SVG_NS = \"http://www.w3.org/2000/svg\";\n\n/**\n * Root elements for the renderer's DOM mount point.\n * Defaults to document.body/head/documentElement but can be overridden\n * to render into a shadow DOM or iframe.\n */\nexport interface RendererRoot {\n\t/** The element or shadow root that serves as the `<body>` equivalent. */\n\tbody: Element | ShadowRoot;\n\t/** The element or shadow root that serves as the `<head>` equivalent. */\n\thead: Element | ShadowRoot;\n\t/** The element that serves as the `<html>` equivalent. */\n\thtml: Element;\n}\n\n/**\n * Configuration for automatic content-visibility: auto on top-level children\n * of the mount point, enabling the browser to skip rendering off-screen subtrees.\n */\nexport interface ContentVisibilityConfig {\n\t/** Whether the optimization is active. */\n\tenabled: boolean;\n\t/** CSS `contain-intrinsic-size` value applied to container elements (e.g. `\"auto 500px\"`). */\n\tintrinsicSize: string;\n}\n\n/**\n * Applies DOM mutations from the worker thread to the real browser DOM.\n *\n * Maintains a NodeCache mapping worker-side NodeIds to real DOM Node references.\n * Each mutation type is dispatched through the apply() method, which acts as\n * the single entry point for the scheduler.\n *\n * Security: blocks on* attribute handlers, javascript: URIs, and restricts\n * which DOM properties can be set via an allowlist.\n */\nexport class DomRenderer {\n\t/** Maps NodeId -> real DOM Node for O(1) lookup during mutation application. */\n\tprivate nodeCache: NodeCache;\n\tprivate permissions: RendererPermissions;\n\tprivate root: RendererRoot;\n\tprivate _additionalAllowedProperties: Set<string>;\n\t/** Callback invoked when a node is removed, allowing EventBridge to detach listeners. */\n\tonNodeRemoved: ((id: NodeId) => void) | null = null;\n\tprivate _onWarning: ((entry: WarningLogEntry) => void) | null = null;\n\tprivate _onMutation: ((entry: MutationLogEntry) => void) | null = null;\n\tprivate highlightEnabled = false;\n\tprivate _contentVisibility: ContentVisibilityConfig | null = null;\n\n\tsetDebugHooks(hooks: {\n\t\tonWarning?: ((e: WarningLogEntry) => void) | null;\n\t\tonMutation?: ((e: MutationLogEntry) => void) | null;\n\t}): void {\n\t\tthis._onWarning = hooks.onWarning ?? null;\n\t\tthis._onMutation = hooks.onMutation ?? null;\n\t}\n\n\tenableHighlightUpdates(enabled: boolean): void {\n\t\tthis.highlightEnabled = enabled;\n\t}\n\n\tsetContentVisibility(config: ContentVisibilityConfig | null): void {\n\t\tthis._contentVisibility = config;\n\t}\n\n\tprivate highlightNode(id: NodeId): void {\n\t\tif (!this.highlightEnabled) return;\n\t\tconst node = this.nodeCache.get(id) as HTMLElement | null;\n\t\tif (!node?.style) return;\n\t\tconst prev = node.style.outline;\n\t\tnode.style.outline = \"2px solid rgba(78, 201, 176, 0.8)\";\n\t\tsetTimeout(() => {\n\t\t\tnode.style.outline = prev;\n\t\t}, 300);\n\t}\n\n\tconstructor(\n\t\tnodeCache?: NodeCache,\n\t\tpermissions?: Partial<RendererPermissions>,\n\t\troot?: RendererRoot,\n\t) {\n\t\tthis.nodeCache = nodeCache ?? new NodeCache();\n\t\tthis.permissions = { ...DEFAULT_PERMISSIONS, ...permissions };\n\t\tthis._additionalAllowedProperties = new Set(this.permissions.additionalAllowedProperties ?? []);\n\t\tthis.root = root ?? {\n\t\t\tbody: document.body,\n\t\t\thead: document.head,\n\t\t\thtml: document.documentElement,\n\t\t};\n\t}\n\n\t/**\n\t * Apply a single DOM mutation to the real DOM.\n\t * This is the main entry point called by the FrameScheduler's applier callback.\n\t * Event-related mutations (addEventListener, configureEvent, removeEventListener)\n\t * are no-ops here as they are handled by EventBridge.\n\t *\n\t * @param mutation - The mutation to apply\n\t * @param batchUid - Optional batch identifier for debug logging\n\t */\n\tapply(mutation: DomMutation, batchUid?: number): void {\n\t\tif (this._onMutation) {\n\t\t\tthis._onMutation({\n\t\t\t\tside: \"main\",\n\t\t\t\taction: mutation.action,\n\t\t\t\tmutation,\n\t\t\t\ttimestamp: performance.now(),\n\t\t\t\tbatchUid,\n\t\t\t});\n\t\t}\n\t\tswitch (mutation.action) {\n\t\t\tcase \"createNode\":\n\t\t\t\tthis.createNode(mutation.id, mutation.tag, mutation.textContent);\n\t\t\t\tbreak;\n\t\t\tcase \"createComment\":\n\t\t\t\tthis.createComment(mutation.id, mutation.textContent);\n\t\t\t\tbreak;\n\t\t\tcase \"appendChild\":\n\t\t\t\tthis.appendChild(mutation.id, mutation.childId);\n\t\t\t\tbreak;\n\t\t\tcase \"removeNode\":\n\t\t\t\tthis.removeNode(mutation.id);\n\t\t\t\tbreak;\n\t\t\tcase \"removeChild\":\n\t\t\t\tthis.removeChild(mutation.id, mutation.childId);\n\t\t\t\tbreak;\n\t\t\tcase \"insertBefore\":\n\t\t\t\tthis.insertBefore(mutation.id, mutation.newId, mutation.refId);\n\t\t\t\tbreak;\n\t\t\tcase \"setAttribute\":\n\t\t\t\tthis.setAttribute(mutation.id, mutation.name, mutation.value);\n\t\t\t\tbreak;\n\t\t\tcase \"removeAttribute\":\n\t\t\t\tthis.removeAttribute(mutation.id, mutation.name);\n\t\t\t\tbreak;\n\t\t\tcase \"setStyle\":\n\t\t\t\tthis.setStyle(mutation.id, mutation.property, mutation.value);\n\t\t\t\tbreak;\n\t\t\tcase \"setProperty\":\n\t\t\t\tthis.setProperty(mutation.id, mutation.property, mutation.value);\n\t\t\t\tbreak;\n\t\t\tcase \"setTextContent\":\n\t\t\t\tthis.setTextContent(mutation.id, mutation.textContent);\n\t\t\t\tbreak;\n\t\t\tcase \"setClassName\":\n\t\t\t\tthis.setClassName(mutation.id, mutation.name);\n\t\t\t\tbreak;\n\t\t\tcase \"setHTML\":\n\t\t\t\tthis.setHTML(mutation.id, mutation.html);\n\t\t\t\tbreak;\n\t\t\tcase \"addEventListener\":\n\t\t\t\t// Handled by EventBridge, not the renderer\n\t\t\t\tbreak;\n\t\t\tcase \"configureEvent\":\n\t\t\t\t// Handled by EventBridge, not the renderer\n\t\t\t\tbreak;\n\t\t\tcase \"removeEventListener\":\n\t\t\t\t// Handled by EventBridge, not the renderer\n\t\t\t\tbreak;\n\t\t\tcase \"headAppendChild\":\n\t\t\t\tthis.headAppendChild(mutation.id);\n\t\t\t\tbreak;\n\t\t\tcase \"bodyAppendChild\":\n\t\t\t\tthis.bodyAppendChild(mutation.id);\n\t\t\t\tbreak;\n\t\t\tcase \"pushState\":\n\t\t\t\tif (this.permissions.allowNavigation) {\n\t\t\t\t\twindow.history.pushState(mutation.state, mutation.title, mutation.url);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"replaceState\":\n\t\t\t\tif (this.permissions.allowNavigation) {\n\t\t\t\t\twindow.history.replaceState(mutation.state, mutation.title, mutation.url);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"scrollTo\":\n\t\t\t\tif (this.permissions.allowScroll) {\n\t\t\t\t\twindow.scrollTo(mutation.x, mutation.y);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"insertAdjacentHTML\":\n\t\t\t\tthis.insertAdjacentHTML(mutation.id, mutation.position, mutation.html);\n\t\t\t\tbreak;\n\t\t\tcase \"callMethod\":\n\t\t\t\tthis.callMethod(mutation.id, mutation.method, mutation.args);\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// Highlight visual mutations when debug highlighting is enabled\n\t\tif (this.highlightEnabled && \"id\" in mutation) {\n\t\t\tconst action = mutation.action;\n\t\t\tif (\n\t\t\t\taction === \"appendChild\" ||\n\t\t\t\taction === \"setAttribute\" ||\n\t\t\t\taction === \"setStyle\" ||\n\t\t\t\taction === \"setClassName\" ||\n\t\t\t\taction === \"setTextContent\" ||\n\t\t\t\taction === \"setHTML\"\n\t\t\t) {\n\t\t\t\tthis.highlightNode(mutation.id);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Look up the real DOM node for a given NodeId, or null if not cached. */\n\tgetNode(id: NodeId): Node | null {\n\t\treturn this.nodeCache.get(id);\n\t}\n\n\tclear(): void {\n\t\tthis.nodeCache.clear();\n\t}\n\n\t/**\n\t * Clear the node cache but preserve structural nodes (BODY, HEAD, HTML, DOCUMENT).\n\t * Used during replay to allow re-creation of dynamic nodes while keeping the\n\t * root structure intact.\n\t */\n\tresetNodeCache(): void {\n\t\tthis.nodeCache.clear();\n\t\t// Re-seed structural nodes so replay createNode mutations work correctly\n\t\tthis.nodeCache.set(BODY_NODE_ID, this.root.body as unknown as Node);\n\t\tthis.nodeCache.set(HEAD_NODE_ID, this.root.head as unknown as Node);\n\t\tthis.nodeCache.set(HTML_NODE_ID, this.root.html);\n\t\tthis.nodeCache.set(DOCUMENT_NODE_ID, document as unknown as Node);\n\t}\n\n\tgetRoot(): RendererRoot {\n\t\treturn this.root;\n\t}\n\n\t/**\n\t * Create a DOM element or text node and store it in the node cache.\n\t * Structural tags (HTML, BODY, HEAD) are mapped to existing DOM elements rather than created.\n\t * Tags starting with \"#\" are treated as text nodes.\n\t * SVG tags are created with the SVG namespace.\n\t */\n\tprivate createNode(id: NodeId, tag: string, textContent?: string): void {\n\t\tif (this.nodeCache.has(id)) return;\n\n\t\tif (tag === \"HTML\") {\n\t\t\tthis.nodeCache.set(id, this.root.html);\n\t\t\treturn;\n\t\t}\n\n\t\tif (tag === \"BODY\") {\n\t\t\tthis.nodeCache.set(id, this.root.body as unknown as Node);\n\t\t\treturn;\n\t\t}\n\n\t\tif (tag === \"HEAD\") {\n\t\t\tthis.nodeCache.set(id, this.root.head as unknown as Node);\n\t\t\treturn;\n\t\t}\n\n\t\t// Text node\n\t\tif (tag.charAt(0) === \"#\") {\n\t\t\tconst textNode = document.createTextNode(textContent ?? \"\");\n\t\t\tthis.nodeCache.set(id, textNode);\n\t\t\treturn;\n\t\t}\n\n\t\tconst lowerTag = tag.toLowerCase();\n\t\tlet node: Element;\n\n\t\tif (SVG_TAGS.has(lowerTag)) {\n\t\t\tnode = document.createElementNS(SVG_NS, lowerTag);\n\t\t} else {\n\t\t\tnode = document.createElement(tag);\n\t\t}\n\n\t\tif (textContent) {\n\t\t\tnode.textContent = textContent;\n\t\t}\n\t\tthis.nodeCache.set(id, node);\n\t}\n\n\tprivate createComment(id: NodeId, textContent: string): void {\n\t\tif (this.nodeCache.has(id)) return;\n\t\tconst node = document.createComment(textContent);\n\t\tthis.nodeCache.set(id, node);\n\t}\n\n\tprivate appendChild(parentId: NodeId, childId: NodeId): void {\n\t\tconst parent = this.nodeCache.get(parentId);\n\t\tconst child = this.nodeCache.get(childId);\n\t\tif (!parent || !child) {\n\t\t\tconst msg = `appendChild: ${!parent ? \"parent\" : \"child\"} not found`;\n\t\t\tconsole.warn(`[async-dom] ${msg}`, { parentId, childId });\n\t\t\tthis._onWarning?.({\n\t\t\t\tcode: WarningCode.MISSING_NODE,\n\t\t\t\tmessage: msg,\n\t\t\t\tcontext: { parentId, childId },\n\t\t\t\ttimestamp: performance.now(),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\t(parent as Element).appendChild(child);\n\t\tthis._applyContentVisibility(parent, child);\n\t}\n\n\tprivate removeNode(id: NodeId): void {\n\t\tconst node = this.nodeCache.get(id);\n\t\tif (!node) {\n\t\t\tconst msg = \"removeNode: node not found\";\n\t\t\tconsole.warn(`[async-dom] ${msg}`, { id });\n\t\t\tthis._onWarning?.({\n\t\t\t\tcode: WarningCode.MISSING_NODE,\n\t\t\t\tmessage: msg,\n\t\t\t\tcontext: { id },\n\t\t\t\ttimestamp: performance.now(),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\t// Detach listeners on this node and all descendants\n\t\tthis._cleanupSubtreeListeners(node, id);\n\t\tthis.nodeCache.delete(id);\n\t\tif (node.parentNode) {\n\t\t\tnode.parentNode.removeChild(node);\n\t\t} else if (\"remove\" in node && typeof node.remove === \"function\") {\n\t\t\t(node as Element).remove();\n\t\t}\n\t}\n\n\tprivate removeChild(parentId: NodeId, childId: NodeId): void {\n\t\tconst parent = this.nodeCache.get(parentId);\n\t\tconst child = this.nodeCache.get(childId);\n\t\tif (parent && child?.parentNode) {\n\t\t\t// Detach listeners on the child and all its descendants\n\t\t\tthis._cleanupSubtreeListeners(child, childId);\n\t\t\tthis.nodeCache.delete(childId);\n\t\t\tchild.parentNode.removeChild(child);\n\t\t}\n\t}\n\n\tprivate insertBefore(parentId: NodeId, newId: NodeId, refId: NodeId | null): void {\n\t\tif (parentId === newId) return;\n\t\tconst parent = this.nodeCache.get(parentId);\n\t\tconst newEl = this.nodeCache.get(newId);\n\t\tif (!parent || !newEl) {\n\t\t\tconst msg = `insertBefore: ${!parent ? \"parent\" : \"newNode\"} not found`;\n\t\t\tconsole.warn(`[async-dom] ${msg}`, { parentId, newId, refId });\n\t\t\tthis._onWarning?.({\n\t\t\t\tcode: WarningCode.MISSING_NODE,\n\t\t\t\tmessage: msg,\n\t\t\t\tcontext: { parentId, newId, refId },\n\t\t\t\ttimestamp: performance.now(),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst refEl = refId ? this.nodeCache.get(refId) : null;\n\t\t(parent as Element).insertBefore(newEl, refEl ?? null);\n\t}\n\n\tprivate setAttribute(id: NodeId, name: string, value: string): void {\n\t\tconst node = this.nodeCache.get(id) as Element | null;\n\t\tif (!node || !(\"setAttribute\" in node)) {\n\t\t\tconst msg = \"setAttribute: node not found\";\n\t\t\tconsole.warn(`[async-dom] ${msg}`, { id, name, value });\n\t\t\tthis._onWarning?.({\n\t\t\t\tcode: WarningCode.MISSING_NODE,\n\t\t\t\tmessage: msg,\n\t\t\t\tcontext: { id, name, value },\n\t\t\t\ttimestamp: performance.now(),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// Block dangerous attributes (on* event handlers, javascript: URIs)\n\t\tconst lowerName = name.toLowerCase();\n\t\tif (/^on/i.test(lowerName)) return;\n\t\tif (DANGEROUS_ATTR_NAMES.has(lowerName)) return;\n\t\tif (DANGEROUS_URI_ATTR_NAMES.has(lowerName) && isDangerousURI(value)) return;\n\n\t\tif (name === \"id\") {\n\t\t\t// Create alias in cache for new id — user-facing IDs are strings,\n\t\t\t// but we store them as NodeId for lookup compatibility\n\t\t\tthis.nodeCache.set(value as unknown as NodeId, node);\n\t\t}\n\t\tnode.setAttribute(name, value);\n\t}\n\n\tprivate removeAttribute(id: NodeId, name: string): void {\n\t\tconst node = this.nodeCache.get(id) as Element | null;\n\t\tif (!node || !(\"removeAttribute\" in node)) return;\n\t\tnode.removeAttribute(name);\n\t}\n\n\tprivate setStyle(id: NodeId, property: string, value: string): void {\n\t\tconst node = this.nodeCache.get(id) as HTMLElement | null;\n\t\tif (!node?.style) {\n\t\t\tconst msg = \"setStyle: node not found\";\n\t\t\tconsole.warn(`[async-dom] ${msg}`, { id, property, value });\n\t\t\tthis._onWarning?.({\n\t\t\t\tcode: WarningCode.MISSING_NODE,\n\t\t\t\tmessage: msg,\n\t\t\t\tcontext: { id, property, value },\n\t\t\t\ttimestamp: performance.now(),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tnode.style.setProperty(property, value);\n\t}\n\n\tprivate setProperty(id: NodeId, property: string, value: unknown): void {\n\t\tconst node = this.nodeCache.get(id);\n\t\tif (!node) return;\n\n\t\tif (!ALLOWED_PROPERTIES.has(property) && !this._additionalAllowedProperties.has(property)) {\n\t\t\tthis._onWarning?.({\n\t\t\t\tcode: WarningCode.BLOCKED_PROPERTY,\n\t\t\t\tmessage: `setProperty: property \"${property}\" is not in the allowed list`,\n\t\t\t\tcontext: { id, property },\n\t\t\t\ttimestamp: performance.now(),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t(node as unknown as Record<string, unknown>)[property] = value;\n\t}\n\n\tprivate setTextContent(id: NodeId, textContent: string): void {\n\t\tconst node = this.nodeCache.get(id);\n\t\tif (!node) return;\n\t\tnode.textContent = textContent;\n\t}\n\n\tprivate setClassName(id: NodeId, name: string): void {\n\t\tconst node = this.nodeCache.get(id) as Element | null;\n\t\tif (!node) return;\n\t\tnode.className = name;\n\t}\n\n\tprivate setHTML(id: NodeId, html: string): void {\n\t\tconst node = this.nodeCache.get(id) as Element | null;\n\t\tif (!node) return;\n\t\tnode.innerHTML = this.permissions.allowUnsafeHTML ? html : sanitizeHTML(html);\n\t}\n\n\tprivate insertAdjacentHTML(id: NodeId, position: InsertPosition, html: string): void {\n\t\tconst node = this.nodeCache.get(id) as Element | null;\n\t\tif (!node || !(\"insertAdjacentHTML\" in node)) return;\n\t\tnode.insertAdjacentHTML(position, this.permissions.allowUnsafeHTML ? html : sanitizeHTML(html));\n\t}\n\n\tprivate headAppendChild(id: NodeId): void {\n\t\tif (!this.permissions.allowHeadAppend) return;\n\t\tconst node = this.nodeCache.get(id);\n\t\tif (node) (this.root.head as unknown as Node).appendChild(node);\n\t}\n\n\tprivate bodyAppendChild(id: NodeId): void {\n\t\tif (!this.permissions.allowBodyAppend) return;\n\t\tconst node = this.nodeCache.get(id);\n\t\tif (node) (this.root.body as unknown as Node).appendChild(node);\n\t}\n\n\t/**\n\t * Call a whitelisted method on a DOM node (e.g., focus, play, showModal).\n\t * Methods not in ALLOWED_METHODS are silently blocked.\n\t */\n\tprivate callMethod(id: NodeId, method: string, args: unknown[]): void {\n\t\tconst node = this.nodeCache.get(id);\n\t\tif (!node) return;\n\t\tif (!ALLOWED_METHODS.has(method)) {\n\t\t\tconsole.warn(`[async-dom] Blocked callMethod: \"${method}\" is not allowed`);\n\t\t\treturn;\n\t\t}\n\t\tconst fn = (node as unknown as Record<string, unknown>)[method];\n\t\tif (typeof fn === \"function\") {\n\t\t\t(fn as (...a: unknown[]) => unknown).apply(node, args);\n\t\t}\n\t}\n\n\t/** Inline element tags that should not receive content-visibility. */\n\tprivate static readonly INLINE_TAGS = new Set([\n\t\t\"SPAN\",\n\t\t\"A\",\n\t\t\"STRONG\",\n\t\t\"EM\",\n\t\t\"B\",\n\t\t\"I\",\n\t\t\"U\",\n\t\t\"S\",\n\t\t\"SMALL\",\n\t\t\"BIG\",\n\t\t\"SUB\",\n\t\t\"SUP\",\n\t\t\"ABBR\",\n\t\t\"CITE\",\n\t\t\"CODE\",\n\t\t\"KBD\",\n\t\t\"SAMP\",\n\t\t\"VAR\",\n\t\t\"MARK\",\n\t\t\"Q\",\n\t\t\"TIME\",\n\t\t\"LABEL\",\n\t\t\"BR\",\n\t\t\"WBR\",\n\t\t\"IMG\",\n\t]);\n\n\t/**\n\t * Apply content-visibility: auto to top-level children of the mount point.\n\t * Only applies to block-level HTMLElements that don't already have it set.\n\t */\n\tprivate _applyContentVisibility(parent: Node, child: Node): void {\n\t\tif (!this._contentVisibility) return;\n\t\t// Only apply to direct children of the mount point (root.body)\n\t\tconst mountPoint = this.root.body;\n\t\tif (parent !== (mountPoint as unknown as Node)) return;\n\t\t// Only apply to HTMLElements (not text nodes, comments, or SVG)\n\t\tif (!(child instanceof HTMLElement)) return;\n\t\t// Skip inline elements\n\t\tif (DomRenderer.INLINE_TAGS.has(child.tagName)) return;\n\t\t// Don't override if already set\n\t\tif (child.style.contentVisibility) return;\n\t\tchild.style.contentVisibility = \"auto\";\n\t\tchild.style.containIntrinsicSize = this._contentVisibility.intrinsicSize;\n\t}\n\n\t/**\n\t * Notify onNodeRemoved for a node and all its descendants.\n\t * This ensures EventBridge detaches listeners on the entire subtree.\n\t */\n\tprivate _cleanupSubtreeListeners(node: Node, id: NodeId): void {\n\t\tthis.onNodeRemoved?.(id);\n\t\tconst children = node.childNodes;\n\t\tfor (let i = 0; i < children.length; i++) {\n\t\t\tconst child = children[i];\n\t\t\tconst childId = this.nodeCache.getId(child);\n\t\t\tif (childId) {\n\t\t\t\tthis._cleanupSubtreeListeners(child, childId);\n\t\t\t\tthis.nodeCache.delete(childId);\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { AppId, Message } from \"../core/protocol.ts\";\nimport { createAppId } from \"../core/protocol.ts\";\nimport type { Transport } from \"../transport/base.ts\";\nimport { BinaryWorkerTransport } from \"../transport/binary-worker-transport.ts\";\nimport { WorkerTransport } from \"../transport/worker-transport.ts\";\nimport { WebSocketTransport, type WebSocketTransportOptions } from \"../transport/ws-transport.ts\";\n\nexport interface WorkerConfig {\n\tworker: Worker;\n\ttransport?: Transport;\n\t/** Human-readable name for this app (shown in DevTools instead of a random hash) */\n\tname?: string;\n}\n\nexport interface RemoteConfig {\n\ttransport: Transport;\n\tname?: string;\n}\n\nexport interface WebSocketConfig {\n\turl: string;\n\toptions?: WebSocketTransportOptions;\n\t/** Human-readable name for this app (shown in DevTools instead of a random hash) */\n\tname?: string;\n}\n\ninterface ThreadConnection {\n\ttransport: Transport;\n\tappId: AppId;\n}\n\n/**\n * Manages multiple worker/WebSocket connections, routing messages\n * between the main thread and isolated app threads.\n */\nexport class ThreadManager {\n\tprivate threads = new Map<AppId, ThreadConnection>();\n\tprivate messageHandlers: Array<(appId: AppId, message: Message) => void> = [];\n\n\tcreateWorkerThread(config: WorkerConfig): AppId {\n\t\tconst appId = this._uniqueAppId(config.name);\n\t\tconst useBinary = typeof __ASYNC_DOM_BINARY__ !== \"undefined\" && __ASYNC_DOM_BINARY__;\n\t\tconst transport =\n\t\t\tconfig.transport ??\n\t\t\t(useBinary ? new BinaryWorkerTransport(config.worker) : new WorkerTransport(config.worker));\n\n\t\ttransport.onMessage((message) => {\n\t\t\tthis.notifyHandlers(appId, message);\n\t\t});\n\n\t\tthis.threads.set(appId, { transport, appId });\n\t\treturn appId;\n\t}\n\n\tcreateRemoteThread(config: RemoteConfig): AppId {\n\t\tconst appId = this._uniqueAppId(config.name);\n\t\tconst transport = config.transport;\n\n\t\ttransport.onMessage((message) => {\n\t\t\tthis.notifyHandlers(appId, message);\n\t\t});\n\n\t\tthis.threads.set(appId, { transport, appId });\n\t\treturn appId;\n\t}\n\n\tcreateWebSocketThread(config: WebSocketConfig): AppId {\n\t\tconst appId = this._uniqueAppId(config.name);\n\t\tconst transport = new WebSocketTransport(config.url, config.options);\n\n\t\ttransport.onMessage((message) => {\n\t\t\tthis.notifyHandlers(appId, message);\n\t\t});\n\n\t\tthis.threads.set(appId, { transport, appId });\n\t\treturn appId;\n\t}\n\n\tsendToThread(appId: AppId, message: Message): void {\n\t\tconst thread = this.threads.get(appId);\n\t\tif (thread) {\n\t\t\tthread.transport.send(message);\n\t\t}\n\t}\n\n\tbroadcast(message: Message): void {\n\t\tfor (const thread of this.threads.values()) {\n\t\t\tthread.transport.send(message);\n\t\t}\n\t}\n\n\tdestroyThread(appId: AppId): void {\n\t\tconst thread = this.threads.get(appId);\n\t\tif (thread) {\n\t\t\tthread.transport.close();\n\t\t\tthis.threads.delete(appId);\n\t\t}\n\t}\n\n\tdestroyAll(): void {\n\t\tfor (const appId of [...this.threads.keys()]) {\n\t\t\tthis.destroyThread(appId);\n\t\t}\n\t}\n\n\tonMessage(handler: (appId: AppId, message: Message) => void): void {\n\t\tthis.messageHandlers.push(handler);\n\t}\n\n\tgetTransport(appId: AppId): Transport | null {\n\t\treturn this.threads.get(appId)?.transport ?? null;\n\t}\n\n\tprivate notifyHandlers(appId: AppId, message: Message): void {\n\t\tfor (const handler of this.messageHandlers) {\n\t\t\thandler(appId, message);\n\t\t}\n\t}\n\n\t/** Generate a unique AppId, appending a suffix if the name already exists. */\n\tprivate _uniqueAppId(name?: string): AppId {\n\t\tif (!name) {\n\t\t\treturn createAppId(Math.random().toString(36).slice(2, 7));\n\t\t}\n\t\tlet appId = createAppId(name);\n\t\tif (!this.threads.has(appId)) return appId;\n\t\t// Name collision — append a suffix\n\t\tlet i = 2;\n\t\twhile (this.threads.has(createAppId(`${name}-${i}`))) i++;\n\t\tappId = createAppId(`${name}-${i}`);\n\t\treturn appId;\n\t}\n}\n","import type { DebugOptions } from \"../core/debug.ts\";\nimport { DebugStats, MutationEventCorrelation, resolveDebugHooks } from \"../core/debug.ts\";\nimport { NodeCache } from \"../core/node-cache.ts\";\nimport type { AppId, DomMutation, Message, NodeId, PerfEntryData } from \"../core/protocol.ts\";\nimport {\n\tBODY_NODE_ID,\n\tDOCUMENT_NODE_ID,\n\tHEAD_NODE_ID,\n\tHTML_NODE_ID,\n\tisMutationMessage,\n\tisSystemMessage,\n} from \"../core/protocol.ts\";\nimport { FrameScheduler, type SchedulerConfig } from \"../core/scheduler.ts\";\nimport { QueryType, SyncChannelHost } from \"../core/sync-channel.ts\";\nimport { CausalityTracker } from \"../debug/causality-graph.ts\";\nimport {\n\tcaptureEvent,\n\tcaptureMutation,\n\tcaptureSyncRead,\n\tcaptureWarning,\n\tcreateDevtoolsPanel,\n} from \"../debug/devtools-panel.ts\";\nimport { EventBridge } from \"./event-bridge.ts\";\nimport { type ContentVisibilityConfig, DomRenderer, type RendererRoot } from \"./renderer.ts\";\nimport { ThreadManager } from \"./thread-manager.ts\";\n\n// Allowlist of safe window properties accessible via sync channel.\n// Prevents workers from reading sensitive data like document.cookie.\nconst ALLOWED_WINDOW_PROPERTIES = new Set([\n\t\"innerWidth\",\n\t\"innerHeight\",\n\t\"outerWidth\",\n\t\"outerHeight\",\n\t\"devicePixelRatio\",\n\t\"screen.width\",\n\t\"screen.height\",\n\t\"screen.availWidth\",\n\t\"screen.availHeight\",\n\t\"screen.colorDepth\",\n\t\"screen.pixelDepth\",\n\t\"screen.orientation.type\",\n\t\"scrollX\",\n\t\"scrollY\",\n\t\"visualViewport.width\",\n\t\"visualViewport.height\",\n\t\"navigator.language\",\n\t\"navigator.languages\",\n\t\"navigator.userAgent\",\n\t\"navigator.hardwareConcurrency\",\n\t\"document.visibilityState\",\n\t\"document.hidden\",\n\t\"localStorage.getItem\",\n\t\"localStorage.setItem\",\n\t\"localStorage.removeItem\",\n\t\"localStorage.length\",\n\t\"localStorage.key\",\n\t\"sessionStorage.getItem\",\n\t\"sessionStorage.setItem\",\n\t\"sessionStorage.removeItem\",\n\t\"sessionStorage.length\",\n\t\"sessionStorage.key\",\n]);\n\n/**\n * Configuration for {@link createAsyncDom}.\n *\n * At minimum, provide a `target` element where worker-rendered DOM will be mounted.\n * Optionally pass a `worker` to immediately register the first app.\n */\nexport interface AsyncDomConfig {\n\t/** The DOM element that serves as the rendering root for worker-produced mutations. */\n\ttarget: Element;\n\t/** Optional initial worker. If provided, it is registered as the first app automatically. */\n\tworker?: Worker;\n\t/** Frame-budget scheduler tuning options. */\n\tscheduler?: SchedulerConfig;\n\t/** Debug logging and devtools panel options. */\n\tdebug?: DebugOptions;\n\t/**\n\t * Enable `content-visibility: auto` on top-level container elements for off-screen\n\t * rendering optimization. Pass `true` for defaults, or an object with a custom\n\t * `intrinsicSize` (CSS value, default `\"auto 500px\"`).\n\t */\n\tcontentVisibility?: boolean | { intrinsicSize?: string };\n}\n\n/**\n * Configuration for adding a worker-backed app via {@link AsyncDomInstance.addApp}.\n */\nexport interface AppConfig {\n\t/** The Web Worker instance that runs this app's UI logic. */\n\tworker: Worker;\n\t/** Human-readable name for this app (shown in DevTools instead of a random hash). */\n\tname?: string;\n\t/** CSS selector or Element where this app's DOM will be mounted. Defaults to the instance root. */\n\tmountPoint?: string | Element;\n\t/** Attach to a Shadow DOM root for CSS isolation. Pass `true` for `{ mode: \"open\" }` or a custom `ShadowRootInit`. */\n\tshadow?: boolean | ShadowRootInit;\n\t/** Custom transport to use instead of the default `WorkerTransport`. */\n\ttransport?: import(\"../transport/base.ts\").Transport;\n\t/** Called when the worker reports an unhandled error or unhandled promise rejection. */\n\tonError?: (error: import(\"../core/protocol.ts\").SerializedError, appId: AppId) => void;\n}\n\n/**\n * Configuration for adding a remote (non-worker) app via {@link AsyncDomInstance.addRemoteApp}.\n *\n * Remote apps communicate over a custom transport (e.g. WebSocket) rather than\n * a local Web Worker.\n */\nexport interface RemoteAppConfig {\n\t/** The transport used to communicate with the remote process. */\n\ttransport: import(\"../transport/base.ts\").Transport;\n\t/** Human-readable name for this app (shown in DevTools instead of a random hash). */\n\tname?: string;\n\t/** CSS selector or Element where this app's DOM will be mounted. Defaults to the instance root. */\n\tmountPoint?: string | Element;\n\t/** Attach to a Shadow DOM root for CSS isolation. Pass `true` for `{ mode: \"open\" }` or a custom `ShadowRootInit`. */\n\tshadow?: boolean | ShadowRootInit;\n\t/** Called when the remote process reports an unhandled error. */\n\tonError?: (error: import(\"../core/protocol.ts\").SerializedError, appId: AppId) => void;\n\t/** Enable `SharedArrayBuffer`-based sync channel for synchronous DOM reads. Default: `false`. */\n\tenableSyncChannel?: boolean;\n}\n\n/**\n * Handle returned by {@link createAsyncDom}.\n *\n * Controls the lifecycle of the async-dom instance: starting/stopping the\n * scheduler, adding/removing apps, and tearing down all resources.\n */\nexport interface AsyncDomInstance {\n\t/** Start the frame-budget scheduler. Mutations begin applying to the DOM. */\n\tstart(): void;\n\t/** Pause the scheduler. Mutations are queued but not applied until `start()` is called. */\n\tstop(): void;\n\t/** Stop the scheduler, flush remaining mutations, tear down all apps, and release all resources. */\n\tdestroy(): void;\n\t/** Register a new worker-backed app. Returns a unique `AppId` for later removal. */\n\taddApp(config: AppConfig): AppId;\n\t/** Register a new remote app using a custom transport. Returns a unique `AppId` for later removal. */\n\taddRemoteApp(config: RemoteAppConfig): AppId;\n\t/** Remove an app by its `AppId`, detaching its event listeners and clearing its rendered DOM. */\n\tremoveApp(appId: AppId): void;\n}\n\n/**\n * Creates a new async-dom instance on the main thread.\n *\n * This is the primary entry point for using async-dom. It:\n * - Creates a scheduler for frame-budgeted rendering\n * - Creates per-app renderers for applying DOM mutations (isolation)\n * - Creates an event bridge for forwarding events to workers\n * - Manages worker threads\n */\nexport function createAsyncDom(config: AsyncDomConfig): AsyncDomInstance {\n\tconst scheduler = new FrameScheduler(config.scheduler);\n\tconst threadManager = new ThreadManager();\n\tconst eventBridges = new Map<AppId, EventBridge>();\n\tconst syncHosts = new Map<AppId, SyncChannelHost>();\n\tconst debugHooks = resolveDebugHooks(config.debug);\n\tconst debugStats = new DebugStats();\n\n\t// Resolve content-visibility config\n\tconst contentVisibilityConfig: ContentVisibilityConfig | null = config.contentVisibility\n\t\t? {\n\t\t\t\tenabled: true,\n\t\t\t\tintrinsicSize:\n\t\t\t\t\ttypeof config.contentVisibility === \"object\" && config.contentVisibility.intrinsicSize\n\t\t\t\t\t\t? config.contentVisibility.intrinsicSize\n\t\t\t\t\t\t: \"auto 500px\",\n\t\t\t}\n\t\t: null;\n\n\t// Feature 15: Causality tracker for building event -> batch -> node DAG\n\tconst causalityTracker = new CausalityTracker();\n\n\t// Feature 16: Worker CPU profiler entries storage\n\tconst workerPerfEntries = new Map<AppId, PerfEntryData[]>();\n\tconst MAX_PERF_ENTRIES = 200;\n\n\t// Feature 19: Mutation-to-event correlation index\n\tconst mutationCorrelation = new MutationEventCorrelation();\n\n\t// Per-app DomRenderer map (each has its own NodeCache)\n\tconst renderers = new Map<AppId, DomRenderer>();\n\tlet lastRenderer: DomRenderer | null = null;\n\tlet lastAppId: AppId | null = null;\n\n\t// Debug data cache: stores virtual DOM trees and worker stats received from workers\n\tconst debugData = new Map<\n\t\tAppId,\n\t\t{\n\t\t\ttree: unknown;\n\t\t\tworkerStats: unknown;\n\t\t\tperTypeCoalesced: unknown;\n\t\t\tcoalescedLog: unknown;\n\t\t}\n\t>();\n\n\tfunction requestDebugData(appId: AppId): void {\n\t\tthreadManager.sendToThread(appId, { type: \"debugQuery\", query: \"tree\" });\n\t\tthreadManager.sendToThread(appId, { type: \"debugQuery\", query: \"stats\" });\n\t\tthreadManager.sendToThread(appId, { type: \"debugQuery\", query: \"perTypeCoalesced\" });\n\t\tthreadManager.sendToThread(appId, { type: \"debugQuery\", query: \"coalescedLog\" });\n\t}\n\n\tfunction handleSyncQuery(\n\t\tappRenderer: DomRenderer,\n\t\tquery: { queryType: QueryType; data: string },\n\t): unknown {\n\t\tconst startTime = performance.now();\n\t\tlet resultStatus: \"success\" | \"timeout\" | \"error\" = \"success\";\n\t\tlet parsedNodeId: string = \"\";\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(query.data);\n\t\t\tconst nodeId = parsed.nodeId;\n\t\t\tparsedNodeId = String(nodeId ?? \"\");\n\t\t\tconst property = parsed.property;\n\n\t\t\tswitch (query.queryType) {\n\t\t\t\tcase QueryType.BoundingRect: {\n\t\t\t\t\tconst node = appRenderer.getNode(nodeId) as Element | null;\n\t\t\t\t\tif (!node || !(\"getBoundingClientRect\" in node)) return null;\n\t\t\t\t\tconst rect = node.getBoundingClientRect();\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttop: rect.top,\n\t\t\t\t\t\tleft: rect.left,\n\t\t\t\t\t\tright: rect.right,\n\t\t\t\t\t\tbottom: rect.bottom,\n\t\t\t\t\t\twidth: rect.width,\n\t\t\t\t\t\theight: rect.height,\n\t\t\t\t\t\tx: rect.x,\n\t\t\t\t\t\ty: rect.y,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tcase QueryType.ComputedStyle: {\n\t\t\t\t\tconst node = appRenderer.getNode(nodeId) as Element | null;\n\t\t\t\t\tif (!node) return {};\n\t\t\t\t\tconst cs = window.getComputedStyle(node);\n\t\t\t\t\tconst result: Record<string, string> = {};\n\t\t\t\t\tconst props = [\n\t\t\t\t\t\t\"display\",\n\t\t\t\t\t\t\"position\",\n\t\t\t\t\t\t\"top\",\n\t\t\t\t\t\t\"left\",\n\t\t\t\t\t\t\"right\",\n\t\t\t\t\t\t\"bottom\",\n\t\t\t\t\t\t\"width\",\n\t\t\t\t\t\t\"height\",\n\t\t\t\t\t\t\"color\",\n\t\t\t\t\t\t\"background-color\",\n\t\t\t\t\t\t\"font-size\",\n\t\t\t\t\t\t\"font-family\",\n\t\t\t\t\t\t\"font-weight\",\n\t\t\t\t\t\t\"line-height\",\n\t\t\t\t\t\t\"text-align\",\n\t\t\t\t\t\t\"visibility\",\n\t\t\t\t\t\t\"opacity\",\n\t\t\t\t\t\t\"overflow\",\n\t\t\t\t\t\t\"z-index\",\n\t\t\t\t\t\t\"float\",\n\t\t\t\t\t\t\"clear\",\n\t\t\t\t\t\t\"cursor\",\n\t\t\t\t\t\t\"pointer-events\",\n\t\t\t\t\t\t\"box-sizing\",\n\t\t\t\t\t\t\"flex-direction\",\n\t\t\t\t\t\t\"justify-content\",\n\t\t\t\t\t\t\"align-items\",\n\t\t\t\t\t\t\"flex-wrap\",\n\t\t\t\t\t\t\"flex-grow\",\n\t\t\t\t\t\t\"flex-shrink\",\n\t\t\t\t\t\t\"flex-basis\",\n\t\t\t\t\t\t\"grid-template-columns\",\n\t\t\t\t\t\t\"grid-template-rows\",\n\t\t\t\t\t\t\"gap\",\n\t\t\t\t\t\t\"transform\",\n\t\t\t\t\t\t\"border-radius\",\n\t\t\t\t\t\t\"box-shadow\",\n\t\t\t\t\t\t\"text-decoration\",\n\t\t\t\t\t\t\"white-space\",\n\t\t\t\t\t\t\"word-break\",\n\t\t\t\t\t\t\"overflow-wrap\",\n\t\t\t\t\t\t\"min-width\",\n\t\t\t\t\t\t\"max-width\",\n\t\t\t\t\t\t\"min-height\",\n\t\t\t\t\t\t\"max-height\",\n\t\t\t\t\t\t\"margin-top\",\n\t\t\t\t\t\t\"margin-right\",\n\t\t\t\t\t\t\"margin-bottom\",\n\t\t\t\t\t\t\"margin-left\",\n\t\t\t\t\t\t\"padding-top\",\n\t\t\t\t\t\t\"padding-right\",\n\t\t\t\t\t\t\"padding-bottom\",\n\t\t\t\t\t\t\"padding-left\",\n\t\t\t\t\t];\n\t\t\t\t\tfor (const p of props) {\n\t\t\t\t\t\tconst v = cs.getPropertyValue(p);\n\t\t\t\t\t\tif (v) result[p] = v;\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t\tcase QueryType.NodeProperty: {\n\t\t\t\t\tconst node = appRenderer.getNode(nodeId);\n\t\t\t\t\tif (!node || !property) return null;\n\t\t\t\t\treturn (node as unknown as Record<string, unknown>)[property] ?? null;\n\t\t\t\t}\n\t\t\t\tcase QueryType.WindowProperty: {\n\t\t\t\t\tif (!property) return null;\n\t\t\t\t\t// Allowlist of safe window properties to prevent data exfiltration\n\t\t\t\t\tif (!ALLOWED_WINDOW_PROPERTIES.has(property)) return null;\n\n\t\t\t\t\t// Handle storage method calls (localStorage.getItem, etc.)\n\t\t\t\t\tif (property.startsWith(\"localStorage.\") || property.startsWith(\"sessionStorage.\")) {\n\t\t\t\t\t\tconst dotIndex = property.indexOf(\".\");\n\t\t\t\t\t\tconst storageType = property.slice(0, dotIndex);\n\t\t\t\t\t\tconst method = property.slice(dotIndex + 1);\n\t\t\t\t\t\tconst storage =\n\t\t\t\t\t\t\tstorageType === \"localStorage\" ? window.localStorage : window.sessionStorage;\n\t\t\t\t\t\tconst args = parsed.args as string[] | undefined;\n\t\t\t\t\t\tif (method === \"getItem\" && args?.[0] != null) {\n\t\t\t\t\t\t\treturn storage.getItem(args[0]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (method === \"setItem\" && args?.[0] != null && args[1] !== undefined) {\n\t\t\t\t\t\t\tstorage.setItem(args[0], args[1]);\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (method === \"removeItem\" && args?.[0] != null) {\n\t\t\t\t\t\t\tstorage.removeItem(args[0]);\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (method === \"length\") {\n\t\t\t\t\t\t\treturn storage.length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (method === \"key\" && args?.[0] !== undefined) {\n\t\t\t\t\t\t\treturn storage.key(Number(args[0]));\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support dotted paths like \"screen.width\"\n\t\t\t\t\tconst parts = property.split(\".\");\n\t\t\t\t\tlet current: unknown = window;\n\t\t\t\t\tfor (const part of parts) {\n\t\t\t\t\t\tif (current == null) return null;\n\t\t\t\t\t\tcurrent = (current as Record<string, unknown>)[part];\n\t\t\t\t\t}\n\t\t\t\t\treturn current ?? null;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn null;\n\t\t\t}\n\t\t} catch {\n\t\t\tresultStatus = \"error\";\n\t\t\treturn null;\n\t\t} finally {\n\t\t\tdebugStats.syncReadRequests++;\n\t\t\tif (debugHooks.onSyncRead) {\n\t\t\t\tconst latencyMs = performance.now() - startTime;\n\t\t\t\tdebugHooks.onSyncRead({\n\t\t\t\t\tqueryType: query.queryType,\n\t\t\t\t\tnodeId: parsedNodeId,\n\t\t\t\t\tlatencyMs,\n\t\t\t\t\tresult: resultStatus,\n\t\t\t\t\ttimestamp: performance.now(),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// Wire scheduler to renderer — appId is used to route mutations\n\t// to the correct per-app renderer and event bridge\n\tscheduler.setApplier((mutation: DomMutation, appId: AppId, batchUid?: number) => {\n\t\t// Handle addEventListener specially — route to the owning app's EventBridge\n\t\tif (mutation.action === \"addEventListener\") {\n\t\t\tconst bridge = eventBridges.get(appId);\n\t\t\tif (bridge) {\n\t\t\t\tbridge.attach(mutation.id, mutation.name, mutation.listenerId);\n\t\t\t\tdebugStats.eventsForwarded++;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (mutation.action === \"configureEvent\") {\n\t\t\tconst bridge = eventBridges.get(appId);\n\t\t\tif (bridge) {\n\t\t\t\tbridge.configureEvent(mutation.id, mutation.name, {\n\t\t\t\t\tpreventDefault: mutation.preventDefault,\n\t\t\t\t\tpassive: mutation.passive,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (mutation.action === \"removeEventListener\") {\n\t\t\tconst bridge = eventBridges.get(appId);\n\t\t\tif (bridge) {\n\t\t\t\tbridge.detach(mutation.listenerId);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Fast path: skip map lookup for single/repeated app\n\t\tlet renderer: DomRenderer | undefined;\n\t\tif (appId === lastAppId && lastRenderer) {\n\t\t\trenderer = lastRenderer;\n\t\t} else {\n\t\t\trenderer = renderers.get(appId);\n\t\t\tif (renderer) {\n\t\t\t\tlastRenderer = renderer;\n\t\t\t\tlastAppId = appId;\n\t\t\t}\n\t\t}\n\t\tif (renderer) {\n\t\t\trenderer.apply(mutation, batchUid);\n\t\t\tdebugStats.mutationsApplied++;\n\t\t}\n\t});\n\n\t// Handle incoming messages from workers\n\tthreadManager.onMessage((appId: AppId, message: Message) => {\n\t\tif (isMutationMessage(message)) {\n\t\t\tif (message.sentAt != null) {\n\t\t\t\tscheduler.recordWorkerLatency(message.sentAt);\n\t\t\t}\n\t\t\tscheduler.enqueue(message.mutations, appId, message.priority ?? \"normal\", message.uid);\n\n\t\t\t// Feature 15: record causal batch\n\t\t\tif (message.causalEvent) {\n\t\t\t\tconst nodeIds = message.mutations\n\t\t\t\t\t.filter((m) => \"id\" in m)\n\t\t\t\t\t.map((m) => (m as { id: number }).id);\n\t\t\t\tcausalityTracker.recordBatch(\n\t\t\t\t\tmessage.uid,\n\t\t\t\t\tnodeIds,\n\t\t\t\t\tmessage.mutations.length,\n\t\t\t\t\tmessage.causalEvent,\n\t\t\t\t);\n\t\t\t\t// Feature 19: register batch event for correlation\n\t\t\t\tmutationCorrelation.registerBatchEvent(message.uid, message.causalEvent);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\t// Handle event timing results from the worker\n\t\tif (isSystemMessage(message) && message.type === \"eventTimingResult\") {\n\t\t\tconst bridge = eventBridges.get(appId);\n\t\t\tif (bridge) {\n\t\t\t\tbridge.updateTraceWithWorkerTiming(\n\t\t\t\t\tmessage.listenerId,\n\t\t\t\t\tmessage.dispatchMs,\n\t\t\t\t\tmessage.mutationCount,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Feature 16: handle worker performance entries\n\t\tif (isSystemMessage(message) && message.type === \"perfEntries\") {\n\t\t\tconst perfMsg = message as { type: \"perfEntries\"; appId: AppId; entries: PerfEntryData[] };\n\t\t\tlet entries = workerPerfEntries.get(appId);\n\t\t\tif (!entries) {\n\t\t\t\tentries = [];\n\t\t\t\tworkerPerfEntries.set(appId, entries);\n\t\t\t}\n\t\t\tentries.push(...perfMsg.entries);\n\t\t\tif (entries.length > MAX_PERF_ENTRIES) {\n\t\t\t\tentries.splice(0, entries.length - MAX_PERF_ENTRIES);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Cache debug results from worker threads\n\t\tif (isSystemMessage(message) && message.type === \"debugResult\") {\n\t\t\tconst debugMsg = message as { type: \"debugResult\"; query: string; result: unknown };\n\t\t\tconst data = debugData.get(appId) ?? {\n\t\t\t\ttree: null,\n\t\t\t\tworkerStats: null,\n\t\t\t\tperTypeCoalesced: null,\n\t\t\t\tcoalescedLog: null,\n\t\t\t};\n\t\t\tif (debugMsg.query === \"tree\") data.tree = debugMsg.result;\n\t\t\tif (debugMsg.query === \"stats\") data.workerStats = debugMsg.result;\n\t\t\tif (debugMsg.query === \"perTypeCoalesced\") data.perTypeCoalesced = debugMsg.result;\n\t\t\tif (debugMsg.query === \"coalescedLog\") data.coalescedLog = debugMsg.result;\n\t\t\tdebugData.set(appId, data);\n\t\t}\n\t});\n\n\t// Wire mutation/warning/event/syncRead capture for the devtools panel\n\t// BEFORE adding the first app, so that addAppInternal sees non-null hooks\n\tif (config.debug?.exposeDevtools) {\n\t\tconst origOnMutation = debugHooks.onMutation;\n\t\tconst origOnWarning = debugHooks.onWarning;\n\t\tconst origOnEvent = debugHooks.onEvent;\n\t\tconst origOnSyncRead = debugHooks.onSyncRead;\n\t\tdebugHooks.onMutation = (entry) => {\n\t\t\torigOnMutation?.(entry);\n\t\t\tcaptureMutation(entry);\n\t\t\t// Feature 19: index mutation for \"Why Updated?\" lookups\n\t\t\tmutationCorrelation.indexMutation(entry);\n\t\t};\n\t\tdebugHooks.onWarning = (entry) => {\n\t\t\torigOnWarning?.(entry);\n\t\t\tcaptureWarning(entry);\n\t\t};\n\t\tdebugHooks.onEvent = (entry) => {\n\t\t\torigOnEvent?.(entry);\n\t\t\tcaptureEvent(entry);\n\t\t};\n\t\tdebugHooks.onSyncRead = (entry) => {\n\t\t\torigOnSyncRead?.(entry);\n\t\t\tcaptureSyncRead(entry);\n\t\t};\n\t}\n\n\t// If a worker was provided in config, add it as the first app\n\tif (config.worker) {\n\t\taddAppInternal(config.worker, config.target);\n\t}\n\n\tfunction addAppInternal(\n\t\tworker: Worker | undefined,\n\t\tmountPoint?: string | Element,\n\t\tshadow?: boolean | ShadowRootInit,\n\t\tcustomTransport?: import(\"../transport/base.ts\").Transport,\n\t\tonError?: (error: import(\"../core/protocol.ts\").SerializedError, appId: AppId) => void,\n\t\tname?: string,\n\t\tenableSyncChannel?: boolean,\n\t): AppId {\n\t\tlet appId: AppId;\n\t\tif (worker) {\n\t\t\tappId = threadManager.createWorkerThread({ worker, transport: customTransport, name });\n\t\t} else if (customTransport) {\n\t\t\tappId = threadManager.createRemoteThread({ transport: customTransport, name });\n\t\t} else {\n\t\t\tthrow new Error(\"[async-dom] addAppInternal requires either a worker or a transport\");\n\t\t}\n\n\t\t// Per-app NodeCache and DomRenderer for isolation\n\t\tconst appNodeCache = new NodeCache();\n\n\t\t// Resolve mount point element\n\t\tlet mountEl: Element | null = null;\n\t\tif (mountPoint) {\n\t\t\tmountEl = typeof mountPoint === \"string\" ? document.querySelector(mountPoint) : mountPoint;\n\t\t}\n\n\t\t// Set up renderer root (shadow DOM for CSS isolation)\n\t\tlet rendererRoot: RendererRoot | undefined;\n\t\tif (mountEl && shadow) {\n\t\t\tconst shadowInit: ShadowRootInit = shadow === true ? { mode: \"open\" } : shadow;\n\t\t\tconst shadowRoot = mountEl.attachShadow(shadowInit);\n\t\t\trendererRoot = {\n\t\t\t\tbody: shadowRoot,\n\t\t\t\thead: shadowRoot,\n\t\t\t\thtml: mountEl,\n\t\t\t};\n\t\t} else if (mountEl) {\n\t\t\trendererRoot = {\n\t\t\t\tbody: mountEl,\n\t\t\t\thead: document.head,\n\t\t\t\thtml: mountEl,\n\t\t\t};\n\t\t}\n\n\t\tconst appRenderer = new DomRenderer(appNodeCache, undefined, rendererRoot);\n\n\t\tif (contentVisibilityConfig) {\n\t\t\tappRenderer.setContentVisibility(contentVisibilityConfig);\n\t\t}\n\n\t\tif (debugHooks.onWarning || debugHooks.onMutation) {\n\t\t\tappRenderer.setDebugHooks({\n\t\t\t\tonWarning: debugHooks.onWarning,\n\t\t\t\tonMutation: debugHooks.onMutation,\n\t\t\t});\n\t\t}\n\n\t\t// Seed structural nodes (always — without these, worker mutations targeting body/head/html are silently dropped)\n\t\tconst root = appRenderer.getRoot();\n\t\tappNodeCache.set(BODY_NODE_ID, root.body as unknown as Node);\n\t\tappNodeCache.set(HEAD_NODE_ID, root.head as unknown as Node);\n\t\tappNodeCache.set(HTML_NODE_ID, root.html);\n\n\t\t// Seed document node for document-level event listeners\n\t\tappNodeCache.set(DOCUMENT_NODE_ID, document as unknown as Node);\n\n\t\t// When a node is removed, detach event listeners for this app\n\t\tappRenderer.onNodeRemoved = (id) => {\n\t\t\tconst bridge = eventBridges.get(appId);\n\t\t\tif (bridge) {\n\t\t\t\tbridge.detachByNodeId(id);\n\t\t\t}\n\t\t};\n\n\t\trenderers.set(appId, appRenderer);\n\n\t\tconst bridge = new EventBridge(appId, appNodeCache);\n\t\tconst appTransport = threadManager.getTransport(appId);\n\t\tif (appTransport) {\n\t\t\t// Enable transport stats measurement when devtools are active\n\t\t\tif (config.debug?.exposeDevtools) {\n\t\t\t\tappTransport.enableStats?.(true);\n\t\t\t}\n\t\t\tbridge.setTransport(appTransport);\n\n\t\t\t// Wire transport error/close handlers for crash recovery (B4)\n\t\t\tconst cleanupDeadApp = () => {\n\t\t\t\tbridge.detachAll();\n\t\t\t\teventBridges.delete(appId);\n\t\t\t\tappRenderer.clear();\n\t\t\t\trenderers.delete(appId);\n\t\t\t\tif (lastAppId === appId) {\n\t\t\t\t\tlastRenderer = null;\n\t\t\t\t\tlastAppId = null;\n\t\t\t\t}\n\t\t\t\tconst host = syncHosts.get(appId);\n\t\t\t\tif (host) {\n\t\t\t\t\thost.stopPolling();\n\t\t\t\t\tsyncHosts.delete(appId);\n\t\t\t\t}\n\t\t\t\tscheduler.setAppCount(renderers.size);\n\t\t\t};\n\n\t\t\tconsole.debug(\n\t\t\t\t\"[async-dom] App\",\n\t\t\t\tappId,\n\t\t\t\t\"transport ready, readyState:\",\n\t\t\t\tappTransport.readyState,\n\t\t\t);\n\n\t\t\tappTransport.onError = (error: Error) => {\n\t\t\t\tconsole.error(\"[async-dom] App\", appId, \"worker error:\", error.message);\n\t\t\t\tonError?.({ message: error.message, stack: error.stack, name: error.name }, appId);\n\t\t\t};\n\n\t\t\tappTransport.onClose = () => {\n\t\t\t\tconsole.warn(\"[async-dom] App\", appId, \"worker disconnected, cleaning up\");\n\t\t\t\tcleanupDeadApp();\n\t\t\t};\n\n\t\t\t// Also handle error system messages from the worker\n\t\t\tappTransport.onMessage((message: Message) => {\n\t\t\t\tif (isSystemMessage(message) && message.type === \"error\" && \"error\" in message) {\n\t\t\t\t\tconst errMsg = message as {\n\t\t\t\t\t\ttype: \"error\";\n\t\t\t\t\t\tappId: AppId;\n\t\t\t\t\t\terror: import(\"../core/protocol.ts\").SerializedError;\n\t\t\t\t\t};\n\t\t\t\t\tonError?.(errMsg.error, appId);\n\t\t\t\t\t// Route worker errors to devtools panel as formatted warnings\n\t\t\t\t\tconst err = errMsg.error;\n\t\t\t\t\tconst location = err.filename\n\t\t\t\t\t\t? ` at ${err.filename}:${err.lineno ?? \"?\"}:${err.colno ?? \"?\"}`\n\t\t\t\t\t\t: \"\";\n\t\t\t\t\tcaptureWarning({\n\t\t\t\t\t\tcode: err.isUnhandledRejection ? \"WORKER_UNHANDLED_REJECTION\" : \"WORKER_ERROR\",\n\t\t\t\t\t\tmessage: `[${String(appId)}] ${err.name ?? \"Error\"}: ${err.message}${location}${err.stack ? `\\n${err.stack}` : \"\"}`,\n\t\t\t\t\t\tcontext: { appId: String(appId), error: err },\n\t\t\t\t\t\ttimestamp: performance.now(),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\t// Wire timing result callback to emit EventLogEntry via debug hooks\n\t\tif (debugHooks.onEvent) {\n\t\t\tbridge.onTimingResult = (trace) => {\n\t\t\t\tdebugHooks.onEvent?.({\n\t\t\t\t\tside: \"main\",\n\t\t\t\t\tphase: \"dispatch\",\n\t\t\t\t\teventType: trace.eventType,\n\t\t\t\t\tlistenerId: trace.listenerId,\n\t\t\t\t\ttargetId: null,\n\t\t\t\t\ttimestamp: trace.timestamp,\n\t\t\t\t\ttransportMs: trace.transportMs,\n\t\t\t\t\tdispatchMs: trace.dispatchMs,\n\t\t\t\t\tmutationCount: trace.mutationCount,\n\t\t\t\t});\n\t\t\t};\n\t\t}\n\t\teventBridges.set(appId, bridge);\n\t\tscheduler.setAppCount(renderers.size);\n\n\t\t// Create sync channel for synchronous DOM reads\n\t\t// For remote apps (no worker), skip SAB unless explicitly enabled\n\t\tconst shouldCreateSyncChannel = worker ? true : (enableSyncChannel ?? false);\n\t\tlet sharedBuffer: SharedArrayBuffer | undefined;\n\t\tif (shouldCreateSyncChannel && typeof SharedArrayBuffer !== \"undefined\") {\n\t\t\ttry {\n\t\t\t\tsharedBuffer = new SharedArrayBuffer(65536);\n\t\t\t\tconst host = new SyncChannelHost(sharedBuffer);\n\t\t\t\thost.startPolling((query) => handleSyncQuery(appRenderer, query));\n\t\t\t\tsyncHosts.set(appId, host);\n\t\t\t} catch {\n\t\t\t\t// SharedArrayBuffer may not be available (missing COOP/COEP headers)\n\t\t\t\tsharedBuffer = undefined;\n\t\t\t}\n\t\t}\n\n\t\t// Handle async query messages from the worker\n\t\tif (appTransport) {\n\t\t\tappTransport.onMessage((message: Message) => {\n\t\t\t\tif (isSystemMessage(message) && message.type === \"query\") {\n\t\t\t\t\tconst queryMsg = message as {\n\t\t\t\t\t\ttype: \"query\";\n\t\t\t\t\t\tuid: number;\n\t\t\t\t\t\tnodeId: NodeId;\n\t\t\t\t\t\tquery: string;\n\t\t\t\t\t\tproperty?: string;\n\t\t\t\t\t};\n\t\t\t\t\tconst queryTypeMap: Record<string, QueryType> = {\n\t\t\t\t\t\tboundingRect: QueryType.BoundingRect,\n\t\t\t\t\t\tcomputedStyle: QueryType.ComputedStyle,\n\t\t\t\t\t\tnodeProperty: QueryType.NodeProperty,\n\t\t\t\t\t\twindowProperty: QueryType.WindowProperty,\n\t\t\t\t\t};\n\t\t\t\t\tconst queryType = queryTypeMap[queryMsg.query] ?? QueryType.NodeProperty;\n\t\t\t\t\tconst result = handleSyncQuery(appRenderer, {\n\t\t\t\t\t\tqueryType,\n\t\t\t\t\t\tdata: JSON.stringify({ nodeId: queryMsg.nodeId, property: queryMsg.property }),\n\t\t\t\t\t});\n\t\t\t\t\tappTransport.send({ type: \"queryResult\", uid: queryMsg.uid, result });\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// Send init message with shared buffer\n\t\tthreadManager.sendToThread(appId, {\n\t\t\ttype: \"init\",\n\t\t\tappId,\n\t\t\tlocation: {\n\t\t\t\thash: window.location.hash,\n\t\t\t\thref: window.location.href,\n\t\t\t\tport: window.location.port,\n\t\t\t\thost: window.location.host,\n\t\t\t\torigin: window.location.origin,\n\t\t\t\thostname: window.location.hostname,\n\t\t\t\tpathname: window.location.pathname,\n\t\t\t\tprotocol: window.location.protocol,\n\t\t\t\tsearch: window.location.search,\n\t\t\t\tstate: window.history.state,\n\t\t\t},\n\t\t\tsharedBuffer,\n\t\t});\n\n\t\treturn appId;\n\t}\n\n\tlet devtoolsPanelHandle: { destroy: () => void } | null = null;\n\n\tif (config.debug?.exposeDevtools) {\n\t\t(globalThis as Record<string, unknown>).__ASYNC_DOM_DEVTOOLS__ = {\n\t\t\tscheduler: {\n\t\t\t\tpending: () => scheduler.pendingCount,\n\t\t\t\tstats: () => scheduler.getStats(),\n\t\t\t\tframeLog: () => scheduler.getFrameLog(),\n\t\t\t\tflush: () => scheduler.flush(),\n\t\t\t\tstop: () => scheduler.stop(),\n\t\t\t\tstart: () => scheduler.start(),\n\t\t\t},\n\t\t\tgetEventTraces: () => {\n\t\t\t\tconst traces: Array<{\n\t\t\t\t\teventType: string;\n\t\t\t\t\tserializeMs: number;\n\t\t\t\t\ttimestamp: number;\n\t\t\t\t}> = [];\n\t\t\t\tfor (const bridge of eventBridges.values()) {\n\t\t\t\t\ttraces.push(...bridge.getEventTraces());\n\t\t\t\t}\n\t\t\t\ttraces.sort((a, b) => a.timestamp - b.timestamp);\n\t\t\t\treturn traces;\n\t\t\t},\n\t\t\tenableHighlightUpdates: (enabled: boolean) => {\n\t\t\t\tfor (const r of renderers.values()) {\n\t\t\t\t\tr.enableHighlightUpdates(enabled);\n\t\t\t\t}\n\t\t\t},\n\t\t\tfindRealNode: (nodeId: number) => {\n\t\t\t\tfor (const r of renderers.values()) {\n\t\t\t\t\tconst node = r.getNode(nodeId as NodeId);\n\t\t\t\t\tif (node) return node;\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t},\n\t\t\tgetListenersForNode: (nodeId: number) => {\n\t\t\t\tconst results: Array<{ listenerId: string; eventName: string }> = [];\n\t\t\t\tfor (const bridge of eventBridges.values()) {\n\t\t\t\t\tresults.push(...bridge.getListenersForNode(nodeId as NodeId));\n\t\t\t\t}\n\t\t\t\treturn results;\n\t\t\t},\n\t\t\tdebugStats: () => debugStats.snapshot(),\n\t\t\tapps: () => [...renderers.keys()],\n\t\t\trenderers: () => {\n\t\t\t\tconst info: Record<string, unknown> = {};\n\t\t\t\tfor (const [appId, r] of renderers) {\n\t\t\t\t\tinfo[String(appId)] = { root: r.getRoot() };\n\t\t\t\t}\n\t\t\t\treturn info;\n\t\t\t},\n\t\t\t// Request fresh virtual DOM tree + stats from all worker threads\n\t\t\trefreshDebugData: () => {\n\t\t\t\tfor (const appId of renderers.keys()) {\n\t\t\t\t\trequestDebugData(appId);\n\t\t\t\t}\n\t\t\t},\n\t\t\t// Get cached debug data for a specific app\n\t\t\tgetAppData: (appId: string) => debugData.get(appId as AppId),\n\t\t\t// Get transport stats for all apps\n\t\t\tgetTransportStats: () => {\n\t\t\t\tconst result: Record<\n\t\t\t\t\tstring,\n\t\t\t\t\t{\n\t\t\t\t\t\tmessageCount: number;\n\t\t\t\t\t\ttotalBytes: number;\n\t\t\t\t\t\tlargestMessageBytes: number;\n\t\t\t\t\t\tlastMessageBytes: number;\n\t\t\t\t\t} | null\n\t\t\t\t> = {};\n\t\t\t\tfor (const appId of renderers.keys()) {\n\t\t\t\t\tconst transport = threadManager.getTransport(appId);\n\t\t\t\t\tresult[String(appId)] = transport?.getStats?.() ?? null;\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\t// Get all apps' cached debug data\n\t\t\tgetAllAppsData: () => {\n\t\t\t\tconst result: Record<\n\t\t\t\t\tstring,\n\t\t\t\t\t{\n\t\t\t\t\t\ttree: unknown;\n\t\t\t\t\t\tworkerStats: unknown;\n\t\t\t\t\t\tperTypeCoalesced: unknown;\n\t\t\t\t\t\tcoalescedLog: unknown;\n\t\t\t\t\t}\n\t\t\t\t> = {};\n\t\t\t\tfor (const [appId, data] of debugData) {\n\t\t\t\t\tresult[String(appId)] = data;\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\t// Replay: apply a single mutation through the renderer\n\t\t\treplayMutation: (mutation: DomMutation, appId: string) => {\n\t\t\t\tconst renderer = renderers.get(appId as AppId);\n\t\t\t\tif (renderer) {\n\t\t\t\t\trenderer.apply(mutation);\n\t\t\t\t}\n\t\t\t},\n\t\t\t// Replay: clear the renderer's DOM subtree and re-apply mutations up to a given index\n\t\t\tclearAndReapply: (\n\t\t\t\tmutations: Array<{ mutation: DomMutation; batchUid?: number }>,\n\t\t\t\tupToIndex: number,\n\t\t\t\tappId?: string,\n\t\t\t) => {\n\t\t\t\t// Route to the correct renderer by appId, or fall back to first\n\t\t\t\tlet renderer: DomRenderer | undefined;\n\t\t\t\tif (appId) {\n\t\t\t\t\trenderer = renderers.get(appId as AppId);\n\t\t\t\t}\n\t\t\t\tif (!renderer) {\n\t\t\t\t\tfor (const r of renderers.values()) {\n\t\t\t\t\t\trenderer = r;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (renderer) {\n\t\t\t\t\tconst root = renderer.getRoot();\n\t\t\t\t\tif (root) {\n\t\t\t\t\t\troot.body.textContent = \"\";\n\t\t\t\t\t\troot.head.textContent = \"\";\n\t\t\t\t\t}\n\t\t\t\t\trenderer.resetNodeCache();\n\t\t\t\t\tconst end = Math.min(upToIndex, mutations.length);\n\t\t\t\t\tfor (let i = 0; i < end; i++) {\n\t\t\t\t\t\trenderer.apply(mutations[i].mutation, mutations[i].batchUid);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t// Feature 15: Causality graph\n\t\t\tgetCausalityTracker: () => causalityTracker,\n\t\t\t// Feature 16: Worker CPU profiler entries\n\t\t\tgetWorkerPerfEntries: () => {\n\t\t\t\tconst result: Record<string, PerfEntryData[]> = {};\n\t\t\t\tfor (const [appId, entries] of workerPerfEntries) {\n\t\t\t\t\tresult[String(appId)] = entries.slice();\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\t// Feature 19: Mutation-to-event correlation\n\t\t\tgetMutationCorrelation: () => mutationCorrelation,\n\t\t};\n\n\t\t// Inject the in-page devtools panel\n\t\tif (typeof document !== \"undefined\") {\n\t\t\tdevtoolsPanelHandle = createDevtoolsPanel();\n\t\t}\n\t}\n\n\tconsole.debug(\"[async-dom] Initialized\", {\n\t\tapps: config.worker ? 1 : 0,\n\t\tdebug: !!config.debug,\n\t\tscheduler: config.scheduler ?? \"default\",\n\t});\n\n\t// Visibility change forwarding\n\tconst visibilityHandler = () => {\n\t\tthreadManager.broadcast({\n\t\t\ttype: \"visibility\",\n\t\t\tstate: document.visibilityState,\n\t\t});\n\t};\n\tdocument.addEventListener(\"visibilitychange\", visibilityHandler);\n\n\treturn {\n\t\tstart() {\n\t\t\tscheduler.start();\n\t\t},\n\n\t\tstop() {\n\t\t\tscheduler.stop();\n\t\t},\n\n\t\tdestroy() {\n\t\t\tscheduler.stop();\n\t\t\tscheduler.flush();\n\t\t\tfor (const r of renderers.values()) {\n\t\t\t\tr.clear();\n\t\t\t}\n\t\t\trenderers.clear();\n\t\t\tlastRenderer = null;\n\t\t\tlastAppId = null;\n\t\t\tfor (const bridge of eventBridges.values()) {\n\t\t\t\tbridge.detachAll();\n\t\t\t}\n\t\t\tfor (const host of syncHosts.values()) {\n\t\t\t\thost.stopPolling();\n\t\t\t}\n\t\t\tsyncHosts.clear();\n\t\t\tdocument.removeEventListener(\"visibilitychange\", visibilityHandler);\n\t\t\tthreadManager.destroyAll();\n\t\t\tif (devtoolsPanelHandle) {\n\t\t\t\tdevtoolsPanelHandle.destroy();\n\t\t\t\tdevtoolsPanelHandle = null;\n\t\t\t}\n\t\t},\n\n\t\taddApp(appConfig: AppConfig): AppId {\n\t\t\treturn addAppInternal(\n\t\t\t\tappConfig.worker,\n\t\t\t\tappConfig.mountPoint,\n\t\t\t\tappConfig.shadow,\n\t\t\t\tappConfig.transport,\n\t\t\t\tappConfig.onError,\n\t\t\t\tappConfig.name,\n\t\t\t);\n\t\t},\n\n\t\taddRemoteApp(remoteConfig: RemoteAppConfig): AppId {\n\t\t\treturn addAppInternal(\n\t\t\t\tundefined,\n\t\t\t\tremoteConfig.mountPoint,\n\t\t\t\tremoteConfig.shadow,\n\t\t\t\tremoteConfig.transport,\n\t\t\t\tremoteConfig.onError,\n\t\t\t\tremoteConfig.name,\n\t\t\t\tremoteConfig.enableSyncChannel,\n\t\t\t);\n\t\t},\n\n\t\tremoveApp(appId: AppId): void {\n\t\t\tconst bridge = eventBridges.get(appId);\n\t\t\tif (bridge) {\n\t\t\t\tbridge.detachAll();\n\t\t\t\teventBridges.delete(appId);\n\t\t\t}\n\t\t\tconst renderer = renderers.get(appId);\n\t\t\tif (renderer) {\n\t\t\t\trenderer.clear();\n\t\t\t\trenderers.delete(appId);\n\t\t\t}\n\t\t\tif (lastAppId === appId) {\n\t\t\t\tlastRenderer = null;\n\t\t\t\tlastAppId = null;\n\t\t\t}\n\t\t\tconst host = syncHosts.get(appId);\n\t\t\tif (host) {\n\t\t\t\thost.stopPolling();\n\t\t\t\tsyncHosts.delete(appId);\n\t\t\t}\n\t\t\tthreadManager.destroyThread(appId);\n\t\t\tscheduler.setAppCount(renderers.size);\n\t\t},\n\t};\n}\n\nexport { FrameScheduler, type SchedulerConfig } from \"../core/scheduler.ts\";\nexport { EventBridge } from \"./event-bridge.ts\";\nexport {\n\ttype ContentVisibilityConfig,\n\tDomRenderer,\n\ttype RendererPermissions,\n\ttype RendererRoot,\n} from \"./renderer.ts\";\nexport type { RemoteConfig, WebSocketConfig, WorkerConfig } from \"./thread-manager.ts\";\nexport { ThreadManager } from \"./thread-manager.ts\";\n"],"mappings":"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"}
|