@guidelytech/guide-runtime 0.9.0 → 0.10.0
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/dist/capture.cjs +152 -34
- package/dist/capture.cjs.map +1 -1
- package/dist/capture.js +8 -13
- package/dist/capture.js.map +1 -1
- package/dist/chunk-GUH2PQJ7.js +462 -0
- package/dist/chunk-GUH2PQJ7.js.map +1 -0
- package/dist/index.cjs +219 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -7
- package/dist/index.d.ts +52 -7
- package/dist/index.js +35 -15
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/capture.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/capture.ts","../src/capture-styles.ts","../src/selectors.ts","../src/capture-dom.ts","../src/capture-screen.ts","../src/styles.ts","../src/host.ts"],"sourcesContent":["import type { CaptureStepInput, HowToAction } from \"@guidelytech/shared\";\nimport { CAPTURE_STYLES } from \"./capture-styles\";\nimport {\n actionTarget,\n collectRedactions,\n describeCapturedElement,\n fieldValue,\n isMaskedElement,\n isSensitiveField,\n isTextEntry,\n labelControl,\n looksLikeSecretValue,\n normalizeRect,\n selectedOptionText,\n} from \"./capture-dom\";\nimport { canCaptureScreen, redactCanvas, requestTabCapture, type ScreenSource } from \"./capture-screen\";\nimport { createScope } from \"./host\";\nimport { describeElement, isGuidelyElement } from \"./selectors\";\n\nexport * from \"./capture-dom\";\nexport { canCaptureScreen, encodeScreenshot, grabFrame, redactCanvas, requestTabCapture, screenshotDataUrl } from \"./capture-screen\";\nexport type { ScreenResult, ScreenSource } from \"./capture-screen\";\n\n/** A captured step before the SDK gives it a `clientId`. */\nexport type CaptureStepDraft = Omit<CaptureStepInput, \"clientId\">;\n\nexport interface CapturedStep {\n step: CaptureStepDraft;\n /**\n * The screenshot, already redacted (encode it with `encodeScreenshot`); null without screenshots.\n * A promise when the current frame predates a scroll or resize: it resolves with the next frame,\n * after `step.highlight` and `step.redactions` were updated to match it.\n */\n frame: HTMLCanvasElement | Promise<HTMLCanvasElement | null> | null;\n}\n\nexport interface CaptureOptions {\n /** How-to title shown in the toolbar before recording starts. */\n title: string;\n /** Steps already recorded (a recording continues across full page loads). */\n stepCount?: number;\n /** False when the server cannot store screenshots: record steps only. Default true. */\n screenshots?: boolean;\n /**\n * Continue a recording after a full page load: start recording straight away. `navigate` adds a\n * step for the new page; `screenshots` offers \"Screenshots paused — Resume\" (the stream is gone).\n */\n resume?: { navigate: boolean; screenshots: boolean };\n /** Comma-joined CSS selectors whose text and pixels are never captured. */\n maskSelector?: string;\n onStep(step: CapturedStep): void;\n /** Recording started; `screenshots` is whether the user chose to take screenshots. */\n onStart?(info: { screenshots: boolean }): void;\n onFinish(): void;\n onCancel(): void;\n doc?: Document;\n}\n\nexport interface CaptureSession {\n /** Shows \"Saving…\" (and stops recording) while queued uploads finish. */\n setSaving(saving: boolean): void;\n isRecording(): boolean;\n stop(): void;\n}\n\n/** A repeat press on the same element within this window is a double click, not a new step. */\nexport const DOUBLE_CLICK_MS = 400;\n/** URL changes this soon after an interaction were caused by it (no separate navigate step). */\nexport const NAV_AFTER_ACTION_MS = 1500;\n/** Wait for the page to settle before capturing a navigate step. */\nexport const NAV_SETTLE_MS = 600;\n\ntype Phase = \"ready\" | \"recording\" | \"paused\" | \"saving\";\n\nconst NOTICES = {\n \"wrong-surface\": \"Share this tab (not a window or the whole screen) so screenshots match the page.\",\n denied: \"Screen sharing was cancelled. Start again, or record without screenshots.\",\n error: \"Screen capture could not start. Try again, or record without screenshots.\",\n unsupported: \"This browser cannot capture screenshots; steps are recorded without them.\",\n lost: \"Screenshots paused: sharing stopped or the page reloaded.\",\n} as const;\n\nfunction button(doc: Document, text: string, cls: string, attr: string): HTMLButtonElement {\n const b = doc.createElement(\"button\");\n b.type = \"button\";\n b.className = `g-btn ${cls}`;\n b.textContent = text;\n b.setAttribute(attr, \"\");\n return b;\n}\n\nfunction eventTarget(e: Event): Element | null {\n const path = typeof e.composedPath === \"function\" ? e.composedPath() : [];\n const first = (path[0] ?? e.target) as Node | null;\n if (!first) return null;\n return first.nodeType === 1 ? (first as Element) : first.parentElement;\n}\n\n/** The focused element inside a shadow-DOM subtree, if any. */\nfunction deepActiveElementIn(el: Element): Element | null {\n const root = el.getRootNode() as Document | ShadowRoot;\n return root.activeElement ?? null;\n}\n\nfunction deepActiveElement(doc: Document): Element | null {\n let el = doc.activeElement;\n while (el?.shadowRoot?.activeElement) el = el.shadowRoot.activeElement;\n return el;\n}\n\n/**\n * Starts how-to capture: a Shadow-DOM toolbar (bottom centre, a small pill while recording) and passive capture-phase\n * listeners that turn clicks, typing, selections and navigations into steps. The app keeps\n * receiving every event; nothing is prevented.\n */\nexport function startCapture(options: CaptureOptions): CaptureSession {\n const doc = options.doc ?? document;\n const win = doc.defaultView ?? window;\n const mask = options.maskSelector ?? \"\";\n const shotsAllowed = options.screenshots !== false;\n const scope = createScope(null, { theme: \"light\", animation: \"fade\" }, doc);\n const style = doc.createElement(\"style\");\n style.textContent = CAPTURE_STYLES;\n scope.el.appendChild(style);\n\n const bar = doc.createElement(\"div\");\n bar.className = \"g-cap\";\n bar.setAttribute(\"data-guidely-capture-bar\", \"\");\n bar.setAttribute(\"role\", \"toolbar\");\n bar.setAttribute(\"aria-label\", \"Guidely how-to recorder\");\n const note = doc.createElement(\"div\");\n note.className = \"g-cap-note\";\n note.setAttribute(\"data-guidely-capture-notice\", \"\");\n note.hidden = true;\n const row = doc.createElement(\"div\");\n row.className = \"g-cap-row\";\n const dot = doc.createElement(\"span\");\n dot.className = \"g-cap-dot\";\n const status = doc.createElement(\"span\");\n status.className = \"g-cap-status\";\n status.setAttribute(\"aria-live\", \"polite\");\n const count_ = doc.createElement(\"span\");\n count_.className = \"g-cap-count\";\n count_.setAttribute(\"aria-hidden\", \"true\");\n const start = button(doc, \"Start recording\", \"g-btn-primary\", \"data-guidely-capture-start\");\n const noShots = button(doc, \"Record without screenshots\", \"g-btn-secondary\", \"data-guidely-capture-no-screenshots\");\n const resumeShots = button(doc, \"Screenshots paused — Resume\", \"g-cap-warn\", \"data-guidely-capture-resume-screenshots\");\n const pause = button(doc, \"Pause\", \"g-btn-secondary\", \"data-guidely-capture-pause\");\n const done = button(doc, \"Done\", \"g-btn-primary\", \"data-guidely-capture-done\");\n const cancel = button(doc, \"Cancel\", \"g-btn-ghost\", \"data-guidely-capture-cancel\");\n row.append(dot, count_, status, start, noShots, resumeShots, pause, done, cancel);\n bar.append(note, row);\n scope.el.appendChild(bar);\n\n let phase: Phase = \"ready\";\n let count = options.stepCount ?? 0;\n let screen: ScreenSource | null = null;\n /** The user chose screenshots (so a lost stream shows \"Resume\"). */\n let wantShots = false;\n let requesting = false;\n let stopped = false;\n let lastAction = 0;\n /** `performance.now()` of the last scroll or resize: frames older than that do not match the DOM. */\n let movedAt = -1;\n let lastPress: { el: Element; at: number } | null = null;\n let lastUrl = win.location.href;\n let navTimer: ReturnType<typeof setTimeout> | null = null;\n let pulseTimer: ReturnType<typeof setTimeout> | null = null;\n /** `performance.now()` of the last keystroke in a field: a `type` step needs a frame that shows it. */\n let typedAt = -1;\n /**\n * While recording, the bar is a small pill (dot and step count) unless the pointer or focus is on\n * it, so screenshots show as little of it as possible.\n */\n let expanded = false; /** Field value at focus (or when last recorded), so each edit is recorded once. */\n const baseline = new WeakMap<Element, string>();\n\n const recording = () => phase === \"recording\" && !stopped;\n const steps = (n: number) => `${n} step${n === 1 ? \"\" : \"s\"}`;\n\n const render = () => {\n bar.setAttribute(\"data-state\", phase);\n bar.toggleAttribute(\"data-compact\", phase === \"recording\" && !expanded);\n const ready = phase === \"ready\";\n const active = phase === \"recording\" || phase === \"paused\";\n start.hidden = !ready;\n start.disabled = requesting;\n noShots.hidden = !ready || !shotsAllowed || !canCaptureScreen();\n noShots.disabled = requesting;\n resumeShots.hidden = !active || !wantShots || !!screen?.live();\n resumeShots.disabled = requesting;\n pause.hidden = !active;\n pause.textContent = phase === \"paused\" ? \"Resume\" : \"Pause\";\n done.hidden = !active;\n cancel.hidden = phase === \"saving\";\n if (ready) status.textContent = requesting ? \"Choose this tab to share…\" : `Ready to record “${options.title}”`;\n else if (phase === \"saving\") status.textContent = \"Saving steps…\";\n else status.textContent = `${phase === \"paused\" ? \"Paused\" : \"Recording\"} · ${steps(count)}`;\n count_.textContent = String(count);\n };\n\n const showNotice = (text: string | null) => {\n note.textContent = text ?? \"\";\n note.hidden = !text;\n };\n\n /** Briefly turns the dot green: a step was captured. */\n const pulse = () => {\n bar.setAttribute(\"data-captured\", \"\");\n if (pulseTimer) clearTimeout(pulseTimer);\n pulseTimer = setTimeout(() => bar.removeAttribute(\"data-captured\"), 700);\n };\n\n /** Grabs the frame, blurs sensitive regions and sets the highlight; all from the same moment's layout. */\n const shoot = (step: CaptureStepDraft, highlightEl: Element | null): HTMLCanvasElement | null => {\n const frame = screen?.live() ? screen.grab() : null;\n if (!frame) return null;\n const viewport = { width: win.innerWidth, height: win.innerHeight };\n try {\n step.redactions = redactCanvas(frame, collectRedactions(doc, { maskSelector: mask }), viewport);\n } catch {\n // Never upload a frame that could not be redacted.\n return null;\n }\n const highlight = highlightEl?.isConnected ? normalizeRect(highlightEl.getBoundingClientRect(), viewport) : null;\n if (highlight) step.highlight = highlight;\n else delete step.highlight;\n return frame;\n };\n\n /** Captures one step. The frame is grabbed synchronously, before the app reacts to the event. */\n const record = (action: HowToAction, el: Element | null, extra: { value?: string; valueRedacted?: boolean; highlightEl?: Element | null } = {}) => {\n const step: CaptureStepDraft = { action, url: win.location.href, pageTitle: (doc.title || \"\").slice(0, 300), redactions: 0, occurredAt: new Date().toISOString() };\n let highlightEl: Element | null = null;\n if (el) {\n const masked = isMaskedElement(el, mask);\n step.element = describeCapturedElement(el, mask);\n step.selectors = describeElement(el).selectors.filter((s) => !masked || s.kind !== \"text\");\n const box = extra.highlightEl?.getBoundingClientRect();\n highlightEl = extra.highlightEl && box && (box.width || box.height) ? extra.highlightEl : el;\n }\n let frame: CapturedStep[\"frame\"] = null;\n if (screen?.live()) {\n const s = screen;\n // A frame older than the last scroll shows content where it no longer is (redactions would miss it), and one\n // older than the last keystroke may not show the typed text yet: use the next one. A click keeps the current\n // frame, which shows the page before the app reacted.\n const changedAt = action === \"type\" || action === \"select\" ? Math.max(movedAt, typedAt) : movedAt;\n if (s.freshSince(changedAt)) frame = shoot(step, highlightEl);\n else frame = s.nextFrame().then(() => shoot(step, highlightEl));\n }\n if (extra.value !== undefined) step.value = extra.value;\n if (extra.valueRedacted) step.valueRedacted = true;\n if (action !== \"navigate\") lastAction = Date.now();\n count++;\n render();\n pulse();\n options.onStep({ step, frame });\n };\n\n /** Records a `type` step when the field's value changed since focus (or since it was last recorded). */\n const flushField = (el: Element) => {\n if (!recording() || !isTextEntry(el)) return;\n const host = el.tagName === \"INPUT\" || el.tagName === \"TEXTAREA\" ? el : actionTarget(el);\n const value = fieldValue(host);\n if (value === (baseline.get(host) ?? \"\")) return;\n baseline.set(host, value);\n if (!value) return;\n if (isSensitiveField(host, mask) || looksLikeSecretValue(value)) record(\"type\", host, { valueRedacted: true });\n else record(\"type\", host, { value });\n };\n\n const onPointerDown = (e: PointerEvent) => {\n if (!recording() || e.button !== 0) return;\n const target = eventTarget(e);\n if (!target || isGuidelyElement(target)) return;\n // Typing into the focused field happened before this click: record it first.\n const active = deepActiveElement(doc);\n if (active && active !== target && !active.contains(target) && isTextEntry(active)) flushField(active);\n let el = actionTarget(target);\n let highlightEl: Element | null = null;\n const control = labelControl(el);\n if (control) {\n if (isTextEntry(control) || control.tagName === \"SELECT\") return; // the label only focuses the field\n highlightEl = el;\n el = control;\n }\n if (isTextEntry(el) || el.tagName === \"SELECT\" || el.closest(\"select\")) return; // `change` records these\n if ((el as HTMLButtonElement).disabled) return;\n const now = Date.now();\n if (lastPress && lastPress.el === el && now - lastPress.at < DOUBLE_CLICK_MS) {\n lastPress.at = now;\n return;\n }\n lastPress = { el, at: now };\n record(\"click\", el, { highlightEl });\n };\n\n const onChange = (e: Event) => {\n if (!recording()) return;\n const el = eventTarget(e);\n if (!el || isGuidelyElement(el)) return;\n if (el.tagName === \"SELECT\") {\n const sensitive = isSensitiveField(el, mask);\n const value = sensitive ? \"\" : selectedOptionText(el as HTMLSelectElement);\n record(\"select\", el, sensitive ? { valueRedacted: true } : value ? { value } : {});\n return;\n }\n const type = el.tagName === \"INPUT\" ? (el.getAttribute(\"type\") || \"\").toLowerCase() : \"\";\n if (type === \"checkbox\" || type === \"radio\") {\n // Toggled with the keyboard (no pointer press on it or its label just now).\n const pressed = lastPress && Date.now() - lastPress.at < 1000 && lastPress.el === el;\n if (!pressed) record(\"click\", el);\n return;\n }\n if (isTextEntry(el)) flushField(el);\n };\n\n const onFocusIn = (e: FocusEvent) => {\n const el = eventTarget(e);\n if (el && !isGuidelyElement(el) && isTextEntry(el)) {\n const host = el.tagName === \"INPUT\" || el.tagName === \"TEXTAREA\" ? el : actionTarget(el);\n baseline.set(host, fieldValue(host));\n }\n };\n\n const onFocusOut = (e: FocusEvent) => {\n const el = eventTarget(e);\n // Inputs report edits through `change`; contenteditable regions only through blur.\n if (el && el.tagName !== \"INPUT\" && el.tagName !== \"TEXTAREA\" && isTextEntry(el)) flushField(el);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== \"Enter\" || e.isComposing) return;\n const el = eventTarget(e);\n if (el && (el.tagName === \"INPUT\" || ((e.metaKey || e.ctrlKey) && isTextEntry(el)))) flushField(el);\n };\n\n const checkUrl = () => {\n const url = win.location.href;\n if (url === lastUrl) return;\n lastUrl = url;\n if (!recording() || Date.now() - lastAction < NAV_AFTER_ACTION_MS) return;\n if (navTimer) clearTimeout(navTimer);\n navTimer = setTimeout(() => {\n navTimer = null;\n if (recording()) record(\"navigate\", null);\n }, NAV_SETTLE_MS);\n };\n const poll = setInterval(checkUrl, 300);\n\n const onMove = () => {\n movedAt = performance.now();\n };\n const onInput = (e: Event) => {\n const el = eventTarget(e);\n if (el && !isGuidelyElement(el)) typedAt = performance.now();\n };\n const expand = (open: boolean) => {\n if (expanded === open) return;\n expanded = open;\n render();\n };\n const onBarEnter = () => expand(true);\n const onBarLeave = () => expand(bar.contains(deepActiveElementIn(bar)));\n const onBarFocusOut = (e: FocusEvent) => expand(!!e.relatedTarget && bar.contains(e.relatedTarget as Node));\n bar.addEventListener(\"pointerenter\", onBarEnter);\n bar.addEventListener(\"pointerleave\", onBarLeave);\n bar.addEventListener(\"focusin\", onBarEnter);\n bar.addEventListener(\"focusout\", onBarFocusOut);\n\n const listen = { capture: true, passive: true } as const;\n doc.addEventListener(\"scroll\", onMove, listen);\n win.addEventListener(\"resize\", onMove);\n doc.addEventListener(\"pointerdown\", onPointerDown, listen);\n doc.addEventListener(\"change\", onChange, listen);\n doc.addEventListener(\"input\", onInput, listen);\n doc.addEventListener(\"focusin\", onFocusIn, listen);\n doc.addEventListener(\"focusout\", onFocusOut, listen);\n doc.addEventListener(\"keydown\", onKeyDown, listen);\n win.addEventListener(\"popstate\", checkUrl);\n win.addEventListener(\"hashchange\", checkUrl);\n\n const onLost = () => {\n screen = null;\n if (!stopped && wantShots) showNotice(NOTICES.lost);\n render();\n };\n\n /** Asks for the tab stream (needs the click that called it). */\n const requestScreen = async (): Promise<boolean> => {\n requesting = true;\n showNotice(null);\n render();\n const res = await requestTabCapture(scope.el, doc);\n requesting = false;\n if (stopped) {\n if (res.ok) res.screen.stop();\n return false;\n }\n if (res.ok) {\n screen = res.screen;\n screen.onEnded(onLost);\n } else showNotice(NOTICES[res.reason]);\n render();\n return res.ok;\n };\n\n const begin = (shots: boolean) => {\n wantShots = shots;\n phase = \"recording\";\n // Collapse to the pill even though the pointer is still on the Start button, and take the first\n // screenshot from a frame drawn after that.\n expanded = false;\n movedAt = performance.now();\n primeActive();\n lastUrl = win.location.href;\n render();\n options.onStart?.({ screenshots: shots });\n record(\"navigate\", null);\n };\n\n start.addEventListener(\"click\", () => {\n if (requesting) return;\n if (!shotsAllowed || !canCaptureScreen()) {\n if (shotsAllowed) showNotice(NOTICES.unsupported);\n return begin(false);\n }\n void requestScreen().then((ok) => {\n if (ok) begin(true);\n });\n });\n noShots.addEventListener(\"click\", () => {\n showNotice(null);\n begin(false);\n });\n resumeShots.addEventListener(\"click\", () => {\n if (!requesting) void requestScreen();\n });\n pause.addEventListener(\"click\", () => {\n if (phase === \"recording\") {\n flushActive();\n phase = \"paused\";\n } else if (phase === \"paused\") {\n phase = \"recording\";\n lastUrl = win.location.href;\n }\n render();\n });\n /** Typing still in the focused field (Safari does not move focus to a clicked button). */\n const flushActive = () => {\n const active = deepActiveElement(doc);\n if (active && !isGuidelyElement(active) && isTextEntry(active)) flushField(active);\n };\n const primeActive = () => {\n const active = deepActiveElement(doc);\n if (active && !isGuidelyElement(active) && isTextEntry(active)) baseline.set(active, fieldValue(active));\n };\n\n done.addEventListener(\"click\", () => {\n if (phase === \"saving\") return;\n flushActive();\n options.onFinish();\n });\n cancel.addEventListener(\"click\", () => {\n stop();\n options.onCancel();\n });\n\n const stop = () => {\n if (stopped) return;\n stopped = true;\n clearInterval(poll);\n if (navTimer) clearTimeout(navTimer);\n if (pulseTimer) clearTimeout(pulseTimer);\n doc.removeEventListener(\"scroll\", onMove, listen);\n win.removeEventListener(\"resize\", onMove);\n doc.removeEventListener(\"pointerdown\", onPointerDown, listen);\n doc.removeEventListener(\"change\", onChange, listen);\n doc.removeEventListener(\"input\", onInput, listen);\n doc.removeEventListener(\"focusin\", onFocusIn, listen);\n doc.removeEventListener(\"focusout\", onFocusOut, listen);\n doc.removeEventListener(\"keydown\", onKeyDown, listen);\n win.removeEventListener(\"popstate\", checkUrl);\n win.removeEventListener(\"hashchange\", checkUrl);\n screen?.stop();\n screen = null;\n scope.destroy();\n };\n\n if (options.resume) {\n wantShots = shotsAllowed && options.resume.screenshots && canCaptureScreen();\n phase = \"recording\";\n if (wantShots) showNotice(NOTICES.lost);\n primeActive();\n render();\n if (options.resume.navigate) record(\"navigate\", null);\n } else render();\n\n return {\n setSaving: (saving) => {\n if (stopped) return;\n phase = saving ? \"saving\" : \"recording\";\n render();\n },\n isRecording: recording,\n stop,\n };\n}\n","/** How-to capture toolbar styles, injected into the Guidely shadow root when capture starts. */\nexport const CAPTURE_STYLES = `\n.g-cap{position:fixed;left:50%;bottom:16px;transform:translateX(-50%);z-index:calc(var(--g-z) + 10);pointer-events:auto;display:flex;flex-direction:column;align-items:center;gap:6px;max-width:calc(100vw - 32px);font:500 13px/1.4 var(--g-font);color:#fff}\n.g-cap-row{display:flex;align-items:center;flex-wrap:wrap;gap:8px;padding:6px 6px 6px 14px;background:#111827;border-radius:999px;box-shadow:0 6px 24px rgba(0,0,0,.28)}\n.g-cap-dot{position:relative;flex:none;width:10px;height:10px;border-radius:999px;background:#9ca3af}\n.g-cap[data-state=\"recording\"] .g-cap-dot{background:#ef4444}\n.g-cap[data-state=\"recording\"] .g-cap-dot::after{content:\"\";position:absolute;inset:0;border-radius:inherit;background:#ef4444;animation:g-pulse 1.4s ease-out infinite}\n.g-cap-status{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:min(340px,60vw)}\n.g-cap .g-btn{min-height:28px;padding:3px 12px;font-size:13px;border-radius:999px}\n.g-cap .g-btn-secondary{background:rgba(255,255,255,.14);color:#fff;border-color:transparent}\n.g-cap .g-btn-secondary:hover{background:rgba(255,255,255,.22)}\n.g-cap .g-btn-ghost{color:#d1d5db}\n.g-cap .g-btn-ghost:hover{background:rgba(255,255,255,.1);color:#fff}\n.g-cap .g-cap-warn{background:#f59e0b;color:#111827}\n.g-cap-note{max-width:min(420px,calc(100vw - 32px));padding:6px 12px;border-radius:10px;background:#7c2d12;box-shadow:0 6px 24px rgba(0,0,0,.28)}\n.g-cap-count{display:none;font-variant-numeric:tabular-nums}\n.g-cap[data-compact] .g-cap-row{gap:6px;padding:5px 10px;opacity:.85}\n.g-cap[data-compact] .g-cap-row>:not(.g-cap-dot):not(.g-cap-count):not(.g-cap-warn){display:none}\n.g-cap[data-compact] .g-cap-count{display:inline}\n.g-cap[data-captured] .g-cap-dot,.g-cap[data-captured] .g-cap-dot::after{background:#22c55e}\n`;\n","import { matchUrlPattern } from \"@guidelytech/shared/runtime\";\nimport type { SelectorStrategy, StepTarget } from \"@guidelytech/shared\";\n\n/**\n * URL matching used for `step.url`, `urlPatterns` and `trigger.urlPattern`: a pattern matches the\n * full URL, the path+query+hash, or the bare path (so `/deals` also matches `/deals?x=1`).\n */\nexport function urlMatches(pattern: string | undefined | null, url: string): boolean {\n if (!pattern) return true;\n if (matchUrlPattern(pattern, url)) return true;\n try {\n const u = new URL(url, \"http://localhost\");\n if (!pattern.includes(\"?\") && !pattern.includes(\"#\")) return matchUrlPattern(pattern, u.pathname) || matchUrlPattern(pattern, u.origin + u.pathname);\n } catch {\n /* ignore */\n }\n return false;\n}\n\nexport type QueryRoot = Document | DocumentFragment | Element;\n\nconst TEXT_CANDIDATES =\n \"button, a, [role='button'], [role='link'], [role='tab'], [role='menuitem'], h1, h2, h3, h4, h5, h6, label, summary\";\n\nconst HOST_ID = \"guidely-root\";\n\nfunction docOf(root: QueryRoot): Document {\n return root.nodeType === 9 ? (root as Document) : (root.ownerDocument as Document);\n}\n\n/** True when the environment has a layout engine (real browsers). happy-dom/jsdom report zero sizes. */\nfunction hasLayout(doc: Document): boolean {\n const de = doc.documentElement;\n if (!de) return false;\n const r = de.getBoundingClientRect();\n return r.width > 0 || r.height > 0;\n}\n\n/** Normalises whitespace in a text snippet. */\nexport function normalizeText(text: string | null | undefined): string {\n return (text || \"\").replace(/\\s+/g, \" \").trim();\n}\n\n/** Is the element rendered (not hidden by `hidden`, `display:none`, `visibility:hidden`, or zero size)? */\nexport function isVisible(el: Element): boolean {\n if (!el.isConnected) return false;\n const doc = el.ownerDocument;\n const win = doc.defaultView;\n let cur: Element | null = el;\n while (cur && cur !== doc.documentElement) {\n if ((cur as HTMLElement).hidden) return false;\n if (win) {\n const cs = win.getComputedStyle(cur);\n if (cs.display === \"none\" || cs.visibility === \"hidden\") return false;\n }\n cur = cur.parentElement ?? ((cur.getRootNode() as ShadowRoot).host as Element | undefined) ?? null;\n }\n if (hasLayout(doc)) {\n const r = el.getBoundingClientRect();\n if (r.width === 0 && r.height === 0) return false;\n }\n return true;\n}\n\n/** Elements that belong to Guidely's own UI are never valid targets. */\nexport function isGuidelyElement(el: Element | null): boolean {\n if (!el) return false;\n const root = el.getRootNode();\n if (root instanceof ShadowRoot && root.host.id === HOST_ID) return true;\n return el.id === HOST_ID || !!el.closest?.(`#${HOST_ID}`);\n}\n\nfunction safeQueryAll(root: QueryRoot, selector: string): Element[] {\n try {\n return Array.from(root.querySelectorAll(selector));\n } catch {\n return [];\n }\n}\n\nfunction escapeCss(value: string): string {\n const g = globalThis as { CSS?: { escape?: (v: string) => string } };\n if (g.CSS && typeof g.CSS.escape === \"function\") return g.CSS.escape(value);\n return value.replace(/[\"\\\\]/g, \"\\\\$&\");\n}\n\nfunction queryXPath(root: QueryRoot, expr: string): Element[] {\n const doc = docOf(root);\n const d = doc as Document & { evaluate?: Document[\"evaluate\"] };\n if (typeof d.evaluate !== \"function\") return [];\n try {\n const result = d.evaluate(expr, root, null, 7 /* ORDERED_NODE_SNAPSHOT_TYPE */, null);\n const out: Element[] = [];\n for (let i = 0; i < result.snapshotLength; i++) {\n const n = result.snapshotItem(i);\n if (n && n.nodeType === 1) out.push(n as Element);\n }\n return out;\n } catch {\n return [];\n }\n}\n\nfunction queryText(root: QueryRoot, text: string): Element[] {\n const needle = normalizeText(text).toLowerCase();\n if (!needle) return [];\n const candidates = safeQueryAll(root, TEXT_CANDIDATES);\n const exact = candidates.filter((c) => normalizeText(c.textContent).toLowerCase() === needle);\n if (exact.length) return exact;\n return candidates.filter((c) => normalizeText(c.textContent).toLowerCase().includes(needle));\n}\n\n/** Resolves every element matching one strategy (visible or not). */\nexport function querySelectorStrategy(strategy: SelectorStrategy, root: QueryRoot): Element[] {\n const value = strategy.value.trim();\n if (!value) return [];\n switch (strategy.kind) {\n case \"id\": {\n const id = value.startsWith(\"#\") ? value.slice(1) : value;\n return safeQueryAll(root, `#${escapeCss(id)}`);\n }\n case \"guidely-id\": {\n const id = value.startsWith(\"#\") ? value.slice(1) : value;\n return safeQueryAll(root, attrSelector(\"data-guidely-id\", id));\n }\n case \"data-attr\":\n case \"aria\":\n case \"css\":\n return safeQueryAll(root, value.startsWith(\"[\") || /^[a-z*#.[]/i.test(value) ? value : `[${value}]`);\n case \"text\":\n return queryText(root, value);\n case \"xpath\":\n return queryXPath(root, value);\n default:\n return [];\n }\n}\n\n/**\n * Resolves a step target by trying each strategy in order. A strategy wins only when it\n * resolves to exactly one *visible* element; otherwise the next strategy is tried.\n */\nexport function resolveTarget(target: Pick<StepTarget, \"selectors\"> | SelectorStrategy[], root: QueryRoot = document): Element | null {\n const selectors = Array.isArray(target) ? target : target.selectors;\n for (const strategy of selectors) {\n const matches = querySelectorStrategy(strategy, root).filter((el) => !isGuidelyElement(el) && isVisible(el));\n if (matches.length === 1) return matches[0] as Element;\n }\n return null;\n}\n\nexport interface WaitForTargetOptions {\n /** Give up after this many milliseconds (default 5000). */\n timeoutMs?: number;\n /** Abort early. */\n signal?: AbortSignal;\n root?: QueryRoot;\n /** Polling fallback interval (default 250ms, which is also the maximum). */\n pollMs?: number;\n}\n\nexport class TargetTimeoutError extends Error {\n override name = \"TargetTimeoutError\";\n constructor(message = \"Target element not found before timeout\") {\n super(message);\n }\n}\n\n/**\n * Waits until `resolveTarget` finds an element. Uses a MutationObserver plus a polling fallback\n * (at most every 250ms) so visibility changes without DOM mutations are also detected.\n */\nexport function waitForTarget(target: Pick<StepTarget, \"selectors\"> | SelectorStrategy[], options: WaitForTargetOptions = {}): Promise<Element> {\n const timeoutMs = options.timeoutMs ?? 5000;\n const root = options.root ?? document;\n const pollMs = Math.min(250, Math.max(16, options.pollMs ?? 250));\n return new Promise<Element>((resolve, reject) => {\n const immediate = resolveTarget(target, root);\n if (immediate) return resolve(immediate);\n if (options.signal?.aborted) return reject(new DOMException(\"Aborted\", \"AbortError\"));\n let done = false;\n let observer: MutationObserver | null = null;\n let timer: ReturnType<typeof setInterval> | null = null;\n let timeout: ReturnType<typeof setTimeout> | null = null;\n const cleanup = () => {\n done = true;\n observer?.disconnect();\n if (timer) clearInterval(timer);\n if (timeout) clearTimeout(timeout);\n options.signal?.removeEventListener(\"abort\", onAbort);\n };\n const check = () => {\n if (done) return;\n const el = resolveTarget(target, root);\n if (el) {\n cleanup();\n resolve(el);\n }\n };\n const onAbort = () => {\n cleanup();\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n };\n options.signal?.addEventListener(\"abort\", onAbort);\n const observeRoot = root.nodeType === 9 ? (root as Document).documentElement : (root as Element);\n if (typeof MutationObserver !== \"undefined\" && observeRoot) {\n observer = new MutationObserver(check);\n observer.observe(observeRoot, { childList: true, subtree: true, attributes: true, attributeFilter: [\"class\", \"style\", \"hidden\", \"id\", \"data-tour\", \"data-guidely-id\", \"aria-label\"] });\n }\n timer = setInterval(check, pollMs);\n if (timeoutMs > 0) {\n timeout = setTimeout(() => {\n cleanup();\n reject(new TargetTimeoutError());\n }, timeoutMs);\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Selector generation (used by the element picker)\n// ---------------------------------------------------------------------------\n\nconst GENERATED_ID = /(\\d{4,}|:r[0-9a-z]+:|^radix-|^headlessui-|^mui-|^ember\\d|^react-|^\\w*-\\d+$|__|^[a-f0-9]{8,}$|^svelte-)/i;\nconst GENERATED_CLASS = /(^css-|^sc-|^jss\\d|^svelte-|^emotion-|^chakra-|^Mui|^_|[0-9a-f]{6,}|^\\w{1,2}$|^[a-z]+-\\d+$|[:[\\]/])/;\nconst PREFERRED_DATA_ATTRS = [\"data-testid\", \"data-tour\", \"data-test\", \"data-test-id\", \"data-cy\", \"data-qa\", \"data-id\", \"data-name\", \"data-guidely\"];\nconst IGNORED_DATA_ATTRS = /^data-(guidely-id|state|v-|reactid|react|radix|headlessui|svelte|hydrated|orientation|highlighted|focus|key|index|rbd|dnd|rk-|sveltekit)/i;\n\n/** Is this id stable enough to be used as a selector (not generated by a framework)? */\nexport function isStableId(id: string): boolean {\n return !!id && /^[A-Za-z][\\w-]*$/.test(id) && !GENERATED_ID.test(id);\n}\n\nfunction isStableClass(cls: string): boolean {\n return !!cls && !GENERATED_CLASS.test(cls) && cls.length <= 40;\n}\n\nfunction uniqueIn(doc: Document, selector: string, el: Element): boolean {\n const all = safeQueryAll(doc, selector);\n return all.length === 1 && all[0] === el;\n}\n\nfunction attrSelector(name: string, value: string): string {\n return `[${name}='${value.replace(/\\\\/g, \"\\\\\\\\\").replace(/'/g, \"\\\\'\")}']`;\n}\n\nfunction cssPath(el: Element, doc: Document): string | null {\n const segments: string[] = [];\n let cur: Element | null = el;\n while (cur && cur.nodeType === 1 && cur !== doc.body && cur !== doc.documentElement) {\n const tag = cur.tagName.toLowerCase();\n if (isStableId(cur.id)) {\n segments.unshift(`#${cur.id}`);\n break;\n }\n let seg = tag;\n const parent: Element | null = cur.parentElement;\n if (parent) {\n const sameTag = Array.from(parent.children).filter((c) => c.tagName === cur!.tagName);\n if (sameTag.length > 1) {\n const stableCls = Array.from(cur.classList).find((c) => isStableClass(c) && sameTag.filter((s) => s.classList.contains(c)).length === 1);\n seg += stableCls ? `.${escapeCss(stableCls)}` : `:nth-of-type(${sameTag.indexOf(cur) + 1})`;\n }\n }\n segments.unshift(seg);\n const candidate = segments.join(\" > \");\n if (uniqueIn(doc, candidate, el)) return candidate;\n cur = parent;\n }\n const full = segments.join(\" > \");\n return uniqueIn(doc, full, el) ? full : null;\n}\n\n/** Short human-readable text for an element, trimmed to 200 characters. */\nexport function textSnapshotOf(el: Element): string {\n const he = el as HTMLElement;\n const own = normalizeText(he.innerText ?? el.textContent);\n const alt = normalizeText(el.getAttribute(\"aria-label\") || el.getAttribute(\"title\") || el.getAttribute(\"placeholder\") || el.getAttribute(\"alt\") || (el as HTMLInputElement).value);\n return (own || alt).slice(0, 200);\n}\n\n/**\n * Generates an ordered list of selector strategies for an element, most robust first:\n * stable id → data-* attributes → aria-label → role/name → short unique CSS path → visible text.\n */\nexport function generateSelectors(el: Element): SelectorStrategy[] {\n const doc = el.ownerDocument;\n const out: SelectorStrategy[] = [];\n const seen = new Set<string>();\n const push = (s: SelectorStrategy) => {\n const k = `${s.kind}:${s.value}`;\n if (!seen.has(k)) {\n seen.add(k);\n out.push(s);\n }\n };\n const tag = el.tagName.toLowerCase();\n\n // A Guidely id is shared with the mobile apps, so it is the most portable target there is.\n const guidelyId = el.getAttribute(\"data-guidely-id\");\n if (guidelyId && uniqueIn(doc, attrSelector(\"data-guidely-id\", guidelyId), el)) push({ kind: \"guidely-id\", value: guidelyId, label: `Guidely id ${guidelyId}` });\n if (isStableId(el.id) && uniqueIn(doc, `#${escapeCss(el.id)}`, el)) push({ kind: \"id\", value: `#${el.id}`, label: `id ${el.id}` });\n\n const dataAttrs = Array.from(el.attributes).filter((a) => a.name.startsWith(\"data-\") && !IGNORED_DATA_ATTRS.test(a.name) && a.value && a.value.length <= 120 && !/\\d{5,}/.test(a.value));\n dataAttrs.sort((a, b) => {\n const ia = PREFERRED_DATA_ATTRS.indexOf(a.name);\n const ib = PREFERRED_DATA_ATTRS.indexOf(b.name);\n return (ia === -1 ? 99 : ia) - (ib === -1 ? 99 : ib);\n });\n for (const a of dataAttrs) {\n const sel = attrSelector(a.name, a.value);\n if (uniqueIn(doc, sel, el)) push({ kind: \"data-attr\", value: sel, label: `${a.name}=${a.value}` });\n else if (uniqueIn(doc, tag + sel, el)) push({ kind: \"data-attr\", value: tag + sel, label: `${a.name}=${a.value}` });\n }\n\n const aria = el.getAttribute(\"aria-label\");\n if (aria && aria.length <= 120) {\n const sel = attrSelector(\"aria-label\", aria);\n if (uniqueIn(doc, sel, el)) push({ kind: \"aria\", value: sel, label: aria });\n else if (uniqueIn(doc, tag + sel, el)) push({ kind: \"aria\", value: tag + sel, label: aria });\n }\n\n const name = el.getAttribute(\"name\");\n if (name && uniqueIn(doc, tag + attrSelector(\"name\", name), el)) push({ kind: \"css\", value: tag + attrSelector(\"name\", name), label: `${tag} name=${name}` });\n const role = el.getAttribute(\"role\");\n if (role) {\n const title = el.getAttribute(\"title\") || el.getAttribute(\"aria-labelledby\");\n const sel = title ? `[role='${role}']${attrSelector(el.getAttribute(\"title\") ? \"title\" : \"aria-labelledby\", title)}` : `[role='${role}']`;\n if (uniqueIn(doc, sel, el)) push({ kind: \"css\", value: sel, label: `role ${role}` });\n }\n if (tag === \"a\") {\n const href = el.getAttribute(\"href\");\n if (href && href.length <= 200 && uniqueIn(doc, `a${attrSelector(\"href\", href)}`, el)) push({ kind: \"css\", value: `a${attrSelector(\"href\", href)}`, label: `link ${href}` });\n }\n\n const path = cssPath(el, doc);\n if (path) push({ kind: \"css\", value: path, label: \"css path\" });\n\n if (/^(button|a|h[1-6]|label|summary)$/.test(tag) || role === \"button\" || role === \"link\" || role === \"tab\" || role === \"menuitem\") {\n const text = normalizeText((el as HTMLElement).innerText ?? el.textContent);\n if (text && text.length <= 80) push({ kind: \"text\", value: text, label: `text \"${text}\"` });\n }\n return out.slice(0, 10);\n}\n\nexport interface ElementDescription {\n selectors: SelectorStrategy[];\n textSnapshot: string;\n rect: { x: number; y: number; width: number; height: number };\n tag: string;\n}\n\n/** Everything the authoring picker needs for one element. */\nexport function describeElement(el: Element): ElementDescription {\n const r = el.getBoundingClientRect();\n return {\n selectors: generateSelectors(el),\n textSnapshot: textSnapshotOf(el),\n rect: { x: r.x, y: r.y, width: r.width, height: r.height },\n tag: el.tagName.toLowerCase(),\n };\n}\n","import type { CapturedElement, NormalizedRect } from \"@guidelytech/shared\";\nimport { normalizeText } from \"./selectors\";\n\n/**\n * Pure DOM helpers for how-to capture: which element an interaction is about, how to name it for\n * people, which fields and on-screen text are sensitive, and where things sit in a screenshot.\n */\n\n/** Elements a click is \"about\" when it lands on them or inside them. */\nexport const CAPTURE_INTERACTIVE_SELECTOR =\n \"a,button,input,select,textarea,label,summary,[role=button],[role=link],[role=tab],[role=menuitem],[role=menuitemcheckbox],[role=menuitemradio],[role=option],[role=checkbox],[role=radio],[role=switch],[role=combobox],[contenteditable]:not([contenteditable=false])\";\n\n/** Always-redacted elements (on top of the project's mask selectors). */\nexport const REDACT_SELECTOR = \"[data-guidely-redact]\";\n\nconst TEXT_INPUT_TYPES = new Set([\"\", \"text\", \"email\", \"search\", \"tel\", \"url\", \"number\", \"password\", \"date\", \"datetime-local\", \"month\", \"week\", \"time\"]);\n\nfunction closestSafe(el: Element, selector: string): Element | null {\n if (!selector) return null;\n try {\n return el.closest(selector);\n } catch {\n return null;\n }\n}\n\nfunction inputType(el: Element): string {\n return el.tagName === \"INPUT\" ? (el.getAttribute(\"type\") || \"\").toLowerCase() : \"\";\n}\n\nfunction isEditableHost(el: Element): boolean {\n const v = el.getAttribute(\"contenteditable\");\n return v != null && v.toLowerCase() !== \"false\";\n}\n\n/** Fields whose typed text becomes a `type` step (instead of a click). */\nexport function isTextEntry(el: Element): boolean {\n if (el.tagName === \"TEXTAREA\") return true;\n if (el.tagName === \"INPUT\") return TEXT_INPUT_TYPES.has(inputType(el));\n return isEditableHost(el) || !!closestSafe(el, \"[contenteditable]:not([contenteditable=false])\");\n}\n\n/** The element a pointer interaction is about: the closest interactive ancestor, else the target itself. */\nexport function actionTarget(target: Element): Element {\n const hit = closestSafe(target, CAPTURE_INTERACTIVE_SELECTOR) ?? target;\n // A contenteditable descendant belongs to its editing host.\n if (!isEditableHost(hit) && isTextEntry(hit) && hit.tagName !== \"INPUT\" && hit.tagName !== \"TEXTAREA\") return closestSafe(hit, \"[contenteditable]:not([contenteditable=false])\") ?? hit;\n return hit;\n}\n\n/** The control a `<label>` is for (clicking the label acts on it), if any. */\nexport function labelControl(el: Element): Element | null {\n if (el.tagName !== \"LABEL\") return null;\n const label = el as HTMLLabelElement;\n if (label.control) return label.control;\n const forId = label.getAttribute(\"for\");\n if (forId) return label.ownerDocument.getElementById(forId);\n return label.querySelector(\"input,select,textarea\");\n}\n\n/** Is the element (or an ancestor) covered by the mask selectors or `[data-guidely-redact]`? */\nexport function isMaskedElement(el: Element, maskSelector: string): boolean {\n return !!closestSafe(el, REDACT_SELECTOR) || !!closestSafe(el, maskSelector);\n}\n\nconst SENSITIVE_NAME = /pass|card|cvv|cvc|ssn|secret|token|otp/i;\nconst SENSITIVE_AUTOCOMPLETE = /cc-|one-time-code|current-password|new-password/i;\n\n/** Fields whose value is never recorded and whose pixels are redacted from screenshots. */\nexport function isSensitiveField(el: Element, maskSelector = \"\"): boolean {\n if (inputType(el) === \"password\") return true;\n if (SENSITIVE_AUTOCOMPLETE.test(el.getAttribute(\"autocomplete\") || \"\")) return true;\n if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (SENSITIVE_NAME.test(el.getAttribute(\"name\") || \"\") || SENSITIVE_NAME.test(el.id || \"\"))) return true;\n return isMaskedElement(el, maskSelector);\n}\n\n// ---------------------------------------------------------------------------\n// Sensitive text patterns\n// ---------------------------------------------------------------------------\n\nconst EMAIL = /[A-Z0-9._%+-]+@[A-Z0-9-]+(?:\\.[A-Z0-9-]+)*\\.[A-Z]{2,}/gi;\n/** A run of digit groups (optionally `+cc` and `(area)`) separated by single spaces, dots or dashes. */\nconst NUMBER_RUN = /(?:\\+\\d{1,3}[ .-]?)?(?:\\(\\d{2,4}\\)[ .-]?)?\\d+(?:[ .-]\\d+)*/g;\n\nexport type SensitiveNumberKind = \"card\" | \"ssn\" | \"phone\";\n\n/**\n * Classifies a number run: card (13–19 digits in groups of 4+), US SSN (3-2-4) or phone\n * (10–13 digits written with a country code, area-code parentheses or 3+ groups ending in 4 digits).\n * Dates, times, prices, versions and IP addresses do not match.\n */\nexport function classifyNumber(run: string): SensitiveNumberKind | null {\n const groups = run.match(/\\d+/g) ?? [];\n const lens = groups.map((g) => g.length);\n const digits = lens.reduce((a, b) => a + b, 0);\n const special = /[+(.]/.test(run);\n if (lens.length === 3 && lens[0] === 3 && lens[1] === 2 && lens[2] === 4 && /^\\d{3}[ -]\\d{2}[ -]\\d{4}$/.test(run)) return \"ssn\";\n if (digits >= 13 && digits <= 19 && !special && lens.every((l) => l >= 4)) return \"card\";\n if (digits >= 10 && digits <= 13 && (/[+(]/.test(run) || (lens.length >= 3 && lens[lens.length - 1] === 4 && lens.every((l) => l >= 2) && !run.includes(\".\")))) return \"phone\";\n return null;\n}\n\n/** Character ranges `[start, end)` of emails, card numbers, SSNs and phone numbers in `text`. */\nexport function findSensitiveText(text: string): Array<[number, number]> {\n const out: Array<[number, number]> = [];\n if (text.length < 7) return out;\n if (text.includes(\"@\")) {\n EMAIL.lastIndex = 0;\n for (let m = EMAIL.exec(text); m && out.length < 200; m = EMAIL.exec(text)) out.push([m.index, m.index + m[0].length]);\n }\n if (/\\d{3}/.test(text)) {\n NUMBER_RUN.lastIndex = 0;\n for (let m = NUMBER_RUN.exec(text); m && out.length < 200; m = NUMBER_RUN.exec(text)) {\n if (m[0].length >= 9 && classifyNumber(m[0])) out.push([m.index, m.index + m[0].length]);\n }\n }\n return out;\n}\n\n/** Typed values are recorded verbatim unless they contain something like a card number or SSN. */\nexport function looksLikeSecretValue(value: string): boolean {\n NUMBER_RUN.lastIndex = 0;\n for (let m = NUMBER_RUN.exec(value); m; m = NUMBER_RUN.exec(value)) {\n const kind = classifyNumber(m[0]);\n if (kind === \"card\" || kind === \"ssn\") return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Element description\n// ---------------------------------------------------------------------------\n\nconst ROLE_MAP: Record<string, string> = {\n button: \"button\",\n link: \"link\",\n tab: \"tab\",\n menuitem: \"menuitem\",\n menuitemcheckbox: \"menuitem\",\n menuitemradio: \"menuitem\",\n checkbox: \"checkbox\",\n radio: \"radio\",\n switch: \"switch\",\n option: \"option\",\n combobox: \"dropdown\",\n listbox: \"dropdown\",\n textbox: \"field\",\n searchbox: \"field\",\n spinbutton: \"field\",\n};\n\n/** Normalised role: button, link, tab, menuitem, checkbox, radio, switch, field, dropdown, option or element. */\nexport function captureRole(el: Element): string {\n const explicit = (el.getAttribute(\"role\") || \"\").trim().split(/\\s+/)[0]!.toLowerCase();\n if (ROLE_MAP[explicit]) return ROLE_MAP[explicit]!;\n const tag = el.tagName.toLowerCase();\n if (tag === \"a\") return el.hasAttribute(\"href\") ? \"link\" : \"element\";\n if (tag === \"button\" || tag === \"summary\") return \"button\";\n if (tag === \"select\") return \"dropdown\";\n if (tag === \"option\") return \"option\";\n if (tag === \"textarea\") return \"field\";\n if (tag === \"input\") {\n const t = inputType(el);\n if (t === \"checkbox\") return \"checkbox\";\n if (t === \"radio\") return \"radio\";\n if (t === \"button\" || t === \"submit\" || t === \"reset\" || t === \"image\") return \"button\";\n return \"field\";\n }\n if (isEditableHost(el)) return \"field\";\n return \"element\";\n}\n\nconst clip = (s: string, max = 80) => (s.length > max ? `${s.slice(0, max - 1).trimEnd()}…` : s);\n\nfunction textOf(el: Element): string {\n return normalizeText((el as HTMLElement).innerText ?? el.textContent);\n}\n\nfunction labelledBy(el: Element): string {\n const ids = (el.getAttribute(\"aria-labelledby\") || \"\").split(/\\s+/).filter(Boolean);\n return normalizeText(ids.map((id) => el.ownerDocument.getElementById(id)).filter((x): x is HTMLElement => !!x).map(textOf).join(\" \"));\n}\n\nfunction associatedLabel(el: Element): string {\n const labels = (el as HTMLInputElement).labels;\n if (labels && labels.length) return normalizeText(Array.from(labels).map(textOf).join(\" \"));\n if (el.id) {\n try {\n const l = el.ownerDocument.querySelector(`label[for=\"${el.id.replace(/[\"\\\\]/g, \"\\\\$&\")}\"]`);\n if (l) return textOf(l);\n } catch {\n /* ignore */\n }\n }\n const wrap = el.parentElement?.closest(\"label\");\n return wrap ? textOf(wrap) : \"\";\n}\n\n/**\n * Visible name of an element for people: aria-label, aria-labelledby, its `<label>`, its text\n * (not for fields, whose value is user data), placeholder, alt, title or name. Max 80 characters.\n */\nexport function captureLabel(el: Element): string {\n const attr = (name: string) => normalizeText(el.getAttribute(name));\n const tag = el.tagName;\n const field = tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\" || isEditableHost(el);\n const candidates: Array<() => string> = [\n () => attr(\"aria-label\"),\n () => labelledBy(el),\n () => (/^(INPUT|TEXTAREA|SELECT|METER|PROGRESS|OUTPUT)$/.test(tag) ? associatedLabel(el) : \"\"),\n () => (tag === \"INPUT\" && /^(button|submit|reset)$/.test(inputType(el)) ? normalizeText((el as HTMLInputElement).value) : \"\"),\n () => (field ? \"\" : textOf(el)),\n () => attr(\"placeholder\"),\n () => attr(\"alt\"),\n () => normalizeText(el.querySelector?.(\"img[alt]\")?.getAttribute(\"alt\")),\n () => attr(\"title\"),\n () => normalizeText(el.querySelector?.(\"svg title\")?.textContent),\n () => attr(\"name\"),\n ];\n for (const c of candidates) {\n const v = c();\n if (v) return clip(v);\n }\n return \"\";\n}\n\n/** People-facing description of the element; masked elements get no label (never their text). */\nexport function describeCapturedElement(el: Element, maskSelector = \"\"): CapturedElement {\n return { label: isMaskedElement(el, maskSelector) ? \"\" : captureLabel(el), role: captureRole(el), tag: el.tagName.toLowerCase() };\n}\n\n/** The value a `type` step records: trimmed, at most 200 characters. */\nexport function fieldValue(el: Element): string {\n const raw = el.tagName === \"INPUT\" || el.tagName === \"TEXTAREA\" ? (el as HTMLInputElement).value : textOf(el);\n return (raw || \"\").trim().slice(0, 200);\n}\n\n/** Text of the selected option(s) of a `<select>`. */\nexport function selectedOptionText(el: HTMLSelectElement): string {\n return normalizeText(Array.from(el.selectedOptions ?? []).map((o) => o.text || o.value).join(\", \")).slice(0, 200);\n}\n\n// ---------------------------------------------------------------------------\n// Geometry\n// ---------------------------------------------------------------------------\n\nexport interface Box {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nconst clamp01 = (n: number) => Math.min(1, Math.max(0, n));\nconst round = (n: number) => Math.round(n * 10000) / 10000;\n\n/**\n * Maps a viewport rect (CSS px) to fractions of a screenshot of that viewport, padded by `pad`\n * CSS px and clamped to the frame. Returns null when nothing of it is on screen.\n */\nexport function normalizeRect(rect: Box, viewport: { width: number; height: number }, pad = 4): NormalizedRect | null {\n if (!viewport.width || !viewport.height || rect.width <= 0 || rect.height <= 0) return null;\n const x0 = clamp01((rect.x - pad) / viewport.width);\n const y0 = clamp01((rect.y - pad) / viewport.height);\n const x1 = clamp01((rect.x + rect.width + pad) / viewport.width);\n const y1 = clamp01((rect.y + rect.height + pad) / viewport.height);\n if (x1 <= x0 || y1 <= y0) return null;\n return { x: round(x0), y: round(y0), width: round(x1 - x0), height: round(y1 - y0) };\n}\n\n/** Scales a viewport rect (CSS px) to frame pixels, clipped to the frame. */\nexport function toFrameRect(rect: Box, scaleX: number, scaleY: number, frame: { width: number; height: number }, pad = 0): Box | null {\n const x0 = Math.max(0, Math.floor((rect.x - pad) * scaleX));\n const y0 = Math.max(0, Math.floor((rect.y - pad) * scaleY));\n const x1 = Math.min(frame.width, Math.ceil((rect.x + rect.width + pad) * scaleX));\n const y1 = Math.min(frame.height, Math.ceil((rect.y + rect.height + pad) * scaleY));\n return x1 > x0 && y1 > y0 ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } : null;\n}\n\nfunction intersectsViewport(r: Box, vw: number, vh: number): boolean {\n return r.width > 0 && r.height > 0 && r.x < vw && r.y < vh && r.x + r.width > 0 && r.y + r.height > 0;\n}\n\nconst SKIP_TEXT_PARENTS = /^(SCRIPT|STYLE|NOSCRIPT|TEMPLATE|TEXTAREA|OPTION)$/;\n\nexport interface RedactionOptions {\n maskSelector?: string;\n /** Stop after this many text nodes (keeps the synchronous scan cheap on huge pages). */\n maxTextNodes?: number;\n}\n\n/**\n * Viewport rects (CSS px) to blur in a screenshot: password and other sensitive fields, masked and\n * `[data-guidely-redact]` elements, field values and visible text that look like emails, card\n * numbers, SSNs or phone numbers. Runs synchronously so it matches the frame grabbed with it.\n */\nexport function collectRedactions(doc: Document, options: RedactionOptions = {}): Box[] {\n const win = doc.defaultView;\n const vw = win?.innerWidth ?? 0;\n const vh = win?.innerHeight ?? 0;\n const out: Box[] = [];\n const push = (r: Box) => {\n if (intersectsViewport(r, vw, vh)) out.push({ x: r.x, y: r.y, width: r.width, height: r.height });\n };\n const root = doc.body;\n if (!root) return out;\n const mask = options.maskSelector || \"\";\n const blocks = new Set<Element>();\n try {\n root.querySelectorAll(mask ? `${REDACT_SELECTOR},${mask}` : REDACT_SELECTOR).forEach((el) => blocks.add(el));\n } catch {\n root.querySelectorAll(REDACT_SELECTOR).forEach((el) => blocks.add(el));\n }\n root.querySelectorAll(\"input,textarea,select,[contenteditable]:not([contenteditable=false])\").forEach((el) => {\n if (blocks.has(el)) return;\n const t = inputType(el);\n if (t === \"hidden\" || t === \"checkbox\" || t === \"radio\" || t === \"button\" || t === \"submit\" || t === \"reset\") return;\n if (isSensitiveField(el, mask)) blocks.add(el);\n else if ((el.tagName === \"INPUT\" || el.tagName === \"TEXTAREA\") && findSensitiveText((el as HTMLInputElement).value || \"\").length) blocks.add(el);\n });\n blocks.forEach((el) => push(el.getBoundingClientRect()));\n\n const max = options.maxTextNodes ?? 5000;\n const walker = doc.createTreeWalker(root, 4 /* NodeFilter.SHOW_TEXT */);\n let range: Range | null = null;\n let seen = 0;\n for (let node = walker.nextNode(); node && seen < max; node = walker.nextNode()) {\n const text = node.nodeValue || \"\";\n if (text.length < 7) continue;\n seen++;\n const parent = node.parentElement;\n if (!parent || SKIP_TEXT_PARENTS.test(parent.tagName)) continue;\n const hits = findSensitiveText(text);\n if (!hits.length) continue;\n // Text inside an element that is already blurred as a whole needs no second pass.\n if (Array.from(blocks).some((b) => b.contains(parent))) continue;\n range ??= doc.createRange();\n for (const [start, end] of hits) {\n try {\n range.setStart(node, start);\n range.setEnd(node, end);\n Array.from(range.getClientRects()).forEach(push);\n } catch {\n /* node changed under us */\n }\n }\n }\n return out;\n}\n","import { toFrameRect, type Box } from \"./capture-dom\";\n\n/**\n * Screenshots for how-to capture: a tab-capture stream (`getDisplayMedia`) played into a hidden\n * video, frames grabbed synchronously into a canvas, sensitive regions blurred into the pixels and\n * the result encoded — all in the browser, so raw pixels of redacted regions never leave it.\n */\n\nexport type ScreenResult = { ok: true; screen: ScreenSource } | { ok: false; reason: \"unsupported\" | \"denied\" | \"wrong-surface\" | \"error\" };\n\nexport interface ScreenSource {\n /** True while the stream delivers frames. */\n live(): boolean;\n /** Called once when the user stops sharing (or the stream ends otherwise). */\n onEnded(cb: () => void): void;\n /** Draws the current frame into a new canvas (synchronously). Null when no frame is available. */\n grab(): HTMLCanvasElement | null;\n /** Does the current frame show the page as it is after `changedAt` (a `performance.now()` time)? */\n freshSince(changedAt: number): boolean;\n /** Resolves when the next frame arrives (or after `timeoutMs`). */\n nextFrame(timeoutMs?: number): Promise<void>;\n stop(): void;\n}\n\n/** Can this browser capture the tab at all? */\nexport function canCaptureScreen(): boolean {\n return typeof navigator !== \"undefined\" && !!navigator.mediaDevices && typeof navigator.mediaDevices.getDisplayMedia === \"function\";\n}\n\n/**\n * Asks the user to share this tab (must run from a user gesture) and plays the stream into a\n * hidden `<video>` appended to `container`. Rejects windows and screens: their frames do not\n * match the page's viewport, so highlights and redactions would land in the wrong place.\n */\nexport async function requestTabCapture(container: Node, doc: Document = document): Promise<ScreenResult> {\n if (!canCaptureScreen()) return { ok: false, reason: \"unsupported\" };\n let stream: MediaStream;\n try {\n stream = await navigator.mediaDevices.getDisplayMedia({\n video: { displaySurface: \"browser\", frameRate: 5 },\n audio: false,\n preferCurrentTab: true,\n selfBrowserSurface: \"include\",\n surfaceSwitching: \"exclude\",\n } as DisplayMediaStreamOptions);\n } catch (err) {\n return { ok: false, reason: (err as { name?: string })?.name === \"NotAllowedError\" ? \"denied\" : \"error\" };\n }\n const track = stream.getVideoTracks()[0];\n if (!track) {\n stream.getTracks().forEach((t) => t.stop());\n return { ok: false, reason: \"error\" };\n }\n const surface = (track.getSettings?.() as { displaySurface?: string } | undefined)?.displaySurface;\n if (surface && surface !== \"browser\") {\n stream.getTracks().forEach((t) => t.stop());\n return { ok: false, reason: \"wrong-surface\" };\n }\n const video = doc.createElement(\"video\");\n video.muted = true;\n video.playsInline = true;\n video.setAttribute(\"aria-hidden\", \"true\");\n // Kept rendered (not display:none) so browsers keep decoding frames.\n video.style.cssText = \"position:fixed;left:0;top:0;width:2px;height:2px;opacity:0;pointer-events:none\";\n try {\n video.srcObject = stream;\n container.appendChild(video);\n } catch {\n stream.getTracks().forEach((t) => t.stop());\n return { ok: false, reason: \"error\" };\n }\n try {\n await video.play();\n if (!video.videoWidth) await new Promise<void>((resolve) => {\n const done = () => resolve();\n video.addEventListener(\"loadeddata\", done, { once: true });\n setTimeout(done, 1500);\n });\n } catch {\n /* frames may still arrive; grab() returns null until they do */\n }\n let ended = false;\n const listeners: Array<() => void> = [];\n // Frame timing: `requestVideoFrameCallback` where supported, else assume one frame period (5 fps) of lag.\n type FrameVideo = HTMLVideoElement & { requestVideoFrameCallback?: (cb: (now: number) => void) => number };\n const fv = video as FrameVideo;\n const rvfc = typeof fv.requestVideoFrameCallback === \"function\";\n let frameAt = 0;\n let waiters: Array<() => void> = [];\n const onFrame = (now: number) => {\n frameAt = now;\n waiters.splice(0).forEach((w) => w());\n if (!ended) fv.requestVideoFrameCallback!(onFrame);\n };\n if (rvfc) fv.requestVideoFrameCallback!(onFrame);\n const end = () => {\n if (ended) return;\n ended = true;\n stream.getTracks().forEach((t) => t.stop());\n video.srcObject = null;\n video.remove();\n listeners.splice(0).forEach((cb) => cb());\n };\n track.addEventListener(\"ended\", end);\n return {\n ok: true,\n screen: {\n live: () => !ended && track.readyState === \"live\",\n onEnded: (cb) => (ended ? cb() : listeners.push(cb)),\n grab: () => (ended ? null : grabFrame(video, doc)),\n freshSince: (changedAt) => (rvfc ? frameAt > changedAt : performance.now() - changedAt > 250),\n nextFrame: (timeoutMs = 500) =>\n new Promise<void>((resolve) => {\n const t = setTimeout(done, rvfc ? timeoutMs : 250);\n function done() {\n clearTimeout(t);\n waiters = waiters.filter((w) => w !== done);\n resolve();\n }\n if (rvfc) waiters.push(done);\n }),\n stop: () => {\n listeners.length = 0;\n end();\n },\n },\n };\n}\n\n/** Copies the video's current frame into a new canvas. */\nexport function grabFrame(video: HTMLVideoElement, doc: Document = document): HTMLCanvasElement | null {\n const w = video.videoWidth;\n const h = video.videoHeight;\n if (!w || !h) return null;\n const canvas = doc.createElement(\"canvas\");\n canvas.width = w;\n canvas.height = h;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n ctx.drawImage(video, 0, 0, w, h);\n return canvas;\n}\n\n/**\n * Blurs viewport rects (CSS px) into the canvas by averaging each region down to a few samples per\n * line of text and scaling it back up, which leaves nothing legible to recover. Returns the number\n * of regions blurred.\n */\nexport function redactCanvas(canvas: HTMLCanvasElement, rects: Box[], viewport: { width: number; height: number }): number {\n const ctx = canvas.getContext(\"2d\");\n if (!ctx || !rects.length || !viewport.width || !viewport.height) return 0;\n const sx = canvas.width / viewport.width;\n const sy = canvas.height / viewport.height;\n const tmp = canvas.ownerDocument.createElement(\"canvas\");\n const tctx = tmp.getContext(\"2d\");\n if (!tctx) return 0;\n let count = 0;\n for (const rect of rects) {\n const r = toFrameRect(rect, sx, sy, canvas, 4);\n if (!r) continue;\n // One sample per ~line height (at least 16 CSS px) in both directions.\n const block = Math.max(16 * sy, Math.min(r.height, 48 * sy));\n tmp.width = Math.max(1, Math.round(r.width / block));\n tmp.height = Math.max(1, Math.round(r.height / block));\n tctx.imageSmoothingEnabled = true;\n tctx.drawImage(canvas, r.x, r.y, r.width, r.height, 0, 0, tmp.width, tmp.height);\n ctx.imageSmoothingEnabled = true;\n ctx.drawImage(tmp, 0, 0, tmp.width, tmp.height, r.x, r.y, r.width, r.height);\n // A light tint so readers can tell the region was hidden on purpose.\n ctx.fillStyle = \"rgba(120,120,120,.28)\";\n ctx.fillRect(r.x, r.y, r.width, r.height);\n count++;\n }\n return count;\n}\n\nfunction scaled(canvas: HTMLCanvasElement, maxWidth: number): HTMLCanvasElement {\n if (canvas.width <= maxWidth) return canvas;\n const out = canvas.ownerDocument.createElement(\"canvas\");\n out.width = maxWidth;\n out.height = Math.round((canvas.height * maxWidth) / canvas.width);\n const ctx = out.getContext(\"2d\");\n if (!ctx) return canvas;\n ctx.imageSmoothingQuality = \"high\";\n ctx.drawImage(canvas, 0, 0, out.width, out.height);\n return out;\n}\n\nconst toBlob = (canvas: HTMLCanvasElement, type: string, quality: number) =>\n new Promise<Blob | null>((resolve) => {\n try {\n canvas.toBlob((b) => resolve(b), type, quality);\n } catch {\n resolve(null);\n }\n });\n\n/** Encodes as WebP (JPEG where WebP encoding is unsupported), at most `maxWidth` wide and `maxBytes` big. */\nexport async function encodeScreenshot(canvas: HTMLCanvasElement, options: { maxWidth?: number; maxBytes?: number } = {}): Promise<Blob | null> {\n const src = scaled(canvas, options.maxWidth ?? 2560);\n const maxBytes = options.maxBytes ?? 8 * 1024 * 1024;\n let blob = await toBlob(src, \"image/webp\", 0.85);\n // Browsers without a WebP encoder silently return PNG.\n if (!blob || blob.type !== \"image/webp\") blob = await toBlob(src, \"image/jpeg\", 0.85);\n if (blob && blob.size > maxBytes) blob = await toBlob(src, \"image/jpeg\", 0.6);\n return blob && blob.size <= maxBytes ? blob : null;\n}\n\n/** Synchronous JPEG data URL (≤ 1600 px wide), for persisting an unsent screenshot while the page unloads. */\nexport function screenshotDataUrl(canvas: HTMLCanvasElement): string | null {\n try {\n return scaled(canvas, 1600).toDataURL(\"image/jpeg\", 0.7);\n } catch {\n return null;\n }\n}\n","/** All runtime CSS, injected once into the Shadow DOM host. Tokens are CSS custom properties. */\nexport const STYLES = `\n:host{all:initial;position:static;display:block;contain:none}\n*,*::before,*::after{box-sizing:border-box}\n.g-scope [hidden]{display:none!important}\n.g-scope{\n --g-primary:#4f46e5;--g-bg:#ffffff;--g-text:#111827;--g-radius:12px;--g-font:Inter,system-ui,-apple-system,sans-serif;--g-z:2147483000;--g-overlay:.5;\n --g-muted:color-mix(in srgb,var(--g-text) 62%,transparent);--g-border:color-mix(in srgb,var(--g-text) 12%,transparent);\n --g-subtle:color-mix(in srgb,var(--g-text) 5%,transparent);--g-shadow:0 10px 40px rgba(0,0,0,.18),0 2px 8px rgba(0,0,0,.08);\n --g-primary-text:#ffffff;\n font-family:var(--g-font);font-size:14px;line-height:1.5;color:var(--g-text);-webkit-font-smoothing:antialiased;\n}\n.g-scope[data-theme=\"dark\"]{--g-shadow:0 10px 40px rgba(0,0,0,.5),0 2px 8px rgba(0,0,0,.3)}\n.g-live{position:fixed;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n.g-layer{position:fixed;inset:0;z-index:var(--g-z);pointer-events:none}\n.g-overlay{position:fixed;inset:0;background:rgba(0,0,0,var(--g-overlay));z-index:calc(var(--g-z) + 3);pointer-events:auto}\n.g-overlay.g-transparent{background:transparent}\n.g-spot-rect{position:fixed;background:rgba(0,0,0,var(--g-overlay));z-index:calc(var(--g-z) + 3);pointer-events:auto}\n.g-spot-ring{position:fixed;z-index:calc(var(--g-z) + 3);pointer-events:none;border-radius:6px;box-shadow:0 0 0 2px var(--g-primary),0 0 0 6px color-mix(in srgb,var(--g-primary) 30%,transparent)}\n.g-card{\n position:fixed;z-index:calc(var(--g-z) + 4);pointer-events:auto;background:var(--g-bg);color:var(--g-text);border-radius:var(--g-radius);\n box-shadow:var(--g-shadow);border:1px solid var(--g-border);width:min(360px,calc(100vw - 32px));max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);overflow:auto;outline:none;\n}\n.g-card.g-modal{left:50%;top:50%;transform:translate(-50%,-50%);width:min(480px,calc(100vw - 32px))}\n.g-card.g-tooltip,.g-card.g-popover,.g-card.g-spotlight-card,.g-card.g-hotspot-card{top:0;left:0;width:min(320px,calc(100vw - 32px))}\n.g-card.g-slideout{width:min(360px,calc(100vw - 32px));margin:16px}\n.g-pos-bottom-right{right:0;bottom:0}.g-pos-bottom-left{left:0;bottom:0}.g-pos-top-right{right:0;top:0}.g-pos-top-left{left:0;top:0}\n.g-pos-center{left:50%;top:50%;transform:translate(-50%,-50%)}\n.g-pos-top{top:0;left:0;right:0}.g-pos-bottom{bottom:0;left:0;right:0}\n.g-banner{position:fixed;left:0;right:0;z-index:calc(var(--g-z) + 1);pointer-events:auto;background:var(--g-primary);color:var(--g-primary-text);padding:10px 48px 10px 16px;display:flex;align-items:center;gap:12px;font-size:14px;box-shadow:0 2px 10px rgba(0,0,0,.15);max-width:100vw}\n.g-banner .g-body{flex:1;min-width:0}\n.g-banner .g-body a{color:inherit;text-decoration:underline}\n.g-banner .g-close{color:inherit;right:8px;top:50%;transform:translateY(-50%)}\n.g-banner .g-btn{background:rgba(255,255,255,.18);color:inherit;border-color:transparent;min-height:36px}\n.g-banner.g-pos-top{top:0}.g-banner.g-pos-bottom{bottom:0}\n.g-inner{padding:20px}\n.g-close{position:absolute;top:8px;right:8px;width:40px;height:40px;display:inline-flex;align-items:center;justify-content:center;border:0;background:transparent;color:var(--g-muted);border-radius:999px;cursor:pointer;font:inherit;font-size:20px;line-height:1}\n.g-close:hover,.g-close:focus-visible{background:var(--g-subtle);color:var(--g-text);outline:none}\n.g-close:focus-visible,.g-btn:focus-visible,.g-task:focus-visible,.g-choice:focus-visible,.g-scale button:focus-visible,.g-launcher:focus-visible,.g-input:focus-visible,.g-rc-item:focus-visible{outline:2px solid var(--g-primary);outline-offset:2px}\n.g-image{display:block;width:100%;max-height:220px;object-fit:cover;border-radius:var(--g-radius) var(--g-radius) 0 0}\n.g-title{margin:0 28px 6px 0;font-size:16px;font-weight:600;line-height:1.3}\n.g-body{font-size:14px;color:var(--g-text)}\n.g-body p{margin:0 0 8px}.g-body p:last-child{margin-bottom:0}\n.g-body ul,.g-body ol{margin:6px 0;padding-left:20px}\n.g-body a{color:var(--g-primary)}\n.g-body img{max-width:100%;height:auto;border-radius:6px}\n.g-body video,.g-body iframe{display:block;width:100%;max-width:100%;border:0;border-radius:6px;margin:8px 0;background:#000}\n.g-body video{height:auto;max-height:60vh}\n.g-body iframe{aspect-ratio:16/9;height:auto}\n.g-body .gd-pdf{margin:10px 0;border:1px solid var(--g-border);border-radius:10px;background:var(--g-subtle);overflow:hidden}\n.g-body a.gd-file{display:flex;align-items:center;gap:8px;padding:8px 10px;color:var(--g-text);font-size:13px;font-weight:500;text-decoration:none;min-height:40px;overflow-wrap:anywhere}\n.g-body a.gd-file::before{content:\"PDF\";flex:none;font-size:9px;font-weight:700;letter-spacing:.04em;line-height:1;color:#fff;background:#e5484d;border-radius:4px;padding:4px 5px}\n.g-body a.gd-file::after{content:\"⤢\";margin-left:auto;padding-left:8px;color:var(--g-muted);font-size:15px}\n.g-body a.gd-file:hover::after,.g-body a.gd-file:focus-visible::after{color:var(--g-primary)}\n.g-body a.gd-file:focus-visible{outline:2px solid var(--g-primary);outline-offset:-2px;border-radius:10px}\n.g-body > a.gd-file,.g-body p > a.gd-file{margin:10px 0;border:1px solid var(--g-border);border-radius:10px;background:var(--g-subtle)}\n.g-body > a.gd-file::after,.g-body p > a.gd-file::after,.g-body .gd-pdf:not([data-g-ready]) > a.gd-file::after{content:\"↗\"}\n.g-pdf-viewport{position:relative}\n.g-body .gd-pdf-pages{display:flex;gap:10px;overflow-x:auto;scroll-snap-type:x mandatory;overscroll-behavior-x:contain;scrollbar-width:none;padding:0 10px 10px;scroll-padding:0 10px}\n.g-body .gd-pdf-pages::-webkit-scrollbar{display:none}\n.g-body .gd-pdf-pages:focus-visible{outline:2px solid var(--g-primary);outline-offset:-2px}\n.g-body .gd-pdf-pages img{flex:0 0 100%;width:100%;height:auto;margin:0;scroll-snap-align:center;background:#fff;border-radius:4px;box-shadow:0 1px 3px rgba(0,0,0,.18);cursor:zoom-in}\n.g-pdf-viewport .gd-pdf-pages{padding:0;scroll-padding:0;margin:0 10px 10px}\n.g-pdf-count{position:absolute;right:18px;bottom:18px;padding:2px 8px;border-radius:999px;background:rgba(17,17,17,.72);color:#fff;font-size:11px;font-weight:500;pointer-events:none;font-variant-numeric:tabular-nums}\n.g-pdf-nav{position:absolute;top:calc(50% - 21px);width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:999px;background:rgba(17,17,17,.6);color:#fff;font:inherit;font-size:20px;line-height:1;cursor:pointer;opacity:0;transition:opacity .15s}\n.g-pdf-prev{left:16px}.g-pdf-next{right:16px}\n.g-pdf-viewport:hover .g-pdf-nav,.g-pdf-nav:focus-visible{opacity:1}\n.g-pdf-nav:disabled,.g-pdf-single .g-pdf-nav,.g-pdf-single .g-pdf-count{display:none}\n.g-pdf-nav:focus-visible{outline:2px solid #fff;outline-offset:1px}\n@media (hover:none){.g-pdf-nav{display:none}}\n.g-pdf-reader{position:fixed;inset:0;z-index:calc(var(--g-z) + 10);display:flex;flex-direction:column;background:#0b0b0d;pointer-events:auto;color:#fff}\n.g-pdf-bar{display:flex;align-items:center;gap:10px;padding:8px 8px 8px 16px;min-height:56px}\n.g-pdf-title{flex:1;min-width:0;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.g-pdf-bar .g-btn{min-height:36px;color:#fff;background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.18)}\n.g-pdf-close{position:static;color:#fff}\n.g-pdf-close:hover,.g-pdf-close:focus-visible{background:rgba(255,255,255,.14);color:#fff}\n.g-pdf-scroll{position:relative;flex:1;overflow-y:auto;overscroll-behavior:contain;padding:4px 16px 24px;display:flex;flex-direction:column;align-items:center;gap:12px;outline:none}\n.g-pdf-scroll img{display:block;width:100%;max-width:900px;height:auto;background:#fff;border-radius:2px;box-shadow:0 2px 12px rgba(0,0,0,.4)}\n.g-body code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;background:var(--g-subtle);padding:1px 4px;border-radius:4px}\n.g-body pre{background:var(--g-subtle);padding:10px;border-radius:6px;overflow:auto}\n.g-body blockquote{margin:6px 0;padding-left:10px;border-left:3px solid var(--g-border);color:var(--g-muted)}\n.g-footer{display:flex;align-items:center;gap:8px;margin-top:14px;flex-wrap:wrap}\n.g-progress{font-size:12px;color:var(--g-muted);margin-right:auto}\n.g-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:40px;padding:8px 14px;border-radius:calc(var(--g-radius) * .66);border:1px solid transparent;font:inherit;font-size:14px;font-weight:500;cursor:pointer;text-decoration:none;transition:background .15s,color .15s,border-color .15s}\n.g-btn-primary{background:var(--g-primary);color:var(--g-primary-text)}\n.g-btn-primary:hover{filter:brightness(1.08)}\n.g-btn-secondary{background:var(--g-subtle);color:var(--g-text);border-color:var(--g-border)}\n.g-btn-secondary:hover{background:color-mix(in srgb,var(--g-text) 10%,transparent)}\n.g-btn-ghost{background:transparent;color:var(--g-muted)}\n.g-btn-ghost:hover{background:var(--g-subtle);color:var(--g-text)}\n.g-btn-link{background:transparent;color:var(--g-primary);padding-left:4px;padding-right:4px}\n.g-btn-link:hover{text-decoration:underline}\n.g-btn:disabled{opacity:.5;cursor:not-allowed}\n.g-arrow{position:absolute;width:12px;height:12px;background:var(--g-bg);transform:rotate(45deg);border:1px solid var(--g-border);z-index:-1}\n.g-hotspot{position:fixed;z-index:calc(var(--g-z) + 1);pointer-events:auto;border-radius:999px;background:var(--g-primary);border:2px solid #fff;box-shadow:0 0 0 2px color-mix(in srgb,var(--g-primary) 40%,transparent);cursor:pointer;padding:0;margin:0}\n.g-hotspot::after{content:\"\";position:absolute;inset:-4px;border-radius:999px;border:2px solid var(--g-primary);opacity:0}\n.g-hotspot.g-pulse::after{animation:g-pulse 1.8s ease-out infinite}\n.g-hotspot-hit{position:absolute;inset:-14px}\n.g-custom{position:fixed;z-index:calc(var(--g-z) + 4);pointer-events:auto;left:50%;top:50%;transform:translate(-50%,-50%);max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);overflow:auto}\n/* animations */\n.g-scope[data-anim=\"fade\"] .g-card,.g-scope[data-anim=\"fade\"] .g-banner,.g-scope[data-anim=\"fade\"] .g-panel{animation:g-fade .18s ease-out}\n.g-scope[data-anim=\"slide\"] .g-card,.g-scope[data-anim=\"slide\"] .g-panel{animation:g-slide .22s ease-out}\n.g-scope[data-anim=\"none\"] *{animation:none!important;transition:none!important}\n@keyframes g-fade{from{opacity:0}to{opacity:1}}\n@keyframes g-slide{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}\n@keyframes g-pulse{0%{transform:scale(.6);opacity:.9}100%{transform:scale(2.2);opacity:0}}\n@media (prefers-reduced-motion:reduce){.g-scope *{animation:none!important;transition:none!important}}\n/* launcher + panel (checklist / resource center) */\n.g-launcher{position:fixed;z-index:calc(var(--g-z) + 1);pointer-events:auto;display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:10px 16px;border-radius:999px;border:0;background:var(--g-primary);color:var(--g-primary-text);font:inherit;font-size:14px;font-weight:600;cursor:pointer;box-shadow:var(--g-shadow);margin:16px}\n.g-launcher .g-ring{width:22px;height:22px;border-radius:999px;background:conic-gradient(#fff var(--g-pct,0%),rgba(255,255,255,.3) 0);display:inline-flex;align-items:center;justify-content:center;font-size:10px;position:relative}\n.g-launcher .g-ring::after{content:\"\";position:absolute;inset:3px;border-radius:999px;background:var(--g-primary)}\n.g-launcher .g-count{position:relative;z-index:1}\n.g-panel{position:fixed;z-index:calc(var(--g-z) + 2);pointer-events:auto;width:min(380px,calc(100vw - 32px));max-height:min(620px,calc(100vh - 100px));display:flex;flex-direction:column;background:var(--g-bg);color:var(--g-text);border-radius:var(--g-radius);box-shadow:var(--g-shadow);border:1px solid var(--g-border);margin:16px;bottom:60px;overflow:hidden}\n.g-panel-head{padding:16px 48px 12px 20px;border-bottom:1px solid var(--g-border);position:relative}\n.g-panel-title{margin:0;font-size:16px;font-weight:600}\n.g-panel-sub{margin:4px 0 0;font-size:12px;color:var(--g-muted)}\n.g-panel-body{overflow:auto;padding:8px 0;flex:1}\n.g-help{display:flex;flex-direction:column;min-height:0;flex:1}\n.g-bar{height:6px;border-radius:999px;background:var(--g-subtle);overflow:hidden;margin-top:10px}\n.g-bar > span{display:block;height:100%;background:var(--g-primary);transition:width .3s}\n.g-task{display:flex;gap:12px;align-items:flex-start;width:100%;padding:12px 20px;border:0;background:transparent;text-align:left;font:inherit;color:inherit;cursor:pointer;min-height:44px}\n.g-task:hover{background:var(--g-subtle)}\n.g-task[disabled]{cursor:not-allowed;opacity:.55}\n.g-task .g-check{flex:none;width:22px;height:22px;border-radius:999px;border:2px solid var(--g-border);display:inline-flex;align-items:center;justify-content:center;font-size:13px;margin-top:1px;color:#fff}\n.g-task.g-done .g-check{background:var(--g-primary);border-color:var(--g-primary)}\n.g-task.g-done .g-task-title{text-decoration:line-through;color:var(--g-muted)}\n.g-task-title{font-weight:500}\n.g-task-desc{font-size:12px;color:var(--g-muted);margin-top:2px}\n.g-panel-foot{padding:10px 20px;border-top:1px solid var(--g-border);display:flex;justify-content:flex-end;gap:8px}\n.g-complete{padding:28px 20px;text-align:center}\n.g-complete .g-title{margin-right:0;font-size:18px}\n/* survey */\n.g-question{margin-bottom:16px}\n.g-q-title{font-weight:600;margin:0 0 4px}\n.g-q-desc{font-size:12px;color:var(--g-muted);margin:0 0 8px}\n.g-scale{display:flex;gap:4px;flex-wrap:wrap}\n.g-scale button{min-width:34px;height:40px;flex:1;padding:0 4px;border-radius:6px;border:1px solid var(--g-border);background:var(--g-subtle);color:var(--g-text);font:inherit;cursor:pointer}\n.g-scale button[aria-pressed=\"true\"],.g-scale button:hover{background:var(--g-primary);color:var(--g-primary-text);border-color:var(--g-primary)}\n.g-scale-labels{display:flex;justify-content:space-between;font-size:11px;color:var(--g-muted);margin-top:4px}\n.g-stars button,.g-thumbs button{font-size:22px;background:transparent;border:0;cursor:pointer;color:var(--g-muted);min-width:40px;height:40px;font:inherit}\n.g-stars button[aria-pressed=\"true\"],.g-stars button.g-on{color:#f59e0b}\n.g-thumbs button[aria-pressed=\"true\"]{color:var(--g-primary)}\n.g-choice{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--g-border);border-radius:8px;margin-bottom:6px;cursor:pointer;min-height:40px;font:inherit;background:transparent;color:inherit;width:100%;text-align:left}\n.g-choice[aria-checked=\"true\"]{border-color:var(--g-primary);background:color-mix(in srgb,var(--g-primary) 8%,transparent)}\n.g-choice .g-dot{width:16px;height:16px;border-radius:999px;border:2px solid var(--g-border);flex:none}\n.g-choice.g-multi .g-dot{border-radius:4px}\n.g-choice[aria-checked=\"true\"] .g-dot{background:var(--g-primary);border-color:var(--g-primary)}\n.g-input{width:100%;min-height:40px;padding:8px 10px;border:1px solid var(--g-border);border-radius:8px;background:var(--g-bg);color:var(--g-text);font:inherit;resize:vertical}\n.g-error{color:#dc2626;font-size:12px;margin-top:4px}\n/* resource center */\n.g-rc-search{padding:12px 20px 4px}\n.g-rc-section{padding:8px 20px 4px;font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--g-muted);font-weight:600}\n.g-rc-section[data-depth]{text-transform:none;letter-spacing:0;font-size:12px}\n.g-rc-item{display:flex;align-items:flex-start;gap:10px;width:100%;padding:10px 20px;border:0;background:transparent;font:inherit;color:inherit;text-align:left;cursor:pointer;min-height:44px;text-decoration:none}\n.g-rc-item:hover{background:var(--g-subtle)}\n.g-rc-item .g-rc-title{font-weight:500}\n.g-rc-item .g-rc-sum{font-size:12px;color:var(--g-muted);margin-top:2px}\n.g-rc-item .g-rc-icon{flex:none;width:20px;text-align:center;color:var(--g-primary)}\n.g-rc-row{display:flex;align-items:center;gap:6px;padding-right:16px}\n.g-rc-row>.g-rc-item{flex:1;min-width:0;padding-right:4px}\n.g-rc-row:hover{background:var(--g-subtle)}\n.g-rc-row:hover>.g-rc-item{background:transparent}\n.g-rc-showme{flex:none;min-height:32px;padding:4px 10px;font-size:12px;white-space:nowrap}\n.g-help-showme{margin:4px 0 12px}\n.g-rc-article{padding:16px 20px}\n.g-resource-center .g-panel{transition:width .2s ease,max-height .2s ease}\n.g-resource-center .g-panel.g-panel-reading{width:min(720px,calc(100vw - 32px));max-height:calc(100vh - 100px)}\n.g-rc-back{margin-bottom:8px}\n.g-rc-empty{padding:24px 20px;color:var(--g-muted);text-align:center}\n.g-faq-a{padding:0 20px 12px 50px;font-size:13px;color:var(--g-muted)}\n.g-faq-a[hidden]{display:none}\n/* authoring */\n.g-auth-bar{position:fixed;top:0;left:0;right:0;z-index:calc(var(--g-z) + 10);pointer-events:auto;display:flex;align-items:center;gap:12px;padding:8px 16px;background:#111827;color:#fff;font:500 13px/1.4 var(--g-font);box-shadow:0 2px 10px rgba(0,0,0,.3)}\n.g-auth-bar .g-dot-live{width:8px;height:8px;border-radius:999px;background:#22c55e;box-shadow:0 0 0 3px rgba(34,197,94,.3)}\n.g-auth-bar .g-spacer{flex:1}\n.g-auth-bar .g-btn{min-height:32px;padding:4px 12px;font-size:13px}\n.g-auth-bar .g-btn-secondary{background:rgba(255,255,255,.12);color:#fff;border-color:transparent}\n.g-auth-outline{position:fixed;z-index:calc(var(--g-z) + 9);pointer-events:none;border:2px solid var(--g-primary);background:color-mix(in srgb,var(--g-primary) 12%,transparent);border-radius:4px;transition:all .06s linear}\n.g-auth-label{position:absolute;left:-2px;top:-24px;background:var(--g-primary);color:#fff;font:600 11px/1 var(--g-font);padding:5px 7px;border-radius:4px;white-space:nowrap;max-width:320px;overflow:hidden;text-overflow:ellipsis}\n.g-auth-outline.g-picked{border-style:dashed;border-color:#22c55e;background:rgba(34,197,94,.12)}\n.g-auth-outline.g-picked .g-auth-label{background:#16a34a}\n.g-highlight{position:fixed;z-index:calc(var(--g-z) + 8);pointer-events:none;border:2px dashed #f59e0b;background:rgba(245,158,11,.12);border-radius:4px}\n@media (max-width:480px){.g-card.g-modal,.g-panel{width:calc(100vw - 32px)}.g-inner{padding:16px}}\n`;\n","import type { Appearance, ProjectTheme } from \"@guidelytech/shared\";\nimport { STYLES } from \"./styles\";\n\nexport const HOST_ID = \"guidely-root\";\n\nexport interface HostHandle {\n host: HTMLElement;\n shadow: ShadowRoot;\n /** Polite live region for screen-reader announcements. */\n live: HTMLElement;\n announce(text: string): void;\n destroy(): void;\n}\n\nlet current: HostHandle | null = null;\n\n/** Default project theme used when the config has not loaded yet. */\nexport const DEFAULT_THEME: ProjectTheme = {\n primaryColor: \"#4f46e5\",\n backgroundColor: \"#ffffff\",\n textColor: \"#111827\",\n borderRadius: 12,\n fontFamily: \"Inter, system-ui, -apple-system, sans-serif\",\n};\n\n/** Returns (creating when needed) the single Shadow-DOM host appended to `document.body`. */\nexport function ensureHost(doc: Document = document): HostHandle {\n if (current && current.host.isConnected && current.host.ownerDocument === doc) return current;\n let host = doc.getElementById(HOST_ID) as HTMLElement | null;\n if (!host) {\n host = doc.createElement(\"div\");\n host.id = HOST_ID;\n host.setAttribute(\"data-guidely\", \"\");\n (doc.body || doc.documentElement).appendChild(host);\n }\n const shadow = host.shadowRoot ?? host.attachShadow({ mode: \"open\" });\n if (!shadow.querySelector(\"style[data-g-base]\")) {\n const style = doc.createElement(\"style\");\n style.setAttribute(\"data-g-base\", \"\");\n style.textContent = STYLES;\n shadow.appendChild(style);\n }\n let live = shadow.querySelector<HTMLElement>(\".g-live\");\n if (!live) {\n live = doc.createElement(\"div\");\n live.className = \"g-live\";\n live.setAttribute(\"aria-live\", \"polite\");\n live.setAttribute(\"aria-atomic\", \"true\");\n shadow.appendChild(live);\n }\n const liveEl = live;\n current = {\n host,\n shadow,\n live: liveEl,\n announce(text: string) {\n liveEl.textContent = \"\";\n setTimeout(() => {\n liveEl.textContent = text;\n }, 30);\n },\n destroy() {\n host?.remove();\n if (current?.host === host) current = null;\n },\n };\n return current;\n}\n\n/** Removes the host from the document (all overlays with it). */\nexport function destroyHost(): void {\n current?.destroy();\n const stray = typeof document !== \"undefined\" ? document.getElementById(HOST_ID) : null;\n stray?.remove();\n current = null;\n}\n\nexport type ResolvedThemeMode = \"light\" | \"dark\";\n\nfunction prefersDark(): boolean {\n try {\n return typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n } catch {\n return false;\n }\n}\n\nexport function prefersReducedMotion(): boolean {\n try {\n return typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n } catch {\n return false;\n }\n}\n\nexport interface ThemeVars {\n primary: string;\n bg: string;\n text: string;\n radius: number;\n font: string;\n z: number;\n overlay: number;\n mode: ResolvedThemeMode;\n animation: Appearance[\"animation\"];\n}\n\n/** Merges project theme + guide appearance into CSS custom property values. */\nexport function resolveTheme(theme: Partial<ProjectTheme> | null | undefined, appearance?: Partial<Appearance> | null): ThemeVars {\n const t = { ...DEFAULT_THEME, ...(theme || {}) };\n const a = appearance || {};\n const requested = a.theme ?? \"auto\";\n const mode: ResolvedThemeMode = requested === \"auto\" ? (prefersDark() ? \"dark\" : \"light\") : requested;\n const dark = mode === \"dark\";\n return {\n primary: a.primaryColor || t.primaryColor,\n bg: a.backgroundColor || (dark ? \"#1f2937\" : t.backgroundColor),\n text: a.textColor || (dark ? \"#f9fafb\" : t.textColor),\n radius: a.borderRadius ?? t.borderRadius,\n font: a.fontFamily || t.fontFamily,\n z: a.zIndex ?? 2147483000,\n overlay: a.overlayOpacity ?? 0.5,\n mode,\n animation: prefersReducedMotion() ? \"none\" : (a.animation ?? \"fade\"),\n };\n}\n\n/** Applies theme variables to a scope element. */\nexport function applyTheme(el: HTMLElement, vars: ThemeVars): void {\n el.style.setProperty(\"--g-primary\", vars.primary);\n el.style.setProperty(\"--g-bg\", vars.bg);\n el.style.setProperty(\"--g-text\", vars.text);\n el.style.setProperty(\"--g-radius\", `${vars.radius}px`);\n el.style.setProperty(\"--g-font\", vars.font);\n el.style.setProperty(\"--g-z\", String(vars.z));\n el.style.setProperty(\"--g-overlay\", String(vars.overlay));\n el.setAttribute(\"data-theme\", vars.mode);\n el.setAttribute(\"data-anim\", vars.animation);\n}\n\n/**\n * Creates a themed scope container inside the shadow root. Each guide/widget renders inside its\n * own scope so appearance settings never leak between guides.\n */\nexport function createScope(theme?: Partial<ProjectTheme> | null, appearance?: Partial<Appearance> | null, doc: Document = document): { el: HTMLElement; vars: ThemeVars; destroy(): void } {\n const handle = ensureHost(doc);\n const el = doc.createElement(\"div\");\n el.className = \"g-scope\";\n const vars = resolveTheme(theme, appearance);\n applyTheme(el, vars);\n handle.shadow.appendChild(el);\n let mq: MediaQueryList | null = null;\n const onChange = () => applyTheme(el, resolveTheme(theme, appearance));\n if ((appearance?.theme ?? \"auto\") === \"auto\" && typeof window !== \"undefined\" && typeof window.matchMedia === \"function\") {\n try {\n mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n mq.addEventListener?.(\"change\", onChange);\n } catch {\n mq = null;\n }\n }\n return {\n el,\n vars,\n destroy() {\n mq?.removeEventListener?.(\"change\", onChange);\n el.remove();\n },\n };\n}\n"],"mappings":"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","names":["HOST_ID"]}
|
|
1
|
+
{"version":3,"sources":["../src/capture.ts","../src/capture-styles.ts","../src/selectors.ts","../src/capture-dom.ts","../src/capture-screen.ts","../src/styles.ts","../src/host.ts"],"sourcesContent":["import type { CaptureStepInput, HowToAction } from \"@guidelytech/shared\";\nimport { CAPTURE_STYLES } from \"./capture-styles\";\nimport {\n actionTarget,\n collectRedactions,\n describeCapturedElement,\n fieldValue,\n isMaskedElement,\n isSensitiveField,\n isTextEntry,\n labelControl,\n looksLikeSecretValue,\n normalizeRect,\n selectedOptionText,\n} from \"./capture-dom\";\nimport { canCaptureScreen, redactCanvas, requestTabCapture, type ScreenSource } from \"./capture-screen\";\nimport { createScope } from \"./host\";\nimport { composedTarget, describeElement, isGuidelyElement } from \"./selectors\";\n\nexport * from \"./capture-dom\";\nexport { canCaptureScreen, encodeScreenshot, grabFrame, redactCanvas, requestTabCapture, screenshotDataUrl } from \"./capture-screen\";\nexport type { ScreenResult, ScreenSource } from \"./capture-screen\";\n\n/** A captured step before the SDK gives it a `clientId`. */\nexport type CaptureStepDraft = Omit<CaptureStepInput, \"clientId\">;\n\nexport interface CapturedStep {\n step: CaptureStepDraft;\n /**\n * The screenshot, already redacted (encode it with `encodeScreenshot`); null without screenshots.\n * A promise when the current frame predates a scroll or resize: it resolves with the next frame,\n * after `step.highlight` and `step.redactions` were updated to match it.\n */\n frame: HTMLCanvasElement | Promise<HTMLCanvasElement | null> | null;\n}\n\nexport interface CaptureOptions {\n /** How-to title shown in the toolbar before recording starts. */\n title: string;\n /** Steps already recorded (a recording continues across full page loads). */\n stepCount?: number;\n /** False when the server cannot store screenshots: record steps only. Default true. */\n screenshots?: boolean;\n /**\n * Continue a recording after a full page load: start recording straight away. `navigate` adds a\n * step for the new page; `screenshots` offers \"Screenshots paused — Resume\" (the stream is gone).\n */\n resume?: { navigate: boolean; screenshots: boolean };\n /** Comma-joined CSS selectors whose text and pixels are never captured. */\n maskSelector?: string;\n onStep(step: CapturedStep): void;\n /** Recording started; `screenshots` is whether the user chose to take screenshots. */\n onStart?(info: { screenshots: boolean }): void;\n onFinish(): void;\n onCancel(): void;\n doc?: Document;\n}\n\nexport interface CaptureSession {\n /** Shows \"Saving…\" (and stops recording) while queued uploads finish. */\n setSaving(saving: boolean): void;\n isRecording(): boolean;\n stop(): void;\n}\n\n/** A repeat press on the same element within this window is a double click, not a new step. */\nexport const DOUBLE_CLICK_MS = 400;\n/** URL changes this soon after an interaction were caused by it (no separate navigate step). */\nexport const NAV_AFTER_ACTION_MS = 1500;\n/** Wait for the page to settle before capturing a navigate step. */\nexport const NAV_SETTLE_MS = 600;\n\ntype Phase = \"ready\" | \"recording\" | \"paused\" | \"saving\";\n\nconst NOTICES = {\n \"wrong-surface\": \"Share this tab (not a window or the whole screen) so screenshots match the page.\",\n denied: \"Screen sharing was cancelled. Start again, or record without screenshots.\",\n error: \"Screen capture could not start. Try again, or record without screenshots.\",\n unsupported: \"This browser cannot capture screenshots; steps are recorded without them.\",\n lost: \"Screenshots paused: sharing stopped or the page reloaded.\",\n} as const;\n\nfunction button(doc: Document, text: string, cls: string, attr: string): HTMLButtonElement {\n const b = doc.createElement(\"button\");\n b.type = \"button\";\n b.className = `g-btn ${cls}`;\n b.textContent = text;\n b.setAttribute(attr, \"\");\n return b;\n}\n\n/** The focused element inside a shadow-DOM subtree, if any. */\nfunction deepActiveElementIn(el: Element): Element | null {\n const root = el.getRootNode() as Document | ShadowRoot;\n return root.activeElement ?? null;\n}\n\nfunction deepActiveElement(doc: Document): Element | null {\n let el = doc.activeElement;\n while (el?.shadowRoot?.activeElement) el = el.shadowRoot.activeElement;\n return el;\n}\n\n/**\n * Starts how-to capture: a Shadow-DOM toolbar (bottom centre, a small pill while recording) and passive capture-phase\n * listeners that turn clicks, typing, selections and navigations into steps. The app keeps\n * receiving every event; nothing is prevented.\n */\nexport function startCapture(options: CaptureOptions): CaptureSession {\n const doc = options.doc ?? document;\n const win = doc.defaultView ?? window;\n const mask = options.maskSelector ?? \"\";\n const shotsAllowed = options.screenshots !== false;\n const scope = createScope(null, { theme: \"light\", animation: \"fade\" }, doc);\n const style = doc.createElement(\"style\");\n style.textContent = CAPTURE_STYLES;\n scope.el.appendChild(style);\n\n const bar = doc.createElement(\"div\");\n bar.className = \"g-cap\";\n bar.setAttribute(\"data-guidely-capture-bar\", \"\");\n bar.setAttribute(\"role\", \"toolbar\");\n bar.setAttribute(\"aria-label\", \"Guidely how-to recorder\");\n const note = doc.createElement(\"div\");\n note.className = \"g-cap-note\";\n note.setAttribute(\"data-guidely-capture-notice\", \"\");\n note.hidden = true;\n const row = doc.createElement(\"div\");\n row.className = \"g-cap-row\";\n const dot = doc.createElement(\"span\");\n dot.className = \"g-cap-dot\";\n const status = doc.createElement(\"span\");\n status.className = \"g-cap-status\";\n status.setAttribute(\"aria-live\", \"polite\");\n const count_ = doc.createElement(\"span\");\n count_.className = \"g-cap-count\";\n count_.setAttribute(\"aria-hidden\", \"true\");\n const start = button(doc, \"Start recording\", \"g-btn-primary\", \"data-guidely-capture-start\");\n const noShots = button(doc, \"Record without screenshots\", \"g-btn-secondary\", \"data-guidely-capture-no-screenshots\");\n const resumeShots = button(doc, \"Screenshots paused — Resume\", \"g-cap-warn\", \"data-guidely-capture-resume-screenshots\");\n const pause = button(doc, \"Pause\", \"g-btn-secondary\", \"data-guidely-capture-pause\");\n const done = button(doc, \"Done\", \"g-btn-primary\", \"data-guidely-capture-done\");\n const cancel = button(doc, \"Cancel\", \"g-btn-ghost\", \"data-guidely-capture-cancel\");\n row.append(dot, count_, status, start, noShots, resumeShots, pause, done, cancel);\n bar.append(note, row);\n scope.el.appendChild(bar);\n\n let phase: Phase = \"ready\";\n let count = options.stepCount ?? 0;\n let screen: ScreenSource | null = null;\n /** The user chose screenshots (so a lost stream shows \"Resume\"). */\n let wantShots = false;\n let requesting = false;\n let stopped = false;\n let lastAction = 0;\n /** `performance.now()` of the last scroll or resize: frames older than that do not match the DOM. */\n let movedAt = -1;\n let lastPress: { el: Element; at: number } | null = null;\n let lastUrl = win.location.href;\n let navTimer: ReturnType<typeof setTimeout> | null = null;\n let pulseTimer: ReturnType<typeof setTimeout> | null = null;\n /** `performance.now()` of the last keystroke in a field: a `type` step needs a frame that shows it. */\n let typedAt = -1;\n /**\n * While recording, the bar is a small pill (dot and step count) unless the pointer or focus is on\n * it, so screenshots show as little of it as possible.\n */\n let expanded = false; /** Field value at focus (or when last recorded), so each edit is recorded once. */\n const baseline = new WeakMap<Element, string>();\n\n const recording = () => phase === \"recording\" && !stopped;\n const steps = (n: number) => `${n} step${n === 1 ? \"\" : \"s\"}`;\n\n const render = () => {\n bar.setAttribute(\"data-state\", phase);\n bar.toggleAttribute(\"data-compact\", phase === \"recording\" && !expanded);\n const ready = phase === \"ready\";\n const active = phase === \"recording\" || phase === \"paused\";\n start.hidden = !ready;\n start.disabled = requesting;\n noShots.hidden = !ready || !shotsAllowed || !canCaptureScreen();\n noShots.disabled = requesting;\n resumeShots.hidden = !active || !wantShots || !!screen?.live();\n resumeShots.disabled = requesting;\n pause.hidden = !active;\n pause.textContent = phase === \"paused\" ? \"Resume\" : \"Pause\";\n done.hidden = !active;\n cancel.hidden = phase === \"saving\";\n if (ready) status.textContent = requesting ? \"Choose this tab to share…\" : `Ready to record “${options.title}”`;\n else if (phase === \"saving\") status.textContent = \"Saving steps…\";\n else status.textContent = `${phase === \"paused\" ? \"Paused\" : \"Recording\"} · ${steps(count)}`;\n count_.textContent = String(count);\n };\n\n const showNotice = (text: string | null) => {\n note.textContent = text ?? \"\";\n note.hidden = !text;\n };\n\n /** Briefly turns the dot green: a step was captured. */\n const pulse = () => {\n bar.setAttribute(\"data-captured\", \"\");\n if (pulseTimer) clearTimeout(pulseTimer);\n pulseTimer = setTimeout(() => bar.removeAttribute(\"data-captured\"), 700);\n };\n\n /** Grabs the frame, blurs sensitive regions and sets the highlight; all from the same moment's layout. */\n const shoot = (step: CaptureStepDraft, highlightEl: Element | null): HTMLCanvasElement | null => {\n const frame = screen?.live() ? screen.grab() : null;\n if (!frame) return null;\n const viewport = { width: win.innerWidth, height: win.innerHeight };\n try {\n step.redactions = redactCanvas(frame, collectRedactions(doc, { maskSelector: mask }), viewport);\n } catch {\n // Never upload a frame that could not be redacted.\n return null;\n }\n const highlight = highlightEl?.isConnected ? normalizeRect(highlightEl.getBoundingClientRect(), viewport) : null;\n if (highlight) step.highlight = highlight;\n else delete step.highlight;\n return frame;\n };\n\n /** Captures one step. The frame is grabbed synchronously, before the app reacts to the event. */\n const record = (action: HowToAction, el: Element | null, extra: { value?: string; valueRedacted?: boolean; highlightEl?: Element | null } = {}) => {\n const step: CaptureStepDraft = { action, url: win.location.href, pageTitle: (doc.title || \"\").slice(0, 300), redactions: 0, occurredAt: new Date().toISOString() };\n let highlightEl: Element | null = null;\n if (el) {\n const masked = isMaskedElement(el, mask);\n step.element = describeCapturedElement(el, mask);\n step.selectors = describeElement(el).selectors.filter((s) => !masked || s.kind !== \"text\");\n const box = extra.highlightEl?.getBoundingClientRect();\n highlightEl = extra.highlightEl && box && (box.width || box.height) ? extra.highlightEl : el;\n }\n let frame: CapturedStep[\"frame\"] = null;\n if (screen?.live()) {\n const s = screen;\n // A frame older than the last scroll shows content where it no longer is (redactions would miss it), and one\n // older than the last keystroke may not show the typed text yet: use the next one. A click keeps the current\n // frame, which shows the page before the app reacted.\n const changedAt = action === \"type\" || action === \"select\" ? Math.max(movedAt, typedAt) : movedAt;\n if (s.freshSince(changedAt)) frame = shoot(step, highlightEl);\n else frame = s.nextFrame().then(() => shoot(step, highlightEl));\n }\n if (extra.value !== undefined) step.value = extra.value;\n if (extra.valueRedacted) step.valueRedacted = true;\n if (action !== \"navigate\") lastAction = Date.now();\n count++;\n render();\n pulse();\n options.onStep({ step, frame });\n };\n\n /** Records a `type` step when the field's value changed since focus (or since it was last recorded). */\n const flushField = (el: Element) => {\n if (!recording() || !isTextEntry(el)) return;\n const host = el.tagName === \"INPUT\" || el.tagName === \"TEXTAREA\" ? el : actionTarget(el);\n const value = fieldValue(host);\n if (value === (baseline.get(host) ?? \"\")) return;\n baseline.set(host, value);\n if (!value) return;\n if (isSensitiveField(host, mask) || looksLikeSecretValue(value)) record(\"type\", host, { valueRedacted: true });\n else record(\"type\", host, { value });\n };\n\n const onPointerDown = (e: PointerEvent) => {\n if (!recording() || e.button !== 0) return;\n const target = composedTarget(e);\n if (!target || isGuidelyElement(target)) return;\n // Typing into the focused field happened before this click: record it first.\n const active = deepActiveElement(doc);\n if (active && active !== target && !active.contains(target) && isTextEntry(active)) flushField(active);\n let el = actionTarget(target);\n let highlightEl: Element | null = null;\n const control = labelControl(el);\n if (control) {\n if (isTextEntry(control) || control.tagName === \"SELECT\") return; // the label only focuses the field\n highlightEl = el;\n el = control;\n }\n if (isTextEntry(el) || el.tagName === \"SELECT\" || el.closest(\"select\")) return; // `change` records these\n if ((el as HTMLButtonElement).disabled) return;\n const now = Date.now();\n if (lastPress && lastPress.el === el && now - lastPress.at < DOUBLE_CLICK_MS) {\n lastPress.at = now;\n return;\n }\n lastPress = { el, at: now };\n record(\"click\", el, { highlightEl });\n };\n\n const onChange = (e: Event) => {\n if (!recording()) return;\n const el = composedTarget(e);\n if (!el || isGuidelyElement(el)) return;\n if (el.tagName === \"SELECT\") {\n const sensitive = isSensitiveField(el, mask);\n const value = sensitive ? \"\" : selectedOptionText(el as HTMLSelectElement);\n record(\"select\", el, sensitive ? { valueRedacted: true } : value ? { value } : {});\n return;\n }\n const type = el.tagName === \"INPUT\" ? (el.getAttribute(\"type\") || \"\").toLowerCase() : \"\";\n if (type === \"checkbox\" || type === \"radio\") {\n // Toggled with the keyboard (no pointer press on it or its label just now).\n const pressed = lastPress && Date.now() - lastPress.at < 1000 && lastPress.el === el;\n if (!pressed) record(\"click\", el);\n return;\n }\n if (isTextEntry(el)) flushField(el);\n };\n\n const onFocusIn = (e: FocusEvent) => {\n const el = composedTarget(e);\n if (el && !isGuidelyElement(el) && isTextEntry(el)) {\n const host = el.tagName === \"INPUT\" || el.tagName === \"TEXTAREA\" ? el : actionTarget(el);\n baseline.set(host, fieldValue(host));\n }\n };\n\n const onFocusOut = (e: FocusEvent) => {\n const el = composedTarget(e);\n // Inputs report edits through `change`; contenteditable regions only through blur.\n if (el && el.tagName !== \"INPUT\" && el.tagName !== \"TEXTAREA\" && isTextEntry(el)) flushField(el);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== \"Enter\" || e.isComposing) return;\n const el = composedTarget(e);\n if (el && (el.tagName === \"INPUT\" || ((e.metaKey || e.ctrlKey) && isTextEntry(el)))) flushField(el);\n };\n\n const checkUrl = () => {\n const url = win.location.href;\n if (url === lastUrl) return;\n lastUrl = url;\n if (!recording() || Date.now() - lastAction < NAV_AFTER_ACTION_MS) return;\n if (navTimer) clearTimeout(navTimer);\n navTimer = setTimeout(() => {\n navTimer = null;\n if (recording()) record(\"navigate\", null);\n }, NAV_SETTLE_MS);\n };\n const poll = setInterval(checkUrl, 300);\n\n const onMove = () => {\n movedAt = performance.now();\n };\n const onInput = (e: Event) => {\n const el = composedTarget(e);\n if (el && !isGuidelyElement(el)) typedAt = performance.now();\n };\n const expand = (open: boolean) => {\n if (expanded === open) return;\n expanded = open;\n render();\n };\n const onBarEnter = () => expand(true);\n const onBarLeave = () => expand(bar.contains(deepActiveElementIn(bar)));\n const onBarFocusOut = (e: FocusEvent) => expand(!!e.relatedTarget && bar.contains(e.relatedTarget as Node));\n bar.addEventListener(\"pointerenter\", onBarEnter);\n bar.addEventListener(\"pointerleave\", onBarLeave);\n bar.addEventListener(\"focusin\", onBarEnter);\n bar.addEventListener(\"focusout\", onBarFocusOut);\n\n const listen = { capture: true, passive: true } as const;\n doc.addEventListener(\"scroll\", onMove, listen);\n win.addEventListener(\"resize\", onMove);\n doc.addEventListener(\"pointerdown\", onPointerDown, listen);\n doc.addEventListener(\"change\", onChange, listen);\n doc.addEventListener(\"input\", onInput, listen);\n doc.addEventListener(\"focusin\", onFocusIn, listen);\n doc.addEventListener(\"focusout\", onFocusOut, listen);\n doc.addEventListener(\"keydown\", onKeyDown, listen);\n win.addEventListener(\"popstate\", checkUrl);\n win.addEventListener(\"hashchange\", checkUrl);\n\n const onLost = () => {\n screen = null;\n if (!stopped && wantShots) showNotice(NOTICES.lost);\n render();\n };\n\n /** Asks for the tab stream (needs the click that called it). */\n const requestScreen = async (): Promise<boolean> => {\n requesting = true;\n showNotice(null);\n render();\n const res = await requestTabCapture(scope.el, doc);\n requesting = false;\n if (stopped) {\n if (res.ok) res.screen.stop();\n return false;\n }\n if (res.ok) {\n screen = res.screen;\n screen.onEnded(onLost);\n } else showNotice(NOTICES[res.reason]);\n render();\n return res.ok;\n };\n\n const begin = (shots: boolean) => {\n wantShots = shots;\n phase = \"recording\";\n // Collapse to the pill even though the pointer is still on the Start button, and take the first\n // screenshot from a frame drawn after that.\n expanded = false;\n movedAt = performance.now();\n primeActive();\n lastUrl = win.location.href;\n render();\n options.onStart?.({ screenshots: shots });\n record(\"navigate\", null);\n };\n\n start.addEventListener(\"click\", () => {\n if (requesting) return;\n if (!shotsAllowed || !canCaptureScreen()) {\n if (shotsAllowed) showNotice(NOTICES.unsupported);\n return begin(false);\n }\n void requestScreen().then((ok) => {\n if (ok) begin(true);\n });\n });\n noShots.addEventListener(\"click\", () => {\n showNotice(null);\n begin(false);\n });\n resumeShots.addEventListener(\"click\", () => {\n if (!requesting) void requestScreen();\n });\n pause.addEventListener(\"click\", () => {\n if (phase === \"recording\") {\n flushActive();\n phase = \"paused\";\n } else if (phase === \"paused\") {\n phase = \"recording\";\n lastUrl = win.location.href;\n }\n render();\n });\n /** Typing still in the focused field (Safari does not move focus to a clicked button). */\n const flushActive = () => {\n const active = deepActiveElement(doc);\n if (active && !isGuidelyElement(active) && isTextEntry(active)) flushField(active);\n };\n const primeActive = () => {\n const active = deepActiveElement(doc);\n if (active && !isGuidelyElement(active) && isTextEntry(active)) baseline.set(active, fieldValue(active));\n };\n\n done.addEventListener(\"click\", () => {\n if (phase === \"saving\") return;\n flushActive();\n options.onFinish();\n });\n cancel.addEventListener(\"click\", () => {\n stop();\n options.onCancel();\n });\n\n const stop = () => {\n if (stopped) return;\n stopped = true;\n clearInterval(poll);\n if (navTimer) clearTimeout(navTimer);\n if (pulseTimer) clearTimeout(pulseTimer);\n doc.removeEventListener(\"scroll\", onMove, listen);\n win.removeEventListener(\"resize\", onMove);\n doc.removeEventListener(\"pointerdown\", onPointerDown, listen);\n doc.removeEventListener(\"change\", onChange, listen);\n doc.removeEventListener(\"input\", onInput, listen);\n doc.removeEventListener(\"focusin\", onFocusIn, listen);\n doc.removeEventListener(\"focusout\", onFocusOut, listen);\n doc.removeEventListener(\"keydown\", onKeyDown, listen);\n win.removeEventListener(\"popstate\", checkUrl);\n win.removeEventListener(\"hashchange\", checkUrl);\n screen?.stop();\n screen = null;\n scope.destroy();\n };\n\n if (options.resume) {\n wantShots = shotsAllowed && options.resume.screenshots && canCaptureScreen();\n phase = \"recording\";\n if (wantShots) showNotice(NOTICES.lost);\n primeActive();\n render();\n if (options.resume.navigate) record(\"navigate\", null);\n } else render();\n\n return {\n setSaving: (saving) => {\n if (stopped) return;\n phase = saving ? \"saving\" : \"recording\";\n render();\n },\n isRecording: recording,\n stop,\n };\n}\n","/** How-to capture toolbar styles, injected into the Guidely shadow root when capture starts. */\nexport const CAPTURE_STYLES = `\n.g-cap{position:fixed;left:50%;bottom:16px;transform:translateX(-50%);z-index:calc(var(--g-z) + 10);pointer-events:auto;display:flex;flex-direction:column;align-items:center;gap:6px;max-width:calc(100vw - 32px);font:500 13px/1.4 var(--g-font);color:#fff}\n.g-cap-row{display:flex;align-items:center;flex-wrap:wrap;gap:8px;padding:6px 6px 6px 14px;background:#111827;border-radius:999px;box-shadow:0 6px 24px rgba(0,0,0,.28)}\n.g-cap-dot{position:relative;flex:none;width:10px;height:10px;border-radius:999px;background:#9ca3af}\n.g-cap[data-state=\"recording\"] .g-cap-dot{background:#ef4444}\n.g-cap[data-state=\"recording\"] .g-cap-dot::after{content:\"\";position:absolute;inset:0;border-radius:inherit;background:#ef4444;animation:g-pulse 1.4s ease-out infinite}\n.g-cap-status{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:min(340px,60vw)}\n.g-cap .g-btn{min-height:28px;padding:3px 12px;font-size:13px;border-radius:999px}\n.g-cap .g-btn-secondary{background:rgba(255,255,255,.14);color:#fff;border-color:transparent}\n.g-cap .g-btn-secondary:hover{background:rgba(255,255,255,.22)}\n.g-cap .g-btn-ghost{color:#d1d5db}\n.g-cap .g-btn-ghost:hover{background:rgba(255,255,255,.1);color:#fff}\n.g-cap .g-cap-warn{background:#f59e0b;color:#111827}\n.g-cap-note{max-width:min(420px,calc(100vw - 32px));padding:6px 12px;border-radius:10px;background:#7c2d12;box-shadow:0 6px 24px rgba(0,0,0,.28)}\n.g-cap-count{display:none;font-variant-numeric:tabular-nums}\n.g-cap[data-compact] .g-cap-row{gap:6px;padding:5px 10px;opacity:.85}\n.g-cap[data-compact] .g-cap-row>:not(.g-cap-dot):not(.g-cap-count):not(.g-cap-warn){display:none}\n.g-cap[data-compact] .g-cap-count{display:inline}\n.g-cap[data-captured] .g-cap-dot,.g-cap[data-captured] .g-cap-dot::after{background:#22c55e}\n`;\n","import { matchUrlPattern } from \"@guidelytech/shared/runtime\";\nimport type { SelectorStrategy, StepTarget } from \"@guidelytech/shared\";\n\n/**\n * URL matching used for `step.url`, `urlPatterns` and `trigger.urlPattern`: a pattern matches the\n * full URL, the path+query+hash, or the bare path (so `/deals` also matches `/deals?x=1`).\n */\nexport function urlMatches(pattern: string | undefined | null, url: string): boolean {\n if (!pattern) return true;\n if (matchUrlPattern(pattern, url)) return true;\n try {\n const u = new URL(url, \"http://localhost\");\n if (!pattern.includes(\"?\") && !pattern.includes(\"#\")) return matchUrlPattern(pattern, u.pathname) || matchUrlPattern(pattern, u.origin + u.pathname);\n } catch {\n /* ignore */\n }\n return false;\n}\n\nexport type QueryRoot = Document | DocumentFragment | Element;\n\nconst TEXT_CANDIDATES =\n \"button, a, [role='button'], [role='link'], [role='tab'], [role='menuitem'], h1, h2, h3, h4, h5, h6, label, summary\";\n\nconst HOST_ID = \"guidely-root\";\n\nfunction docOf(root: QueryRoot): Document {\n return root.nodeType === 9 ? (root as Document) : (root.ownerDocument as Document);\n}\n\n/** True when the environment has a layout engine (real browsers). happy-dom/jsdom report zero sizes. */\nfunction hasLayout(doc: Document): boolean {\n const de = doc.documentElement;\n if (!de) return false;\n const r = de.getBoundingClientRect();\n return r.width > 0 || r.height > 0;\n}\n\n/** Normalises whitespace in a text snippet. */\nexport function normalizeText(text: string | null | undefined): string {\n return (text || \"\").replace(/\\s+/g, \" \").trim();\n}\n\n/** Is the element rendered (not hidden by `hidden`, `display:none`, `visibility:hidden`, or zero size)? */\nexport function isVisible(el: Element): boolean {\n if (!el.isConnected) return false;\n const doc = el.ownerDocument;\n const win = doc.defaultView;\n let cur: Element | null = el;\n while (cur && cur !== doc.documentElement) {\n if ((cur as HTMLElement).hidden) return false;\n if (win) {\n const cs = win.getComputedStyle(cur);\n if (cs.display === \"none\" || cs.visibility === \"hidden\") return false;\n }\n cur = cur.parentElement ?? ((cur.getRootNode() as ShadowRoot).host as Element | undefined) ?? null;\n }\n if (hasLayout(doc)) {\n const r = el.getBoundingClientRect();\n if (r.width === 0 && r.height === 0) return false;\n }\n return true;\n}\n\n/** Elements that belong to Guidely's own UI are never valid targets. */\nexport function isGuidelyElement(el: Element | null): boolean {\n if (!el) return false;\n const root = el.getRootNode();\n if (root instanceof ShadowRoot && root.host.id === HOST_ID) return true;\n return el.id === HOST_ID || !!el.closest?.(`#${HOST_ID}`);\n}\n\nfunction safeQueryAll(root: QueryRoot, selector: string): Element[] {\n try {\n return Array.from(root.querySelectorAll(selector));\n } catch {\n return [];\n }\n}\n\n// ---------------------------------------------------------------------------\n// Shadow DOM. Web-component apps (Salesforce Lightning Web Components, Shoelace, Ionic, Lit) keep\n// most of their elements inside shadow roots, which `querySelectorAll` never enters. Selectors\n// therefore search open shadow roots too, and a CSS value can step into one explicitly:\n// `c-app >>> button.save` is `button.save` anywhere inside `c-app`'s shadow tree. Closed shadow\n// roots are unreachable by design.\n// ---------------------------------------------------------------------------\n\n/** Separates the shadow-host steps of a CSS selector (`>>>` is not valid CSS, so it never clashes). */\nexport const SHADOW_SEPARATOR = \" >>> \";\nconst SHADOW_SPLIT = /\\s*>>>\\s*/;\n\nfunction isShadowRoot(node: Node | null | undefined): node is ShadowRoot {\n return !!node && node.nodeType === 11 && !!(node as ShadowRoot).host;\n}\n\n/** The shadow root an element lives in, or null when it is in the document itself. */\nfunction shadowRootOf(el: Element): ShadowRoot | null {\n const root = el.getRootNode?.();\n return isShadowRoot(root) ? root : null;\n}\n\n/** The element's parent in the composed tree: its parent element, or its shadow host at the top of a shadow root. */\nexport function composedParent(el: Element): Element | null {\n return el.parentElement ?? shadowRootOf(el)?.host ?? null;\n}\n\n/** Does `ancestor` contain `node`, looking through shadow boundaries? */\nexport function containsComposed(ancestor: Element, node: Node | null): boolean {\n let cur: Element | null = node ? (node.nodeType === 1 ? (node as Element) : node.parentElement) : null;\n for (; cur; cur = composedParent(cur)) if (cur === ancestor) return true;\n return false;\n}\n\n/** The element an event really started on: inside a shadow root `e.target` is retargeted to the host. */\nexport function composedTarget(e: Event): Element | null {\n const path = typeof e.composedPath === \"function\" ? e.composedPath() : [];\n const first = (path[0] ?? e.target) as Node | null;\n if (!first) return null;\n return first.nodeType === 1 ? (first as Element) : first.parentElement;\n}\n\n/** Set while `resolveTarget` runs, so its strategies share one walk of the page per root. */\nlet shadowRootCache: Map<QueryRoot, ShadowRoot[]> | null = null;\n\n/** Every open shadow root below `root`, nested ones included, except Guidely's own UI. */\nfunction shadowRootsIn(root: QueryRoot): ShadowRoot[] {\n const cached = shadowRootCache?.get(root);\n if (cached) return cached;\n const out: ShadowRoot[] = [];\n const visit = (scope: QueryRoot) => {\n const own = scope.nodeType === 1 ? (scope as Element).shadowRoot : null;\n const hosts = own ? [scope as Element] : [];\n for (const el of safeQueryAll(scope, \"*\")) if (el.shadowRoot) hosts.push(el);\n for (const host of hosts) {\n if (host.id === HOST_ID || !host.shadowRoot || out.includes(host.shadowRoot)) continue;\n out.push(host.shadowRoot);\n visit(host.shadowRoot);\n }\n };\n visit(root);\n shadowRootCache?.set(root, out);\n return out;\n}\n\n/** `querySelectorAll` that also searches every open shadow root below `root`. */\nfunction queryAllDeep(root: QueryRoot, selector: string): Element[] {\n const out = safeQueryAll(root, selector);\n for (const sr of shadowRootsIn(root)) out.push(...safeQueryAll(sr, selector));\n return out;\n}\n\n/**\n * Resolves a CSS selector. With `deep`, open shadow roots are searched too. A `>>>` chain is always\n * deep: each step is looked for anywhere inside the shadow trees of the previous step's matches.\n */\nfunction queryCss(root: QueryRoot, selector: string, deep: boolean): Element[] {\n if (!selector.includes(\">>>\")) return deep ? queryAllDeep(root, selector) : safeQueryAll(root, selector);\n const steps = selector.split(SHADOW_SPLIT).filter(Boolean);\n let scopes: QueryRoot[] = [root];\n let matches: Element[] = [];\n steps.forEach((step, i) => {\n matches = Array.from(new Set(scopes.flatMap((scope) => queryAllDeep(scope, step))));\n if (i < steps.length - 1) scopes = matches.map((el) => el.shadowRoot).filter((sr): sr is ShadowRoot => !!sr);\n });\n return matches;\n}\n\n/**\n * `Element.closest` across shadow boundaries: the nearest element, from `el` up through its shadow\n * hosts, that matches `selector` (which may be a `>>>` chain). Throws on an invalid plain selector,\n * like `closest` does.\n */\nexport function closestComposed(el: Element, selector: string): Element | null {\n if (selector.includes(\">>>\")) {\n const hits = new Set(queryCss(docOf(el), selector, true));\n for (let cur: Element | null = el; cur; cur = composedParent(cur)) if (hits.has(cur)) return cur;\n return null;\n }\n for (let cur: Element | null = el; cur; cur = composedParent(cur)) if (cur.matches(selector)) return cur;\n return null;\n}\n\n/** The innermost element at a point, looking inside open shadow roots (`elementFromPoint` stops at the host). */\nexport function deepElementFromPoint(doc: Document, x: number, y: number): Element | null {\n let el = doc.elementFromPoint(x, y);\n while (el?.shadowRoot && el.id !== HOST_ID && typeof el.shadowRoot.elementFromPoint === \"function\") {\n const inner = el.shadowRoot.elementFromPoint(x, y);\n if (!inner || inner === el) break;\n el = inner;\n }\n return el;\n}\n\nfunction escapeCss(value: string): string {\n const g = globalThis as { CSS?: { escape?: (v: string) => string } };\n if (g.CSS && typeof g.CSS.escape === \"function\") return g.CSS.escape(value);\n return value.replace(/[\"\\\\]/g, \"\\\\$&\");\n}\n\nfunction queryXPath(root: QueryRoot, expr: string): Element[] {\n const doc = docOf(root);\n const d = doc as Document & { evaluate?: Document[\"evaluate\"] };\n if (typeof d.evaluate !== \"function\") return [];\n try {\n const result = d.evaluate(expr, root, null, 7 /* ORDERED_NODE_SNAPSHOT_TYPE */, null);\n const out: Element[] = [];\n for (let i = 0; i < result.snapshotLength; i++) {\n const n = result.snapshotItem(i);\n if (n && n.nodeType === 1) out.push(n as Element);\n }\n return out;\n } catch {\n return [];\n }\n}\n\nfunction queryText(root: QueryRoot, text: string, deep: boolean): Element[] {\n const needle = normalizeText(text).toLowerCase();\n if (!needle) return [];\n const candidates = queryCss(root, TEXT_CANDIDATES, deep);\n const exact = candidates.filter((c) => normalizeText(c.textContent).toLowerCase() === needle);\n if (exact.length) return exact;\n return candidates.filter((c) => normalizeText(c.textContent).toLowerCase().includes(needle));\n}\n\n/**\n * Resolves every element matching one strategy (visible or not). `deep` (the default) also searches\n * open shadow roots; `>>>` chains are always followed. XPath cannot cross shadow boundaries.\n */\nexport function querySelectorStrategy(strategy: SelectorStrategy, root: QueryRoot, deep = true): Element[] {\n const value = strategy.value.trim();\n if (!value) return [];\n switch (strategy.kind) {\n case \"id\": {\n const id = value.startsWith(\"#\") ? value.slice(1) : value;\n return queryCss(root, `#${escapeCss(id)}`, deep);\n }\n case \"guidely-id\": {\n const id = value.startsWith(\"#\") ? value.slice(1) : value;\n return queryCss(root, attrSelector(\"data-guidely-id\", id), deep);\n }\n case \"data-attr\":\n case \"aria\":\n case \"css\":\n return queryCss(root, value.startsWith(\"[\") || /^[a-z*#.[]/i.test(value) ? value : `[${value}]`, deep);\n case \"text\":\n return queryText(root, value, deep);\n case \"xpath\":\n return queryXPath(root, value);\n default:\n return [];\n }\n}\n\n/**\n * Resolves a step target by trying each strategy in order. A strategy wins only when it\n * resolves to exactly one *visible* element; otherwise the next strategy is tried. Each strategy\n * looks in the document first and only searches shadow roots when nothing there is visible, so a\n * target that resolved before shadow-DOM support still resolves to the same element.\n */\nexport function resolveTarget(target: Pick<StepTarget, \"selectors\"> | SelectorStrategy[], root: QueryRoot = document): Element | null {\n const selectors = Array.isArray(target) ? target : target.selectors;\n const visibleMatches = (strategy: SelectorStrategy, deep: boolean) => querySelectorStrategy(strategy, root, deep).filter((el) => !isGuidelyElement(el) && isVisible(el));\n const outer = shadowRootCache;\n shadowRootCache ??= new Map();\n try {\n for (const strategy of selectors) {\n let matches = visibleMatches(strategy, false);\n if (!matches.length && strategy.kind !== \"xpath\") matches = visibleMatches(strategy, true);\n if (matches.length === 1) return matches[0] as Element;\n }\n return null;\n } finally {\n shadowRootCache = outer;\n }\n}\n\nexport interface WaitForTargetOptions {\n /** Give up after this many milliseconds (default 5000). */\n timeoutMs?: number;\n /** Abort early. */\n signal?: AbortSignal;\n root?: QueryRoot;\n /** Polling fallback interval (default 250ms, which is also the maximum). */\n pollMs?: number;\n}\n\nexport class TargetTimeoutError extends Error {\n override name = \"TargetTimeoutError\";\n constructor(message = \"Target element not found before timeout\") {\n super(message);\n }\n}\n\n/**\n * Waits until `resolveTarget` finds an element. Uses a MutationObserver plus a polling fallback\n * (at most every 250ms) so visibility changes without DOM mutations, and changes inside shadow\n * roots (which the observer does not see), are also detected.\n */\nexport function waitForTarget(target: Pick<StepTarget, \"selectors\"> | SelectorStrategy[], options: WaitForTargetOptions = {}): Promise<Element> {\n const timeoutMs = options.timeoutMs ?? 5000;\n const root = options.root ?? document;\n const pollMs = Math.min(250, Math.max(16, options.pollMs ?? 250));\n return new Promise<Element>((resolve, reject) => {\n const immediate = resolveTarget(target, root);\n if (immediate) return resolve(immediate);\n if (options.signal?.aborted) return reject(new DOMException(\"Aborted\", \"AbortError\"));\n let done = false;\n let observer: MutationObserver | null = null;\n let timer: ReturnType<typeof setInterval> | null = null;\n let timeout: ReturnType<typeof setTimeout> | null = null;\n const cleanup = () => {\n done = true;\n observer?.disconnect();\n if (timer) clearInterval(timer);\n if (timeout) clearTimeout(timeout);\n options.signal?.removeEventListener(\"abort\", onAbort);\n };\n const check = () => {\n if (done) return;\n const el = resolveTarget(target, root);\n if (el) {\n cleanup();\n resolve(el);\n }\n };\n const onAbort = () => {\n cleanup();\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n };\n options.signal?.addEventListener(\"abort\", onAbort);\n const observeRoot = root.nodeType === 9 ? (root as Document).documentElement : (root as Element);\n if (typeof MutationObserver !== \"undefined\" && observeRoot) {\n observer = new MutationObserver(check);\n observer.observe(observeRoot, { childList: true, subtree: true, attributes: true, attributeFilter: [\"class\", \"style\", \"hidden\", \"id\", \"data-tour\", \"data-guidely-id\", \"aria-label\"] });\n }\n timer = setInterval(check, pollMs);\n if (timeoutMs > 0) {\n timeout = setTimeout(() => {\n cleanup();\n reject(new TargetTimeoutError());\n }, timeoutMs);\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Selector generation (used by the element picker)\n// ---------------------------------------------------------------------------\n\nconst GENERATED_ID = /(\\d{4,}|:r[0-9a-z]+:|^radix-|^headlessui-|^mui-|^ember\\d|^react-|^\\w*-\\d+$|__|^[a-f0-9]{8,}$|^svelte-)/i;\nconst GENERATED_CLASS = /(^css-|^sc-|^jss\\d|^svelte-|^emotion-|^chakra-|^Mui|^_|[0-9a-f]{6,}|^\\w{1,2}$|^[a-z]+-\\d+$|[:[\\]/])/;\nconst PREFERRED_DATA_ATTRS = [\"data-testid\", \"data-tour\", \"data-test\", \"data-test-id\", \"data-cy\", \"data-qa\", \"data-id\", \"data-name\", \"data-guidely\"];\nconst IGNORED_DATA_ATTRS = /^data-(guidely-id|state|v-|reactid|react|radix|headlessui|svelte|hydrated|orientation|highlighted|focus|key|index|rbd|dnd|rk-|sveltekit)/i;\n\n/** Is this id stable enough to be used as a selector (not generated by a framework)? */\nexport function isStableId(id: string): boolean {\n return !!id && /^[A-Za-z][\\w-]*$/.test(id) && !GENERATED_ID.test(id);\n}\n\nfunction isStableClass(cls: string): boolean {\n return !!cls && !GENERATED_CLASS.test(cls) && cls.length <= 40;\n}\n\n/** Does `selector` match exactly `el` and nothing else directly inside `root` (shadow roots below are not searched)? */\nfunction uniqueWithin(root: QueryRoot, selector: string, el: Element): boolean {\n const all = safeQueryAll(root, selector);\n return all.length === 1 && all[0] === el;\n}\n\nfunction attrSelector(name: string, value: string): string {\n return `[${name}='${value.replace(/\\\\/g, \"\\\\\\\\\").replace(/'/g, \"\\\\'\")}']`;\n}\n\n/** Shortest unique `>`-path to `el` within its own root (the document, or the shadow root it lives in). */\nfunction cssPath(el: Element, root: Document | ShadowRoot): string | null {\n const doc = el.ownerDocument;\n const segments: string[] = [];\n let cur: Element | null = el;\n while (cur && cur.nodeType === 1 && cur !== doc.body && cur !== doc.documentElement) {\n const tag = cur.tagName.toLowerCase();\n if (isStableId(cur.id)) {\n segments.unshift(`#${cur.id}`);\n break;\n }\n let seg = tag;\n const parent: Element | null = cur.parentElement;\n if (parent) {\n const sameTag = Array.from(parent.children).filter((c) => c.tagName === cur!.tagName);\n if (sameTag.length > 1) {\n const stableCls = Array.from(cur.classList).find((c) => isStableClass(c) && sameTag.filter((s) => s.classList.contains(c)).length === 1);\n seg += stableCls ? `.${escapeCss(stableCls)}` : `:nth-of-type(${sameTag.indexOf(cur) + 1})`;\n }\n }\n segments.unshift(seg);\n const candidate = segments.join(\" > \");\n if (uniqueWithin(root, candidate, el)) return candidate;\n cur = parent;\n }\n const full = segments.join(\" > \");\n return uniqueWithin(root, full, el) ? full : null;\n}\n\n/**\n * The `>>>` chain of shadow hosts above an element (`c-app >>> c-form`), or \"\" for an element in\n * the document itself; null when some host has no unique path within its own root.\n */\nexport function shadowHostChain(el: Element): string | null {\n const steps: string[] = [];\n for (let root = shadowRootOf(el); root; root = shadowRootOf(root.host)) {\n const host = root.host;\n const step = cssPath(host, shadowRootOf(host) ?? host.ownerDocument);\n if (!step) return null;\n steps.unshift(step);\n }\n return steps.join(SHADOW_SEPARATOR);\n}\n\n/**\n * Turns a selector that is unique within `el`'s own root into one the resolver maps back to `el`.\n * In the document that is the selector itself (as before shadow-DOM support). Inside a shadow root\n * the bare selector is kept when no other match exists in any shadow tree; otherwise it is scoped\n * with the host chain. Returns null when neither form resolves to exactly `el`.\n */\nfunction selectorFor(el: Element, selector: string): string | null {\n const root = shadowRootOf(el);\n if (!root) return uniqueWithin(el.ownerDocument, selector, el) ? selector : null;\n if (!uniqueWithin(root, selector, el)) return null;\n const doc = el.ownerDocument;\n const only = (sel: string) => {\n const all = queryCss(doc, sel, true);\n return all.length === 1 && all[0] === el;\n };\n if (only(selector)) return selector;\n const chain = shadowHostChain(el);\n const scoped = chain ? chain + SHADOW_SEPARATOR + selector : null;\n return scoped && only(scoped) ? scoped : null;\n}\n\n/** Text a component renders in its shadow root (`innerText` of a host only covers its light DOM). */\nfunction shadowText(el: Element): string {\n if (!el.shadowRoot) return \"\";\n const parts = Array.from(el.shadowRoot.children).filter((c) => !/^(STYLE|SCRIPT|TEMPLATE)$/.test(c.tagName));\n return normalizeText(parts.map((c) => (c as HTMLElement).innerText ?? c.textContent).join(\" \"));\n}\n\n/** Short human-readable text for an element, trimmed to 200 characters. */\nexport function textSnapshotOf(el: Element): string {\n const he = el as HTMLElement;\n const own = normalizeText(he.innerText ?? el.textContent) || shadowText(el);\n const alt = normalizeText(el.getAttribute(\"aria-label\") || el.getAttribute(\"title\") || el.getAttribute(\"placeholder\") || el.getAttribute(\"alt\") || (el as HTMLInputElement).value);\n return (own || alt).slice(0, 200);\n}\n\n/**\n * Generates an ordered list of selector strategies for an element, most robust first:\n * stable id → data-* attributes → aria-label → role/name → short unique CSS path → visible text.\n */\nexport function generateSelectors(el: Element): SelectorStrategy[] {\n const out: SelectorStrategy[] = [];\n const seen = new Set<string>();\n const push = (s: SelectorStrategy) => {\n const k = `${s.kind}:${s.value}`;\n if (!seen.has(k)) {\n seen.add(k);\n out.push(s);\n }\n };\n const tag = el.tagName.toLowerCase();\n // A selector scoped into a shadow root (`host >>> sel`) is always pushed as plain CSS.\n const pushFor = (kind: SelectorStrategy[\"kind\"], selector: string, value: string, label: string) => {\n const resolved = selectorFor(el, selector);\n if (resolved === selector) push({ kind, value, label });\n else if (resolved) push({ kind: \"css\", value: resolved, label });\n return !!resolved;\n };\n\n // A Guidely id is shared with the mobile apps, so it is the most portable target there is.\n const guidelyId = el.getAttribute(\"data-guidely-id\");\n if (guidelyId) pushFor(\"guidely-id\", attrSelector(\"data-guidely-id\", guidelyId), guidelyId, `Guidely id ${guidelyId}`);\n if (isStableId(el.id)) pushFor(\"id\", `#${escapeCss(el.id)}`, `#${el.id}`, `id ${el.id}`);\n\n const dataAttrs = Array.from(el.attributes).filter((a) => a.name.startsWith(\"data-\") && !IGNORED_DATA_ATTRS.test(a.name) && a.value && a.value.length <= 120 && !/\\d{5,}/.test(a.value));\n dataAttrs.sort((a, b) => {\n const ia = PREFERRED_DATA_ATTRS.indexOf(a.name);\n const ib = PREFERRED_DATA_ATTRS.indexOf(b.name);\n return (ia === -1 ? 99 : ia) - (ib === -1 ? 99 : ib);\n });\n for (const a of dataAttrs) {\n const sel = attrSelector(a.name, a.value);\n if (!pushFor(\"data-attr\", sel, sel, `${a.name}=${a.value}`)) pushFor(\"data-attr\", tag + sel, tag + sel, `${a.name}=${a.value}`);\n }\n\n const aria = el.getAttribute(\"aria-label\");\n if (aria && aria.length <= 120) {\n const sel = attrSelector(\"aria-label\", aria);\n if (!pushFor(\"aria\", sel, sel, aria)) pushFor(\"aria\", tag + sel, tag + sel, aria);\n }\n\n const name = el.getAttribute(\"name\");\n if (name) pushFor(\"css\", tag + attrSelector(\"name\", name), tag + attrSelector(\"name\", name), `${tag} name=${name}`);\n const role = el.getAttribute(\"role\");\n if (role) {\n const title = el.getAttribute(\"title\") || el.getAttribute(\"aria-labelledby\");\n const sel = title ? `[role='${role}']${attrSelector(el.getAttribute(\"title\") ? \"title\" : \"aria-labelledby\", title)}` : `[role='${role}']`;\n pushFor(\"css\", sel, sel, `role ${role}`);\n }\n if (tag === \"a\") {\n const href = el.getAttribute(\"href\");\n if (href && href.length <= 200) pushFor(\"css\", `a${attrSelector(\"href\", href)}`, `a${attrSelector(\"href\", href)}`, `link ${href}`);\n }\n\n const path = cssPath(el, shadowRootOf(el) ?? el.ownerDocument);\n if (path) pushFor(\"css\", path, path, \"css path\");\n\n if (/^(button|a|h[1-6]|label|summary)$/.test(tag) || role === \"button\" || role === \"link\" || role === \"tab\" || role === \"menuitem\") {\n const text = normalizeText((el as HTMLElement).innerText ?? el.textContent);\n if (text && text.length <= 80) push({ kind: \"text\", value: text, label: `text \"${text}\"` });\n }\n return out.slice(0, 10);\n}\n\nexport interface ElementDescription {\n selectors: SelectorStrategy[];\n textSnapshot: string;\n rect: { x: number; y: number; width: number; height: number };\n tag: string;\n}\n\n/**\n * An element's on-screen box. For a shadow host that is its own box joined with its shadow content's:\n * an `inline` host (the default for custom elements) is only a line tall around a taller button, and\n * a `display: contents` host has no box at all.\n */\nexport function visualRect(el: Element): DOMRect {\n const own = el.getBoundingClientRect();\n if (!el.shadowRoot) return own;\n const boxes = [own, ...Array.from(el.shadowRoot.children).map((c) => c.getBoundingClientRect())].filter((r) => r.width > 0 && r.height > 0);\n if (boxes.length < 2) return boxes[0] ?? own;\n const left = Math.min(...boxes.map((r) => r.left));\n const top = Math.min(...boxes.map((r) => r.top));\n const right = Math.max(...boxes.map((r) => r.right));\n const bottom = Math.max(...boxes.map((r) => r.bottom));\n return new DOMRect(left, top, right - left, bottom - top);\n}\n\n/** Growth from a control's box to its component's that still counts as \"the same control\" (label + field). */\nconst ANCHOR_MAX_AREA_RATIO = 4;\nconst CONTROL_SELECTOR = \"button, a[href], input, select, textarea, [role='button'], [role='link'], [role='checkbox'], [role='radio'], [role='switch'], [role='tab'], [role='menuitem'], [role='combobox'], [role='option']\";\n\n/**\n * The element a pick should target. Inside a component (a shadow host) that is little more than the\n * picked control (`lightning-button` around its `<button>`, also when the pick is the button's icon;\n * `lightning-input` around its label and field), that is the component itself: the app's markup around a component is the app's, while a\n * design system can change a component's internals in any release. Repeats up nested components and\n * stops at the first one that is clearly more (a list, a form, the whole app). Without layout (tests,\n * hidden pages) the element is kept.\n */\nexport function componentAnchor(el: Element): Element {\n if (!hasLayout(el.ownerDocument)) return el;\n let cur = el;\n for (let root = shadowRootOf(cur); root; root = shadowRootOf(cur)) {\n const host = root.host;\n if (host.id === HOST_ID) break;\n let control: Element | null = null;\n try {\n control = cur.closest(CONTROL_SELECTOR); // stays within this shadow root\n } catch {\n /* ignore */\n }\n const r = visualRect(control ?? cur);\n const area = r.width * r.height;\n const h = visualRect(host);\n const hostArea = h.width * h.height;\n const inside = r.left >= h.left - 1 && r.top >= h.top - 1 && r.right <= h.right + 1 && r.bottom <= h.bottom + 1;\n if (!area || !inside || hostArea > area * ANCHOR_MAX_AREA_RATIO) break;\n cur = host;\n }\n return cur;\n}\n\n/**\n * Everything the authoring picker and how-to capture need for one element. Selectors and rect are\n * for its `componentAnchor`; the text falls back to the element's own.\n */\nexport function describeElement(el: Element): ElementDescription {\n const target = componentAnchor(el);\n const r = visualRect(target);\n return {\n selectors: generateSelectors(target),\n textSnapshot: textSnapshotOf(target) || textSnapshotOf(el),\n rect: { x: r.x, y: r.y, width: r.width, height: r.height },\n tag: target.tagName.toLowerCase(),\n };\n}\n","import type { CapturedElement, NormalizedRect } from \"@guidelytech/shared\";\nimport { normalizeText } from \"./selectors\";\n\n/**\n * Pure DOM helpers for how-to capture: which element an interaction is about, how to name it for\n * people, which fields and on-screen text are sensitive, and where things sit in a screenshot.\n */\n\n/** Elements a click is \"about\" when it lands on them or inside them. */\nexport const CAPTURE_INTERACTIVE_SELECTOR =\n \"a,button,input,select,textarea,label,summary,[role=button],[role=link],[role=tab],[role=menuitem],[role=menuitemcheckbox],[role=menuitemradio],[role=option],[role=checkbox],[role=radio],[role=switch],[role=combobox],[contenteditable]:not([contenteditable=false])\";\n\n/** Always-redacted elements (on top of the project's mask selectors). */\nexport const REDACT_SELECTOR = \"[data-guidely-redact]\";\n\nconst TEXT_INPUT_TYPES = new Set([\"\", \"text\", \"email\", \"search\", \"tel\", \"url\", \"number\", \"password\", \"date\", \"datetime-local\", \"month\", \"week\", \"time\"]);\n\nfunction closestSafe(el: Element, selector: string): Element | null {\n if (!selector) return null;\n try {\n return el.closest(selector);\n } catch {\n return null;\n }\n}\n\nfunction inputType(el: Element): string {\n return el.tagName === \"INPUT\" ? (el.getAttribute(\"type\") || \"\").toLowerCase() : \"\";\n}\n\nfunction isEditableHost(el: Element): boolean {\n const v = el.getAttribute(\"contenteditable\");\n return v != null && v.toLowerCase() !== \"false\";\n}\n\n/** Fields whose typed text becomes a `type` step (instead of a click). */\nexport function isTextEntry(el: Element): boolean {\n if (el.tagName === \"TEXTAREA\") return true;\n if (el.tagName === \"INPUT\") return TEXT_INPUT_TYPES.has(inputType(el));\n return isEditableHost(el) || !!closestSafe(el, \"[contenteditable]:not([contenteditable=false])\");\n}\n\n/** The element a pointer interaction is about: the closest interactive ancestor, else the target itself. */\nexport function actionTarget(target: Element): Element {\n const hit = closestSafe(target, CAPTURE_INTERACTIVE_SELECTOR) ?? target;\n // A contenteditable descendant belongs to its editing host.\n if (!isEditableHost(hit) && isTextEntry(hit) && hit.tagName !== \"INPUT\" && hit.tagName !== \"TEXTAREA\") return closestSafe(hit, \"[contenteditable]:not([contenteditable=false])\") ?? hit;\n return hit;\n}\n\n/** The control a `<label>` is for (clicking the label acts on it), if any. */\nexport function labelControl(el: Element): Element | null {\n if (el.tagName !== \"LABEL\") return null;\n const label = el as HTMLLabelElement;\n if (label.control) return label.control;\n const forId = label.getAttribute(\"for\");\n if (forId) return label.ownerDocument.getElementById(forId);\n return label.querySelector(\"input,select,textarea\");\n}\n\n/** Is the element (or an ancestor) covered by the mask selectors or `[data-guidely-redact]`? */\nexport function isMaskedElement(el: Element, maskSelector: string): boolean {\n return !!closestSafe(el, REDACT_SELECTOR) || !!closestSafe(el, maskSelector);\n}\n\nconst SENSITIVE_NAME = /pass|card|cvv|cvc|ssn|secret|token|otp/i;\nconst SENSITIVE_AUTOCOMPLETE = /cc-|one-time-code|current-password|new-password/i;\n\n/** Fields whose value is never recorded and whose pixels are redacted from screenshots. */\nexport function isSensitiveField(el: Element, maskSelector = \"\"): boolean {\n if (inputType(el) === \"password\") return true;\n if (SENSITIVE_AUTOCOMPLETE.test(el.getAttribute(\"autocomplete\") || \"\")) return true;\n if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName) && (SENSITIVE_NAME.test(el.getAttribute(\"name\") || \"\") || SENSITIVE_NAME.test(el.id || \"\"))) return true;\n return isMaskedElement(el, maskSelector);\n}\n\n// ---------------------------------------------------------------------------\n// Sensitive text patterns\n// ---------------------------------------------------------------------------\n\nconst EMAIL = /[A-Z0-9._%+-]+@[A-Z0-9-]+(?:\\.[A-Z0-9-]+)*\\.[A-Z]{2,}/gi;\n/** A run of digit groups (optionally `+cc` and `(area)`) separated by single spaces, dots or dashes. */\nconst NUMBER_RUN = /(?:\\+\\d{1,3}[ .-]?)?(?:\\(\\d{2,4}\\)[ .-]?)?\\d+(?:[ .-]\\d+)*/g;\n\nexport type SensitiveNumberKind = \"card\" | \"ssn\" | \"phone\";\n\n/**\n * Classifies a number run: card (13–19 digits in groups of 4+), US SSN (3-2-4) or phone\n * (10–13 digits written with a country code, area-code parentheses or 3+ groups ending in 4 digits).\n * Dates, times, prices, versions and IP addresses do not match.\n */\nexport function classifyNumber(run: string): SensitiveNumberKind | null {\n const groups = run.match(/\\d+/g) ?? [];\n const lens = groups.map((g) => g.length);\n const digits = lens.reduce((a, b) => a + b, 0);\n const special = /[+(.]/.test(run);\n if (lens.length === 3 && lens[0] === 3 && lens[1] === 2 && lens[2] === 4 && /^\\d{3}[ -]\\d{2}[ -]\\d{4}$/.test(run)) return \"ssn\";\n if (digits >= 13 && digits <= 19 && !special && lens.every((l) => l >= 4)) return \"card\";\n if (digits >= 10 && digits <= 13 && (/[+(]/.test(run) || (lens.length >= 3 && lens[lens.length - 1] === 4 && lens.every((l) => l >= 2) && !run.includes(\".\")))) return \"phone\";\n return null;\n}\n\n/** Character ranges `[start, end)` of emails, card numbers, SSNs and phone numbers in `text`. */\nexport function findSensitiveText(text: string): Array<[number, number]> {\n const out: Array<[number, number]> = [];\n if (text.length < 7) return out;\n if (text.includes(\"@\")) {\n EMAIL.lastIndex = 0;\n for (let m = EMAIL.exec(text); m && out.length < 200; m = EMAIL.exec(text)) out.push([m.index, m.index + m[0].length]);\n }\n if (/\\d{3}/.test(text)) {\n NUMBER_RUN.lastIndex = 0;\n for (let m = NUMBER_RUN.exec(text); m && out.length < 200; m = NUMBER_RUN.exec(text)) {\n if (m[0].length >= 9 && classifyNumber(m[0])) out.push([m.index, m.index + m[0].length]);\n }\n }\n return out;\n}\n\n/** Typed values are recorded verbatim unless they contain something like a card number or SSN. */\nexport function looksLikeSecretValue(value: string): boolean {\n NUMBER_RUN.lastIndex = 0;\n for (let m = NUMBER_RUN.exec(value); m; m = NUMBER_RUN.exec(value)) {\n const kind = classifyNumber(m[0]);\n if (kind === \"card\" || kind === \"ssn\") return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Element description\n// ---------------------------------------------------------------------------\n\nconst ROLE_MAP: Record<string, string> = {\n button: \"button\",\n link: \"link\",\n tab: \"tab\",\n menuitem: \"menuitem\",\n menuitemcheckbox: \"menuitem\",\n menuitemradio: \"menuitem\",\n checkbox: \"checkbox\",\n radio: \"radio\",\n switch: \"switch\",\n option: \"option\",\n combobox: \"dropdown\",\n listbox: \"dropdown\",\n textbox: \"field\",\n searchbox: \"field\",\n spinbutton: \"field\",\n};\n\n/** Normalised role: button, link, tab, menuitem, checkbox, radio, switch, field, dropdown, option or element. */\nexport function captureRole(el: Element): string {\n const explicit = (el.getAttribute(\"role\") || \"\").trim().split(/\\s+/)[0]!.toLowerCase();\n if (ROLE_MAP[explicit]) return ROLE_MAP[explicit]!;\n const tag = el.tagName.toLowerCase();\n if (tag === \"a\") return el.hasAttribute(\"href\") ? \"link\" : \"element\";\n if (tag === \"button\" || tag === \"summary\") return \"button\";\n if (tag === \"select\") return \"dropdown\";\n if (tag === \"option\") return \"option\";\n if (tag === \"textarea\") return \"field\";\n if (tag === \"input\") {\n const t = inputType(el);\n if (t === \"checkbox\") return \"checkbox\";\n if (t === \"radio\") return \"radio\";\n if (t === \"button\" || t === \"submit\" || t === \"reset\" || t === \"image\") return \"button\";\n return \"field\";\n }\n if (isEditableHost(el)) return \"field\";\n return \"element\";\n}\n\nconst clip = (s: string, max = 80) => (s.length > max ? `${s.slice(0, max - 1).trimEnd()}…` : s);\n\nfunction textOf(el: Element): string {\n return normalizeText((el as HTMLElement).innerText ?? el.textContent);\n}\n\nfunction labelledBy(el: Element): string {\n const ids = (el.getAttribute(\"aria-labelledby\") || \"\").split(/\\s+/).filter(Boolean);\n return normalizeText(ids.map((id) => el.ownerDocument.getElementById(id)).filter((x): x is HTMLElement => !!x).map(textOf).join(\" \"));\n}\n\nfunction associatedLabel(el: Element): string {\n const labels = (el as HTMLInputElement).labels;\n if (labels && labels.length) return normalizeText(Array.from(labels).map(textOf).join(\" \"));\n if (el.id) {\n try {\n const l = el.ownerDocument.querySelector(`label[for=\"${el.id.replace(/[\"\\\\]/g, \"\\\\$&\")}\"]`);\n if (l) return textOf(l);\n } catch {\n /* ignore */\n }\n }\n const wrap = el.parentElement?.closest(\"label\");\n return wrap ? textOf(wrap) : \"\";\n}\n\n/**\n * Visible name of an element for people: aria-label, aria-labelledby, its `<label>`, its text\n * (not for fields, whose value is user data), placeholder, alt, title or name. Max 80 characters.\n */\nexport function captureLabel(el: Element): string {\n const attr = (name: string) => normalizeText(el.getAttribute(name));\n const tag = el.tagName;\n const field = tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\" || isEditableHost(el);\n const candidates: Array<() => string> = [\n () => attr(\"aria-label\"),\n () => labelledBy(el),\n () => (/^(INPUT|TEXTAREA|SELECT|METER|PROGRESS|OUTPUT)$/.test(tag) ? associatedLabel(el) : \"\"),\n () => (tag === \"INPUT\" && /^(button|submit|reset)$/.test(inputType(el)) ? normalizeText((el as HTMLInputElement).value) : \"\"),\n () => (field ? \"\" : textOf(el)),\n () => attr(\"placeholder\"),\n () => attr(\"alt\"),\n () => normalizeText(el.querySelector?.(\"img[alt]\")?.getAttribute(\"alt\")),\n () => attr(\"title\"),\n () => normalizeText(el.querySelector?.(\"svg title\")?.textContent),\n () => attr(\"name\"),\n ];\n for (const c of candidates) {\n const v = c();\n if (v) return clip(v);\n }\n return \"\";\n}\n\n/** People-facing description of the element; masked elements get no label (never their text). */\nexport function describeCapturedElement(el: Element, maskSelector = \"\"): CapturedElement {\n return { label: isMaskedElement(el, maskSelector) ? \"\" : captureLabel(el), role: captureRole(el), tag: el.tagName.toLowerCase() };\n}\n\n/** The value a `type` step records: trimmed, at most 200 characters. */\nexport function fieldValue(el: Element): string {\n const raw = el.tagName === \"INPUT\" || el.tagName === \"TEXTAREA\" ? (el as HTMLInputElement).value : textOf(el);\n return (raw || \"\").trim().slice(0, 200);\n}\n\n/** Text of the selected option(s) of a `<select>`. */\nexport function selectedOptionText(el: HTMLSelectElement): string {\n return normalizeText(Array.from(el.selectedOptions ?? []).map((o) => o.text || o.value).join(\", \")).slice(0, 200);\n}\n\n// ---------------------------------------------------------------------------\n// Geometry\n// ---------------------------------------------------------------------------\n\nexport interface Box {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nconst clamp01 = (n: number) => Math.min(1, Math.max(0, n));\nconst round = (n: number) => Math.round(n * 10000) / 10000;\n\n/**\n * Maps a viewport rect (CSS px) to fractions of a screenshot of that viewport, padded by `pad`\n * CSS px and clamped to the frame. Returns null when nothing of it is on screen.\n */\nexport function normalizeRect(rect: Box, viewport: { width: number; height: number }, pad = 4): NormalizedRect | null {\n if (!viewport.width || !viewport.height || rect.width <= 0 || rect.height <= 0) return null;\n const x0 = clamp01((rect.x - pad) / viewport.width);\n const y0 = clamp01((rect.y - pad) / viewport.height);\n const x1 = clamp01((rect.x + rect.width + pad) / viewport.width);\n const y1 = clamp01((rect.y + rect.height + pad) / viewport.height);\n if (x1 <= x0 || y1 <= y0) return null;\n return { x: round(x0), y: round(y0), width: round(x1 - x0), height: round(y1 - y0) };\n}\n\n/** Scales a viewport rect (CSS px) to frame pixels, clipped to the frame. */\nexport function toFrameRect(rect: Box, scaleX: number, scaleY: number, frame: { width: number; height: number }, pad = 0): Box | null {\n const x0 = Math.max(0, Math.floor((rect.x - pad) * scaleX));\n const y0 = Math.max(0, Math.floor((rect.y - pad) * scaleY));\n const x1 = Math.min(frame.width, Math.ceil((rect.x + rect.width + pad) * scaleX));\n const y1 = Math.min(frame.height, Math.ceil((rect.y + rect.height + pad) * scaleY));\n return x1 > x0 && y1 > y0 ? { x: x0, y: y0, width: x1 - x0, height: y1 - y0 } : null;\n}\n\nfunction intersectsViewport(r: Box, vw: number, vh: number): boolean {\n return r.width > 0 && r.height > 0 && r.x < vw && r.y < vh && r.x + r.width > 0 && r.y + r.height > 0;\n}\n\nconst SKIP_TEXT_PARENTS = /^(SCRIPT|STYLE|NOSCRIPT|TEMPLATE|TEXTAREA|OPTION)$/;\n\nexport interface RedactionOptions {\n maskSelector?: string;\n /** Stop after this many text nodes (keeps the synchronous scan cheap on huge pages). */\n maxTextNodes?: number;\n}\n\n/**\n * Viewport rects (CSS px) to blur in a screenshot: password and other sensitive fields, masked and\n * `[data-guidely-redact]` elements, field values and visible text that look like emails, card\n * numbers, SSNs or phone numbers. Runs synchronously so it matches the frame grabbed with it.\n */\nexport function collectRedactions(doc: Document, options: RedactionOptions = {}): Box[] {\n const win = doc.defaultView;\n const vw = win?.innerWidth ?? 0;\n const vh = win?.innerHeight ?? 0;\n const out: Box[] = [];\n const push = (r: Box) => {\n if (intersectsViewport(r, vw, vh)) out.push({ x: r.x, y: r.y, width: r.width, height: r.height });\n };\n const root = doc.body;\n if (!root) return out;\n const mask = options.maskSelector || \"\";\n const blocks = new Set<Element>();\n try {\n root.querySelectorAll(mask ? `${REDACT_SELECTOR},${mask}` : REDACT_SELECTOR).forEach((el) => blocks.add(el));\n } catch {\n root.querySelectorAll(REDACT_SELECTOR).forEach((el) => blocks.add(el));\n }\n root.querySelectorAll(\"input,textarea,select,[contenteditable]:not([contenteditable=false])\").forEach((el) => {\n if (blocks.has(el)) return;\n const t = inputType(el);\n if (t === \"hidden\" || t === \"checkbox\" || t === \"radio\" || t === \"button\" || t === \"submit\" || t === \"reset\") return;\n if (isSensitiveField(el, mask)) blocks.add(el);\n else if ((el.tagName === \"INPUT\" || el.tagName === \"TEXTAREA\") && findSensitiveText((el as HTMLInputElement).value || \"\").length) blocks.add(el);\n });\n blocks.forEach((el) => push(el.getBoundingClientRect()));\n\n const max = options.maxTextNodes ?? 5000;\n const walker = doc.createTreeWalker(root, 4 /* NodeFilter.SHOW_TEXT */);\n let range: Range | null = null;\n let seen = 0;\n for (let node = walker.nextNode(); node && seen < max; node = walker.nextNode()) {\n const text = node.nodeValue || \"\";\n if (text.length < 7) continue;\n seen++;\n const parent = node.parentElement;\n if (!parent || SKIP_TEXT_PARENTS.test(parent.tagName)) continue;\n const hits = findSensitiveText(text);\n if (!hits.length) continue;\n // Text inside an element that is already blurred as a whole needs no second pass.\n if (Array.from(blocks).some((b) => b.contains(parent))) continue;\n range ??= doc.createRange();\n for (const [start, end] of hits) {\n try {\n range.setStart(node, start);\n range.setEnd(node, end);\n Array.from(range.getClientRects()).forEach(push);\n } catch {\n /* node changed under us */\n }\n }\n }\n return out;\n}\n","import { toFrameRect, type Box } from \"./capture-dom\";\n\n/**\n * Screenshots for how-to capture: a tab-capture stream (`getDisplayMedia`) played into a hidden\n * video, frames grabbed synchronously into a canvas, sensitive regions blurred into the pixels and\n * the result encoded — all in the browser, so raw pixels of redacted regions never leave it.\n */\n\nexport type ScreenResult = { ok: true; screen: ScreenSource } | { ok: false; reason: \"unsupported\" | \"denied\" | \"wrong-surface\" | \"error\" };\n\nexport interface ScreenSource {\n /** True while the stream delivers frames. */\n live(): boolean;\n /** Called once when the user stops sharing (or the stream ends otherwise). */\n onEnded(cb: () => void): void;\n /** Draws the current frame into a new canvas (synchronously). Null when no frame is available. */\n grab(): HTMLCanvasElement | null;\n /** Does the current frame show the page as it is after `changedAt` (a `performance.now()` time)? */\n freshSince(changedAt: number): boolean;\n /** Resolves when the next frame arrives (or after `timeoutMs`). */\n nextFrame(timeoutMs?: number): Promise<void>;\n stop(): void;\n}\n\n/** Can this browser capture the tab at all? */\nexport function canCaptureScreen(): boolean {\n return typeof navigator !== \"undefined\" && !!navigator.mediaDevices && typeof navigator.mediaDevices.getDisplayMedia === \"function\";\n}\n\n/**\n * Asks the user to share this tab (must run from a user gesture) and plays the stream into a\n * hidden `<video>` appended to `container`. Rejects windows and screens: their frames do not\n * match the page's viewport, so highlights and redactions would land in the wrong place.\n */\nexport async function requestTabCapture(container: Node, doc: Document = document): Promise<ScreenResult> {\n if (!canCaptureScreen()) return { ok: false, reason: \"unsupported\" };\n let stream: MediaStream;\n try {\n stream = await navigator.mediaDevices.getDisplayMedia({\n video: { displaySurface: \"browser\", frameRate: 5 },\n audio: false,\n preferCurrentTab: true,\n selfBrowserSurface: \"include\",\n surfaceSwitching: \"exclude\",\n } as DisplayMediaStreamOptions);\n } catch (err) {\n return { ok: false, reason: (err as { name?: string })?.name === \"NotAllowedError\" ? \"denied\" : \"error\" };\n }\n const track = stream.getVideoTracks()[0];\n if (!track) {\n stream.getTracks().forEach((t) => t.stop());\n return { ok: false, reason: \"error\" };\n }\n const surface = (track.getSettings?.() as { displaySurface?: string } | undefined)?.displaySurface;\n if (surface && surface !== \"browser\") {\n stream.getTracks().forEach((t) => t.stop());\n return { ok: false, reason: \"wrong-surface\" };\n }\n const video = doc.createElement(\"video\");\n video.muted = true;\n video.playsInline = true;\n video.setAttribute(\"aria-hidden\", \"true\");\n // Kept rendered (not display:none) so browsers keep decoding frames.\n video.style.cssText = \"position:fixed;left:0;top:0;width:2px;height:2px;opacity:0;pointer-events:none\";\n try {\n video.srcObject = stream;\n container.appendChild(video);\n } catch {\n stream.getTracks().forEach((t) => t.stop());\n return { ok: false, reason: \"error\" };\n }\n try {\n await video.play();\n if (!video.videoWidth) await new Promise<void>((resolve) => {\n const done = () => resolve();\n video.addEventListener(\"loadeddata\", done, { once: true });\n setTimeout(done, 1500);\n });\n } catch {\n /* frames may still arrive; grab() returns null until they do */\n }\n let ended = false;\n const listeners: Array<() => void> = [];\n // Frame timing: `requestVideoFrameCallback` where supported, else assume one frame period (5 fps) of lag.\n type FrameVideo = HTMLVideoElement & { requestVideoFrameCallback?: (cb: (now: number) => void) => number };\n const fv = video as FrameVideo;\n const rvfc = typeof fv.requestVideoFrameCallback === \"function\";\n let frameAt = 0;\n let waiters: Array<() => void> = [];\n const onFrame = (now: number) => {\n frameAt = now;\n waiters.splice(0).forEach((w) => w());\n if (!ended) fv.requestVideoFrameCallback!(onFrame);\n };\n if (rvfc) fv.requestVideoFrameCallback!(onFrame);\n const end = () => {\n if (ended) return;\n ended = true;\n stream.getTracks().forEach((t) => t.stop());\n video.srcObject = null;\n video.remove();\n listeners.splice(0).forEach((cb) => cb());\n };\n track.addEventListener(\"ended\", end);\n return {\n ok: true,\n screen: {\n live: () => !ended && track.readyState === \"live\",\n onEnded: (cb) => (ended ? cb() : listeners.push(cb)),\n grab: () => (ended ? null : grabFrame(video, doc)),\n freshSince: (changedAt) => (rvfc ? frameAt > changedAt : performance.now() - changedAt > 250),\n nextFrame: (timeoutMs = 500) =>\n new Promise<void>((resolve) => {\n const t = setTimeout(done, rvfc ? timeoutMs : 250);\n function done() {\n clearTimeout(t);\n waiters = waiters.filter((w) => w !== done);\n resolve();\n }\n if (rvfc) waiters.push(done);\n }),\n stop: () => {\n listeners.length = 0;\n end();\n },\n },\n };\n}\n\n/** Copies the video's current frame into a new canvas. */\nexport function grabFrame(video: HTMLVideoElement, doc: Document = document): HTMLCanvasElement | null {\n const w = video.videoWidth;\n const h = video.videoHeight;\n if (!w || !h) return null;\n const canvas = doc.createElement(\"canvas\");\n canvas.width = w;\n canvas.height = h;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n ctx.drawImage(video, 0, 0, w, h);\n return canvas;\n}\n\n/**\n * Blurs viewport rects (CSS px) into the canvas by averaging each region down to a few samples per\n * line of text and scaling it back up, which leaves nothing legible to recover. Returns the number\n * of regions blurred.\n */\nexport function redactCanvas(canvas: HTMLCanvasElement, rects: Box[], viewport: { width: number; height: number }): number {\n const ctx = canvas.getContext(\"2d\");\n if (!ctx || !rects.length || !viewport.width || !viewport.height) return 0;\n const sx = canvas.width / viewport.width;\n const sy = canvas.height / viewport.height;\n const tmp = canvas.ownerDocument.createElement(\"canvas\");\n const tctx = tmp.getContext(\"2d\");\n if (!tctx) return 0;\n let count = 0;\n for (const rect of rects) {\n const r = toFrameRect(rect, sx, sy, canvas, 4);\n if (!r) continue;\n // One sample per ~line height (at least 16 CSS px) in both directions.\n const block = Math.max(16 * sy, Math.min(r.height, 48 * sy));\n tmp.width = Math.max(1, Math.round(r.width / block));\n tmp.height = Math.max(1, Math.round(r.height / block));\n tctx.imageSmoothingEnabled = true;\n tctx.drawImage(canvas, r.x, r.y, r.width, r.height, 0, 0, tmp.width, tmp.height);\n ctx.imageSmoothingEnabled = true;\n ctx.drawImage(tmp, 0, 0, tmp.width, tmp.height, r.x, r.y, r.width, r.height);\n // A light tint so readers can tell the region was hidden on purpose.\n ctx.fillStyle = \"rgba(120,120,120,.28)\";\n ctx.fillRect(r.x, r.y, r.width, r.height);\n count++;\n }\n return count;\n}\n\nfunction scaled(canvas: HTMLCanvasElement, maxWidth: number): HTMLCanvasElement {\n if (canvas.width <= maxWidth) return canvas;\n const out = canvas.ownerDocument.createElement(\"canvas\");\n out.width = maxWidth;\n out.height = Math.round((canvas.height * maxWidth) / canvas.width);\n const ctx = out.getContext(\"2d\");\n if (!ctx) return canvas;\n ctx.imageSmoothingQuality = \"high\";\n ctx.drawImage(canvas, 0, 0, out.width, out.height);\n return out;\n}\n\nconst toBlob = (canvas: HTMLCanvasElement, type: string, quality: number) =>\n new Promise<Blob | null>((resolve) => {\n try {\n canvas.toBlob((b) => resolve(b), type, quality);\n } catch {\n resolve(null);\n }\n });\n\n/** Encodes as WebP (JPEG where WebP encoding is unsupported), at most `maxWidth` wide and `maxBytes` big. */\nexport async function encodeScreenshot(canvas: HTMLCanvasElement, options: { maxWidth?: number; maxBytes?: number } = {}): Promise<Blob | null> {\n const src = scaled(canvas, options.maxWidth ?? 2560);\n const maxBytes = options.maxBytes ?? 8 * 1024 * 1024;\n let blob = await toBlob(src, \"image/webp\", 0.85);\n // Browsers without a WebP encoder silently return PNG.\n if (!blob || blob.type !== \"image/webp\") blob = await toBlob(src, \"image/jpeg\", 0.85);\n if (blob && blob.size > maxBytes) blob = await toBlob(src, \"image/jpeg\", 0.6);\n return blob && blob.size <= maxBytes ? blob : null;\n}\n\n/** Synchronous JPEG data URL (≤ 1600 px wide), for persisting an unsent screenshot while the page unloads. */\nexport function screenshotDataUrl(canvas: HTMLCanvasElement): string | null {\n try {\n return scaled(canvas, 1600).toDataURL(\"image/jpeg\", 0.7);\n } catch {\n return null;\n }\n}\n","/** All runtime CSS, injected once into the Shadow DOM host. Tokens are CSS custom properties. */\nexport const STYLES = `\n:host{all:initial;position:static;display:block;contain:none}\n*,*::before,*::after{box-sizing:border-box}\n.g-scope [hidden]{display:none!important}\n.g-scope{\n --g-primary:#4f46e5;--g-bg:#ffffff;--g-text:#111827;--g-radius:12px;--g-font:Inter,system-ui,-apple-system,sans-serif;--g-z:2147483000;--g-overlay:.5;\n --g-muted:color-mix(in srgb,var(--g-text) 62%,transparent);--g-border:color-mix(in srgb,var(--g-text) 12%,transparent);\n --g-subtle:color-mix(in srgb,var(--g-text) 5%,transparent);--g-shadow:0 10px 40px rgba(0,0,0,.18),0 2px 8px rgba(0,0,0,.08);\n --g-primary-text:#ffffff;\n font-family:var(--g-font);font-size:14px;line-height:1.5;color:var(--g-text);-webkit-font-smoothing:antialiased;\n}\n.g-scope[data-theme=\"dark\"]{--g-shadow:0 10px 40px rgba(0,0,0,.5),0 2px 8px rgba(0,0,0,.3)}\n.g-live{position:fixed;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n.g-layer{position:fixed;inset:0;z-index:var(--g-z);pointer-events:none}\n.g-overlay{position:fixed;inset:0;background:rgba(0,0,0,var(--g-overlay));z-index:calc(var(--g-z) + 3);pointer-events:auto}\n.g-overlay.g-transparent{background:transparent}\n.g-spot-rect{position:fixed;background:rgba(0,0,0,var(--g-overlay));z-index:calc(var(--g-z) + 3);pointer-events:auto}\n.g-spot-ring{position:fixed;z-index:calc(var(--g-z) + 3);pointer-events:none;border-radius:6px;box-shadow:0 0 0 2px var(--g-primary),0 0 0 6px color-mix(in srgb,var(--g-primary) 30%,transparent)}\n.g-card{\n position:fixed;z-index:calc(var(--g-z) + 4);pointer-events:auto;background:var(--g-bg);color:var(--g-text);border-radius:var(--g-radius);\n box-shadow:var(--g-shadow);border:1px solid var(--g-border);width:min(360px,calc(100vw - 32px));max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);overflow:auto;outline:none;\n}\n.g-card.g-modal{left:50%;top:50%;transform:translate(-50%,-50%);width:min(480px,calc(100vw - 32px))}\n.g-card.g-tooltip,.g-card.g-popover,.g-card.g-spotlight-card,.g-card.g-hotspot-card{top:0;left:0;width:min(320px,calc(100vw - 32px))}\n.g-card.g-slideout{width:min(360px,calc(100vw - 32px));margin:16px}\n.g-pos-bottom-right{right:0;bottom:0}.g-pos-bottom-left{left:0;bottom:0}.g-pos-top-right{right:0;top:0}.g-pos-top-left{left:0;top:0}\n.g-pos-center{left:50%;top:50%;transform:translate(-50%,-50%)}\n.g-pos-top{top:0;left:0;right:0}.g-pos-bottom{bottom:0;left:0;right:0}\n.g-banner{position:fixed;left:0;right:0;z-index:calc(var(--g-z) + 1);pointer-events:auto;background:var(--g-primary);color:var(--g-primary-text);padding:10px 48px 10px 16px;display:flex;align-items:center;gap:12px;font-size:14px;box-shadow:0 2px 10px rgba(0,0,0,.15);max-width:100vw}\n.g-banner .g-body{flex:1;min-width:0}\n.g-banner .g-body a{color:inherit;text-decoration:underline}\n.g-banner .g-close{color:inherit;right:8px;top:50%;transform:translateY(-50%)}\n.g-banner .g-btn{background:rgba(255,255,255,.18);color:inherit;border-color:transparent;min-height:36px}\n.g-banner.g-pos-top{top:0}.g-banner.g-pos-bottom{bottom:0}\n.g-inner{padding:20px}\n.g-close{position:absolute;top:8px;right:8px;width:40px;height:40px;display:inline-flex;align-items:center;justify-content:center;border:0;background:transparent;color:var(--g-muted);border-radius:999px;cursor:pointer;font:inherit;font-size:20px;line-height:1}\n.g-close:hover,.g-close:focus-visible{background:var(--g-subtle);color:var(--g-text);outline:none}\n.g-close:focus-visible,.g-btn:focus-visible,.g-task:focus-visible,.g-choice:focus-visible,.g-scale button:focus-visible,.g-launcher:focus-visible,.g-input:focus-visible,.g-rc-item:focus-visible{outline:2px solid var(--g-primary);outline-offset:2px}\n.g-image{display:block;width:100%;max-height:220px;object-fit:cover;border-radius:var(--g-radius) var(--g-radius) 0 0}\n.g-title{margin:0 28px 6px 0;font-size:16px;font-weight:600;line-height:1.3}\n.g-body{font-size:14px;color:var(--g-text)}\n.g-body p{margin:0 0 8px}.g-body p:last-child{margin-bottom:0}\n.g-body ul,.g-body ol{margin:6px 0;padding-left:20px}\n.g-body a{color:var(--g-primary)}\n.g-body img{max-width:100%;height:auto;border-radius:6px}\n.g-body video,.g-body iframe{display:block;width:100%;max-width:100%;border:0;border-radius:6px;margin:8px 0;background:#000}\n.g-body video{height:auto;max-height:60vh}\n.g-body iframe{aspect-ratio:16/9;height:auto}\n.g-body .gd-pdf{margin:10px 0;border:1px solid var(--g-border);border-radius:10px;background:var(--g-subtle);overflow:hidden}\n.g-body a.gd-file{display:flex;align-items:center;gap:8px;padding:8px 10px;color:var(--g-text);font-size:13px;font-weight:500;text-decoration:none;min-height:40px;overflow-wrap:anywhere}\n.g-body a.gd-file::before{content:\"PDF\";flex:none;font-size:9px;font-weight:700;letter-spacing:.04em;line-height:1;color:#fff;background:#e5484d;border-radius:4px;padding:4px 5px}\n.g-body a.gd-file::after{content:\"⤢\";margin-left:auto;padding-left:8px;color:var(--g-muted);font-size:15px}\n.g-body a.gd-file:hover::after,.g-body a.gd-file:focus-visible::after{color:var(--g-primary)}\n.g-body a.gd-file:focus-visible{outline:2px solid var(--g-primary);outline-offset:-2px;border-radius:10px}\n.g-body > a.gd-file,.g-body p > a.gd-file{margin:10px 0;border:1px solid var(--g-border);border-radius:10px;background:var(--g-subtle)}\n.g-body > a.gd-file::after,.g-body p > a.gd-file::after,.g-body .gd-pdf:not([data-g-ready]) > a.gd-file::after{content:\"↗\"}\n.g-pdf-viewport{position:relative}\n.g-body .gd-pdf-pages{display:flex;gap:10px;overflow-x:auto;scroll-snap-type:x mandatory;overscroll-behavior-x:contain;scrollbar-width:none;padding:0 10px 10px;scroll-padding:0 10px}\n.g-body .gd-pdf-pages::-webkit-scrollbar{display:none}\n.g-body .gd-pdf-pages:focus-visible{outline:2px solid var(--g-primary);outline-offset:-2px}\n.g-body .gd-pdf-pages img{flex:0 0 100%;width:100%;height:auto;margin:0;scroll-snap-align:center;background:#fff;border-radius:4px;box-shadow:0 1px 3px rgba(0,0,0,.18);cursor:zoom-in}\n.g-pdf-viewport .gd-pdf-pages{padding:0;scroll-padding:0;margin:0 10px 10px}\n.g-pdf-count{position:absolute;right:18px;bottom:18px;padding:2px 8px;border-radius:999px;background:rgba(17,17,17,.72);color:#fff;font-size:11px;font-weight:500;pointer-events:none;font-variant-numeric:tabular-nums}\n.g-pdf-nav{position:absolute;top:calc(50% - 21px);width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:999px;background:rgba(17,17,17,.6);color:#fff;font:inherit;font-size:20px;line-height:1;cursor:pointer;opacity:0;transition:opacity .15s}\n.g-pdf-prev{left:16px}.g-pdf-next{right:16px}\n.g-pdf-viewport:hover .g-pdf-nav,.g-pdf-nav:focus-visible{opacity:1}\n.g-pdf-nav:disabled,.g-pdf-single .g-pdf-nav,.g-pdf-single .g-pdf-count{display:none}\n.g-pdf-nav:focus-visible{outline:2px solid #fff;outline-offset:1px}\n@media (hover:none){.g-pdf-nav{display:none}}\n.g-pdf-reader{position:fixed;inset:0;z-index:calc(var(--g-z) + 10);display:flex;flex-direction:column;background:#0b0b0d;pointer-events:auto;color:#fff}\n.g-pdf-bar{display:flex;align-items:center;gap:10px;padding:8px 8px 8px 16px;min-height:56px}\n.g-pdf-title{flex:1;min-width:0;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.g-pdf-bar .g-btn{min-height:36px;color:#fff;background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.18)}\n.g-pdf-close{position:static;color:#fff}\n.g-pdf-close:hover,.g-pdf-close:focus-visible{background:rgba(255,255,255,.14);color:#fff}\n.g-pdf-scroll{position:relative;flex:1;overflow-y:auto;overscroll-behavior:contain;padding:4px 16px 24px;display:flex;flex-direction:column;align-items:center;gap:12px;outline:none}\n.g-pdf-scroll img{display:block;width:100%;max-width:900px;height:auto;background:#fff;border-radius:2px;box-shadow:0 2px 12px rgba(0,0,0,.4)}\n.g-body code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;background:var(--g-subtle);padding:1px 4px;border-radius:4px}\n.g-body pre{background:var(--g-subtle);padding:10px;border-radius:6px;overflow:auto}\n.g-body blockquote{margin:6px 0;padding-left:10px;border-left:3px solid var(--g-border);color:var(--g-muted)}\n.g-footer{display:flex;align-items:center;gap:8px;margin-top:14px;flex-wrap:wrap}\n.g-progress{font-size:12px;color:var(--g-muted);margin-right:auto}\n.g-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:40px;padding:8px 14px;border-radius:calc(var(--g-radius) * .66);border:1px solid transparent;font:inherit;font-size:14px;font-weight:500;cursor:pointer;text-decoration:none;transition:background .15s,color .15s,border-color .15s}\n.g-btn-primary{background:var(--g-primary);color:var(--g-primary-text)}\n.g-btn-primary:hover{filter:brightness(1.08)}\n.g-btn-secondary{background:var(--g-subtle);color:var(--g-text);border-color:var(--g-border)}\n.g-btn-secondary:hover{background:color-mix(in srgb,var(--g-text) 10%,transparent)}\n.g-btn-ghost{background:transparent;color:var(--g-muted)}\n.g-btn-ghost:hover{background:var(--g-subtle);color:var(--g-text)}\n.g-btn-link{background:transparent;color:var(--g-primary);padding-left:4px;padding-right:4px}\n.g-btn-link:hover{text-decoration:underline}\n.g-btn:disabled{opacity:.5;cursor:not-allowed}\n.g-arrow{position:absolute;width:12px;height:12px;background:var(--g-bg);transform:rotate(45deg);border:1px solid var(--g-border);z-index:-1}\n.g-hotspot{position:fixed;z-index:calc(var(--g-z) + 1);pointer-events:auto;border-radius:999px;background:var(--g-primary);border:2px solid #fff;box-shadow:0 0 0 2px color-mix(in srgb,var(--g-primary) 40%,transparent);cursor:pointer;padding:0;margin:0}\n.g-hotspot::after{content:\"\";position:absolute;inset:-4px;border-radius:999px;border:2px solid var(--g-primary);opacity:0}\n.g-hotspot.g-pulse::after{animation:g-pulse 1.8s ease-out infinite}\n.g-hotspot-hit{position:absolute;inset:-14px}\n.g-custom{position:fixed;z-index:calc(var(--g-z) + 4);pointer-events:auto;left:50%;top:50%;transform:translate(-50%,-50%);max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);overflow:auto}\n/* animations */\n.g-scope[data-anim=\"fade\"] .g-card,.g-scope[data-anim=\"fade\"] .g-banner,.g-scope[data-anim=\"fade\"] .g-panel{animation:g-fade .18s ease-out}\n.g-scope[data-anim=\"slide\"] .g-card,.g-scope[data-anim=\"slide\"] .g-panel{animation:g-slide .22s ease-out}\n.g-scope[data-anim=\"none\"] *{animation:none!important;transition:none!important}\n@keyframes g-fade{from{opacity:0}to{opacity:1}}\n@keyframes g-slide{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}\n@keyframes g-pulse{0%{transform:scale(.6);opacity:.9}100%{transform:scale(2.2);opacity:0}}\n@media (prefers-reduced-motion:reduce){.g-scope *{animation:none!important;transition:none!important}}\n/* launcher + panel (checklist / resource center) */\n.g-launcher{position:fixed;z-index:calc(var(--g-z) + 1);pointer-events:auto;display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:10px 16px;border-radius:999px;border:0;background:var(--g-primary);color:var(--g-primary-text);font:inherit;font-size:14px;font-weight:600;cursor:pointer;box-shadow:var(--g-shadow);margin:16px}\n.g-launcher .g-ring{width:22px;height:22px;border-radius:999px;background:conic-gradient(#fff var(--g-pct,0%),rgba(255,255,255,.3) 0);display:inline-flex;align-items:center;justify-content:center;font-size:10px;position:relative}\n.g-launcher .g-ring::after{content:\"\";position:absolute;inset:3px;border-radius:999px;background:var(--g-primary)}\n.g-launcher .g-count{position:relative;z-index:1}\n.g-panel{position:fixed;z-index:calc(var(--g-z) + 2);pointer-events:auto;width:min(380px,calc(100vw - 32px));max-height:min(620px,calc(100vh - 100px));display:flex;flex-direction:column;background:var(--g-bg);color:var(--g-text);border-radius:var(--g-radius);box-shadow:var(--g-shadow);border:1px solid var(--g-border);margin:16px;bottom:60px;overflow:hidden}\n.g-panel-head{padding:16px 48px 12px 20px;border-bottom:1px solid var(--g-border);position:relative}\n.g-panel-title{margin:0;font-size:16px;font-weight:600}\n.g-panel-sub{margin:4px 0 0;font-size:12px;color:var(--g-muted)}\n.g-panel-body{overflow:auto;padding:8px 0;flex:1}\n.g-help{display:flex;flex-direction:column;min-height:0;flex:1}\n.g-bar{height:6px;border-radius:999px;background:var(--g-subtle);overflow:hidden;margin-top:10px}\n.g-bar > span{display:block;height:100%;background:var(--g-primary);transition:width .3s}\n.g-task{display:flex;gap:12px;align-items:flex-start;width:100%;padding:12px 20px;border:0;background:transparent;text-align:left;font:inherit;color:inherit;cursor:pointer;min-height:44px}\n.g-task:hover{background:var(--g-subtle)}\n.g-task[disabled]{cursor:not-allowed;opacity:.55}\n.g-task .g-check{flex:none;width:22px;height:22px;border-radius:999px;border:2px solid var(--g-border);display:inline-flex;align-items:center;justify-content:center;font-size:13px;margin-top:1px;color:#fff}\n.g-task.g-done .g-check{background:var(--g-primary);border-color:var(--g-primary)}\n.g-task.g-done .g-task-title{text-decoration:line-through;color:var(--g-muted)}\n.g-task-title{font-weight:500}\n.g-task-desc{font-size:12px;color:var(--g-muted);margin-top:2px}\n.g-panel-foot{padding:10px 20px;border-top:1px solid var(--g-border);display:flex;justify-content:flex-end;gap:8px}\n.g-complete{padding:28px 20px;text-align:center}\n.g-complete .g-title{margin-right:0;font-size:18px}\n/* survey */\n.g-question{margin-bottom:16px}\n.g-q-title{font-weight:600;margin:0 0 4px}\n.g-q-desc{font-size:12px;color:var(--g-muted);margin:0 0 8px}\n.g-scale{display:flex;gap:4px;flex-wrap:wrap}\n.g-scale button{min-width:34px;height:40px;flex:1;padding:0 4px;border-radius:6px;border:1px solid var(--g-border);background:var(--g-subtle);color:var(--g-text);font:inherit;cursor:pointer}\n.g-scale button[aria-pressed=\"true\"],.g-scale button:hover{background:var(--g-primary);color:var(--g-primary-text);border-color:var(--g-primary)}\n.g-scale-labels{display:flex;justify-content:space-between;font-size:11px;color:var(--g-muted);margin-top:4px}\n.g-stars button,.g-thumbs button{font-size:22px;background:transparent;border:0;cursor:pointer;color:var(--g-muted);min-width:40px;height:40px;font:inherit}\n.g-stars button[aria-pressed=\"true\"],.g-stars button.g-on{color:#f59e0b}\n.g-thumbs button[aria-pressed=\"true\"]{color:var(--g-primary)}\n.g-choice{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--g-border);border-radius:8px;margin-bottom:6px;cursor:pointer;min-height:40px;font:inherit;background:transparent;color:inherit;width:100%;text-align:left}\n.g-choice[aria-checked=\"true\"]{border-color:var(--g-primary);background:color-mix(in srgb,var(--g-primary) 8%,transparent)}\n.g-choice .g-dot{width:16px;height:16px;border-radius:999px;border:2px solid var(--g-border);flex:none}\n.g-choice.g-multi .g-dot{border-radius:4px}\n.g-choice[aria-checked=\"true\"] .g-dot{background:var(--g-primary);border-color:var(--g-primary)}\n.g-input{width:100%;min-height:40px;padding:8px 10px;border:1px solid var(--g-border);border-radius:8px;background:var(--g-bg);color:var(--g-text);font:inherit;resize:vertical}\n.g-error{color:#dc2626;font-size:12px;margin-top:4px}\n/* resource center */\n.g-rc-search{padding:12px 20px 4px}\n.g-rc-section{padding:8px 20px 4px;font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--g-muted);font-weight:600}\n.g-rc-section[data-depth]{text-transform:none;letter-spacing:0;font-size:12px}\n.g-rc-item{display:flex;align-items:flex-start;gap:10px;width:100%;padding:10px 20px;border:0;background:transparent;font:inherit;color:inherit;text-align:left;cursor:pointer;min-height:44px;text-decoration:none}\n.g-rc-item:hover{background:var(--g-subtle)}\n.g-rc-item .g-rc-title{font-weight:500}\n.g-rc-item .g-rc-sum{font-size:12px;color:var(--g-muted);margin-top:2px}\n.g-rc-item .g-rc-icon{flex:none;width:20px;text-align:center;color:var(--g-primary)}\n.g-rc-row{display:flex;align-items:center;gap:6px;padding-right:16px}\n.g-rc-row>.g-rc-item{flex:1;min-width:0;padding-right:4px}\n.g-rc-row:hover{background:var(--g-subtle)}\n.g-rc-row:hover>.g-rc-item{background:transparent}\n.g-rc-showme{flex:none;min-height:32px;padding:4px 10px;font-size:12px;white-space:nowrap}\n.g-help-showme{margin:4px 0 12px}\n.g-rc-article{padding:16px 20px}\n.g-resource-center .g-panel{transition:width .2s ease,max-height .2s ease}\n.g-resource-center .g-panel.g-panel-reading{width:min(720px,calc(100vw - 32px));max-height:calc(100vh - 100px)}\n.g-rc-back{margin-bottom:8px}\n.g-rc-empty{padding:24px 20px;color:var(--g-muted);text-align:center}\n.g-faq-a{padding:0 20px 12px 50px;font-size:13px;color:var(--g-muted)}\n.g-faq-a[hidden]{display:none}\n/* authoring */\n.g-auth-bar{position:fixed;top:0;left:0;right:0;z-index:calc(var(--g-z) + 10);pointer-events:auto;display:flex;align-items:center;gap:12px;padding:8px 16px;background:#111827;color:#fff;font:500 13px/1.4 var(--g-font);box-shadow:0 2px 10px rgba(0,0,0,.3)}\n.g-auth-bar .g-dot-live{width:8px;height:8px;border-radius:999px;background:#22c55e;box-shadow:0 0 0 3px rgba(34,197,94,.3)}\n.g-auth-bar .g-spacer{flex:1}\n.g-auth-bar .g-btn{min-height:32px;padding:4px 12px;font-size:13px}\n.g-auth-bar .g-btn-secondary{background:rgba(255,255,255,.12);color:#fff;border-color:transparent}\n.g-auth-outline{position:fixed;z-index:calc(var(--g-z) + 9);pointer-events:none;border:2px solid var(--g-primary);background:color-mix(in srgb,var(--g-primary) 12%,transparent);border-radius:4px;transition:all .06s linear}\n.g-auth-label{position:absolute;left:-2px;top:-24px;background:var(--g-primary);color:#fff;font:600 11px/1 var(--g-font);padding:5px 7px;border-radius:4px;white-space:nowrap;max-width:320px;overflow:hidden;text-overflow:ellipsis}\n.g-auth-outline.g-picked{border-style:dashed;border-color:#22c55e;background:rgba(34,197,94,.12)}\n.g-auth-outline.g-picked .g-auth-label{background:#16a34a}\n.g-highlight{position:fixed;z-index:calc(var(--g-z) + 8);pointer-events:none;border:2px dashed #f59e0b;background:rgba(245,158,11,.12);border-radius:4px}\n@media (max-width:480px){.g-card.g-modal,.g-panel{width:calc(100vw - 32px)}.g-inner{padding:16px}}\n`;\n","import type { Appearance, ProjectTheme } from \"@guidelytech/shared\";\nimport { STYLES } from \"./styles\";\n\nexport const HOST_ID = \"guidely-root\";\n\nexport interface HostHandle {\n host: HTMLElement;\n shadow: ShadowRoot;\n /** Polite live region for screen-reader announcements. */\n live: HTMLElement;\n announce(text: string): void;\n destroy(): void;\n}\n\nlet current: HostHandle | null = null;\n\n/** Default project theme used when the config has not loaded yet. */\nexport const DEFAULT_THEME: ProjectTheme = {\n primaryColor: \"#4f46e5\",\n backgroundColor: \"#ffffff\",\n textColor: \"#111827\",\n borderRadius: 12,\n fontFamily: \"Inter, system-ui, -apple-system, sans-serif\",\n};\n\n/** Returns (creating when needed) the single Shadow-DOM host appended to `document.body`. */\nexport function ensureHost(doc: Document = document): HostHandle {\n if (current && current.host.isConnected && current.host.ownerDocument === doc) return current;\n let host = doc.getElementById(HOST_ID) as HTMLElement | null;\n if (!host) {\n host = doc.createElement(\"div\");\n host.id = HOST_ID;\n host.setAttribute(\"data-guidely\", \"\");\n (doc.body || doc.documentElement).appendChild(host);\n }\n const shadow = host.shadowRoot ?? host.attachShadow({ mode: \"open\" });\n if (!shadow.querySelector(\"style[data-g-base]\")) {\n const style = doc.createElement(\"style\");\n style.setAttribute(\"data-g-base\", \"\");\n style.textContent = STYLES;\n shadow.appendChild(style);\n }\n let live = shadow.querySelector<HTMLElement>(\".g-live\");\n if (!live) {\n live = doc.createElement(\"div\");\n live.className = \"g-live\";\n live.setAttribute(\"aria-live\", \"polite\");\n live.setAttribute(\"aria-atomic\", \"true\");\n shadow.appendChild(live);\n }\n const liveEl = live;\n current = {\n host,\n shadow,\n live: liveEl,\n announce(text: string) {\n liveEl.textContent = \"\";\n setTimeout(() => {\n liveEl.textContent = text;\n }, 30);\n },\n destroy() {\n host?.remove();\n if (current?.host === host) current = null;\n },\n };\n return current;\n}\n\n/** Removes the host from the document (all overlays with it). */\nexport function destroyHost(): void {\n current?.destroy();\n const stray = typeof document !== \"undefined\" ? document.getElementById(HOST_ID) : null;\n stray?.remove();\n current = null;\n}\n\nexport type ResolvedThemeMode = \"light\" | \"dark\";\n\nfunction prefersDark(): boolean {\n try {\n return typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n } catch {\n return false;\n }\n}\n\nexport function prefersReducedMotion(): boolean {\n try {\n return typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n } catch {\n return false;\n }\n}\n\nexport interface ThemeVars {\n primary: string;\n bg: string;\n text: string;\n radius: number;\n font: string;\n z: number;\n overlay: number;\n mode: ResolvedThemeMode;\n animation: Appearance[\"animation\"];\n}\n\n/** Merges project theme + guide appearance into CSS custom property values. */\nexport function resolveTheme(theme: Partial<ProjectTheme> | null | undefined, appearance?: Partial<Appearance> | null): ThemeVars {\n const t = { ...DEFAULT_THEME, ...(theme || {}) };\n const a = appearance || {};\n const requested = a.theme ?? \"auto\";\n const mode: ResolvedThemeMode = requested === \"auto\" ? (prefersDark() ? \"dark\" : \"light\") : requested;\n const dark = mode === \"dark\";\n return {\n primary: a.primaryColor || t.primaryColor,\n bg: a.backgroundColor || (dark ? \"#1f2937\" : t.backgroundColor),\n text: a.textColor || (dark ? \"#f9fafb\" : t.textColor),\n radius: a.borderRadius ?? t.borderRadius,\n font: a.fontFamily || t.fontFamily,\n z: a.zIndex ?? 2147483000,\n overlay: a.overlayOpacity ?? 0.5,\n mode,\n animation: prefersReducedMotion() ? \"none\" : (a.animation ?? \"fade\"),\n };\n}\n\n/** Applies theme variables to a scope element. */\nexport function applyTheme(el: HTMLElement, vars: ThemeVars): void {\n el.style.setProperty(\"--g-primary\", vars.primary);\n el.style.setProperty(\"--g-bg\", vars.bg);\n el.style.setProperty(\"--g-text\", vars.text);\n el.style.setProperty(\"--g-radius\", `${vars.radius}px`);\n el.style.setProperty(\"--g-font\", vars.font);\n el.style.setProperty(\"--g-z\", String(vars.z));\n el.style.setProperty(\"--g-overlay\", String(vars.overlay));\n el.setAttribute(\"data-theme\", vars.mode);\n el.setAttribute(\"data-anim\", vars.animation);\n}\n\n/**\n * Creates a themed scope container inside the shadow root. Each guide/widget renders inside its\n * own scope so appearance settings never leak between guides.\n */\nexport function createScope(theme?: Partial<ProjectTheme> | null, appearance?: Partial<Appearance> | null, doc: Document = document): { el: HTMLElement; vars: ThemeVars; destroy(): void } {\n const handle = ensureHost(doc);\n const el = doc.createElement(\"div\");\n el.className = \"g-scope\";\n const vars = resolveTheme(theme, appearance);\n applyTheme(el, vars);\n handle.shadow.appendChild(el);\n let mq: MediaQueryList | null = null;\n const onChange = () => applyTheme(el, resolveTheme(theme, appearance));\n if ((appearance?.theme ?? \"auto\") === \"auto\" && typeof window !== \"undefined\" && typeof window.matchMedia === \"function\") {\n try {\n mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n mq.addEventListener?.(\"change\", onChange);\n } catch {\n mq = null;\n }\n }\n return {\n el,\n vars,\n destroy() {\n mq?.removeEventListener?.(\"change\", onChange);\n el.remove();\n },\n };\n}\n"],"mappings":"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","names":["HOST_ID"]}
|