diff --git a/web/standalone/src/components/WasmTool.tsx b/web/standalone/src/components/WasmTool.tsx index 36cb99f..f675ff4 100644 --- a/web/standalone/src/components/WasmTool.tsx +++ b/web/standalone/src/components/WasmTool.tsx @@ -2373,7 +2373,7 @@ export function WasmTool({ {fatal && (

:(

@@ -2403,13 +2403,28 @@ export function WasmTool({ visible on a fatal even with chrome hidden, for the same reason. */} {(!effectiveChromeHidden || fatal) && (

- +
+ + {showLog && ( + + )} +
{showLog && (
               {logs.join("\n")}
diff --git a/web/standalone/src/wasm/fatal-screen.ts b/web/standalone/src/wasm/fatal-screen.ts
index ea849ce..c4348c6 100644
--- a/web/standalone/src/wasm/fatal-screen.ts
+++ b/web/standalone/src/wasm/fatal-screen.ts
@@ -36,8 +36,10 @@ function buildDom(): void {
   const root = doc.createElement("div");
   root.id = "pcbjam-fatal-screen";
   root.setAttribute("data-testid", "fatal-screen-dom");
+  // Same blue as the boot overlay / React fatal screen (#1a1a2e) — one
+  // coherent family across every full-screen state.
   root.style.cssText =
-    "position:fixed;inset:0;z-index:2147483000;background:#1e3a8a;color:#fff;" +
+    "position:fixed;inset:0;z-index:2147483000;background:#1a1a2e;color:#fff;" +
     "display:flex;flex-direction:column;align-items:center;justify-content:center;" +
     "gap:12px;font-family:ui-monospace,Menlo,monospace;padding:24px;box-sizing:border-box;";
 
@@ -67,14 +69,48 @@ function buildDom(): void {
     "padding:4px 14px;font-size:12px;cursor:pointer;font-family:inherit;";
   reload.onclick = () => window.location.reload();
 
+  // Console block mirroring the in-editor one: toggle bar + copy, collapsible.
+  const consoleWrap = doc.createElement("div");
+  consoleWrap.style.cssText = "position:absolute;bottom:0;left:0;right:0;text-align:left;";
+
+  const bar = doc.createElement("div");
+  bar.style.cssText =
+    "display:flex;align-items:center;background:#000000b3;font-size:11px;";
+
+  const logText = () => [...ring, "", dump()].join("\n");
+
+  const toggle = doc.createElement("button");
+  toggle.textContent = "▾ console";
+  toggle.style.cssText =
+    "border:0;background:transparent;color:#fff;padding:4px 12px;cursor:pointer;font:inherit;";
+
+  const copy = doc.createElement("button");
+  copy.textContent = "copy";
+  copy.style.cssText =
+    "border:0;background:transparent;color:#ffffffb3;padding:4px 12px;cursor:pointer;" +
+    "font:inherit;margin-left:auto;";
+  copy.onclick = () => {
+    navigator.clipboard.writeText(logText()).then(
+      () => { copy.textContent = "copied ✓"; },
+      () => { copy.textContent = "copy failed"; },
+    );
+  };
+
   const log = doc.createElement("pre");
   log.style.cssText =
-    "position:absolute;bottom:0;left:0;right:0;max-height:38vh;overflow:auto;" +
-    "margin:0;padding:10px 12px;background:#000000d9;color:#86efac;" +
-    "font-size:11px;line-height:1.35;text-align:left;";
-  log.textContent = [...ring, "", dump()].join("\n");
+    "max-height:38vh;overflow:auto;margin:0;padding:10px 12px;background:#000000d9;" +
+    "color:#86efac;font-size:11px;line-height:1.35;";
+  log.textContent = logText();
 
-  root.append(face, title, err, hint, reload, log);
+  toggle.onclick = () => {
+    const hidden = log.style.display === "none";
+    log.style.display = hidden ? "" : "none";
+    toggle.textContent = hidden ? "▾ console" : "▸ console";
+  };
+
+  bar.append(toggle, copy);
+  consoleWrap.append(bar, log);
+  root.append(face, title, err, hint, reload, consoleWrap);
   doc.body.appendChild(root);
 }