waygraph 0.15.30 → 0.15.32

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.
Files changed (47) hide show
  1. package/dist/auto-explore-run.js +9 -6
  2. package/dist/auto-session/session.js +2 -1
  3. package/dist/pilot-overlay/action-ring.d.ts +16 -0
  4. package/dist/pilot-overlay/action-ring.js +67 -0
  5. package/dist/pilot-overlay/fixtures.js +17 -17
  6. package/dist/pilot-overlay/panel.js +3 -3
  7. package/dist/pilot-overlay/shell.js +27 -27
  8. package/dist/pilot-overlay.d.ts +1 -0
  9. package/dist/pilot-overlay.js +1 -0
  10. package/dist/runner/cursor.js +3 -3
  11. package/dist/runner/inpage/banner.js +2 -2
  12. package/dist/runner/inpage/core.js +23 -23
  13. package/dist/runner/inpage/device.js +11 -11
  14. package/dist/runner/inpage/panel-chrome.js +3 -3
  15. package/dist/runner/inpage/stamp.js +2 -2
  16. package/dist/runner/inpage/swipe-zoom.js +10 -10
  17. package/dist/runner/inpage/todos.js +6 -6
  18. package/dist/runner/overlay-css.js +21 -18
  19. package/dist/runner/overlay-install.js +5 -2
  20. package/dist/runner/rings.js +1 -1
  21. package/dist/runner/slides.js +11 -11
  22. package/dist/runner/step-panels.js +18 -18
  23. package/dist/runner/teardown.js +8 -8
  24. package/dist/runner/todo-dock.js +1 -1
  25. package/dist/step-overlay.js +20 -18
  26. package/dist/ui/components/ring.js +5 -0
  27. package/dist/ui/shadow.d.ts +15 -0
  28. package/dist/ui/shadow.js +42 -0
  29. package/examples/saucedemo/.waygraph-auto/1bd7b7bf.log +0 -0
  30. package/examples/saucedemo/.waygraph-auto/2a577961.log +0 -0
  31. package/examples/saucedemo/.waygraph-auto/2c79c73a.log +0 -0
  32. package/examples/saucedemo/.waygraph-auto/2c94a05b.log +0 -0
  33. package/examples/saucedemo/.waygraph-auto/37b56184.log +0 -0
  34. package/examples/saucedemo/.waygraph-auto/401177a3.log +0 -0
  35. package/examples/saucedemo/.waygraph-auto/476cff76.log +0 -0
  36. package/examples/saucedemo/.waygraph-auto/535e8922.json +8 -0
  37. package/examples/saucedemo/.waygraph-auto/535e8922.log +0 -0
  38. package/examples/saucedemo/.waygraph-auto/68fa0682.log +0 -0
  39. package/examples/saucedemo/.waygraph-auto/73a41843.log +0 -0
  40. package/examples/saucedemo/.waygraph-auto/8598b4c0.log +0 -0
  41. package/examples/saucedemo/.waygraph-auto/982138cf.log +0 -0
  42. package/examples/saucedemo/.waygraph-auto/a8645294.log +0 -0
  43. package/examples/saucedemo/.waygraph-auto/bf8693e7.log +0 -0
  44. package/examples/saucedemo/.waygraph-auto/f86224c6.log +0 -0
  45. package/examples/saucedemo/.waygraph-auto/fc917c18.log +0 -0
  46. package/examples/saucedemo/.waygraph-auto/fe83305d.log +0 -0
  47. package/package.json +1 -1
@@ -10,7 +10,7 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
10
10
  ? payload.sync
11
11
  : "keep";
12
12
  const device = payload && payload.device ? payload.device : null;
13
- const cursor = document.getElementById("wg-cursor");
13
+ const cursor = __wgById("wg-cursor");
14
14
  const MOUSE_SVG =
15
15
  "<svg viewBox='0 0 32 32' width='24' height='24'>" +
16
16
  "<path fill='#0C0C1A' stroke='#fff' stroke-width='1.4' stroke-linejoin='round' " +
@@ -45,12 +45,12 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
45
45
  }
46
46
  };
47
47
  const ensureChip = (preset, touch, remain, orientation) => {
48
- let badge = document.getElementById("wg-device-badge");
48
+ let badge = __wgById("wg-device-badge");
49
49
  if (preset === "desktop" && !touch) {
50
50
  if (badge) {
51
51
  badge.classList.remove("wg-in");
52
52
  setTimeout(() => {
53
- const b = document.getElementById("wg-device-badge");
53
+ const b = __wgById("wg-device-badge");
54
54
  if (b) b.remove();
55
55
  }, 320);
56
56
  }
@@ -60,7 +60,7 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
60
60
  badge = document.createElement("div");
61
61
  badge.id = "wg-device-badge";
62
62
  badge.setAttribute("data-wg-ui", "1");
63
- document.documentElement.appendChild(badge);
63
+ __wgAdd(badge);
64
64
  }
65
65
  badge.dataset.preset = preset;
66
66
  badge.dataset.touch = touch ? "1" : "0";
@@ -85,7 +85,7 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
85
85
  badge.classList.add("wg-in");
86
86
  };
87
87
  const showToast = (preset, touch, title, sub, orientation) => {
88
- let toast = document.getElementById("wg-device-toast");
88
+ let toast = __wgById("wg-device-toast");
89
89
  if (toast && toast._wgTimer) {
90
90
  clearTimeout(toast._wgTimer);
91
91
  toast._wgTimer = null;
@@ -94,10 +94,10 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
94
94
  toast = document.createElement("div");
95
95
  toast.id = "wg-device-toast";
96
96
  toast.setAttribute("data-wg-ui", "1");
97
- document.documentElement.appendChild(toast);
97
+ __wgAdd(toast);
98
98
  }
99
99
  // Hide chip while toast is up (same corner).
100
- const badge = document.getElementById("wg-device-badge");
100
+ const badge = __wgById("wg-device-badge");
101
101
  if (badge) badge.classList.remove("wg-in");
102
102
  toast.dataset.preset = preset;
103
103
  toast.innerHTML =
@@ -115,7 +115,7 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
115
115
  toast.classList.add("wg-out");
116
116
  toast.classList.remove("wg-in");
117
117
  setTimeout(() => {
118
- const t = document.getElementById("wg-device-toast");
118
+ const t = __wgById("wg-device-toast");
119
119
  if (t) t.remove();
120
120
  if (preset !== "desktop" || touch) {
121
121
  ensureChip(preset, touch, true, orientation);
@@ -142,13 +142,13 @@ export function installDevice({ title, favicon, bannerPos, todoPos, envAutoplay,
142
142
  "landscape",
143
143
  );
144
144
  setTimeout(() => {
145
- const badge = document.getElementById("wg-device-badge");
145
+ const badge = __wgById("wg-device-badge");
146
146
  if (badge) badge.remove();
147
147
  }, 2600);
148
148
  } else {
149
- const badge = document.getElementById("wg-device-badge");
149
+ const badge = __wgById("wg-device-badge");
150
150
  if (badge) badge.remove();
151
- const toast = document.getElementById("wg-device-toast");
151
+ const toast = __wgById("wg-device-toast");
152
152
  if (toast) toast.remove();
153
153
  }
154
154
  window.__wgDevicePreset = "desktop";
@@ -69,7 +69,7 @@ export function installPanelChrome({ title, favicon, bannerPos, todoPos, envAuto
69
69
  } catch {
70
70
  /* ignore */
71
71
  }
72
- const runBtn = document.getElementById("wg-run");
72
+ const runBtn = __wgById("wg-run");
73
73
  const show = !!hidden && !auto && !!runBtn;
74
74
  miniNext.classList.toggle("wg-mini-next-show", show);
75
75
  if (runBtn) {
@@ -125,7 +125,7 @@ export function installPanelChrome({ title, favicon, bannerPos, todoPos, envAuto
125
125
  miniNext.dataset.wgWired = "1";
126
126
  miniNext.addEventListener("click", (e) => {
127
127
  e.stopPropagation();
128
- const runBtn = document.getElementById("wg-run");
128
+ const runBtn = __wgById("wg-run");
129
129
  if (runBtn && !runBtn.disabled) {
130
130
  runBtn.click();
131
131
  return;
@@ -133,7 +133,7 @@ export function installPanelChrome({ title, favicon, bannerPos, todoPos, envAuto
133
133
  if (typeof window.__wgNext === "function") window.__wgNext({});
134
134
  });
135
135
  }
136
- const autoCb = document.getElementById("wg-autoplay-cb");
136
+ const autoCb = __wgById("wg-autoplay-cb");
137
137
  if (autoCb && !autoCb.dataset.wgMiniWired) {
138
138
  autoCb.dataset.wgMiniWired = "1";
139
139
  autoCb.addEventListener("change", () => {
@@ -20,7 +20,7 @@ export function installStamp({ title, favicon, bannerPos, todoPos, envAutoplay,
20
20
  el.setAttribute("data-wg-ready", meta.ready === false ? "0" : "1");
21
21
  };
22
22
  window.__wgOverlayBeacon = () => {
23
- return Array.from(document.querySelectorAll("[data-wg-ui=\"1\"]")).map((el) => {
23
+ return Array.from(__wgQA("[data-wg-ui=\"1\"]")).map((el) => {
24
24
  const r = el.getBoundingClientRect();
25
25
  const st = getComputedStyle(el);
26
26
  return {
@@ -41,6 +41,6 @@ export function installStamp({ title, favicon, bannerPos, todoPos, envAutoplay,
41
41
  };
42
42
  });
43
43
  };
44
- const existingBanner = document.getElementById("wg-banner");
44
+ const existingBanner = __wgById("wg-banner");
45
45
  if (existingBanner) window.__wgStampModal(existingBanner, "banner", { ready: true });
46
46
  }
@@ -15,7 +15,7 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
15
15
  o.label ||
16
16
  (dir === "left" || dir === "right" ? "swipe" : "swipe") +
17
17
  (o.hint ? " \u00b7 " + o.hint : "");
18
- let layer = document.getElementById("wg-swipe-layer");
18
+ let layer = __wgById("wg-swipe-layer");
19
19
  if (layer && layer._wgTimer) {
20
20
  clearTimeout(layer._wgTimer);
21
21
  layer._wgTimer = null;
@@ -31,7 +31,7 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
31
31
  lab.textContent = label;
32
32
  layer.appendChild(lab);
33
33
  layer.appendChild(finger);
34
- document.documentElement.appendChild(layer);
34
+ __wgAdd(layer);
35
35
  const vw = window.innerWidth || 390;
36
36
  const vh = window.innerHeight || 844;
37
37
  const pad = Math.min(vw, vh) * 0.18;
@@ -89,7 +89,7 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
89
89
  finger.style.opacity = "0";
90
90
  layer.classList.remove("wg-in");
91
91
  layer._wgTimer = setTimeout(() => {
92
- const el = document.getElementById("wg-swipe-layer");
92
+ const el = __wgById("wg-swipe-layer");
93
93
  if (el) el.remove();
94
94
  }, 380);
95
95
  }
@@ -108,7 +108,7 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
108
108
  delete el.dataset.wgZoomed;
109
109
  });
110
110
  // Undo any prior shell-camera experiment - restore device fit scale only.
111
- const shell = document.getElementById("wg-device-shell");
111
+ const shell = __wgById("wg-device-shell");
112
112
  if (shell && shell.dataset.wgCamBase != null) {
113
113
  shell.style.transform = shell.dataset.wgCamBase;
114
114
  if (shell.dataset.wgCamOrigin) {
@@ -130,12 +130,12 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
130
130
  window.__wgSetZoomBadge = (scale, sel) => {
131
131
  const n = Number(scale);
132
132
  const level = Number.isFinite(n) && n > 0 ? n : 1;
133
- let badge = document.getElementById("wg-zoom-badge");
133
+ let badge = __wgById("wg-zoom-badge");
134
134
  if (!badge) {
135
135
  badge = document.createElement("div");
136
136
  badge.id = "wg-zoom-badge";
137
137
  badge.setAttribute("data-wg-ui", "1");
138
- document.documentElement.appendChild(badge);
138
+ __wgAdd(badge);
139
139
  }
140
140
  const zoomed = level > 1.001 || level < 0.999;
141
141
  badge.dataset.zoomed = zoomed ? "1" : "0";
@@ -156,12 +156,12 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
156
156
  }
157
157
  };
158
158
  window.__wgSetTypingBadge = (on, label) => {
159
- let badge = document.getElementById("wg-typing-badge");
159
+ let badge = __wgById("wg-typing-badge");
160
160
  if (!on) {
161
161
  if (badge) {
162
162
  badge.classList.remove("wg-in");
163
163
  setTimeout(() => {
164
- const b = document.getElementById("wg-typing-badge");
164
+ const b = __wgById("wg-typing-badge");
165
165
  if (b && !b.classList.contains("wg-in")) b.remove();
166
166
  }, 220);
167
167
  }
@@ -171,7 +171,7 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
171
171
  badge = document.createElement("div");
172
172
  badge.id = "wg-typing-badge";
173
173
  badge.setAttribute("data-wg-ui", "1");
174
- document.documentElement.appendChild(badge);
174
+ __wgAdd(badge);
175
175
  }
176
176
  const text = label ? String(label).slice(0, 40) : "typing";
177
177
  badge.innerHTML =
@@ -196,7 +196,7 @@ export function installSwipeZoom({ title, favicon, bannerPos, todoPos, envAutopl
196
196
  el.style.removeProperty("position");
197
197
  delete el.dataset.wgZoomed;
198
198
  });
199
- const shell = document.getElementById("wg-device-shell");
199
+ const shell = __wgById("wg-device-shell");
200
200
  if (shell && shell.dataset.wgCamBase != null) {
201
201
  shell.style.transform = shell.dataset.wgCamBase;
202
202
  shell.style.transformOrigin = shell.dataset.wgCamOrigin || "center center";
@@ -43,10 +43,10 @@ export function installTodos({ title, favicon, bannerPos, todoPos, envAutoplay,
43
43
  "_default";
44
44
 
45
45
  // Drop any in-panel leftover (old builds put #wg-todos in .wg-body).
46
- document.querySelectorAll("#wg-panel #wg-todos").forEach((el) => el.remove());
46
+ __wgQA("#wg-panel #wg-todos").forEach((el) => el.remove());
47
47
 
48
48
  const allDocks = () =>
49
- [...document.querySelectorAll(".wg-todo-dock, #wg-todo-dock")].filter(
49
+ [...__wgQA(".wg-todo-dock, #wg-todo-dock")].filter(
50
50
  (el, i, arr) => arr.indexOf(el) === i,
51
51
  );
52
52
  const relayoutTodoDocks = () => {
@@ -60,11 +60,11 @@ export function installTodos({ title, favicon, bannerPos, todoPos, envAutoplay,
60
60
  const findDock = (key) => {
61
61
  if (key === "_default") {
62
62
  return (
63
- document.querySelector('.wg-todo-dock[data-wg-todo-key="_default"]') ||
64
- document.getElementById("wg-todo-dock")
63
+ __wgQ('.wg-todo-dock[data-wg-todo-key="_default"]') ||
64
+ __wgById("wg-todo-dock")
65
65
  );
66
66
  }
67
- const all = document.querySelectorAll(".wg-todo-dock");
67
+ const all = __wgQA(".wg-todo-dock");
68
68
  for (let i = 0; i < all.length; i++) {
69
69
  if (all[i].getAttribute("data-wg-todo-key") === String(key)) return all[i];
70
70
  }
@@ -141,7 +141,7 @@ export function installTodos({ title, favicon, bannerPos, todoPos, envAutoplay,
141
141
  /* ignore */
142
142
  }
143
143
  });
144
- document.documentElement.appendChild(dock);
144
+ __wgAdd(dock);
145
145
  } else if (wantPos) {
146
146
  dock.dataset.pos = wantPos;
147
147
  try {
@@ -115,24 +115,6 @@ export const RING_CSS =
115
115
  ".wg-todo-dock .wg-todo-dock-title{font:700 11px/1.2 system-ui,sans-serif;color:#c9a6ff;" +
116
116
  "letter-spacing:.04em;text-transform:uppercase;margin:0 0 8px;}" +
117
117
  ".wg-todo-dock .wg-todos-list,#wg-todo-dock #wg-todos,.wg-todo-dock #wg-todos{list-style:none;margin:0;padding:0;background:transparent;border:none;}" +
118
- // Video device stage: keep recordVideo size fixed; center a device-sized shell.
119
- "html.wg-video-device-stage{background:#0b1220 !important;}" +
120
- "html.wg-video-device-stage body{margin:0 !important;min-height:100vh !important;" +
121
- "display:flex !important;align-items:center !important;justify-content:center !important;" +
122
- "background:#0b1220 !important;overflow:hidden !important;}" +
123
- "#wg-device-shell{flex-shrink:0;overflow:auto;background:#fff;" +
124
- "border-radius:16px;box-shadow:0 24px 80px rgba(0,0,0,.55),0 0 0 1px rgba(255,255,255,.08);" +
125
- "transform-origin:center center;" +
126
- /* Force radius clip on all corners (Chrome + transform/scale). */
127
- "-webkit-mask-image:-webkit-radial-gradient(white,black);" +
128
- "isolation:isolate;" +
129
- "transition:border-radius .55s cubic-bezier(.22,1,.36,1),box-shadow .55s ease," +
130
- "transform .55s cubic-bezier(.22,1,.36,1),width .5s ease,height .5s ease,max-width .5s ease,max-height .5s ease;}" +
131
- "#wg-device-shell.wg-shell-enter{border-radius:0;box-shadow:none;}" +
132
- "#wg-device-shell.wg-shell-shutter-out{border-radius:0 !important;" +
133
- "box-shadow:none !important;outline:none !important;border:none !important;}" +
134
- "#wg-device-shell.wg-shell-desktop-flat{border-radius:0 !important;box-shadow:none !important;" +
135
- "outline:none !important;border:none !important;-webkit-mask-image:none;}" +
136
118
  // Always-on zoom HUD - bottom-right (top-left is crowded: todos + banners).
137
119
  "#wg-zoom-badge{position:fixed;z-index:2147483646;bottom:14px;right:14px;" +
138
120
  "display:flex;align-items:center;gap:7px;padding:6px 11px 6px 8px;" +
@@ -329,3 +311,24 @@ export const WAYGRAPH_FAVICON =
329
311
  "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'>" +
330
312
  "<circle cx='16' cy='16' r='14' fill='#7C3AED'/></svg>",
331
313
  );
314
+
315
+ // Rules that style the HOST page (device stage) - these must stay in the light DOM, outside the overlay's shadow root.
316
+ export const HOST_CSS =
317
+ // Video device stage: keep recordVideo size fixed; center a device-sized shell.
318
+ "html.wg-video-device-stage{background:#0b1220 !important;}" +
319
+ "html.wg-video-device-stage body{margin:0 !important;min-height:100vh !important;" +
320
+ "display:flex !important;align-items:center !important;justify-content:center !important;" +
321
+ "background:#0b1220 !important;overflow:hidden !important;}" +
322
+ "#wg-device-shell{flex-shrink:0;overflow:auto;background:#fff;" +
323
+ "border-radius:16px;box-shadow:0 24px 80px rgba(0,0,0,.55),0 0 0 1px rgba(255,255,255,.08);" +
324
+ "transform-origin:center center;" +
325
+ /* Force radius clip on all corners (Chrome + transform/scale). */
326
+ "-webkit-mask-image:-webkit-radial-gradient(white,black);" +
327
+ "isolation:isolate;" +
328
+ "transition:border-radius .55s cubic-bezier(.22,1,.36,1),box-shadow .55s ease," +
329
+ "transform .55s cubic-bezier(.22,1,.36,1),width .5s ease,height .5s ease,max-width .5s ease,max-height .5s ease;}" +
330
+ "#wg-device-shell.wg-shell-enter{border-radius:0;box-shadow:none;}" +
331
+ "#wg-device-shell.wg-shell-shutter-out{border-radius:0 !important;" +
332
+ "box-shadow:none !important;outline:none !important;border:none !important;}" +
333
+ "#wg-device-shell.wg-shell-desktop-flat{border-radius:0 !important;box-shadow:none !important;" +
334
+ "outline:none !important;border:none !important;-webkit-mask-image:none;}";
@@ -1,6 +1,7 @@
1
1
  // Moved verbatim from the former CHAIN_RUNNER_SCRIPT template string in cli.ts (see src/ARCHITECTURE.md).
2
2
  // Runs inside the target project's own waygraph copy - keep it dependency-light and self-contained.
3
- import { RING_CSS, WAYGRAPH_FAVICON } from "./overlay-css.js";
3
+ import { HOST_CSS, RING_CSS, WAYGRAPH_FAVICON } from "./overlay-css.js";
4
+ import { ensureShadowRoot } from "../ui/shadow.js";
4
5
  import { resolveTodoDockUi } from "../highlights.js";
5
6
  import { installCore } from "./inpage/core.js";
6
7
  import { installSwipeZoom } from "./inpage/swipe-zoom.js";
@@ -12,7 +13,9 @@ import { installDevice } from "./inpage/device.js";
12
13
  import { applyVideoDeviceStage } from "./device-stage.js";
13
14
 
14
15
  export async function installOverlay(page, title) {
15
- await page.addStyleTag({ content: RING_CSS }).catch(() => {});
16
+ await ensureShadowRoot(page);
17
+ await page.evaluate(([css, key]) => __wgCss(css, key), [RING_CSS, "wg-overlay-css"]).catch(() => {});
18
+ await page.addStyleTag({ content: HOST_CSS }).catch(() => {});
16
19
  // Default top-left; override with WAYGRAPH_TITLE_POS=left|center|right.
17
20
  // Click cycles left -> center -> right (persisted in localStorage so a
18
21
  // navigation that rebuilds the banner keeps the human's last pick).
@@ -247,7 +247,7 @@ export async function cycleHighlightRings(page, highlights, gatesFast, opts) {
247
247
  return;
248
248
  }
249
249
  // Fallback for pages that never got installOverlay sync helper.
250
- const ul = document.getElementById("wg-todos");
250
+ const ul = __wgById("wg-todos");
251
251
  if (!ul) return;
252
252
  ul.innerHTML = todos
253
253
  .map((t) => {
@@ -66,7 +66,7 @@ export async function presentSlides(page, slides, _gate, opts) {
66
66
  }
67
67
  await page.evaluate(
68
68
  (info) => {
69
- let panel = document.getElementById("wg-panel");
69
+ let panel = __wgById("wg-panel");
70
70
  const isNew = !panel;
71
71
  if (!panel) {
72
72
  panel = document.createElement("div");
@@ -139,7 +139,7 @@ export async function presentSlides(page, slides, _gate, opts) {
139
139
  ">Auto-advancing...</div>" +
140
140
  "</div>";
141
141
  if (isNew) {
142
- document.documentElement.appendChild(panel);
142
+ __wgAdd(panel);
143
143
  requestAnimationFrame(() => panel.classList.add("wg-in"));
144
144
  }
145
145
  if (window.__wgWirePanelChrome) {
@@ -172,7 +172,7 @@ export async function presentSlides(page, slides, _gate, opts) {
172
172
  } catch {
173
173
  /* ignore */
174
174
  }
175
- const cb = document.getElementById("wg-autoplay-cb");
175
+ const cb = __wgById("wg-autoplay-cb");
176
176
  if (cb) {
177
177
  cb.checked = autoNow;
178
178
  cb.addEventListener("change", () => {
@@ -181,17 +181,17 @@ export async function presentSlides(page, slides, _gate, opts) {
181
181
  } catch {
182
182
  /* ignore */
183
183
  }
184
- const manual = document.getElementById("wg-gate-manual");
185
- const auto = document.getElementById("wg-gate-auto");
184
+ const manual = __wgById("wg-gate-manual");
185
+ const auto = __wgById("wg-gate-auto");
186
186
  if (manual) manual.style.display = cb.checked ? "none" : "";
187
187
  if (auto) auto.style.display = cb.checked ? "" : "none";
188
188
  });
189
189
  }
190
- const manual = document.getElementById("wg-gate-manual");
191
- const auto = document.getElementById("wg-gate-auto");
190
+ const manual = __wgById("wg-gate-manual");
191
+ const auto = __wgById("wg-gate-auto");
192
192
  if (manual) manual.style.display = autoNow ? "none" : "";
193
193
  if (auto) auto.style.display = autoNow ? "" : "none";
194
- const runBtn = document.getElementById("wg-run");
194
+ const runBtn = __wgById("wg-run");
195
195
  if (runBtn) {
196
196
  runBtn.removeAttribute("data-wg-acked");
197
197
  runBtn.addEventListener("click", (e) => {
@@ -205,8 +205,8 @@ export async function presentSlides(page, slides, _gate, opts) {
205
205
  const unlockAt = Date.now() + info.dwellMs;
206
206
  const tick = () => {
207
207
  const left = Math.max(0, unlockAt - Date.now());
208
- const hint = document.getElementById("wg-dwell-hint");
209
- const btn = document.getElementById("wg-run");
208
+ const hint = __wgById("wg-dwell-hint");
209
+ const btn = __wgById("wg-run");
210
210
  if (left <= 0) {
211
211
  if (hint) hint.remove();
212
212
  if (btn) btn.disabled = false;
@@ -248,7 +248,7 @@ export async function presentSlides(page, slides, _gate, opts) {
248
248
  for (;;) {
249
249
  const acked = await page
250
250
  .evaluate(() => {
251
- const btn = document.getElementById("wg-run");
251
+ const btn = __wgById("wg-run");
252
252
  return !!(btn && btn.getAttribute("data-wg-acked") === "1");
253
253
  })
254
254
  .catch(() => false);
@@ -33,7 +33,7 @@ export async function renderBeforeStep(page, info) {
33
33
  // flash - it only ever fades in ONCE, the first time this page
34
34
  // genuinely has no panel yet (a real navigation wiped the whole
35
35
  // document, or this is the very first step).
36
- let panel = document.getElementById("wg-panel");
36
+ let panel = __wgById("wg-panel");
37
37
  const isNewPanel = !panel;
38
38
  if (!panel) {
39
39
  panel = document.createElement("div");
@@ -126,7 +126,7 @@ export async function renderBeforeStep(page, info) {
126
126
  ">Auto-advancing...</div>";
127
127
  panel.innerHTML = html;
128
128
  if (isNewPanel) {
129
- document.documentElement.appendChild(panel);
129
+ __wgAdd(panel);
130
130
  requestAnimationFrame(() => panel.classList.add("wg-in"));
131
131
  } else {
132
132
  panel.classList.add("wg-in");
@@ -204,7 +204,7 @@ export async function renderBeforeStep(page, info) {
204
204
  panel.querySelectorAll("textarea[data-key]").forEach((ta) => {
205
205
  ta.addEventListener("input", applyKeyPretty);
206
206
  });
207
- const runBtn = document.getElementById("wg-run");
207
+ const runBtn = __wgById("wg-run");
208
208
  if (runBtn) {
209
209
  runBtn.addEventListener("click", () => {
210
210
  const edits = {};
@@ -220,7 +220,7 @@ export async function renderBeforeStep(page, info) {
220
220
  // still always wins over an active autoplay wait, whichever the
221
221
  // checkbox says - this is the "hybrid" control: autoplay is a
222
222
  // default, not a lockout.
223
- const cb = document.getElementById("wg-autoplay-cb");
223
+ const cb = __wgById("wg-autoplay-cb");
224
224
  if (cb) {
225
225
  cb.addEventListener("change", () => {
226
226
  try {
@@ -228,8 +228,8 @@ export async function renderBeforeStep(page, info) {
228
228
  } catch {
229
229
  /* private mode / blocked storage - toggle still works this page */
230
230
  }
231
- const manual = document.getElementById("wg-gate-manual");
232
- const auto = document.getElementById("wg-gate-auto");
231
+ const manual = __wgById("wg-gate-manual");
232
+ const auto = __wgById("wg-gate-auto");
233
233
  if (manual) manual.style.display = cb.checked ? "none" : "";
234
234
  if (auto) auto.style.display = cb.checked ? "" : "none";
235
235
  });
@@ -256,8 +256,8 @@ export async function renderBeforeStep(page, info) {
256
256
  return {
257
257
  ok: !!(panel && textOk && opacityOk),
258
258
  beacons,
259
- hasRun: !!document.getElementById("wg-run"),
260
- readyAttr: document.getElementById("wg-panel")?.getAttribute("data-wg-ready") || null,
259
+ hasRun: !!__wgById("wg-run"),
260
+ readyAttr: __wgById("wg-panel")?.getAttribute("data-wg-ready") || null,
261
261
  };
262
262
  })
263
263
  .catch((e) => ({ ok: false, reason: String(e && e.message ? e.message : e) }));
@@ -412,7 +412,7 @@ export async function renderAfterStep(page, info) {
412
412
  await page
413
413
  .evaluate((info) => {
414
414
  // Reused in place - see renderBeforeStep's own comment on this.
415
- let panel = document.getElementById("wg-panel");
415
+ let panel = __wgById("wg-panel");
416
416
  const isNewPanel = !panel;
417
417
  if (!panel) {
418
418
  panel = document.createElement("div");
@@ -497,7 +497,7 @@ export async function renderAfterStep(page, info) {
497
497
  resultHtml +
498
498
  gateHtml;
499
499
  if (isNewPanel) {
500
- document.documentElement.appendChild(panel);
500
+ __wgAdd(panel);
501
501
  requestAnimationFrame(() => panel.classList.add("wg-in"));
502
502
  } else {
503
503
  panel.classList.add("wg-in");
@@ -546,9 +546,9 @@ export async function renderAfterStep(page, info) {
546
546
  panel.querySelector(".wg-result-json").style.display = wantPretty ? "none" : "block";
547
547
  });
548
548
  });
549
- const runBtn = document.getElementById("wg-run");
549
+ const runBtn = __wgById("wg-run");
550
550
  if (runBtn) runBtn.addEventListener("click", () => window.__wgNext({}));
551
- const cb = document.getElementById("wg-autoplay-cb");
551
+ const cb = __wgById("wg-autoplay-cb");
552
552
  if (cb) {
553
553
  cb.addEventListener("change", () => {
554
554
  try {
@@ -556,8 +556,8 @@ export async function renderAfterStep(page, info) {
556
556
  } catch {
557
557
  /* private mode / blocked storage - toggle still works this page */
558
558
  }
559
- const manual = document.getElementById("wg-gate-manual");
560
- const auto = document.getElementById("wg-gate-auto");
559
+ const manual = __wgById("wg-gate-manual");
560
+ const auto = __wgById("wg-gate-auto");
561
561
  if (manual) manual.style.display = cb.checked ? "none" : "";
562
562
  if (auto) auto.style.display = cb.checked ? "" : "none";
563
563
  });
@@ -579,7 +579,7 @@ async function renderStepError(page, info) {
579
579
  await page
580
580
  .evaluate((info) => {
581
581
  // Reused in place - see renderBeforeStep's own comment on this.
582
- let panel = document.getElementById("wg-panel");
582
+ let panel = __wgById("wg-panel");
583
583
  const isNewPanel = !panel;
584
584
  if (!panel) {
585
585
  panel = document.createElement("div");
@@ -631,7 +631,7 @@ async function renderStepError(page, info) {
631
631
  "<button id=\"wg-run\" class=\"wg-error-stop\">Stop</button>" +
632
632
  "</div>";
633
633
  if (isNewPanel) {
634
- document.documentElement.appendChild(panel);
634
+ __wgAdd(panel);
635
635
  requestAnimationFrame(() => panel.classList.add("wg-in"));
636
636
  } else {
637
637
  panel.classList.add("wg-in");
@@ -651,9 +651,9 @@ async function renderStepError(page, info) {
651
651
  ready: true,
652
652
  });
653
653
  }
654
- const runBtn = document.getElementById("wg-run");
654
+ const runBtn = __wgById("wg-run");
655
655
  if (runBtn) runBtn.addEventListener("click", () => window.__wgNext({}));
656
- const retryBtn = document.getElementById("wg-error-retry");
656
+ const retryBtn = __wgById("wg-error-retry");
657
657
  if (retryBtn) retryBtn.addEventListener("click", () => window.__wgNext({ __wgRetry: "1" }));
658
658
  }, errorPayload)
659
659
  .catch(() => {});
@@ -38,17 +38,17 @@ import { formatHighlightCaption } from "../highlights.js";
38
38
  export async function markStepRunning(page, _opts) {
39
39
  await page
40
40
  .evaluate(() => {
41
- const runBtn = document.getElementById("wg-run");
41
+ const runBtn = __wgById("wg-run");
42
42
  if (runBtn) {
43
43
  runBtn.disabled = true;
44
44
  runBtn.textContent = "Running \u25B6";
45
45
  }
46
- const autoEl = document.getElementById("wg-gate-auto");
46
+ const autoEl = __wgById("wg-gate-auto");
47
47
  if (autoEl) autoEl.textContent = "Running...";
48
- document.querySelectorAll("#wg-panel textarea[data-key]").forEach((ta) => {
48
+ __wgQA("#wg-panel textarea[data-key]").forEach((ta) => {
49
49
  ta.disabled = true;
50
50
  });
51
- const panel = document.getElementById("wg-panel");
51
+ const panel = __wgById("wg-panel");
52
52
  if (panel) {
53
53
  panel.classList.add("wg-collapsed");
54
54
  panel.setAttribute("data-wg-collapsed", "1");
@@ -83,13 +83,13 @@ export async function markStepRunning(page, _opts) {
83
83
  export async function restoreTheaterAfterNavigation(page, todoDockRef, deviceRef, stubBeforeRef) {
84
84
  const needs =
85
85
  (await page
86
- .evaluate(() => !window.__wgSyncTodos || !document.getElementById("wg-ring"))
86
+ .evaluate(() => !window.__wgSyncTodos || !__wgById("wg-ring"))
87
87
  .catch(() => true)) || false;
88
88
  if (!needs) {
89
89
  // Overlay survived (SPA / no full document wipe) - still refresh dock
90
90
  // if Node has a carry and the DOM lost .wg-todo-dock.
91
91
  const hasDock = await page
92
- .evaluate(() => !!document.querySelector(".wg-todo-dock, #wg-todo-dock"))
92
+ .evaluate(() => !!__wgQ(".wg-todo-dock, #wg-todo-dock"))
93
93
  .catch(() => false);
94
94
  if (hasDock || !todoDockRef || !todoDockRef.current) return;
95
95
  }
@@ -162,10 +162,10 @@ export async function teardownOverlay(page) {
162
162
  "wg-device-toast",
163
163
  "wg-device-badge",
164
164
  ]) {
165
- const el = document.getElementById(id);
165
+ const el = __wgById(id);
166
166
  if (el) el.remove();
167
167
  }
168
- document.querySelectorAll(".wg-todo-dock").forEach((el) => el.remove());
168
+ __wgQA(".wg-todo-dock").forEach((el) => el.remove());
169
169
  document.documentElement.classList.remove("wg-video-device-stage");
170
170
  })
171
171
  .catch(() => {});
@@ -115,7 +115,7 @@ export async function syncTodoDockAdvance(page, todoDockRef, stubIndex, stub) {
115
115
  export async function probeTodoDocksOnPage(page) {
116
116
  return page
117
117
  .evaluate(() => {
118
- const docks = [...document.querySelectorAll(".wg-todo-dock, #wg-todo-dock")];
118
+ const docks = [...__wgQA(".wg-todo-dock, #wg-todo-dock")];
119
119
  return docks.map((el) => {
120
120
  const r = el.getBoundingClientRect();
121
121
  const items = el.querySelectorAll("li");