/* Brain-5D Operator Experience * * Presentation and navigation only. This module never issues runtime control * commands and never fabricates scientific state. Values shown in the chrome * are copied from already-rendered dashboard state or explicitly marked as UI. */ const WORKSPACES = { overview: { icon: "◫", label: "Overview", group: "System", hint: "Live body, health and readiness" }, network: { icon: "⌬", label: "Network", group: "Observe", hint: "Dynamics, topology and populations" }, control: { icon: "▶", label: "Control", group: "Operate", hint: "Runtime, pacing and approvals" }, research: { icon: "⌕", label: "Research", group: "Evidence", hint: "Experiments, provenance and files" }, gate: { icon: "✓", label: "Release", group: "Verify", hint: "Scientific gate and release readiness" }, settings: { icon: "⚙", label: "Settings", group: "Configure", hint: "Runtime-visible configuration" }, embodiment: { icon: "◈", label: "Embodiment", group: "Embody", hint: "Body, devices and interoception" }, }; const STORAGE = { welcome: "brain5d-experience-welcome-dismissed", focus: "brain5d-experience-focus", }; function ensureStylesheet() { // The canonical stylesheet imports the experience layer once. } function activeWorkspaceName() { const section = document.querySelector(".tab-content.active[id^='tab-']"); return section?.id?.replace("tab-", "") || "overview"; } function repairWorkspaceActivation(button) { const name = button?.dataset.tab; if (!name) return; requestAnimationFrame(() => { const active = document.querySelector(".tab-content.active[id^='tab-']"); if (active?.id === `tab-${name}`) return; document.querySelectorAll(".tab-btn[data-tab]").forEach((item) => { item.classList.toggle("active", item === button); }); document.querySelectorAll(".tab-content[id^='tab-']").forEach((tab) => { const selected = tab.id === `tab-${name}`; tab.classList.toggle("active", selected); tab.hidden = !selected; }); document.body.dataset.currentTab = name; }); } function activateWorkspace(name) { const button = document.querySelector(`.tab-btn[data-tab="${name}"]`); if (!button) return; button.click(); repairWorkspaceActivation(button); } function safeText(selector, fallback = "unknown") { const value = document.querySelector(selector)?.textContent?.trim(); return value || fallback; } function makeButton(label, action, title = "") { const button = document.createElement("button"); button.type = "button"; button.className = "experience-icon-button"; button.dataset.experienceAction = action; button.textContent = label; if (title) button.title = title; return button; } function enhanceTopbar() { const topbar = document.querySelector(".topbar"); if (!topbar || topbar.querySelector(".experience-status-cluster")) return; const cluster = document.createElement("div"); cluster.className = "experience-status-cluster"; cluster.setAttribute("aria-label", "Operator context"); cluster.innerHTML = ` WORKSPACEOverview RUNTIMEunknown TICK—`; const right = topbar.querySelector(".topbar-right"); topbar.insertBefore(cluster, right || null); if (right) { right.prepend(makeButton("⌘K", "palette", "Command palette (Ctrl/Cmd+K)")); right.prepend(makeButton("◎", "focus", "Focus mode (F)")); } } function enhanceNavigation() { document.querySelectorAll(".tab-btn[data-tab]").forEach((button) => { const name = button.dataset.tab; const meta = WORKSPACES[name]; if (!meta || button.dataset.experienceEnhanced === "true") return; button.dataset.experienceEnhanced = "true"; button.innerHTML = `${meta.label}${meta.group}`; button.title = meta.hint; }); } function addWorkspaceRibbons() { Object.entries(WORKSPACES).forEach(([name, meta]) => { const tab = document.getElementById(`tab-${name}`); if (!tab || tab.querySelector(":scope > .experience-ribbon")) return; const utility = tab.querySelector(":scope > .dashboard-utility-bar"); const ribbon = document.createElement("aside"); ribbon.className = "experience-ribbon"; ribbon.setAttribute("aria-label", `${meta.label} workspace context`); ribbon.innerHTML = `
${meta.group.toUpperCase()} / ${meta.label.toUpperCase()} ${meta.hint}
`; if (utility) utility.insertAdjacentElement("afterend", ribbon); else tab.prepend(ribbon); }); } function buildWelcome() { if (localStorage.getItem(STORAGE.welcome) === "true") return; const overview = document.getElementById("tab-overview"); if (!overview || overview.querySelector(".experience-welcome")) return; const panel = document.createElement("section"); panel.className = "experience-welcome"; panel.innerHTML = `
OPERATOR ORIENTATION

Vom Systemzustand zur belastbaren Evidenz

Brain-5D trennt Beobachtung, Eingriff, Experiment und Freigabe. Diese Oberfläche führt entlang derselben Kausalitätskette; sie erzeugt keine Messwerte und ersetzt keine wissenschaftlichen Nachweise.

`; const header = overview.querySelector(":scope > .overview-command-bar"); const anchor = overview.querySelector(":scope > .experience-ribbon") || header; anchor?.insertAdjacentElement("afterend", panel); } function buildPalette() { if (document.getElementById("experience-command-palette")) return; const dialog = document.createElement("dialog"); dialog.id = "experience-command-palette"; dialog.className = "experience-dialog experience-command-palette"; dialog.innerHTML = `
COMMAND PALETTE

Navigate Brain-5D

`; document.body.appendChild(dialog); const input = dialog.querySelector("[data-experience-search]"); input.addEventListener("input", () => renderPaletteResults(input.value)); dialog.addEventListener("keydown", handlePaletteKeys); dialog.addEventListener("close", () => { input.value = ""; renderPaletteResults(""); }); renderPaletteResults(""); } function commandItems() { const workspaceItems = Object.entries(WORKSPACES).map(([id, meta]) => ({ id: `workspace:${id}`, icon: meta.icon, label: meta.label, meta: `${meta.group} · ${meta.hint}`, run: () => activateWorkspace(id), })); return [ ...workspaceItems, { id: "action:refresh", icon: "↻", label: "Refresh active view", meta: "Read-only UI refresh", run: () => document.querySelector(".tab-content.active [data-dashboard-action='refresh']")?.click() }, { id: "action:focus", icon: "◎", label: "Toggle focus mode", meta: "Hide secondary chrome", run: toggleFocus }, { id: "action:shortcuts", icon: "?", label: "Keyboard shortcuts", meta: "Show operator navigation keys", run: openShortcuts }, ]; } function renderPaletteResults(query) { const root = document.querySelector("[data-experience-results]"); if (!root) return; const needle = query.trim().toLowerCase(); const items = commandItems().filter((item) => `${item.label} ${item.meta}`.toLowerCase().includes(needle)); root.innerHTML = ""; items.forEach((item, index) => { const button = document.createElement("button"); button.type = "button"; button.className = "experience-command-item"; button.dataset.commandId = item.id; button.dataset.commandIndex = String(index); button.innerHTML = `${item.icon}${item.label}${item.meta}↵`; button.addEventListener("click", () => runCommand(item)); root.appendChild(button); }); root.querySelector("button")?.classList.add("selected"); } function runCommand(item) { document.getElementById("experience-command-palette")?.close(); item.run(); } function handlePaletteKeys(event) { if (!["ArrowDown", "ArrowUp", "Enter"].includes(event.key)) return; const buttons = [...document.querySelectorAll(".experience-command-item")]; if (!buttons.length) return; const current = Math.max(0, buttons.findIndex((button) => button.classList.contains("selected"))); event.preventDefault(); if (event.key === "Enter") { buttons[current]?.click(); return; } buttons[current]?.classList.remove("selected"); const delta = event.key === "ArrowDown" ? 1 : -1; const next = (current + delta + buttons.length) % buttons.length; buttons[next].classList.add("selected"); buttons[next].scrollIntoView({ block: "nearest" }); } function buildShortcuts() { if (document.getElementById("experience-shortcuts")) return; const dialog = document.createElement("dialog"); dialog.id = "experience-shortcuts"; dialog.className = "experience-dialog experience-shortcuts"; dialog.innerHTML = `
KEYBOARD MAP

Operator shortcuts

Ctrl+KCommand palette
?Shortcut map
FFocus mode
1…7Workspace wechseln
EscOverlay schließen

Die globalen Shortcuts navigieren ausschließlich in der Oberfläche. Runtime-Aktionen werden nicht automatisch ausgelöst.

`; document.body.appendChild(dialog); } function openPalette() { const dialog = document.getElementById("experience-command-palette"); if (!dialog) return; dialog.showModal(); requestAnimationFrame(() => dialog.querySelector("[data-experience-search]")?.focus()); } function openShortcuts() { document.getElementById("experience-shortcuts")?.showModal(); } function toggleFocus() { const enabled = document.body.dataset.experienceFocus !== "true"; document.body.dataset.experienceFocus = String(enabled); localStorage.setItem(STORAGE.focus, String(enabled)); document.querySelectorAll('[data-experience-action="focus"]').forEach((button) => { button.classList.toggle("active", enabled); }); } function syncChrome() { const name = activeWorkspaceName(); const meta = WORKSPACES[name] || WORKSPACES.overview; document.querySelectorAll(".experience-status-copy [data-experience-workspace]").forEach((node) => { node.textContent = meta.label; }); document.querySelectorAll("[data-experience-runtime]").forEach((node) => { node.textContent = safeText("#overview-runtime-status", safeText("#control-workspace-state")); }); document.querySelectorAll("[data-experience-tick]").forEach((node) => { node.textContent = safeText("#tick", safeText("#control-workspace-tick", "—")); }); document.body.dataset.experienceWorkspace = name; } function enhanceUnknownStates() { const markers = ["—", "unknown", "pending", "Waiting for component state", "Keine Live-Verbindung."]; document.querySelectorAll(".tab-content strong, .tab-content .overview-empty, .tab-content .heatmap-meta").forEach((node) => { const text = node.textContent?.trim(); if (!markers.includes(text)) return; node.classList.add("experience-unknown-state"); if (!node.title) node.title = "Noch kein beobachteter Wert verfügbar"; }); } function bindActions() { document.addEventListener("click", (event) => { const jump = event.target.closest("[data-jump-workspace]"); if (jump) activateWorkspace(jump.dataset.jumpWorkspace); const action = event.target.closest("[data-experience-action]")?.dataset.experienceAction; if (!action) return; if (action === "palette") openPalette(); if (action === "shortcuts") openShortcuts(); if (action === "focus") toggleFocus(); if (action === "dismiss-welcome") { localStorage.setItem(STORAGE.welcome, "true"); document.querySelector(".experience-welcome")?.remove(); } }); document.addEventListener("keydown", (event) => { const tag = event.target?.tagName?.toLowerCase(); const typing = tag === "input" || tag === "textarea" || tag === "select" || event.target?.isContentEditable; if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "k") { event.preventDefault(); openPalette(); return; } if (typing) return; if (event.key === "?") openShortcuts(); if (event.key.toLowerCase() === "f") toggleFocus(); if (/^[1-7]$/.test(event.key)) activateWorkspace(Object.keys(WORKSPACES)[Number(event.key) - 1]); }); document.querySelectorAll(".tab-btn[data-tab]").forEach((button) => button.addEventListener("click", () => { repairWorkspaceActivation(button); requestAnimationFrame(syncChrome); })); } function observeRenderedState() { const observer = new MutationObserver(() => { syncChrome(); enhanceUnknownStates(); }); ["overview-runtime-status", "tick", "control-workspace-state", "control-workspace-tick"].forEach((id) => { const node = document.getElementById(id); if (node) observer.observe(node, { childList: true, characterData: true, subtree: true }); }); } function restorePreferences() { document.body.dataset.experienceFocus = localStorage.getItem(STORAGE.focus) === "true" ? "true" : "false"; } function init() { ensureStylesheet(); restorePreferences(); enhanceTopbar(); enhanceNavigation(); addWorkspaceRibbons(); buildWelcome(); buildPalette(); buildShortcuts(); bindActions(); observeRenderedState(); syncChrome(); enhanceUnknownStates(); document.body.classList.add("experience-ready"); } ensureStylesheet(); if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", init, { once: true }); else init();