glitchgrab 1.52.0 → 1.53.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/README.md +2 -0
- package/dist/index.js +1123 -517
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1123 -517
- package/dist/index.mjs.map +1 -1
- package/dist/server.d.mts +4 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +2 -0
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/error-boundary.tsx","../../report-ui/src/assist-response.ts","../src/redact.ts","../src/breadcrumbs.ts","../src/runtime.ts","../src/app-context.ts","../src/utils.ts","../src/dedup.ts","../src/capture.ts","../../report-ui/src/report-dialog.tsx","../../report-ui/src/annotation-canvas.tsx","../../report-ui/src/image-encode.ts","../../report-ui/src/assist-sheet.tsx","../../report-ui/src/types.ts","../../report-ui/src/attachments.ts","../../report-ui/src/labels.ts","../../report-ui/src/chat-markdown.tsx","../../report-ui/src/glitchgrab-problem.tsx","../../report-ui/src/shortcut.ts","../../report-ui/src/capture.ts","../../report-ui/src/assist-response.ts","../src/booking-dialog.tsx","../src/rejection.ts","../src/shortcut.ts","../src/report-button.tsx","../src/book-demo-button.tsx","../src/feedback-button.tsx","../src/use-reports.ts","../src/use-feedback.ts"],"sourcesContent":["\"use client\";\n\n// ─── Core (required) ─────────────────────────────────────\nexport { GlitchgrabProvider, useGlitchgrab } from \"./provider\";\n\n// ─── Optional Components ─────────────────────────────────\nexport { ReportButton } from \"./report-button\";\nexport { BookDemoButton } from \"./book-demo-button\";\nexport { FeedbackButton } from \"./feedback-button\";\nexport { GlitchgrabErrorBoundary } from \"./error-boundary\";\n\n// ─── Caught-error reporting ──────────────────────────────\n// Standalone form for call sites outside the provider tree (global-error.tsx)\n// or outside React entirely. Inside the tree, prefer useGlitchgrab().captureError.\nexport { captureError } from \"./capture\";\n\n// ─── App context ─────────────────────────────────────────\n// Key-values attached to every report (orgId, plan, feature flags). Standalone\n// form so non-React code can set them; also on useGlitchgrab().\nexport {\n setContext,\n setContexts,\n getAppContext,\n clearAppContext,\n} from \"./app-context\";\n\n// ─── Hooks ──────────────────────────────────────────────\nexport { useGlitchgrabReports, fetchGlitchgrabReports, useGlitchgrabActions } from \"./use-reports\";\nexport type { GlitchgrabReport } from \"./use-reports\";\nexport { useGlitchgrabFeedback, fetchGlitchgrabFeedback } from \"./use-feedback\";\nexport type { FeedbackQuery } from \"./use-feedback\";\n\n// ─── Breadcrumbs ─────────────────────────────────────────\nexport {\n addBreadcrumb,\n getBreadcrumbs,\n clearBreadcrumbs,\n initBreadcrumbs,\n} from \"./breadcrumbs\";\n\n// ─── Keyboard shortcut ───────────────────────────────────\nexport {\n GLITCHGRAB_SHORTCUT,\n GLITCHGRAB_SHORTCUT_MAC,\n getShortcutLabel,\n matchesShortcut,\n} from \"./shortcut\";\n\n// ─── Utilities ───────────────────────────────────────────\nexport { sanitizeUrl, captureContext, captureDeviceInfo, sendReport, sendFeedback, enhanceText } from \"./utils\";\nexport { computeSignature, shouldSkipDuplicate, clearDedupCache } from \"./dedup\";\n\n// ─── Types ───────────────────────────────────────────────\nexport type {\n CaptureErrorOptions,\n GlitchgrabConfig,\n GlitchgrabProviderProps,\n ReportPayload,\n ReportResult,\n ReportType,\n ReportSeverity,\n CapturedContext,\n DeviceInfo,\n RuntimeInfo,\n Breadcrumb,\n BreadcrumbType,\n UseGlitchgrabReturn,\n ReportButtonProps,\n FeedbackButtonProps,\n FeedbackPayload,\n FeedbackResult,\n GlitchgrabFeedback,\n GlitchgrabSession,\n} from \"./types\";\n","\"use client\";\n\nimport {\n createContext,\n useContext,\n useRef,\n useEffect,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport type {\n CaptureErrorOptions,\n FeedbackResult,\n GlitchgrabProviderProps,\n UseGlitchgrabReturn,\n ReportPayload,\n ReportResult,\n ReportType,\n} from \"./types\";\nimport { GlitchgrabErrorBoundary } from \"./error-boundary\";\nimport { ReportDialog, type GlitchgrabProblemParams } from \"@glitchgrab/report-ui\";\nimport { BookingDialog } from \"./booking-dialog\";\nimport { sanitizeUrl, captureContext, contextMetadata, sendReport, sendFeedback, captureDeviceInfo, enhanceText, assistTurn, findSimilarIssues, transcribeAudio, type EnhanceContext } from \"./utils\";\nimport {\n setContext as setContextInternal,\n setContexts as setContextsInternal,\n setRelease,\n} from \"./app-context\";\nimport { incrementErrorCount } from \"./runtime\";\nimport { computeSignature, shouldSkipDuplicate } from \"./dedup\";\nimport { describeRejection, isUnactionableRejection } from \"./rejection\";\nimport {\n captureError as captureErrorStandalone,\n matchesIgnorePatterns,\n registerCaptureConfig,\n} from \"./capture\";\nimport { GLITCHGRAB_SHORTCUT, getShortcutLabel, matchesShortcut } from \"./shortcut\";\nimport {\n initBreadcrumbs,\n addBreadcrumb as addBreadcrumbInternal,\n getBreadcrumbs,\n} from \"./breadcrumbs\";\n\nconst DEFAULT_BASE_URL = \"https://glitchgrab.dev\";\n\nconst GlitchgrabContext = createContext<UseGlitchgrabReturn | null>(null);\n\n/**\n * Hook to access Glitchgrab in your components.\n *\n * @example\n * ```tsx\n * const { reportBug, report, captureError, addBreadcrumb } = useGlitchgrab();\n *\n * // Report a bug\n * reportBug(\"Login button crashes on mobile\");\n *\n * // Report an error your own boundary already caught (e.g. app/error.tsx)\n * captureError(error, { digest: error.digest, boundary: \"next-app-router\" });\n *\n * // Report a feature request\n * report(\"FEATURE_REQUEST\", \"Add dark mode\");\n *\n * // Add a custom breadcrumb\n * addBreadcrumb(\"User clicked checkout\", { cartItems: \"3\" });\n * ```\n */\nexport function useGlitchgrab(): UseGlitchgrabReturn {\n const ctx = useContext(GlitchgrabContext);\n if (!ctx) {\n throw new Error(\"useGlitchgrab must be used within a GlitchgrabProvider\");\n }\n return ctx;\n}\n\nfunction GlitchgrabProviderInner({\n token,\n session: sessionProp,\n baseUrl,\n onError,\n onReportSent,\n breadcrumbs: enableBreadcrumbs = true,\n maxBreadcrumbs = 50,\n children,\n fallback,\n types,\n showSeverity,\n ignoreErrors,\n release,\n context: appContext,\n responseBodyOrigins,\n}: GlitchgrabProviderProps) {\n const visitedPagesRef = useRef<string[]>([]);\n\n // Hosts build `session` inline from their auth hook, so it is a new object on\n // every host render. Keyed on what it says instead: an unchanged session no\n // longer tears down and re-adds the error listeners, or rebuilds every\n // callback that reads it (#363).\n const sessionKey = sessionProp\n ? [\n sessionProp.userId,\n sessionProp.name,\n sessionProp.email,\n sessionProp.phone,\n sessionProp.avatarUrl,\n sessionProp.image,\n ]\n .map((v) => (v == null ? \"\" : String(v)))\n .join(\"\\u0000\")\n : \"\";\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const session = useMemo(() => sessionProp, [sessionKey]);\n\n // Same reasoning as the capture config below: written during render so a crash\n // on a child's first render still reports which build it came from.\n setRelease(release);\n if (appContext) setContextsInternal(appContext);\n\n // Publish config for the standalone `captureError` export.\n //\n // Written in the render body, not an effect: a crash during a child's *initial*\n // render unwinds to the framework boundary (Next's `error.tsx`) before any effect\n // commits, so an effect-based registration would leave `captureError` unconfigured\n // for exactly the case it exists to cover. The write is idempotent, so React's\n // strict-mode double-invoke and discarded renders are harmless. Never torn down on\n // unmount — `global-error.tsx` replaces the root layout, provider tree included.\n registerCaptureConfig({\n token,\n baseUrl,\n session,\n ignoreErrors,\n getVisitedPages: () => visitedPagesRef.current,\n onError,\n onReportSent,\n });\n\n // Initialize breadcrumbs\n useEffect(() => {\n if (enableBreadcrumbs) {\n initBreadcrumbs(maxBreadcrumbs, { responseBodyOrigins });\n }\n // Keyed on the joined origins, not the array — callers pass this inline, and\n // a fresh array identity each render would re-run the effect every render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enableBreadcrumbs, maxBreadcrumbs, responseBodyOrigins?.join(\",\")]);\n\n // Track page visits\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n\n const trackPage = () => {\n try {\n const sanitized = sanitizeUrl(window.location.href);\n const pages = visitedPagesRef.current;\n if (pages[pages.length - 1] !== sanitized) {\n pages.push(sanitized);\n if (pages.length > 20) {\n pages.splice(0, pages.length - 20);\n }\n }\n } catch {\n // Silently fail\n }\n };\n\n trackPage();\n const handlePopState = () => trackPage();\n window.addEventListener(\"popstate\", handlePopState);\n\n const origPushState = history.pushState.bind(history);\n const origReplaceState = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n origPushState(...args);\n trackPage();\n };\n history.replaceState = function (...args) {\n origReplaceState(...args);\n trackPage();\n };\n\n return () => {\n window.removeEventListener(\"popstate\", handlePopState);\n history.pushState = origPushState;\n history.replaceState = origReplaceState;\n };\n } catch {\n // Never crash\n }\n }, []);\n\n // Unhandled errors and rejections — skip in development\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n if (process.env.NODE_ENV === \"development\") return;\n\n // Matches chrome-extension://, safari-extension://, moz-extension://\n const EXTENSION_ORIGIN_RE = /\\b(?:chrome|safari|moz)-extension:\\/\\//;\n\n // Well-known extension-injected noise that carries no extension origin in\n // filename/stack, so EXTENSION_ORIGIN_RE can't catch it. Not app bugs.\n const KNOWN_NOISE_RE = [\n /Object Not Found Matching Id:\\d+, MethodName:update, ParamCount:\\d+/,\n ];\n\n const matchesIgnore = (message: string): boolean => {\n if (KNOWN_NOISE_RE.some((pattern) => pattern.test(message))) return true;\n return matchesIgnorePatterns(message, ignoreErrors);\n };\n\n const handleError = (event: ErrorEvent) => {\n try {\n // Ignore opaque cross-origin script errors — the browser masks these with no\n // stack, no filename, and no error object, so there is nothing actionable to report.\n const isOpaqueCrossOrigin =\n event.message === \"Script error.\" ||\n event.message === \"Script error\" ||\n (!event.error && !event.filename);\n if (isOpaqueCrossOrigin) {\n return;\n }\n\n // Caller-supplied ignore patterns — known-noisy signatures (e.g. browser\n // extension bridge errors) that aren't app bugs.\n if (matchesIgnore(event.message)) {\n return;\n }\n\n // Ignore benign ResizeObserver warnings — these are triggered by UI libraries\n // (Radix, cmdk, etc.) and are not actionable bugs.\n if (\n event.message === \"ResizeObserver loop completed with undelivered notifications.\" ||\n event.message === \"ResizeObserver loop limit exceeded\"\n ) {\n return;\n }\n\n // Ignore errors thrown by browser extensions — crypto wallets, ad blockers,\n // and other extensions run in the page's JS context but are not part of the app.\n if (\n (event.filename && EXTENSION_ORIGIN_RE.test(event.filename)) ||\n (event.error?.stack && EXTENSION_ORIGIN_RE.test(event.error.stack))\n ) {\n return;\n }\n // Counted before the snapshot, so a report says which error in the run\n // it was — the fifth crash reads very differently from the first.\n incrementErrorCount();\n const context = captureContext(visitedPagesRef.current);\n const sig = computeSignature({\n errorMessage: event.message,\n pageUrl: context.url,\n errorStack: event.error?.stack,\n });\n if (shouldSkipDuplicate(sig)) return;\n const payload: ReportPayload = {\n token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: event.message,\n errorStack: event.error?.stack,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n ...contextMetadata(context),\n filename: event.filename ?? \"\",\n lineno: String(event.lineno ?? \"\"),\n colno: String(event.colno ?? \"\"),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n },\n };\n sendReport(payload, baseUrl).then((result) => {\n if (result && onReportSent) onReportSent(result);\n });\n if (onError && event.error) onError(event.error);\n } catch {\n // Silently fail\n }\n };\n\n const handleRejection = (event: PromiseRejectionEvent) => {\n try {\n const reason = event.reason;\n // Non-Error reasons used to stringify to \"[object Object]\", discarding\n // every field and every chance of a stack.\n const description = describeRejection(reason);\n const errMsg = description.message;\n const errStack = description.stack;\n\n // Ignore generic cross-origin script errors.\n if (errMsg === \"Script error.\" || errMsg === \"Script error\") {\n return;\n }\n\n // Caller-supplied ignore patterns — known-noisy signatures (e.g. browser\n // extension bridge errors) that aren't app bugs.\n if (matchesIgnore(errMsg)) {\n return;\n }\n\n // Ignore unhandled rejections where the call chain passes through a browser\n // extension — these are the extension's own failures, not the app's.\n if (errStack && EXTENSION_ORIGIN_RE.test(errStack)) return;\n\n // No message and no stack — nothing a human or an AI could triage. Reporting\n // it only produces issues titled \"[object Object]\".\n if (isUnactionableRejection(description)) return;\n\n // Snapshot only once the rejection has survived every filter — an\n // ignored rejection must not inflate errorCount for the next report.\n incrementErrorCount();\n const context = captureContext(visitedPagesRef.current);\n\n const sig = computeSignature({\n errorMessage: errMsg,\n pageUrl: context.url,\n errorStack: errStack,\n });\n if (shouldSkipDuplicate(sig)) return;\n const payload: ReportPayload = {\n token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: errMsg,\n errorStack: errStack,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n ...contextMetadata(context),\n type: \"unhandledrejection\",\n ...(description.details ? { rejectionReason: description.details } : {}),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n },\n };\n sendReport(payload, baseUrl).then((result) => {\n if (result && onReportSent) onReportSent(result);\n });\n if (onError && reason instanceof Error) onError(reason);\n } catch {\n // Silently fail\n }\n };\n\n window.addEventListener(\"error\", handleError);\n window.addEventListener(\"unhandledrejection\", handleRejection);\n\n return () => {\n window.removeEventListener(\"error\", handleError);\n window.removeEventListener(\"unhandledrejection\", handleRejection);\n };\n } catch {\n // Never crash\n }\n }, [token, baseUrl, onError, onReportSent, session, ignoreErrors]);\n\n const report = useCallback(\n async (\n type: ReportType,\n description: string,\n metadata?: Record<string, string>\n ): Promise<ReportResult | null> => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const payload: ReportPayload = {\n token,\n source: \"SDK_USER_REPORT\",\n type,\n description,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n ...contextMetadata(context),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n ...metadata,\n },\n };\n const result = await sendReport(payload, baseUrl);\n if (result && onReportSent) onReportSent(result);\n return result;\n } catch {\n return null;\n }\n },\n [token, baseUrl, onReportSent, session]\n );\n\n const reportBug = useCallback(\n (description: string, metadata?: Record<string, string>) =>\n report(\"BUG\", description, metadata),\n [report]\n );\n\n /**\n * \"Problem with Glitchgrab?\" (#366) — a report about the dialog itself, sent\n * to Glitchgrab's own repo with the same session a host report carries:\n * pages visited, breadcrumbs, device info and the dialog's screenshots. Only\n * wired when the project owner opted in, because it leaves their project.\n */\n const reportGlitchgrabProblem = useCallback(\n async (params: GlitchgrabProblemParams): Promise<ReportResult | null> => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const body = JSON.stringify({\n ...params,\n pageUrl: context.url,\n userAgent: context.userAgent,\n deviceInfo: context.deviceInfo ?? undefined,\n visitedPages: context.visitedPages,\n breadcrumbs: context.breadcrumbs,\n ...(session?.userId ? { reporterId: session.userId } : {}),\n ...(session?.name ? { reporterName: String(session.name) } : {}),\n ...(session?.email ? { reporterEmail: String(session.email) } : {}),\n });\n const res = await fetch(`${baseUrl}/api/v1/sdk/glitchgrab-report`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", Authorization: `Bearer ${token}` },\n body,\n // keepalive caps the body at 64KB — screenshots blow past it.\n ...(body.length < 60_000 ? { keepalive: true } : {}),\n });\n const json = (await res.json().catch(() => null)) as {\n success?: boolean;\n error?: string;\n data?: Omit<ReportResult, \"success\">;\n } | null;\n if (!res.ok || !json?.success) {\n return { success: false, message: json?.error ?? \"Couldn't send it\" };\n }\n return { success: true, ...json.data };\n } catch {\n return null;\n }\n },\n [token, baseUrl, session]\n );\n\n const feedback = useCallback(\n async (\n rating: number,\n message?: string,\n metadata?: Record<string, string>\n ): Promise<FeedbackResult | null> => {\n try {\n const context = captureContext(visitedPagesRef.current);\n return await sendFeedback(\n {\n token,\n rating,\n message,\n pageUrl: context.url,\n userAgent: context.userAgent,\n metadata: {\n timestamp: context.timestamp,\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n ...metadata,\n },\n },\n baseUrl\n );\n } catch {\n return null;\n }\n },\n [token, baseUrl, session]\n );\n\n // One dialog, not two — this opens the same report dialog straight onto its\n // RATING tile. A user answering \"what's on your mind?\" shouldn't have to know\n // in advance whether their thought is a bug or a compliment.\n const openFeedbackDialog = useCallback(() => {\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(\n new CustomEvent(\"glitchgrab:open-report\", { detail: { type: \"RATING\" } })\n );\n }\n }, []);\n\n // Stable identity — the documented usage puts this in a `useEffect` dep array.\n // Reads config from the module registry, which this render already refreshed.\n const captureError = useCallback(\n (error: unknown, options?: CaptureErrorOptions) => {\n captureErrorStandalone(error, options);\n },\n []\n );\n\n const setContext = useCallback((key: string, value: unknown) => {\n setContextInternal(key, value);\n }, []);\n\n const setContexts = useCallback((values: Record<string, unknown>) => {\n setContextsInternal(values);\n }, []);\n\n const addBreadcrumb = useCallback(\n (message: string, data?: Record<string, string>) => {\n addBreadcrumbInternal(\"custom\", message, data);\n },\n []\n );\n\n /**\n * Who the host's server vouched for (`signSession` in `glitchgrab/server`).\n * Sent with every paid browser call — AI chat, enhance, similar issues, voice —\n * so a project with signed users on can tell its own users from someone who\n * lifted the token out of the bundle.\n */\n const signedUserId = session?.userId;\n const signature = typeof session?.signature === \"string\" ? session.signature : null;\n const identity = useMemo(\n () => ({ userId: signedUserId ?? null, signature }),\n [signedUserId, signature]\n );\n\n const enhance = useCallback(\n async (text: string, screenshot?: string | null): Promise<string> => {\n try {\n const ctx = captureContext(visitedPagesRef.current);\n const context: EnhanceContext = {\n url: ctx.url,\n visitedPages: ctx.visitedPages.slice(-5),\n breadcrumbs: ctx.breadcrumbs.slice(-10).map((b) => ({ type: b.type, message: b.message })),\n };\n return await enhanceText(text, token, baseUrl, screenshot, context, identity);\n } catch {\n return text;\n }\n },\n [token, baseUrl, identity]\n );\n\n /**\n * One assistant turn. Carries the same session context the enhance button\n * sends — the page, where they had been, what they clicked — because that is\n * most of what a developer would have asked for anyway.\n */\n const assist = useCallback(\n async (params: {\n messages: { role: \"user\" | \"assistant\"; content: string }[];\n conversationId: string | null;\n /** Every image on the report, newest last (#352). */\n screenshots?: string[];\n /** @deprecated Sent beside `screenshots` for older server builds. */\n screenshot?: string | null;\n context?: Record<string, unknown> | null;\n }) => {\n const ctx = captureContext(visitedPagesRef.current);\n return assistTurn(\n {\n ...params,\n // Same identity the report itself carries, from the same prop.\n reporter: session\n ? {\n key: session.userId,\n name: session.name ? String(session.name) : null,\n email: session.email ? String(session.email) : null,\n ...(signature ? { signature } : {}),\n }\n : undefined,\n context: {\n ...(params.context ?? {}),\n url: ctx.url,\n visitedPages: ctx.visitedPages.slice(-5),\n breadcrumbs: ctx.breadcrumbs\n .slice(-25)\n .map((b) => ({ type: b.type, message: b.message })),\n },\n },\n token,\n baseUrl\n );\n },\n [token, baseUrl, session]\n );\n\n // Plain form's \"is this already filed?\" on Send. Wired beside `assist`\n // because the owner's AI-assist switch is its consent too; the server\n // re-checks that switch on every call.\n const findSimilar = useCallback(\n (description: string) => findSimilarIssues(description, token, baseUrl, identity),\n [token, baseUrl, identity]\n );\n\n const transcribe = useCallback(\n async (blob: Blob): Promise<string> => {\n try {\n return await transcribeAudio(blob, token, baseUrl, identity);\n } catch {\n return \"\";\n }\n },\n [token, baseUrl, identity]\n );\n\n const openReportDialog = useCallback((options?: { description?: string; type?: ReportType }) => {\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(new CustomEvent(\"glitchgrab:open-report\", { detail: options }));\n }\n }, []);\n\n /**\n * Tell the Chrome extension this page already has a report dialog.\n *\n * The extension binds the same shortcut on every page that ISN'T running the\n * SDK — someone else's dashboard, a staging site, a video call — so a bug can\n * be filed anywhere. Without a marker it cannot tell those apart, and a host\n * app that embeds the SDK would open two dialogs on one keystroke.\n *\n * An attribute rather than a global: content scripts run in an isolated\n * world and cannot see page JavaScript, but they do share the DOM.\n */\n useEffect(() => {\n try {\n if (typeof document === \"undefined\") return;\n document.documentElement.setAttribute(\"data-glitchgrab-sdk\", \"1\");\n return () => document.documentElement.removeAttribute(\"data-glitchgrab-sdk\");\n } catch {\n // Never crash\n }\n }, []);\n\n /**\n * Which project this app's reports go to.\n *\n * Fixed for the SDK — one token, one repo — but until now invisible, and\n * invisible is indistinguishable from wrong to whoever is about to press\n * send. Shown read-only for the same reason it is not a dropdown: an end\n * user of the host app has no business choosing, or even seeing, which other\n * projects exist.\n */\n const [projectName, setProjectName] = useState<string | null>(null);\n\n /**\n * Whether this project's owner turned the AI report assistant on (#330).\n * Starts false so the dialog never flashes an affordance it may not keep, and\n * is only ever a UI hint — /api/v1/ai/report-chat re-checks the same column\n * on every call.\n */\n const [aiAssist, setAiAssist] = useState(false);\n\n /**\n * Whether the owner switched on \"Problem with Glitchgrab?\" (#366). Same\n * contract as `aiAssist`: starts false, a UI hint only —\n * /api/v1/sdk/glitchgrab-report re-checks the column on every call.\n */\n const [glitchgrabReport, setGlitchgrabReport] = useState(false);\n\n /**\n * The owner's signed-users mode. A UI hint like `aiAssist` — every paid route\n * re-checks the signature itself. Absent on older servers, which read as OFF.\n */\n const [signedUsers, setSignedUsers] = useState<\"OFF\" | \"WARN\" | \"ENFORCE\">(\"OFF\");\n\n /**\n * Enforced and this user is unsigned: the AI features would only answer\n * \"unsigned\", so they are not offered. The plain report form still files —\n * a missing signature must never cost the host a bug report.\n */\n const aiBlockedUnsigned = signedUsers === \"ENFORCE\" && !signature;\n\n /**\n * Demo booking, opened from the host app's own \"Book a demo\" button.\n *\n * State lives here rather than in the button so a host can trigger it from\n * anywhere — a pricing table, a nav item, the end of a blog post — without\n * every one of those places owning a dialog.\n */\n const [bookingOpen, setBookingOpen] = useState(false);\n const openBookingDialog = useCallback(() => setBookingOpen(true), []);\n\n useEffect(() => {\n let cancelled = false;\n fetch(`${baseUrl}/api/v1/sdk/project`, {\n headers: { Authorization: `Bearer ${token}` },\n })\n .then((r) => (r.ok ? r.json() : null))\n .then((json) => {\n if (cancelled || !json?.success || !json.data?.name) return;\n setProjectName(json.data.name as string);\n setAiAssist(json.data.aiAssist === true);\n setGlitchgrabReport(json.data.glitchgrabReport === true);\n const mode = json.data.signedUsers;\n setSignedUsers(mode === \"WARN\" || mode === \"ENFORCE\" ? mode : \"OFF\");\n })\n .catch(() => {\n // The dialog simply omits the line — never block reporting on it.\n });\n return () => { cancelled = true; };\n }, [baseUrl, token]);\n\n // Tell the developer, not the end user: once per mode change, development only.\n useEffect(() => {\n try {\n if (signedUsers === \"OFF\" || signature || !session) return;\n if (typeof process === \"undefined\" || process.env?.NODE_ENV !== \"development\") return;\n console.warn(\n signedUsers === \"ENFORCE\"\n ? \"[glitchgrab] This project enforces signed users and `session.signature` is missing — AI features are hidden. Sign it on your server with signSession() from \\\"glitchgrab/server\\\".\"\n : \"[glitchgrab] This project warns on unsigned users and `session.signature` is missing. Sign it on your server with signSession() from \\\"glitchgrab/server\\\" before the owner switches to Enforce.\"\n );\n } catch {\n // Never crash\n }\n }, [signedUsers, signature, session]);\n\n // Global keyboard shortcut: Cmd+Shift+G (Mac) / Ctrl+Shift+G (Windows/Linux)\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (matchesShortcut(e)) {\n e.preventDefault();\n openReportDialog();\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n } catch {\n // Never crash\n }\n }, [openReportDialog]);\n\n // Who the dialog shows as the reporter. `session` is the SDK's identity\n // primitive; the avatar is read off the extra fields GlitchgrabSession allows,\n // since auth libraries name it `image` (NextAuth) or `avatarUrl`.\n const reporter = useMemo(() => {\n if (!session) return null;\n const avatar = session.avatarUrl ?? session.image;\n return {\n name: session.name,\n email: session.email,\n avatarUrl: typeof avatar === \"string\" ? avatar : null,\n };\n }, [session]);\n\n // Starts as the non-Mac label so SSR and the first client render agree,\n // then resolves to the real platform label after mount.\n const [shortcutLabel, setShortcutLabel] = useState(GLITCHGRAB_SHORTCUT);\n useEffect(() => {\n setShortcutLabel(getShortcutLabel());\n }, []);\n\n return (\n <GlitchgrabContext.Provider\n value={{\n token,\n baseUrl: baseUrl ?? DEFAULT_BASE_URL,\n reportBug,\n report,\n captureError,\n setContext,\n setContexts,\n sendFeedback: feedback,\n openFeedbackDialog,\n addBreadcrumb,\n openReportDialog,\n openBookingDialog,\n enhanceText: enhance,\n shortcutLabel,\n }}\n >\n <GlitchgrabErrorBoundary\n token={token}\n baseUrl={baseUrl}\n session={session}\n onError={onError}\n fallback={fallback}\n visitedPages={visitedPagesRef.current}\n >\n {children}\n </GlitchgrabErrorBoundary>\n <BookingDialog\n token={token}\n baseUrl={baseUrl ?? DEFAULT_BASE_URL}\n open={bookingOpen}\n onClose={() => setBookingOpen(false)}\n />\n <ReportDialog\n report={report}\n sendFeedback={feedback}\n // enhance-text on a token needs the owner's AI-assist switch now, so\n // the link is only offered where it can answer.\n enhanceText={aiAssist && !aiBlockedUnsigned ? enhance : undefined}\n assist={aiAssist && !aiBlockedUnsigned ? assist : undefined}\n findSimilarIssues={aiAssist && !aiBlockedUnsigned ? findSimilar : undefined}\n reportGlitchgrabProblem={glitchgrabReport ? reportGlitchgrabProblem : undefined}\n transcribeAudio={aiBlockedUnsigned ? undefined : transcribe}\n types={types}\n showSeverity={showSeverity}\n reporter={reporter}\n headerSlot={\n projectName ? (\n <div style={{ fontSize: 11, color: \"#9aa0a6\" }}>\n Reporting to <strong style={{ color: \"#e5e5e5\" }}>{projectName}</strong>\n </div>\n ) : null\n }\n />\n </GlitchgrabContext.Provider>\n );\n}\n\nexport function GlitchgrabProvider(props: GlitchgrabProviderProps) {\n // No token = passthrough (SDK disabled)\n if (!props.token) return <>{props.children}</>;\n\n const resolvedProps = {\n ...props,\n baseUrl: props.baseUrl || DEFAULT_BASE_URL,\n };\n\n try {\n return <GlitchgrabProviderInner {...resolvedProps} />;\n } catch {\n return <>{props.children}</>;\n }\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { GlitchgrabSession } from \"./types\";\nimport { sendReport } from \"./utils\";\nimport { buildCapturedErrorPayload } from \"./capture\";\n\ninterface ErrorBoundaryProps {\n token: string;\n baseUrl?: string;\n session?: GlitchgrabSession | null;\n onError?: (error: Error) => void;\n fallback?: React.ReactNode;\n visitedPages: string[];\n children: React.ReactNode;\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n}\n\nexport class GlitchgrabErrorBoundary extends React.Component<\n ErrorBoundaryProps,\n ErrorBoundaryState\n> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(): ErrorBoundaryState {\n return { hasError: true };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n try {\n // Same payload shape and dedup as `captureError` — this boundary is just\n // another caught-error source. Config comes from props, not the module\n // registry, so the boundary works standalone (it's exported on its own).\n // No `ignoreErrors` by design: those are a provider prop this component\n // cannot see when mounted directly by a host app.\n const payload = buildCapturedErrorPayload(\n error,\n { componentStack: errorInfo.componentStack ?? undefined },\n {\n token: this.props.token,\n baseUrl: this.props.baseUrl,\n session: this.props.session,\n getVisitedPages: () => this.props.visitedPages,\n },\n \"GlitchgrabErrorBoundary\"\n );\n\n if (payload) {\n sendReport(payload, this.props.baseUrl);\n }\n\n if (this.props.onError) {\n this.props.onError(error);\n }\n } catch {\n // Never crash the host app\n }\n }\n\n render(): React.ReactNode {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n // Re-render children — allows recovery from transient errors\n return this.props.children;\n }\n\n return this.props.children;\n }\n}\n","import type { AssistTurnResult } from \"./types\";\n\n/**\n * Turning the `/api/v1/ai/report-chat` response into what the sheet renders —\n * one copy for every host.\n *\n * The SDK, the Chrome extension and GlitchRecord each mapped it by hand, and\n * GlitchRecord's copy kept only question/report: its sheet never got the\n * \"Yes, that's it\" chip, \"our team is already on #N\", or an answer from the\n * project's guides. A field added here reaches all three.\n *\n * React-free on purpose: GlitchRecord's Electron main process imports it.\n */\n\n/** Shown when the assistant cannot be reached — the plain form takes over. */\nexport const ASSIST_OFFLINE_MESSAGE =\n \"The assistant is unavailable — write your report below and send it as normal.\";\n\nexport function assistOffline(): AssistTurnResult {\n return { conversationId: null, question: null, report: null, degraded: ASSIST_OFFLINE_MESSAGE };\n}\n\ntype IssueRef = { number: number; title: string; url: string; status?: string };\n\ninterface ReportChatEnvelope {\n success?: boolean;\n error?: string;\n retryable?: boolean;\n data?: {\n conversationId?: string | null;\n question?: string | null;\n options?: unknown;\n report?: string | null;\n duplicate?: IssueRef | null;\n related?: IssueRef | null;\n solved?: string | null;\n aboutGlitchgrab?: boolean;\n };\n}\n\n/**\n * @param ok `response.ok`\n * @param body the parsed JSON body, or `null` when it was not JSON\n */\nexport function toAssistTurnResult(ok: boolean, body: unknown): AssistTurnResult {\n const envelope = (body ?? null) as ReportChatEnvelope | null;\n if (!ok || !envelope?.success) {\n return {\n ...assistOffline(),\n // The server words why (cap, rate limit, switched off). An hourly limit\n // keeps the assistant button for this report.\n degraded: envelope?.error ?? ASSIST_OFFLINE_MESSAGE,\n retryable: envelope?.retryable === true,\n };\n }\n const d = envelope.data ?? {};\n return {\n conversationId: d.conversationId ?? null,\n question: d.question ?? null,\n options: Array.isArray(d.options)\n ? d.options.filter((o): o is string => typeof o === \"string\")\n : [],\n report: d.report ?? null,\n duplicate: d.duplicate ?? null,\n related: d.related ?? null,\n solved: d.solved ?? null,\n aboutGlitchgrab: d.aboutGlitchgrab === true,\n degraded: null,\n };\n}\n","/**\n * Redaction for anything scraped off the wire. Error response bodies are the\n * one place the SDK copies server output verbatim, and servers echo back tokens,\n * emails and password-reset links in their error envelopes.\n */\n\nconst SENSITIVE_KEY_RE =\n /(pass|pwd|secret|token|auth|session|cookie|credential|apikey|api_key|access_key|private|signature|otp|pin|cvv|card|ssn|aadhaar|pan)/i;\n\nconst EMAIL_RE = /[\\w.+-]+@[\\w-]+\\.[\\w.-]+/g;\nconst JWT_RE = /\\beyJ[\\w-]{8,}\\.[\\w-]{8,}\\.[\\w-]{8,}\\b/g;\nconst BEARER_RE = /\\b(bearer\\s+)[\\w-.~+/]{12,}=*/gi;\n\n/** Longest error body kept. Enough for a stack or a validation list, not a page. */\nexport const MAX_BODY_LENGTH = 500;\n\nfunction redactString(value: string): string {\n return value\n .replace(JWT_RE, \"[REDACTED]\")\n .replace(BEARER_RE, \"$1[REDACTED]\")\n .replace(EMAIL_RE, \"[REDACTED_EMAIL]\");\n}\n\nfunction redactValue(value: unknown, depth: number): unknown {\n if (depth > 4) return \"[DEPTH]\";\n if (value === null || value === undefined) return value;\n if (typeof value === \"string\") return redactString(value);\n if (typeof value === \"number\" || typeof value === \"boolean\") return value;\n if (Array.isArray(value)) return value.slice(0, 20).map((v) => redactValue(v, depth + 1));\n if (typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [key, inner] of Object.entries(value as Record<string, unknown>)) {\n out[key] = SENSITIVE_KEY_RE.test(key) ? \"[REDACTED]\" : redactValue(inner, depth + 1);\n }\n return out;\n }\n return String(value);\n}\n\n/**\n * Redact and truncate a response body for breadcrumb metadata.\n * JSON is walked key-by-key so sensitive fields are dropped by name; anything\n * else is treated as opaque text and only pattern-scrubbed. Never throws.\n */\nexport function redactBody(body: string, maxLength: number = MAX_BODY_LENGTH): string {\n try {\n const trimmed = body.trim();\n if (!trimmed) return \"\";\n\n let result: string;\n try {\n result = JSON.stringify(redactValue(JSON.parse(trimmed), 0));\n } catch {\n // Not JSON — HTML error pages, plain text, stack dumps.\n result = redactString(trimmed);\n }\n\n return result.length > maxLength ? `${result.slice(0, maxLength)}…[truncated]` : result;\n } catch {\n return \"\";\n }\n}\n","import type { Breadcrumb, BreadcrumbType } from \"./types\";\nimport { redactBody } from \"./redact\";\n\nconst MAX_DEFAULT = 50;\n\nlet breadcrumbs: Breadcrumb[] = [];\nlet maxBreadcrumbs = MAX_DEFAULT;\nlet initialized = false;\n\n/**\n * Extra origins whose error bodies may be captured. Same-origin is always\n * allowed; everything else must be listed explicitly.\n */\nlet responseBodyOrigins: string[] = [];\n\nexport interface BreadcrumbOptions {\n /**\n * Additional origins to capture error response bodies from, e.g.\n * `[\"https://api.myapp.com\"]`. Same-origin requests are always captured.\n */\n responseBodyOrigins?: string[];\n}\n\n/**\n * Error response bodies are only read for endpoints the host app owns.\n *\n * A 422 from your own API echoes your own validation errors. A 422 from Stripe,\n * Auth0 or an analytics vendor echoes whatever *they* chose to put in it — dates\n * of birth, phone numbers, addresses — under field names no key-based redactor\n * can anticipate. That body would end up in a GitHub issue. Same-origin is the\n * line that separates \"our error shape\" from \"someone else's payload\"; anything\n * beyond it has to be named explicitly.\n */\nfunction mayCaptureBody(url: string): boolean {\n try {\n if (typeof window === \"undefined\") return false;\n const origin = new URL(url, window.location.href).origin;\n if (origin === window.location.origin) return true;\n return responseBodyOrigins.includes(origin);\n } catch {\n return false;\n }\n}\n\nexport function initBreadcrumbs(max?: number, options?: BreadcrumbOptions) {\n // Applied before the early return so a later provider can widen the allowlist\n // even though the interceptors are only installed once.\n if (options?.responseBodyOrigins?.length) {\n responseBodyOrigins = Array.from(\n new Set([...responseBodyOrigins, ...options.responseBodyOrigins])\n );\n }\n if (initialized) return;\n maxBreadcrumbs = max ?? MAX_DEFAULT;\n\n try {\n if (typeof window === \"undefined\") return;\n interceptConsole();\n interceptFetch();\n interceptXhr();\n interceptNavigation();\n interceptClicks();\n initialized = true;\n } catch {\n // Never crash\n }\n}\n\nexport function addBreadcrumb(\n type: BreadcrumbType,\n message: string,\n data?: Record<string, string>\n) {\n try {\n breadcrumbs.push({\n type,\n message: message.slice(0, 200),\n timestamp: new Date().toISOString(),\n data,\n });\n if (breadcrumbs.length > maxBreadcrumbs) {\n breadcrumbs = breadcrumbs.slice(-maxBreadcrumbs);\n }\n } catch {\n // Never crash\n }\n}\n\nexport function getBreadcrumbs(): Breadcrumb[] {\n return [...breadcrumbs];\n}\n\nexport function clearBreadcrumbs() {\n breadcrumbs = [];\n}\n\n/** Test-only — reset the cross-origin body allowlist. */\nexport function clearResponseBodyOrigins() {\n responseBodyOrigins = [];\n}\n\n// ─── Console Interception ────────────────────────────────\n\nfunction interceptConsole() {\n const origLog = console.log;\n const origWarn = console.warn;\n const origError = console.error;\n\n console.log = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[log] ${argsToString(args)}`);\n origLog.apply(console, args);\n };\n\n console.warn = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[warn] ${argsToString(args)}`);\n origWarn.apply(console, args);\n };\n\n console.error = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[error] ${argsToString(args)}`);\n origError.apply(console, args);\n };\n}\n\n/** Longest text a console breadcrumb keeps. */\nconst CONSOLE_TEXT_MAX = 200;\n\nfunction argsToString(args: unknown[]): string {\n try {\n return args\n .map((a) => {\n if (typeof a === \"string\") return a.slice(0, CONSOLE_TEXT_MAX);\n if (a instanceof Error) return a.message;\n try {\n return previewJson(a, CONSOLE_TEXT_MAX);\n } catch {\n return String(a);\n }\n })\n .join(\" \")\n .slice(0, CONSOLE_TEXT_MAX);\n } catch {\n return \"[unknown]\";\n }\n}\n\n/**\n * `JSON.stringify`, but it stops writing once the output passes `max`.\n *\n * Every console call in the host app runs through here, on the host's own\n * thread. `JSON.stringify` cannot stop early, so logging a 5,000-row array — or\n * a DOM node, whose React fiber links back into the whole tree — serialised all\n * of it to keep 200 characters (#363). For plain data the output is identical\n * to `JSON.stringify` up to the cut; a cycle is written as \"[Circular]\" instead\n * of throwing.\n */\nexport function previewJson(value: unknown, max: number): string {\n let out = \"\";\n const path = new WeakSet<object>();\n\n const write = (input: unknown, inArray: boolean): void => {\n if (out.length > max) return;\n let v = input;\n if (v !== null && typeof v === \"object\" && typeof (v as { toJSON?: unknown }).toJSON === \"function\") {\n v = (v as { toJSON: () => unknown }).toJSON();\n }\n if (v === null) {\n out += \"null\";\n return;\n }\n switch (typeof v) {\n case \"string\":\n out += JSON.stringify(v.length > max ? v.slice(0, max) : v);\n return;\n case \"number\":\n out += Number.isFinite(v) ? String(v) : \"null\";\n return;\n case \"boolean\":\n case \"bigint\":\n out += String(v);\n return;\n case \"object\":\n break;\n default:\n // undefined, functions and symbols: dropped from objects, null in arrays.\n if (inArray) out += \"null\";\n return;\n }\n\n const obj = v as object;\n if (path.has(obj)) {\n out += '\"[Circular]\"';\n return;\n }\n path.add(obj);\n if (Array.isArray(obj)) {\n out += \"[\";\n for (let i = 0; i < obj.length && out.length <= max; i++) {\n if (i > 0) out += \",\";\n write(obj[i], true);\n }\n out += \"]\";\n } else {\n out += \"{\";\n let first = true;\n for (const key in obj) {\n if (out.length > max) break;\n if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;\n const child = (obj as Record<string, unknown>)[key];\n if (child === undefined || typeof child === \"function\" || typeof child === \"symbol\") continue;\n out += `${first ? \"\" : \",\"}${JSON.stringify(key)}:`;\n first = false;\n write(child, false);\n }\n out += \"}\";\n }\n // Only a cycle is circular — the same object twice in one value is not.\n path.delete(obj);\n };\n\n write(value, false);\n return out;\n}\n\n// ─── HTTP Interception ───────────────────────────────────\n\n/**\n * Read the body of a failed response without consuming it. `clone()` is what\n * makes this safe — the app still gets an unread body. Only non-2xx responses\n * are read: a \"→ 500\" with no cause is not worth the breadcrumb it's written on,\n * but cloning every successful response would double-buffer real traffic.\n */\nasync function readErrorBody(response: Response, url: string): Promise<string> {\n try {\n if (response.ok) return \"\";\n if (!mayCaptureBody(url)) return \"\";\n const text = await response.clone().text();\n return redactBody(text);\n } catch {\n return \"\";\n }\n}\n\nfunction interceptFetch() {\n const origFetch = window.fetch;\n\n (window.fetch as (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>) = async function (input, init) {\n const url =\n typeof input === \"string\"\n ? input\n : input instanceof URL\n ? input.toString()\n : input instanceof Request\n ? input.url\n : String(input);\n const method = init?.method ?? \"GET\";\n const start = Date.now();\n\n try {\n const response = await origFetch(\n input as Parameters<typeof origFetch>[0],\n init,\n );\n const body = await readErrorBody(response, url);\n addBreadcrumb(\"api\", `${method} ${url.slice(0, 100)} → ${response.status}`, {\n method,\n status: String(response.status),\n duration: `${Date.now() - start}ms`,\n ...(body ? { responseBody: body } : {}),\n });\n return response;\n } catch (err) {\n addBreadcrumb(\"api\", `${method} ${url.slice(0, 100)} → FAILED`, {\n method,\n error: err instanceof Error ? err.message : \"unknown\",\n duration: `${Date.now() - start}ms`,\n });\n throw err;\n }\n };\n}\n\n/**\n * axios, and every library built on it, uses XMLHttpRequest in the browser — not\n * fetch. Without this patch an axios-based app records zero API breadcrumbs and\n * every report arrives with no idea which request preceded the crash.\n */\nfunction interceptXhr() {\n if (typeof XMLHttpRequest === \"undefined\") return;\n\n const origOpen = XMLHttpRequest.prototype.open;\n const origSend = XMLHttpRequest.prototype.send;\n\n interface TrackedXhr extends XMLHttpRequest {\n __ggMethod?: string;\n __ggUrl?: string;\n __ggStart?: number;\n __ggListening?: boolean;\n }\n\n // The listener is attached on open(), not send(): open() is where the method\n // and URL become known, and an XHR that is opened and then aborted before send\n // still deserves the breadcrumb.\n //\n // XHR objects are reusable — open/send/open/send on one instance is legal, and\n // a library may call open() twice before sending. Attaching per open() would\n // leave a stale listener that fires on the *next* request's loadend and writes\n // a breadcrumb with the previous method and URL. One listener per instance,\n // reading __ggMethod/__ggUrl live, avoids that: it always describes the request\n // that actually just finished.\n XMLHttpRequest.prototype.open = function (\n this: TrackedXhr,\n method: string,\n url: string | URL,\n ...rest: unknown[]\n ) {\n try {\n this.__ggMethod = method;\n this.__ggUrl = typeof url === \"string\" ? url : url.toString();\n\n const record = () => {\n try {\n const recordedMethod = this.__ggMethod ?? \"GET\";\n const recordedUrl = (this.__ggUrl ?? \"\").slice(0, 100);\n const duration = `${Date.now() - (this.__ggStart ?? Date.now())}ms`;\n\n // status 0 means the request never completed — offline, CORS, aborted.\n if (!this.status) {\n addBreadcrumb(\"api\", `${recordedMethod} ${recordedUrl} → FAILED`, {\n method: recordedMethod,\n duration,\n });\n return;\n }\n\n const failed = this.status < 200 || this.status >= 300;\n const body = failed && mayCaptureBody(this.__ggUrl ?? \"\") ? readXhrBody(this) : \"\";\n addBreadcrumb(\"api\", `${recordedMethod} ${recordedUrl} → ${this.status}`, {\n method: recordedMethod,\n status: String(this.status),\n duration,\n ...(body ? { responseBody: body } : {}),\n });\n } catch {\n // Never crash\n }\n };\n\n if (!this.__ggListening) {\n this.__ggListening = true;\n this.addEventListener(\"loadend\", record);\n }\n } catch {\n // Never crash\n }\n return (origOpen as unknown as (...args: unknown[]) => void).apply(this, [\n method,\n url,\n ...rest,\n ]);\n } as typeof XMLHttpRequest.prototype.open;\n\n XMLHttpRequest.prototype.send = function (this: TrackedXhr, ...args: unknown[]) {\n try {\n this.__ggStart = Date.now();\n } catch {\n // Never crash\n }\n return (origSend as unknown as (...args: unknown[]) => void).apply(this, args);\n } as typeof XMLHttpRequest.prototype.send;\n}\n\n/**\n * `responseText` throws on a `responseType` of \"blob\"/\"arraybuffer\"/\"json\" —\n * reading it defensively keeps a binary download from breaking the breadcrumb.\n */\nfunction readXhrBody(xhr: XMLHttpRequest): string {\n try {\n if (xhr.responseType && xhr.responseType !== \"text\" && xhr.responseType !== \"json\") return \"\";\n const raw = xhr.responseType === \"json\" ? JSON.stringify(xhr.response) : xhr.responseText;\n return raw ? redactBody(raw) : \"\";\n } catch {\n return \"\";\n }\n}\n\n// ─── Navigation Interception ─────────────────────────────\n\nfunction interceptNavigation() {\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n origPush(...args);\n addBreadcrumb(\"navigation\", `Navigate to ${window.location.pathname}`);\n };\n\n history.replaceState = function (...args) {\n origReplace(...args);\n addBreadcrumb(\"navigation\", `Replace to ${window.location.pathname}`);\n };\n\n window.addEventListener(\"popstate\", () => {\n addBreadcrumb(\"navigation\", `Back/Forward to ${window.location.pathname}`);\n });\n}\n\n// ─── Click Interception ──────────────────────────────────\n\n/** Longest label a click breadcrumb keeps. */\nconst CLICK_TEXT_MAX = 50;\n\n/** Text nodes read before giving up on finding `max` visible characters. */\nconst CLICK_TEXT_NODE_LIMIT = 500;\n\n/**\n * The first `max` characters of an element's text, without building all of it.\n *\n * A click lands on whatever is under the pointer — often a table row, a card\n * grid or a layout wrapper. `textContent` on that joins every text node below\n * it, so each click in a long list built a string of the entire list to keep\n * 50 characters of it, inside the click itself (#363).\n */\nexport function leadingText(el: Node, max: number): string {\n let text = \"\";\n let visited = 0;\n const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);\n while (\n text.trimStart().length < max &&\n visited++ < CLICK_TEXT_NODE_LIMIT &&\n walker.nextNode()\n ) {\n text += walker.currentNode.nodeValue ?? \"\";\n }\n return text.trim().slice(0, max);\n}\n\nfunction interceptClicks() {\n document.addEventListener(\n \"click\",\n (e) => {\n try {\n const target = e.target as HTMLElement;\n const tag = target.tagName?.toLowerCase();\n const text = target instanceof Node ? leadingText(target, CLICK_TEXT_MAX) : \"\";\n const id = target.id ? `#${target.id}` : \"\";\n const cls = target.className && typeof target.className === \"string\"\n ? `.${target.className.split(\" \")[0]}`\n : \"\";\n\n addBreadcrumb(\"click\", `Click ${tag}${id}${cls} \"${text}\"`);\n } catch {\n // Never crash\n }\n },\n { capture: true }\n );\n}\n","import type { RuntimeInfo } from \"./types\";\n\n/**\n * Runtime health at the moment of the crash. `deviceInfo` says what the machine\n * is; this says what shape it was in — a leak that ran the heap to its ceiling,\n * a 2G connection that starved a fetch, a bug that only shows up after ten\n * minutes on the page or on the fifth error in a row.\n */\n\nconst pageLoadedAt = Date.now();\nlet errorCount = 0;\n\n/** Bumped by every auto-captured error so a report says which one in the run it was. */\nexport function incrementErrorCount(): number {\n errorCount += 1;\n return errorCount;\n}\n\n/** Test-only — reset the per-session counter. */\nexport function resetErrorCount(): void {\n errorCount = 0;\n}\n\ninterface MemoryCapableWindow {\n memory?: { usedJSHeapSize?: number; jsHeapSizeLimit?: number };\n}\n\ninterface NetworkInformation {\n effectiveType?: string;\n downlink?: number;\n rtt?: number;\n saveData?: boolean;\n}\n\nconst toMb = (bytes: number | undefined): number | undefined =>\n typeof bytes === \"number\" ? Math.round((bytes / 1048576) * 10) / 10 : undefined;\n\nexport function captureRuntimeInfo(): RuntimeInfo | null {\n try {\n if (typeof window === \"undefined\") return null;\n\n // Chromium-only, and absent entirely under cross-origin isolation.\n const memory = (performance as unknown as MemoryCapableWindow)?.memory;\n // Chromium + Android only.\n const connection = (navigator as unknown as { connection?: NetworkInformation })?.connection;\n\n return {\n timeOnPageMs: Date.now() - pageLoadedAt,\n errorCount,\n visibility: typeof document !== \"undefined\" ? document.visibilityState : \"unknown\",\n ...(memory\n ? {\n jsHeapUsedMb: toMb(memory.usedJSHeapSize),\n jsHeapLimitMb: toMb(memory.jsHeapSizeLimit),\n }\n : {}),\n ...(connection\n ? {\n connectionType: connection.effectiveType,\n downlinkMbps: connection.downlink,\n rttMs: connection.rtt,\n saveData: connection.saveData,\n }\n : {}),\n };\n } catch {\n return null;\n }\n}\n","/**\n * App-owned context: key-values the host app attaches once and every report\n * carries thereafter — orgId, plan, role, active feature flags. The SDK cannot\n * guess these, and they are usually the difference between \"a crash\" and \"a\n * crash for enterprise tenants on the new billing flow\".\n *\n * Module-level, not React state, so it survives the provider unmount that\n * `global-error.tsx` causes and is readable from non-React call sites.\n */\n\nconst MAX_KEYS = 30;\nconst MAX_VALUE_LENGTH = 200;\n\nlet appContext: Record<string, string> = {};\nlet release: string | undefined;\n\nfunction coerce(value: unknown): string {\n if (typeof value === \"string\") return value.slice(0, MAX_VALUE_LENGTH);\n if (value === null || value === undefined) return \"\";\n try {\n return JSON.stringify(value).slice(0, MAX_VALUE_LENGTH);\n } catch {\n return String(value).slice(0, MAX_VALUE_LENGTH);\n }\n}\n\n/**\n * Attach one key-value to every future report. Passing `null`/`undefined`\n * removes the key — so a value that goes away (user logs out of an org) stops\n * being reported instead of going stale.\n */\nexport function setContext(key: string, value: unknown): void {\n try {\n if (!key) return;\n if (value === null || value === undefined) {\n delete appContext[key];\n return;\n }\n if (!(key in appContext) && Object.keys(appContext).length >= MAX_KEYS) return;\n appContext[key] = coerce(value);\n } catch {\n // Never crash the host app\n }\n}\n\n/** Set several keys at once. Merges — it does not replace what's already set. */\nexport function setContexts(values: Record<string, unknown>): void {\n try {\n for (const [key, value] of Object.entries(values ?? {})) setContext(key, value);\n } catch {\n // Never crash the host app\n }\n}\n\nexport function getAppContext(): Record<string, string> {\n return { ...appContext };\n}\n\nexport function clearAppContext(): void {\n appContext = {};\n}\n\n/**\n * The build this crash came from. Explicit `release` prop wins; otherwise the\n * standard Vercel/Next build env vars, which bundlers inline at build time.\n */\nexport function setRelease(value: string | undefined): void {\n if (value) release = value;\n}\n\nexport function getRelease(): string | undefined {\n if (release) return release;\n try {\n const fromEnv =\n process.env.NEXT_PUBLIC_APP_VERSION ||\n process.env.NEXT_PUBLIC_RELEASE ||\n process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA;\n return fromEnv || undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Test-only — reset release resolution between cases. */\nexport function clearRelease(): void {\n release = undefined;\n}\n","import type {\n CapturedContext,\n DeviceInfo,\n FeedbackPayload,\n FeedbackResult,\n ReportPayload,\n ReportResult,\n} from \"./types\";\n// The React-free subpath: utils.ts is also bundled into `glitchgrab/server`.\nimport { assistOffline, toAssistTurnResult } from \"@glitchgrab/report-ui/assist-response\";\nimport type { AssistTurnResult } from \"@glitchgrab/report-ui\";\nimport { getBreadcrumbs } from \"./breadcrumbs\";\nimport { captureRuntimeInfo } from \"./runtime\";\nimport { getAppContext, getRelease } from \"./app-context\";\n\nconst SENSITIVE_PARAMS = [\n \"token\", \"key\", \"secret\", \"password\", \"passwd\", \"auth\", \"authorization\",\n \"session\", \"sessionid\", \"session_id\", \"api_key\", \"apikey\", \"access_token\",\n \"refresh_token\", \"client_secret\", \"code\", \"state\", \"nonce\", \"credential\", \"private\",\n];\n\nexport function sanitizeUrl(url: string): string {\n try {\n const parsed = new URL(url);\n const params = new URLSearchParams(parsed.search);\n let modified = false;\n for (const key of Array.from(params.keys())) {\n if (SENSITIVE_PARAMS.some((s) => key.toLowerCase().includes(s))) {\n params.set(key, \"[REDACTED]\");\n modified = true;\n }\n }\n if (modified) parsed.search = params.toString();\n return parsed.toString();\n } catch {\n return url.split(\"?\")[0] ?? url;\n }\n}\n\nexport function captureDeviceInfo(): DeviceInfo | null {\n try {\n if (typeof window === \"undefined\") return null;\n return {\n screenWidth: screen.width,\n screenHeight: screen.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n platform: navigator.platform ?? \"unknown\",\n language: navigator.language ?? \"unknown\",\n online: navigator.onLine,\n colorScheme: window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\",\n devicePixelRatio: window.devicePixelRatio ?? 1,\n };\n } catch {\n return null;\n }\n}\n\nexport function captureContext(visitedPages: string[]): CapturedContext {\n try {\n return {\n url: sanitizeUrl(typeof window !== \"undefined\" ? window.location.href : \"\"),\n userAgent: typeof navigator !== \"undefined\" ? navigator.userAgent : \"\",\n timestamp: new Date().toISOString(),\n visitedPages: visitedPages.map(sanitizeUrl),\n breadcrumbs: getBreadcrumbs(),\n deviceInfo: captureDeviceInfo(),\n runtime: captureRuntimeInfo(),\n appContext: getAppContext(),\n release: getRelease(),\n };\n } catch {\n return {\n url: \"\",\n userAgent: \"\",\n timestamp: new Date().toISOString(),\n visitedPages: [],\n breadcrumbs: [],\n deviceInfo: null,\n runtime: null,\n appContext: {},\n };\n }\n}\n\n/**\n * Metadata every report carries regardless of how it was raised — release,\n * runtime health, and the host app's own context. One builder so a user-filed\n * report and an auto-captured crash describe the same world; the payload sites\n * only add what is specific to them.\n *\n * App context is prefixed so a key named `timestamp` or `status` can't quietly\n * overwrite a field the dashboard relies on.\n */\nexport function contextMetadata(context: CapturedContext): Record<string, string> {\n try {\n const runtime = context.runtime;\n const appContext = Object.entries(context.appContext ?? {}).reduce<Record<string, string>>(\n (acc, [key, value]) => {\n acc[`ctx_${key}`] = value;\n return acc;\n },\n {}\n );\n\n return {\n ...(context.release ? { release: context.release } : {}),\n ...(runtime\n ? {\n timeOnPageMs: String(runtime.timeOnPageMs),\n errorCount: String(runtime.errorCount),\n visibility: runtime.visibility,\n ...(runtime.jsHeapUsedMb !== undefined\n ? { jsHeapUsedMb: String(runtime.jsHeapUsedMb) }\n : {}),\n ...(runtime.jsHeapLimitMb !== undefined\n ? { jsHeapLimitMb: String(runtime.jsHeapLimitMb) }\n : {}),\n ...(runtime.connectionType ? { connectionType: runtime.connectionType } : {}),\n ...(runtime.downlinkMbps !== undefined\n ? { downlinkMbps: String(runtime.downlinkMbps) }\n : {}),\n ...(runtime.rttMs !== undefined ? { rttMs: String(runtime.rttMs) } : {}),\n ...(runtime.saveData !== undefined ? { saveData: String(runtime.saveData) } : {}),\n }\n : {}),\n ...appContext,\n };\n } catch {\n return {};\n }\n}\n\nexport const DEFAULT_BASE_URL = \"https://glitchgrab.dev\";\nconst MAX_RETRIES = 3;\nconst RETRY_BASE_MS = 500;\n\n/**\n * Send a report and return the result.\n * Never throws — returns null on failure.\n */\nexport async function sendReport(\n payload: ReportPayload,\n baseUrl?: string\n): Promise<ReportResult | null> {\n try {\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/sdk/report`;\n const body = JSON.stringify(payload);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${payload.token}`,\n };\n\n // keepalive has a 64KB body limit in browsers — skip it for large payloads (e.g., screenshots)\n const useKeepalive = body.length < 60_000;\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n ...(useKeepalive ? { keepalive: true } : {}),\n });\n\n if (response.ok) {\n const envelope = (await response.json()) as {\n success: boolean;\n data?: Omit<ReportResult, \"success\">;\n };\n return { success: envelope.success, ...(envelope.data ?? {}) };\n }\n\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return null;\n }\n } catch {\n // Will retry\n }\n\n if (attempt < MAX_RETRIES - 1) {\n await new Promise((resolve) =>\n setTimeout(resolve, RETRY_BASE_MS * Math.pow(2, attempt))\n );\n }\n }\n\n // Fallback: sendBeacon (fire-and-forget, no result)\n if (typeof navigator !== \"undefined\" && navigator.sendBeacon) {\n try {\n navigator.sendBeacon(url, new Blob([body], { type: \"application/json\" }));\n } catch {\n // Silently fail\n }\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Save a star rating your end-user left about your app.\n * Never throws — returns null on failure.\n *\n * Unlike `sendReport`, this is always a deliberate user action with a dialog\n * open in front of them, so it retries on transient failure but skips the\n * sendBeacon fallback: the caller needs a real result to show a thank-you.\n */\nexport async function sendFeedback(\n payload: FeedbackPayload,\n baseUrl?: string\n): Promise<FeedbackResult | null> {\n try {\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/sdk/feedback`;\n const body = JSON.stringify(payload);\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${payload.token}`,\n },\n body,\n });\n\n if (response.ok) {\n const envelope = (await response.json()) as {\n success: boolean;\n data?: Omit<FeedbackResult, \"success\">;\n };\n return { success: envelope.success, ...(envelope.data ?? {}) };\n }\n\n // 4xx other than rate limiting is a caller mistake — retrying won't help.\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return null;\n }\n } catch {\n // Will retry\n }\n\n if (attempt < MAX_RETRIES - 1) {\n await new Promise((resolve) =>\n setTimeout(resolve, RETRY_BASE_MS * Math.pow(2, attempt))\n );\n }\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\nexport interface EnhanceContext {\n url?: string;\n visitedPages?: string[];\n breadcrumbs?: Array<{ type: string; message: string }>;\n}\n\n/**\n * The signed-in user as the host's server vouched for them (`signSession`).\n *\n * Rides in the request BODY, never a header: every token route sets its own\n * CORS allow-list of headers, so a new header would fail preflight on all of\n * them. Omitted entirely when there is no signature — an unsigned id proves\n * nothing, and the server reads its absence as \"unsigned\".\n */\nexport interface SignedIdentity {\n userId?: string | null;\n signature?: string | null;\n}\n\n/** `{ userId, signature }` to spread into a JSON body, or nothing. */\nexport function signedFields(identity?: SignedIdentity | null): { userId?: string; signature?: string } {\n if (!identity?.signature || !identity.userId) return {};\n return { userId: identity.userId, signature: identity.signature };\n}\n\n/**\n * Polish raw description text via the Glitchgrab AI enhance endpoint.\n * Returns the polished text on success, or the original text on any failure.\n * Never throws.\n */\nexport async function enhanceText(\n text: string,\n token: string,\n baseUrl?: string,\n screenshot?: string | null,\n context?: EnhanceContext | null,\n identity?: SignedIdentity | null\n): Promise<string> {\n try {\n const trimmed = text.trim();\n if (!trimmed) return text;\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/ai/enhance-text`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n text: trimmed,\n ...(screenshot ? { screenshot } : {}),\n ...(context ? { context } : {}),\n ...signedFields(identity),\n }),\n });\n if (!response.ok) return text;\n const envelope = (await response.json()) as {\n success: boolean;\n data?: { text?: string };\n };\n if (envelope?.success && typeof envelope.data?.text === \"string\") {\n return envelope.data.text;\n }\n return text;\n } catch {\n return text;\n }\n}\n\n/**\n * \"Is this already filed?\" for the report dialog's plain form. Asked when Send\n * is pressed; a match lets the reporter add to the open issue instead of\n * opening a second one.\n *\n * `[]` when the project has it off, `null` on any failure — the dialog sends\n * straight away on either. Never throws.\n */\nexport async function findSimilarIssues(\n description: string,\n token: string,\n baseUrl?: string,\n identity?: SignedIdentity | null\n): Promise<{ number: number; title: string; url: string; status?: string }[] | null> {\n try {\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/reports/similar`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ text: description, ...signedFields(identity) }),\n });\n const envelope = (await response.json().catch(() => null)) as {\n success?: boolean;\n data?: { enabled?: boolean; matches?: { number: number; title: string; url: string; status?: string }[] };\n } | null;\n if (!response.ok || !envelope?.success) return null;\n if (!envelope.data?.enabled) return [];\n return Array.isArray(envelope.data.matches) ? envelope.data.matches : [];\n } catch {\n return null;\n }\n}\n\n/**\n * One turn of the AI report assistant (#330).\n *\n * Same never-throw contract as everything else in the SDK: a failure comes back\n * as `degraded` and the dialog quietly falls back to the plain form. An\n * end-user of the host app must never see a Glitchgrab error, and must never be\n * blocked from filing a bug because a model was busy.\n */\nexport async function assistTurn(\n params: {\n messages: { role: \"user\" | \"assistant\"; content: string }[];\n conversationId: string | null;\n screenshot?: string | null;\n context?: Record<string, unknown> | null;\n /**\n * Who the host app says is logged in, from the provider's `session` prop.\n * Stored against the conversation so a chat and the report it produced\n * agree on who filed — one SDK token covers every end user of the host app,\n * so without this every stranger's chat looks like the same person.\n */\n reporter?: {\n key?: string | null;\n name?: string | null;\n email?: string | null;\n /** `signSession()` output for `key`; absent when the host did not sign. */\n signature?: string | null;\n };\n },\n token: string,\n baseUrl?: string\n): Promise<AssistTurnResult> {\n const offline = assistOffline();\n try {\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/ai/report-chat`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify(params),\n });\n // One mapping for every host (packages/report-ui/src/assist-response.ts):\n // the server's degrade reason passes through, and nothing the sheet renders\n // is dropped.\n return toAssistTurnResult(response.ok, await response.json().catch(() => null));\n } catch {\n return offline;\n }\n}\n\n/**\n * Send an audio Blob to the Glitchgrab STT proxy (which calls Sarvam).\n * Returns the transcript string, or \"\" on any failure. Never throws.\n */\nexport async function transcribeAudio(\n blob: Blob,\n token: string,\n baseUrl?: string,\n identity?: SignedIdentity | null\n): Promise<string> {\n try {\n if (blob.size === 0) return \"\";\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/sdk/stt`;\n const form = new FormData();\n form.append(\"file\", blob, \"audio.webm\");\n const signed = signedFields(identity);\n if (signed.userId && signed.signature) {\n form.append(\"userId\", signed.userId);\n form.append(\"signature\", signed.signature);\n }\n const response = await fetch(url, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${token}` },\n body: form,\n });\n if (!response.ok) return \"\";\n const envelope = (await response.json()) as {\n success: boolean;\n data?: { transcript?: string };\n };\n if (envelope?.success && typeof envelope.data?.transcript === \"string\") {\n return envelope.data.transcript;\n }\n return \"\";\n } catch {\n return \"\";\n }\n}\n","const DEFAULT_WINDOW_MS = 5 * 60 * 1000;\nconst MAX_ENTRIES = 100;\n\nconst seen = new Map<string, number>();\n\nfunction hashString(input: string): string {\n let h1 = 0xdeadbeef ^ 0;\n let h2 = 0x41c6ce57 ^ 0;\n for (let i = 0; i < input.length; i++) {\n const ch = input.charCodeAt(i);\n h1 = Math.imul(h1 ^ ch, 2654435761);\n h2 = Math.imul(h2 ^ ch, 1597334677);\n }\n h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);\n h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);\n return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);\n}\n\nfunction topStackFrame(stack: string | undefined): string {\n if (!stack) return \"\";\n const lines = stack.split(\"\\n\");\n for (const line of lines) {\n const t = line.trim();\n if (t.startsWith(\"at \") || t.includes(\"@\")) {\n return t;\n }\n }\n return \"\";\n}\n\nfunction stripUrlQuery(url: string | undefined): string {\n if (!url) return \"\";\n try {\n const u = new URL(url);\n return `${u.origin}${u.pathname}`;\n } catch {\n const q = url.indexOf(\"?\");\n return q === -1 ? url : url.slice(0, q);\n }\n}\n\nexport function computeSignature(params: {\n errorMessage: string | undefined;\n pageUrl: string | undefined;\n errorStack?: string | undefined;\n /**\n * Next.js error digest. Production strips server-boundary errors to a generic\n * message with no useful stack, so without the digest every distinct server\n * crash on one page collapses into a single signature.\n */\n digest?: string | undefined;\n}): string {\n const msg = params.errorMessage?.trim() ?? \"\";\n const page = stripUrlQuery(params.pageUrl);\n const frame = topStackFrame(params.errorStack);\n const digest = params.digest?.trim() ?? \"\";\n return hashString(digest ? `${msg}|${page}|${frame}|${digest}` : `${msg}|${page}|${frame}`);\n}\n\nexport function shouldSkipDuplicate(\n signature: string,\n windowMs: number = DEFAULT_WINDOW_MS,\n now: number = Date.now()\n): boolean {\n const last = seen.get(signature);\n if (last !== undefined && now - last < windowMs) {\n return true;\n }\n seen.set(signature, now);\n\n if (seen.size > MAX_ENTRIES) {\n const cutoff = now - windowMs;\n for (const [sig, ts] of seen) {\n if (ts < cutoff) seen.delete(sig);\n }\n if (seen.size > MAX_ENTRIES) {\n const excess = seen.size - MAX_ENTRIES;\n const keys = Array.from(seen.keys()).slice(0, excess);\n for (const k of keys) seen.delete(k);\n }\n }\n return false;\n}\n\nexport function clearDedupCache(): void {\n seen.clear();\n}\n","import type {\n CaptureErrorOptions,\n GlitchgrabSession,\n ReportPayload,\n ReportResult,\n} from \"./types\";\nimport { captureContext, contextMetadata, sendReport } from \"./utils\";\nimport { computeSignature, shouldSkipDuplicate } from \"./dedup\";\nimport { incrementErrorCount } from \"./runtime\";\n\n/**\n * Config the provider publishes so `captureError` works from call sites that\n * cannot reach React context — most importantly `app/global-error.tsx`, which\n * replaces the root layout and therefore renders *outside* the provider tree.\n */\nexport interface CaptureConfig {\n token: string;\n baseUrl?: string;\n session?: GlitchgrabSession | null;\n ignoreErrors?: (string | RegExp)[];\n /**\n * Read the current visitedPages. A getter, not the array itself: `global-error.tsx`\n * unmounts the provider, and the next provider to mount allocates a fresh ref — a\n * captured array reference would go orphaned and report an empty history for exactly\n * the crashes this module exists to file.\n */\n getVisitedPages: () => string[];\n onError?: (error: Error) => void;\n onReportSent?: (result: ReportResult) => void;\n}\n\nlet config: CaptureConfig | null = null;\n\n/**\n * Called from the provider's render body (not an effect) so the config exists\n * before children render. A crash during a child's *initial* render unwinds to\n * the framework boundary before any effect commits — registering in an effect\n * would leave `captureError` unconfigured for exactly the case it exists for.\n *\n * Never cleared on unmount: `global-error.tsx` tears down the provider tree.\n */\nexport function registerCaptureConfig(next: CaptureConfig): void {\n config = next;\n}\n\n/** Test-only — reset the module registry between cases. */\nexport function clearCaptureConfig(): void {\n config = null;\n}\n\nexport function matchesIgnorePatterns(\n message: string,\n patterns: (string | RegExp)[] | undefined\n): boolean {\n if (!patterns || patterns.length === 0) return false;\n return patterns.some((pattern) =>\n pattern instanceof RegExp ? pattern.test(message) : message.includes(pattern)\n );\n}\n\nfunction sessionMetadata(session: GlitchgrabSession | null | undefined): Record<string, string> {\n return {\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n };\n}\n\n/**\n * Build an `SDK_AUTO` payload from an already-caught error, applying dedup.\n * Returns `null` when the error should not be sent (ignored or duplicate).\n */\nexport function buildCapturedErrorPayload(\n error: unknown,\n options: CaptureErrorOptions | undefined,\n cfg: CaptureConfig,\n capturedBy: string = \"captureError\"\n): ReportPayload | null {\n const err = error instanceof Error ? error : undefined;\n const errorMessage = err ? err.message : String(error);\n if (!errorMessage) return null;\n\n if (matchesIgnorePatterns(errorMessage, cfg.ignoreErrors)) return null;\n\n // Counted before the snapshot so the report says which error in the run it is —\n // \"errorCount: 7\" on a first-seen signature means six crashes already preceded it.\n incrementErrorCount();\n const context = captureContext(cfg.getVisitedPages());\n const digest =\n options?.digest ??\n (typeof (error as { digest?: unknown })?.digest === \"string\"\n ? (error as { digest: string }).digest\n : undefined);\n\n const sig = computeSignature({\n errorMessage,\n pageUrl: context.url,\n errorStack: err?.stack,\n digest,\n });\n if (shouldSkipDuplicate(sig)) return null;\n\n return {\n token: cfg.token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage,\n errorStack: err?.stack,\n componentStack: options?.componentStack ?? undefined,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n capturedBy,\n ...contextMetadata(context),\n ...(options?.boundary ? { boundary: options.boundary } : {}),\n ...(digest ? { digest } : {}),\n ...sessionMetadata(cfg.session),\n ...options?.metadata,\n },\n };\n}\n\n/**\n * Report an error your app already caught — a framework error boundary\n * (`app/error.tsx`, `app/global-error.tsx`, React Router `errorElement`, Remix\n * `ErrorBoundary`), a `componentDidCatch`, or a `try/catch` you want filed.\n *\n * These never reach `window.onerror`, so provider auto-capture cannot see them.\n *\n * Fire-and-forget. Never throws, never blocks the fallback UI render. No-ops if\n * no `GlitchgrabProvider` has rendered yet (nothing to authenticate with).\n *\n * @example\n * ```tsx\n * // app/global-error.tsx — renders outside the provider tree\n * \"use client\";\n * import { captureError } from \"glitchgrab\";\n *\n * export default function GlobalError({ error }: { error: Error & { digest?: string } }) {\n * useEffect(() => {\n * captureError(error, { digest: error.digest, boundary: \"next-global-error\" });\n * }, [error]);\n * return <html><body><p>Something went wrong</p></body></html>;\n * }\n * ```\n */\nexport function captureError(error: unknown, options?: CaptureErrorOptions): void {\n try {\n const cfg = config;\n if (!cfg?.token) return;\n\n const payload = buildCapturedErrorPayload(error, options, cfg);\n if (!payload) return;\n\n void sendReport(payload, cfg.baseUrl).then((result) => {\n if (result && cfg.onReportSent) cfg.onReportSent(result);\n });\n\n if (cfg.onError && error instanceof Error) cfg.onError(error);\n } catch {\n // Never crash the host app\n }\n}\n","\"use client\";\n\nimport {\n useState,\n useRef,\n useEffect,\n useMemo,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { AnnotationCanvas } from \"./annotation-canvas\";\nimport { AssistSheet } from \"./assist-sheet\";\nimport { GlitchgrabProblemPanel } from \"./glitchgrab-problem\";\nimport { getShortcutLabel } from \"./shortcut\";\nimport { getTypeLabel } from \"./labels\";\nimport { ATTACHMENT_ACCEPT } from \"./attachments\";\nimport { captureDefaultScreenshot, type CaptureOptions } from \"./capture\";\nimport { encodeImageFile } from \"./image-encode\";\nimport type {\n ReportType,\n ReportSeverity,\n DialogTile,\n ReportFn,\n FeedbackFn,\n EnhanceTextFn,\n AssistFn,\n FindSimilarIssuesFn,\n SimilarIssue,\n AttachKind,\n ReportReporter,\n GlitchgrabProblemFn,\n} from \"./types\";\nimport { SEVERITY_LEVELS, SEVERITY_LABELS } from \"./types\";\n\n/** Shown when Send is pressed on a bug report with no severity picked (#353). */\nconst SEVERITY_REQUIRED = \"Pick how bad it is before sending.\";\n\n/** How long Send waits for a page shot that is still being re-drawn (#363). */\nconst SHOT_WAIT_MS = 3000;\n\n/**\n * How long Send waits on \"is this already filed?\". Past this the report goes\n * out as a new issue — a slow GitHub list must never cost someone their report.\n */\nconst SIMILAR_WAIT_MS = 2500;\n\n/** More than three and the reporter stops reading and sends a new one anyway. */\nconst MAX_SIMILAR_SHOWN = 3;\n\n/** Inline spinner for a button waiting on the network. `gg-spin` lives in the dialog's style block. */\nfunction ButtonSpinner() {\n return (\n <span\n aria-hidden=\"true\"\n style={{\n display: \"inline-block\",\n width: \"11px\",\n height: \"11px\",\n marginRight: \"6px\",\n verticalAlign: \"-1px\",\n border: \"2px solid currentColor\",\n borderRightColor: \"transparent\",\n borderRadius: \"50%\",\n animation: \"gg-spin .7s linear infinite\",\n }}\n />\n );\n}\n\n/**\n * Detect if the host page uses a dark or light theme. Reads computed styles,\n * which forces a style recalculation on the host page — see the call site.\n */\nfunction detectDark(): boolean {\n if (typeof window === \"undefined\") return true;\n try {\n // Check body then html — most sites set background on html, not body\n for (const el of [document.body, document.documentElement]) {\n const bg = getComputedStyle(el).backgroundColor;\n const match = bg.match(\n /rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)(?:\\s*,\\s*([\\d.]+))?\\s*\\)/,\n );\n if (match) {\n const alpha = match[4] !== undefined ? parseFloat(match[4]) : 1;\n if (alpha < 0.05) continue; // transparent — skip to next element\n const [r, g, b] = [\n Number(match[1]),\n Number(match[2]),\n Number(match[3]),\n ];\n return (r * 299 + g * 587 + b * 114) / 1000 < 128;\n }\n }\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n } catch {\n return true;\n }\n}\n\n/** Convert HSL values to a hex color string */\nfunction hslToHex(h: number, s: number, l: number): string {\n s /= 100;\n l /= 100;\n const a = s * Math.min(l, 1 - l);\n const f = (n: number) => {\n const k = (n + h / 30) % 12;\n const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);\n return Math.round(255 * color)\n .toString(16)\n .padStart(2, \"0\");\n };\n return `#${f(0)}${f(8)}${f(4)}`;\n}\n\n/** Parse a CSS color value into [r, g, b] or null */\nfunction parseColorToRgb(value: string): [number, number, number] | null {\n try {\n const trimmed = value.trim();\n\n // hex (#fff, #ffffff)\n const hexMatch = trimmed.match(/^#([0-9a-f]{3,8})$/i);\n if (hexMatch) {\n let hex = hexMatch[1];\n if (hex.length === 3)\n hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n return [\n parseInt(hex.slice(0, 2), 16),\n parseInt(hex.slice(2, 4), 16),\n parseInt(hex.slice(4, 6), 16),\n ];\n }\n\n // rgb(r, g, b) or rgba(r, g, b, a)\n const rgbMatch = trimmed.match(/rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/);\n if (rgbMatch)\n return [Number(rgbMatch[1]), Number(rgbMatch[2]), Number(rgbMatch[3])];\n\n // hsl(h, s%, l%) or hsla(h, s%, l%, a)\n const hslMatch = trimmed.match(\n /hsla?\\(\\s*([\\d.]+)\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%/,\n );\n if (hslMatch) {\n const hex = hslToHex(\n Number(hslMatch[1]),\n Number(hslMatch[2]),\n Number(hslMatch[3]),\n );\n return parseColorToRgb(hex);\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n/** Compute relative luminance and return ideal contrast text color */\nfunction getContrastText(r: number, g: number, b: number): string {\n const luminance = (r * 299 + g * 587 + b * 114) / 1000;\n return luminance > 150 ? \"#09090b\" : \"#ffffff\";\n}\n\n/**\n * Auto-detect the host app's primary/accent color from CSS custom properties.\n * Checks common variable names used by shadcn/ui, Radix, Tailwind, MUI, etc.\n * Returns { accent, accentText } or null if no theme detected.\n */\nfunction detectHostAccent(): { accent: string; accentText: string } | null {\n if (typeof window === \"undefined\") return null;\n try {\n const root = getComputedStyle(document.documentElement);\n\n // Common CSS variable names for primary/accent color\n const varNames = [\n \"--primary\",\n \"--accent\",\n \"--brand\",\n \"--color-primary\",\n \"--theme-primary\",\n \"--chakra-colors-primary-500\",\n \"--mui-palette-primary-main\",\n ];\n\n for (const name of varNames) {\n const raw = root.getPropertyValue(name).trim();\n if (!raw) continue;\n\n // shadcn/ui style: space-separated HSL values like \"243 75% 59%\"\n const hslSpaceMatch = raw.match(/^([\\d.]+)\\s+([\\d.]+)%\\s+([\\d.]+)%$/);\n if (hslSpaceMatch) {\n const hex = hslToHex(\n Number(hslSpaceMatch[1]),\n Number(hslSpaceMatch[2]),\n Number(hslSpaceMatch[3]),\n );\n const rgb = parseColorToRgb(hex);\n return {\n accent: hex,\n accentText: rgb ? getContrastText(...rgb) : \"#ffffff\",\n };\n }\n\n // Standard color values (hex, rgb, hsl)\n const rgb = parseColorToRgb(raw);\n if (rgb) {\n const hex = `#${rgb.map((c) => c.toString(16).padStart(2, \"0\")).join(\"\")}`;\n return { accent: hex, accentText: getContrastText(...rgb) };\n }\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n/** First letters of the first two words — \"Naresh Bhosale\" → \"NB\". */\nfunction initialsOf(name: string): string {\n return name\n .trim()\n .split(/\\s+/)\n .slice(0, 2)\n .map((part) => part[0]?.toUpperCase() ?? \"\")\n .join(\"\");\n}\n\n/**\n * Who this report will be filed as. Anonymous is shown, never hidden — a\n * reporter who assumes they're signed in and isn't would otherwise file\n * something nobody can follow up on, and find out only when no one replies.\n */\nfunction ReporterChip({\n reporter,\n t,\n}: {\n reporter: ReportReporter | null | undefined;\n t: ReturnType<typeof getTheme>;\n}) {\n // An avatar URL that 404s, or one a host's CSP blocks, must not leave an empty\n // circle — fall back to the same initials/glyph as if none had been given.\n const [avatarFailed, setAvatarFailed] = useState(false);\n const avatarUrl = reporter?.avatarUrl || \"\";\n useEffect(() => {\n setAvatarFailed(false);\n }, [avatarUrl]);\n\n const name = reporter?.name?.trim() || \"\";\n const isAnonymous = !name;\n const initials = isAnonymous ? \"\" : initialsOf(name);\n // \"Anonymous\", not \"Not signed in\": `session` is optional in the SDK and many\n // report surfaces are public, so an unauthenticated reporter is a normal state,\n // not an error to flag on every single report.\n const label = isAnonymous ? \"Anonymous\" : name;\n const title = isAnonymous\n ? \"No reporter identity was passed to Glitchgrab — this report won't be attributed to anyone\"\n : [name, reporter?.email, reporter?.role].filter(Boolean).join(\" · \");\n const showAvatarImage = !!avatarUrl && !avatarFailed;\n\n return (\n <span\n title={title}\n style={{ display: \"flex\", alignItems: \"center\", gap: \"6px\", minWidth: 0 }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: \"18px\",\n height: \"18px\",\n flexShrink: 0,\n borderRadius: \"50%\",\n overflow: \"hidden\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"8px\",\n fontWeight: 700,\n letterSpacing: \"0.02em\",\n background: isAnonymous ? t.inputBg : t.accent,\n color: isAnonymous ? t.textMuted : t.accentText,\n border: `1px solid ${isAnonymous ? t.inputBorder : \"transparent\"}`,\n }}\n >\n {showAvatarImage ? (\n <img\n src={avatarUrl}\n alt=\"\"\n width={18}\n height={18}\n onError={() => setAvatarFailed(true)}\n style={{ width: \"100%\", height: \"100%\", objectFit: \"cover\" }}\n />\n ) : initials ? (\n initials\n ) : (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 16 16\" fill=\"none\">\n <circle cx=\"8\" cy=\"5.5\" r=\"2.75\" stroke=\"currentColor\" strokeWidth=\"1.4\" />\n <path\n d=\"M2.75 13.5c0-2.35 2.35-3.75 5.25-3.75s5.25 1.4 5.25 3.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n />\n </svg>\n )}\n </span>\n <span\n style={{\n fontSize: \"11px\",\n color: t.textMuted,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {label}\n {reporter?.role ? ` · ${reporter.role}` : \"\"}\n </span>\n </span>\n );\n}\n\nfunction getTheme(dark: boolean) {\n const hostAccent = detectHostAccent();\n const defaults = dark\n ? {\n bg: \"#1c1c1e\",\n bgSecondary: \"#27272a\",\n border: \"#2c2c2e\",\n text: \"#fafafa\",\n textMuted: \"#a1a1aa\",\n accent: \"#22d3ee\",\n accentText: \"#09090b\",\n inputBg: \"#27272a\",\n inputBorder: \"#3f3f46\",\n }\n : {\n bg: \"#ffffff\",\n bgSecondary: \"#f4f4f5\",\n border: \"#e4e4e7\",\n text: \"#18181b\",\n textMuted: \"#71717a\",\n accent: \"#0891b2\",\n accentText: \"#ffffff\",\n inputBg: \"#fafafa\",\n inputBorder: \"#d4d4d8\",\n };\n\n if (hostAccent) {\n defaults.accent = hostAccent.accent;\n defaults.accentText = hostAccent.accentText;\n }\n\n return defaults;\n}\n\n/** Validate that report text is meaningful — rejects gibberish, throwaway words, random chars */\nfunction isLowQualityText(text: string): string | null {\n const trimmed = text.trim();\n if (!trimmed) return null;\n\n // Exact throwaway words\n const throwaway =\n /^(done|ok|yes|no|hi|hello|hey|test|testing|asdf|qwerty|abc|xyz|foo|bar|baz|lol|lmao|idk|bruh|nice|cool|wow|sup|yo|nah|yep|nope|thanks|thx|ty|k|kk|hmm|hm|na|mm|mhm|aight|bet|gg|wp|rip|omg|pls|plz)$/i;\n if (throwaway.test(trimmed)) {\n return \"Please describe the actual issue you're experiencing\";\n }\n\n // Repeated characters (aaaaaaa, !!!!!!!)\n if (/(.)\\1{4,}/.test(trimmed)) {\n return \"Please provide a meaningful description\";\n }\n\n const letters = trimmed.replace(/[^a-zA-Z]/g, \"\");\n if (letters.length >= 4) {\n // Very low vowel ratio (bkdfghjklmn...)\n const vowels = letters.replace(/[^aeiouAEIOU]/g, \"\").length;\n const vowelRatio = vowels / letters.length;\n if (vowelRatio < 0.08) {\n return \"That doesn't look like a valid description\";\n }\n\n // Keyboard mashing: single word with no real English pattern\n // Detects strings like \"asdfasfsdad\", \"jkljklfsdf\", \"qwertyuio\"\n // Real words have max 3-4 consecutive consonants; gibberish has long runs\n if (/[^aeiou\\s]{5,}/i.test(letters)) {\n const words = trimmed.split(/\\s+/);\n // Only flag if it's a single \"word\" — multi-word text is likely real\n if (words.length <= 2) {\n return \"That doesn't look like a valid description\";\n }\n }\n\n // Check if it looks like a random permutation of a few chars (asdfasfsdad)\n if (letters.length >= 6) {\n const uniqueChars = new Set(letters.toLowerCase()).size;\n const uniqueRatio = uniqueChars / letters.length;\n // Real English has ~0.6-0.9 unique ratio for short text; gibberish reuses few chars\n if (uniqueRatio < 0.4 && trimmed.split(/\\s+/).length <= 2) {\n return \"That doesn't look like a valid description\";\n }\n }\n }\n\n // Single short word that isn't a known tech term\n const words = trimmed.split(/\\s+/).filter((w) => w.length > 0);\n if (words.length === 1 && trimmed.length < 10) {\n const techTerms =\n /^(crash|error|bug|fail|broken|slow|freeze|lag|404|500|null|undefined|nan|timeout|overflow|leak|cors|oom)$/i;\n if (!techTerms.test(trimmed)) {\n return \"Please provide more detail about the issue\";\n }\n }\n\n return null;\n}\n\ninterface ReportDialogProps {\n report: ReportFn;\n /**\n * Saves a star rating. Passing it adds the `RATING` tile to step 1 — a\n * testimonial lives in the same dialog as a bug report because from the\n * user's side it's the same question (\"what's on your mind?\"), even though it\n * takes a completely different path server-side (feedback row, never a GitHub\n * issue). Omit it and the tile never appears.\n */\n sendFeedback?: FeedbackFn;\n enhanceText?: EnhanceTextFn;\n /**\n * Runs one turn of the AI report assistant (#330). Supplying it adds a\n * \"Describe it with AI\" affordance above the description box; omitting it\n * leaves the dialog exactly as it was. The assistant is an EXTRA mode, never\n * a replacement — the plain form stays present and usable throughout, and\n * the assistant closes itself the moment it cannot help.\n *\n * Hosts pass this only when the project has it switched on: the SDK reads\n * `aiAssist` off /api/v1/sdk/project. The server re-checks the same column on\n * every call, so this prop is a UI hint and not a permission.\n */\n assist?: AssistFn;\n /**\n * \"Is this already filed?\", asked when the plain form's Send is pressed. A\n * match shows \"Our team may already have this\" — pickable rows and \"Add to #N\" (the\n * report becomes a comment on that issue, through the same submit path the\n * assistant's duplicate uses) or \"No, mine is different\". No match, `null`, or\n * no answer within `SIMILAR_WAIT_MS` → sent exactly as before. Omit it and\n * Send never waits.\n *\n * Skipped when the assistant was used — it already checked open issues with\n * the reporter, and asking twice is the dialog arguing with itself.\n */\n findSimilarIssues?: FindSimilarIssuesFn;\n /**\n * Session facts handed to the assistant — page URL, pages visited, recent\n * clicks and API calls. The host owns this because only the host has it: the\n * SDK keeps breadcrumbs, the extension has the tab, GlitchRecord has neither.\n */\n assistContext?: Record<string, unknown> | null;\n transcribeAudio?: (blob: Blob) => Promise<string>;\n types?: ReportType[];\n showSeverity?: boolean;\n /**\n * Overrides how the initial/retake screenshot is captured. Defaults to\n * `captureDefaultScreenshot` (correct for the SDK, embedded in the host\n * page): the tab's real pixels on Chromium, html2canvas-pro over\n * `document.body` everywhere else — see `capture.ts`. It is called before\n * the dialog's first await, so the browser still sees the user's click.\n * Standalone hosts must inject their own — the current tab / `document.body`\n * there is the host's OWN tiny window, not the thing being reported:\n * - Chrome extension → `chrome.tabs.captureVisibleTab`\n * - GlitchRecord desktop → `webContents.capturePage` of the GlitchRecord\n * window the reporter was in (its Report Bug files GlitchRecord's own bugs)\n * Return `null` to open without a screenshot. The dialog opens when this\n * resolves, or earlier if it calls `options.onRedraw` — the default does on\n * its html2canvas path, then fills the strip when the re-draw lands (#363).\n */\n captureScreenshot?: (options?: CaptureOptions) => Promise<string | null>;\n /**\n * Who the report will be attributed to. Omit or pass `null` and the footer\n * says \"Not signed in\" rather than showing nothing — silence there reads as\n * \"you're signed in\", which is the failure worth preventing.\n */\n reporter?: ReportReporter | null;\n /**\n * Called when the dialog closes itself (the × or Escape).\n *\n * Hosts that mount this inside something of their own — the extension puts it\n * in a full-page iframe — otherwise have no way to know it is gone, and are\n * left with an invisible overlay still swallowing every click on the page.\n */\n onClose?: () => void;\n /**\n * Rendered at the top of step 1, inside the dialog.\n *\n * For hosts that must ask something the dialog itself knows nothing about —\n * the Chrome extension has to pick WHICH project a bug belongs to, because\n * unlike an SDK embedded in one app it could be reporting on anything. Left\n * outside, that question needed its own panel wrapped around this one, and\n * two stacked cards read as a bug in the bug reporter.\n */\n headerSlot?: ReactNode;\n /**\n * \"Problem with Glitchgrab?\" (#366). Supplying it swaps the footer's\n * \"Powered by Glitchgrab\" for a link, and adds the same link to the AI sheet,\n * both opening a small panel that files into Glitchgrab's own repo — never\n * the host's. The report underneath stays open and untouched.\n *\n * The SDK passes it only when the project owner switched it on; the Chrome\n * extension always does, because its reporters are Glitchgrab testers.\n */\n reportGlitchgrabProblem?: GlitchgrabProblemFn;\n /**\n * `\"modal\"` (default): the form is a centred card over the host page — the\n * SDK and the extension. `\"sheet\"`: the form is a right-side panel, like the\n * AI sheet, so the page being reported stays in view beside it — for a host\n * that opens the report over its own screen (GlitchRecord's Report Bug).\n */\n layout?: \"modal\" | \"sheet\";\n}\n\n/**\n * Recovery copy for every way the microphone can refuse to open.\n *\n * Every one of these ends with a way forward, because the field below still\n * accepts typing: a blocked mic must never read like a blocked report.\n */\nexport const MIC_MESSAGES = {\n blocked:\n \"Microphone is blocked for this site. Allow it in your browser's site settings, then reload this page. You can type your report instead.\",\n notFound:\n \"No microphone found. Connect one and try again, or type your report instead.\",\n inUse:\n \"Microphone is in use by another app. Close it and try again, or type your report instead.\",\n unusable:\n \"This microphone can't be used for recording. Pick another one in your system sound settings.\",\n insecure:\n \"Voice needs a secure (https) connection. Type your report instead.\",\n generic:\n \"Couldn't start the microphone. Try again, or type your report instead.\",\n} as const;\n\n/**\n * Turn a `getUserMedia` rejection into something the reporter can act on.\n *\n * \"Microphone access denied\" was a dead end: it is also what the browser says\n * when the origin holds a *persisted* block, and no code on this side can lift\n * that — only the user can, in site settings, and Chrome then needs a reload\n * before the new setting reaches the page. So the denied copy names both steps.\n *\n * Deliberately host-neutral. This dialog also renders inside the Chrome\n * extension and inside GlitchRecord, where \"the lock icon in the address bar\"\n * points at nothing.\n *\n * `null` means \"not a cause we recognise\" — the caller may still fall through\n * to Web Speech, which can succeed where the recorder stream did not.\n */\nexport const micErrorMessage = (err: unknown): string | null => {\n const name =\n typeof err === \"object\" && err !== null && \"name\" in err\n ? String((err as { name: unknown }).name)\n : \"\";\n switch (name) {\n case \"NotAllowedError\":\n case \"PermissionDeniedError\":\n case \"SecurityError\":\n return MIC_MESSAGES.blocked;\n case \"NotFoundError\":\n case \"DevicesNotFoundError\":\n return MIC_MESSAGES.notFound;\n case \"NotReadableError\":\n case \"TrackStartError\":\n return MIC_MESSAGES.inUse;\n case \"OverconstrainedError\":\n case \"ConstraintNotSatisfiedError\":\n return MIC_MESSAGES.unusable;\n default:\n return null;\n }\n};\n\n/**\n * The report dialog — rendered inside GlitchgrabProvider automatically.\n * Opens via the `glitchgrab:open-report` custom event (triggered by `openReportDialog()`).\n */\nexport function ReportDialog({\n report,\n sendFeedback,\n enhanceText,\n assist,\n findSimilarIssues,\n assistContext = null,\n transcribeAudio,\n types,\n showSeverity = true,\n captureScreenshot = captureDefaultScreenshot,\n reporter,\n onClose,\n headerSlot,\n reportGlitchgrabProblem,\n layout = \"modal\",\n}: ReportDialogProps) {\n const sheet = layout === \"sheet\";\n const [isEnhancing, setIsEnhancing] = useState(false);\n\n /**\n * AI assistant (#330). Closed until asked for, and one-way: once it degrades\n * or hands over a description it does not reopen itself. `assistNotice` is\n * why it went away, shown once under the box so the reporter is never left\n * wondering where the button went.\n */\n const [assistOpen, setAssistOpen] = useState(false);\n const [assistNotice, setAssistNotice] = useState<string | null>(null);\n const [assistUsed, setAssistUsed] = useState(false);\n /** Which surface opened the \"Problem with Glitchgrab?\" panel (#366); null = closed. */\n const [selfReportFrom, setSelfReportFrom] = useState<\"form\" | \"assist\" | null>(null);\n /** What the panel opens with — the reporter's chat words when the assistant offered it. */\n const [selfReportPrefill, setSelfReportPrefill] = useState(\"\");\n /**\n * Has anyone actually said what this report is?\n *\n * `reportType` has always defaulted to \"BUG\", which was fine while the tile\n * grid was the first thing anyone saw. Now that ⌘⇧G opens the assistant\n * first, that default would silently file a rating request as a bug — so the\n * sheet asks, and this is how it knows whether it still has to.\n */\n const [typeChosen, setTypeChosen] = useState(false);\n /**\n * The already-open issue the assistant matched this report to (#330\n * follow-up). Held here rather than in the sheet because `handleSubmit` is\n * the one submit path — the number rides in report metadata and the server\n * re-validates it, so a comment replaces the second identical issue.\n */\n const [duplicateIssueNumber, setDuplicateIssueNumber] = useState<number | null>(null);\n /**\n * Why it goes onto that issue: the SAME problem, or a different requirement\n * for the same feature the reporter chose to keep there (practise_stack #1868\n * beside #1867). Only `related` is sent — the server's comment then says it is\n * new work that closing the issue does not cover.\n */\n const [duplicateKind, setDuplicateKind] = useState<AttachKind>(\"duplicate\");\n /** The last report went on as a related request — the success line says so. */\n const [addedAsRelated, setAddedAsRelated] = useState(false);\n /**\n * What the plain form's duplicate check matched when Send was pressed.\n * Non-null swaps the Send button for the \"Our team may already have this\" card. `attachingTo` is\n * the choice now sending, so only that button spins.\n */\n const [similarIssues, setSimilarIssues] = useState<SimilarIssue[] | null>(null);\n const [checkingSimilar, setCheckingSimilar] = useState(false);\n const [attachingTo, setAttachingTo] = useState<number | \"new\" | null>(null);\n /** The row picked in that card. Starts on the best match — the button still names the number. */\n const [pickedSimilar, setPickedSimilar] = useState<number | null>(null);\n /** The open issue the last report was added to, for the success line. */\n const [addedToIssue, setAddedToIssue] = useState<number | null>(null);\n /**\n * The assistant chat that produced this description, if one did. Rides along\n * in metadata so the server can join the filed report back to the chat.\n */\n const [aiConversationId, setAiConversationId] = useState<string | null>(null);\n const [isEnhanced, setIsEnhanced] = useState(false);\n const [originalDescription, setOriginalDescription] = useState<string | null>(\n null,\n );\n const [isListening, setIsListening] = useState(false);\n const [isTranscribing, setIsTranscribing] = useState(false);\n const [voiceError, setVoiceError] = useState<string | null>(null);\n const [screenshotDragOver, setScreenshotDragOver] = useState(false);\n // Prevent hydration mismatch — render nothing until after hydration\n const [mounted, setMounted] = useState(false);\n useEffect(() => {\n setMounted(true);\n }, []);\n\n const [isOpen, setIsOpen] = useState(false);\n const [description, setDescription] = useState(\"\");\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n // Set when the server saved the report but could not file it yet — GitHub\n // refused access (status QUEUED). \"Bug sent\" would be a lie about an issue.\n const [queuedMessage, setQueuedMessage] = useState<string | null>(null);\n const [screenshots, setScreenshots] = useState<string[]>([]);\n /**\n * Which entry of `screenshots` this dialog captured itself on open. Anything\n * else was pasted or picked by the reporter, and the assistant is told so —\n * a WhatsApp screenshot pasted on the dashboard is about WhatsApp, not the\n * dashboard (#357). Matched by value, so removing or reordering is safe.\n */\n const [pageShot, setPageShot] = useState<string | null>(null);\n /**\n * The page shot is still being re-drawn (#363). The dialog no longer waits\n * for it: it opens at once, the strip shows a placeholder, and Send gives it\n * SHOT_WAIT_MS to make it in.\n */\n const [shotPending, setShotPending] = useState(false);\n const pendingShotRef = useRef<Promise<string | null> | null>(null);\n /**\n * Bumped on close. A capture that settles after its dialog closed carries a\n * stale number and is dropped — it belongs to a report nobody is writing.\n */\n const openGenRef = useRef(0);\n const [attachments, setAttachments] = useState<\n { name: string; size: number; dataUrl: string }[]\n >([]);\n const [previewIndex, setPreviewIndex] = useState<number | null>(null);\n const [annotatingIndex, setAnnotatingIndex] = useState<number | null>(null);\n // Lightbox zoom: false = fit to screen, true = 100% natural size with pan.\n const [previewZoomed, setPreviewZoomed] = useState(false);\n const [previewNatural, setPreviewNatural] = useState<{\n w: number;\n h: number;\n } | null>(null);\n const previewScrollRef = useRef<HTMLDivElement>(null);\n const previewImgElRef = useRef<HTMLImageElement>(null);\n const panRef = useRef<{\n x: number;\n y: number;\n left: number;\n top: number;\n moved: boolean;\n } | null>(null);\n // Fraction of the image the user clicked, so zooming in keeps that spot centred.\n const zoomAnchorRef = useRef<{ fx: number; fy: number } | null>(null);\n\n // Every preview opens fit-to-screen, so zoom state is reset alongside the\n // index rather than by an effect chasing it.\n const resetPreviewZoom = () => {\n setPreviewZoomed(false);\n setPreviewNatural(null);\n zoomAnchorRef.current = null;\n };\n const openPreview = (i: number) => {\n resetPreviewZoom();\n setPreviewIndex(i);\n };\n const closePreview = () => {\n resetPreviewZoom();\n setPreviewIndex(null);\n };\n const fileInputRef = useRef<HTMLInputElement>(null);\n const modalRef = useRef<HTMLDivElement>(null);\n const previewImgRef = useRef<HTMLDivElement>(null);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const recognitionRef = useRef<any>(null);\n const voiceBaseRef = useRef(\"\");\n const usingWebSpeechRef = useRef(false);\n const textBeforeVoiceRef = useRef(\"\");\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const streamRef = useRef<MediaStream | null>(null);\n const sarvamChunksRef = useRef<Blob[]>([]);\n const spaceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const isPushToTalkRef = useRef(false);\n // Edits seen since the space that armed push-to-talk. The space itself lands\n // as one native change; a second means the user is still typing, not holding.\n const spaceEditsRef = useRef(0);\n // Live mirror of `description` for the voice callbacks, which fire outside\n // React's render and would otherwise read the value captured when listening\n // started — see `rebaseVoiceOnUserEdits`.\n const descriptionRef = useRef(\"\");\n // The exact text voice last wrote into the field. Anything else in there is\n // the user's own typing.\n const lastVoiceTextRef = useRef<string | null>(null);\n // Did this run get a live Web Speech preview? Decides whether the Sarvam\n // result replaces text on screen or defers to it.\n const hadWebSpeechRef = useRef(false);\n\n // A host focus trap — Radix `FocusScope` inside a Dialog, DropdownMenu, Select,\n // or any other library doing the same — keeps document-level `focusin`/`focusout`\n // listeners that yank focus straight back into its own container. While one is\n // live, GlitchGrab's textarea is unusable: clicks land, but typing and\n // drag-select do nothing, because focus never stays where the user put it.\n //\n // `inert` is the counter: focusing *into* an inert subtree is a no-op, so the\n // trap's grab fails silently instead of fighting us for the caret. Re-applied\n // by a MutationObserver rather than snapshotted once at open — a host layer\n // that mounts after GlitchGrab (a prompt fired by a late query, a menu still\n // mounted through its close animation) would otherwise keep its trap.\n useEffect(() => {\n if (!isOpen) return;\n\n const HOST_LAYERS =\n '[role=\"dialog\"],[role=\"alertdialog\"],[role=\"menu\"],[role=\"listbox\"]';\n // Only the ones *we* set inert get it removed again on cleanup — a host that\n // was already inert must stay that way.\n const inerted = new Set<HTMLElement>();\n\n const applyInert = () => {\n document.querySelectorAll<HTMLElement>(HOST_LAYERS).forEach((el) => {\n // Our own layers, and anything wrapping them, must stay interactive.\n if (el.closest(\"[data-glitchgrab-layer]\")) return;\n if (el.querySelector(\"[data-glitchgrab-layer]\")) return;\n if (inerted.has(el) || el.hasAttribute(\"inert\")) return;\n el.setAttribute(\"inert\", \"\");\n inerted.add(el);\n });\n };\n\n applyInert();\n\n const observer = new MutationObserver((mutations) => {\n // Attribute-only churn (a `data-state` flip, a class swap) can't introduce a\n // layer we haven't seen, so skip the query unless nodes actually moved.\n const structural = mutations.some(\n (m) => m.addedNodes.length > 0 || m.removedNodes.length > 0,\n );\n if (structural) applyInert();\n });\n observer.observe(document.body, { childList: true, subtree: true });\n\n return () => {\n observer.disconnect();\n inerted.forEach((el) => el.removeAttribute(\"inert\"));\n };\n }, [isOpen]);\n\n // Stepper state\n const [step, setStep] = useState<1 | 2>(1);\n const [reportType, setReportType] = useState<DialogTile>(\"BUG\");\n /**\n * `null` until the reporter picks. It used to default to \"medium\", which put\n * a lit-up button on screen that nobody had chosen — so every report arrived\n * `severity:medium` and the field told triage nothing (#353).\n */\n const [severity, setSeverity] = useState<ReportSeverity | null>(null);\n const [validationError, setValidationError] = useState<string | null>(null);\n const [placeholderIdx, setPlaceholderIdx] = useState(0);\n /** 0 = nothing picked yet. Only meaningful while the RATING tile is selected. */\n const [rating, setRating] = useState(0);\n const [hoveredStar, setHoveredStar] = useState(0);\n\n const isRating = reportType === \"RATING\";\n\n // A rating is gated on the stars, not the words — the message is optional.\n const submitDisabled = isSubmitting || (isRating ? rating < 1 : !description.trim());\n\n /**\n * The picker turns red only after a send was actually refused for it — an\n * untouched form that already looks like an error trains people to ignore it.\n */\n const needsSeverity =\n validationError === SEVERITY_REQUIRED &&\n showSeverity &&\n reportType === \"BUG\" &&\n !severity;\n\n // RATING is deliberately NOT a tile: it gets the hero row above the grid, so\n // the stars are one click away instead of three, and its icon can't be\n // confused with Feature Request's star.\n // OTHER is gone from the default set: the rating hero is now the home for\n // \"general feedback\", and the two side by side asked the same question twice.\n // Hosts that still want it can pass it explicitly via `types`.\n const availableTypes: DialogTile[] = types ?? [\n \"BUG\",\n \"FEATURE_REQUEST\",\n \"UI_IMPROVEMENT\",\n \"PERFORMANCE\",\n \"SECURITY\",\n \"QUESTION\",\n ];\n\n const tileGridRef = useRef<HTMLDivElement>(null);\n\n /**\n * Step-1 shortcuts. Digits 1–5 set the rating and go straight to the message\n * box; letters jump to the tile they start with (b=bug, f=feature, u=ui,\n * p=performance, s=security, q=question).\n *\n * Digits are the rating rather than the tiles because the two would collide,\n * and the hero is the primary action — tiles are still one keystroke away by\n * letter, plus arrows and Tab.\n */\n useEffect(() => {\n if (!isOpen || step !== 1) return;\n const onKey = (e: KeyboardEvent) => {\n // Never hijack a key someone is typing into a field.\n const el = e.target as HTMLElement | null;\n const tag = el?.tagName;\n if (tag === \"INPUT\" || tag === \"TEXTAREA\" || el?.isContentEditable) return;\n if (e.metaKey || e.ctrlKey || e.altKey) return;\n\n if (sendFeedback && /^[1-5]$/.test(e.key)) {\n e.preventDefault();\n setRating(Number(e.key));\n setReportType(\"RATING\");\n setTypeChosen(true);\n setStep(2);\n return;\n }\n\n const letter = e.key.toLowerCase();\n if (!/^[a-z]$/.test(letter)) return;\n const match = availableTypes.find(\n (type) => getTypeLabel(type).toLowerCase().startsWith(letter)\n );\n if (match) {\n e.preventDefault();\n setReportType(match);\n setTypeChosen(true);\n setStep(2);\n }\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n // `availableTypes` is rebuilt each render; its contents are what matter.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, step, sendFeedback, availableTypes.join(\",\")]);\n\n /**\n * Arrow keys walk the tile grid, so the whole picker works without a mouse.\n * Two columns, so up/down is ±2 and left/right is ±1; Enter and Space are\n * left to the buttons themselves.\n */\n const handleTileGridKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n const keys = [\"ArrowRight\", \"ArrowLeft\", \"ArrowDown\", \"ArrowUp\"];\n if (!keys.includes(e.key)) return;\n const tiles = Array.from(\n tileGridRef.current?.querySelectorAll<HTMLButtonElement>(\"button[data-gg-type]\") ?? []\n );\n if (tiles.length === 0) return;\n e.preventDefault();\n const current = tiles.indexOf(document.activeElement as HTMLButtonElement);\n const delta =\n e.key === \"ArrowRight\" ? 1 : e.key === \"ArrowLeft\" ? -1 : e.key === \"ArrowDown\" ? 2 : -2;\n // From \"nothing focused\", the first arrow press should land on the first\n // tile rather than jumping into the middle of the grid.\n const next = current === -1 ? 0 : Math.min(Math.max(current + delta, 0), tiles.length - 1);\n tiles[next]?.focus();\n };\n\n // Once per open. Computed-style reads force a style recalc on the host page,\n // and this used to run on every host re-render while the dialog sat closed.\n const isDark = useMemo(() => (isOpen ? detectDark() : true), [isOpen]);\n const t = getTheme(isDark);\n /** The slice of the theme the layers above the dialog (AI sheet, #366 panel) paint with. */\n const layerTheme = {\n bg: t.bg,\n bgSecondary: t.bgSecondary,\n border: t.border,\n text: t.text,\n textMuted: t.textMuted,\n inputBg: t.inputBg,\n inputBorder: t.inputBorder,\n accent: t.accent,\n accentText: t.accentText,\n };\n\n // Zooming only earns its place when the screenshot holds more pixels than the\n // fit-to-screen view can show.\n const canZoomPreview =\n previewNatural !== null &&\n typeof window !== \"undefined\" &&\n (previewNatural.w > window.innerWidth - 32 ||\n previewNatural.h > window.innerHeight - 80);\n\n const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = e.target.files;\n if (!files || files.length === 0) return;\n addFiles(Array.from(files));\n e.target.value = \"\";\n };\n\n const addFiles = (files: File[]) => {\n // Images are held to the screenshot budget — a raw retina paste alone can\n // exceed the request-body limit. All in one update, in the order dropped.\n const images = files.filter((file) => file.type.startsWith(\"image/\"));\n if (images.length > 0) {\n void Promise.all(images.map((file) => encodeImageFile(file).catch(() => null))).then(\n (encoded) => {\n const added = encoded.filter((url): url is string => !!url);\n if (added.length > 0) setScreenshots((prev) => [...prev, ...added]);\n },\n );\n }\n files\n .filter((file) => !file.type.startsWith(\"image/\"))\n .forEach((file) => {\n const reader = new FileReader();\n reader.onload = () => {\n setAttachments((prev) => [\n ...prev,\n { name: file.name, size: file.size, dataUrl: reader.result as string },\n ]);\n };\n reader.readAsDataURL(file);\n });\n };\n\n const handleOpen = async () => {\n const gen = openGenRef.current;\n setSubmitted(false);\n // Belt to `handleClose`'s braces: every open starts on the form, never on a\n // preview or annotator left over from last time. Asserted here rather than\n // only on close so it holds however the dialog was dismissed.\n closePreview();\n setAnnotatingIndex(null);\n if (availableTypes.length === 1) {\n setReportType(availableTypes[0]);\n setTypeChosen(true);\n setStep(2);\n }\n const show = () => {\n if (gen !== openGenRef.current) return;\n // The assistant is the front door now, not a button inside the form: ⌘⇧G\n // opens the sheet, which asks what this is before anything else. The tile\n // grid is still exactly one tap away (\"Write it myself\"), and a project\n // without the assistant — or one whose assistant degraded earlier in this\n // page's life — opens on the grid the way it always did.\n if (assist && !assistUsed) setAssistOpen(true);\n setIsOpen(true);\n };\n // Called before the first await, so the browser still sees the click.\n const capture = captureScreenshot({\n onRedraw: () => {\n if (gen !== openGenRef.current) return;\n setShotPending(true);\n show();\n },\n });\n pendingShotRef.current = capture;\n const previousPageShot = pageShot;\n const shot = await capture.catch(() => null);\n if (gen !== openGenRef.current) return;\n pendingShotRef.current = null;\n setShotPending(false);\n setPageShot(shot ?? null);\n // Merged, not replaced: the dialog may have been open while the re-draw\n // ran, and the reporter may have pasted an image. Only the last open's page\n // shot goes — it shows the page as it was then.\n if (shot) {\n setScreenshots((prev) => [\n shot,\n ...prev.filter((s) => s !== shot && s !== previousPageShot),\n ]);\n }\n show();\n };\n\n // Listen for programmatic open via openReportDialog()\n useEffect(() => {\n const handler = (e: Event) => {\n if (isOpen) return;\n const detail = (e as CustomEvent).detail;\n if (detail?.description) setDescription(detail.description);\n if (detail?.type) {\n setReportType(detail.type);\n setTypeChosen(true);\n setStep(2);\n }\n handleOpen();\n };\n window.addEventListener(\"glitchgrab:open-report\", handler);\n return () => window.removeEventListener(\"glitchgrab:open-report\", handler);\n }, [isOpen, handleOpen]);\n\n // Close on Escape\n useEffect(() => {\n if (!isOpen) return;\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n // Escape unwinds one layer at a time, topmost first:\n // annotate → zoom → preview → dialog. Annotate has to lead — it renders\n // above the preview, so skipping it would close the layer *underneath*\n // the one the user is looking at and strand the canvas on screen.\n if (annotatingIndex !== null) setAnnotatingIndex(null);\n else if (previewZoomed) setPreviewZoomed(false);\n else if (previewIndex !== null) closePreview();\n else handleClose();\n }\n };\n document.addEventListener(\"keydown\", handleEsc);\n return () => document.removeEventListener(\"keydown\", handleEsc);\n }, [isOpen, previewIndex, previewZoomed, annotatingIndex]);\n\n // Close screenshot preview on outside click. Registered in the CAPTURE phase\n // so it fires before the host page's own outside-click handlers (e.g. Radix\n // DismissableLayer) can stop the event from ever bubbling to our onClick.\n useEffect(() => {\n if (previewIndex === null || annotatingIndex !== null) return;\n const handlePointerDown = (e: PointerEvent) => {\n if (!previewImgRef.current?.contains(e.target as Node)) {\n closePreview();\n }\n };\n document.addEventListener(\"pointerdown\", handlePointerDown, true);\n return () =>\n document.removeEventListener(\"pointerdown\", handlePointerDown, true);\n }, [previewIndex, annotatingIndex]);\n\n // After zooming in, scroll so the point the user clicked is centred.\n useEffect(() => {\n const el = previewScrollRef.current;\n if (!previewZoomed || !el) return;\n const anchor = zoomAnchorRef.current ?? { fx: 0.5, fy: 0.5 };\n el.scrollLeft = anchor.fx * el.scrollWidth - el.clientWidth / 2;\n el.scrollTop = anchor.fy * el.scrollHeight - el.clientHeight / 2;\n }, [previewZoomed]);\n\n // Lives on the scroll container, not the <img>: while panning we hold pointer\n // capture on the container, and Chrome retargets the resulting click there\n // too — a handler on the image would never fire in the zoomed state.\n const togglePreviewZoom = (e: React.MouseEvent<HTMLDivElement>) => {\n e.stopPropagation();\n // A drag that panned the image must not also flip the zoom state.\n if (panRef.current?.moved) return;\n if (!previewZoomed && !canZoomPreview) return;\n const img = previewImgElRef.current;\n if (!previewZoomed && img) {\n const rect = img.getBoundingClientRect();\n zoomAnchorRef.current = {\n fx: (e.clientX - rect.left) / rect.width,\n fy: (e.clientY - rect.top) / rect.height,\n };\n }\n setPreviewZoomed((z) => !z);\n };\n\n const handlePanStart = (e: React.PointerEvent<HTMLDivElement>) => {\n const el = previewScrollRef.current;\n if (!previewZoomed || !el) return;\n panRef.current = {\n x: e.clientX,\n y: e.clientY,\n left: el.scrollLeft,\n top: el.scrollTop,\n moved: false,\n };\n el.setPointerCapture(e.pointerId);\n };\n\n const handlePanMove = (e: React.PointerEvent<HTMLDivElement>) => {\n const el = previewScrollRef.current;\n const start = panRef.current;\n if (!el || !start) return;\n const dx = e.clientX - start.x;\n const dy = e.clientY - start.y;\n if (Math.abs(dx) > 4 || Math.abs(dy) > 4) start.moved = true;\n el.scrollLeft = start.left - dx;\n el.scrollTop = start.top - dy;\n };\n\n const handlePanEnd = (e: React.PointerEvent<HTMLDivElement>) => {\n const el = previewScrollRef.current;\n const moved = panRef.current?.moved ?? false;\n try {\n el?.releasePointerCapture(e.pointerId);\n } catch {\n /* pointer already released */\n }\n // Keep `moved` readable through the click that follows this pointerup.\n if (moved) {\n panRef.current = { x: 0, y: 0, left: 0, top: 0, moved: true };\n setTimeout(() => {\n panRef.current = null;\n }, 0);\n } else {\n panRef.current = null;\n }\n };\n\n // Paste files from clipboard (Cmd+V / Ctrl+V) when dialog is open. Images land\n // in the screenshot strip, any other pasted file becomes an attachment. Plain\n // text is untouched so typing into the textarea still pastes normally.\n useEffect(() => {\n if (!isOpen) return;\n const handlePaste = (e: ClipboardEvent) => {\n try {\n const items = e.clipboardData?.items;\n if (!items) return;\n const pasted: File[] = [];\n for (let i = 0; i < items.length; i++) {\n if (items[i].kind !== \"file\") continue;\n const file = items[i].getAsFile();\n if (file) pasted.push(file);\n }\n if (pasted.length > 0) {\n e.preventDefault();\n addFiles(pasted);\n }\n } catch {\n // silently fail\n }\n };\n window.addEventListener(\"paste\", handlePaste);\n return () => window.removeEventListener(\"paste\", handlePaste);\n }, [isOpen]);\n\n useEffect(() => {\n if (!isOpen || !transcribeAudio) return;\n const id = setInterval(() => {\n setPlaceholderIdx((i) => (i + 1) % 2);\n }, 3000);\n return () => clearInterval(id);\n }, [isOpen, transcribeAudio]);\n\n // Voice callbacks fire outside React's render, so they need the current text,\n // not the text that was on screen when listening started.\n useEffect(() => {\n descriptionRef.current = description;\n }, [description]);\n\n /**\n * Adopt the user's own typing as the base voice appends to.\n *\n * `voiceBaseRef` is a snapshot taken when listening started. Every speech\n * result rewrote the whole field from that snapshot, so a sentence typed\n * while the mic was open vanished on the next word recognised. If the field\n * no longer holds what voice last wrote, the difference is the user's, and\n * the next result appends to it instead of replacing it.\n */\n const rebaseVoiceOnUserEdits = () => {\n const live = descriptionRef.current;\n // Before voice has written anything, the field's own starting text is the\n // baseline; after that it's whatever voice put there last.\n const baseline = lastVoiceTextRef.current ?? textBeforeVoiceRef.current;\n if (live === baseline) return;\n voiceBaseRef.current = live;\n textBeforeVoiceRef.current = live;\n };\n\n /** Write voice output and remember it, so later edits are detectable. */\n const setDescriptionFromVoice = (text: string) => {\n lastVoiceTextRef.current = text;\n descriptionRef.current = text;\n setDescription(text);\n };\n\n const stopVoice = () => {\n usingWebSpeechRef.current = false;\n recognitionRef.current?.stop();\n recognitionRef.current = null;\n sarvamChunksRef.current = [];\n const stream = streamRef.current;\n streamRef.current = null;\n stream?.getTracks().forEach((t) => t.stop());\n try { mediaRecorderRef.current?.stop(); } catch { /* ignore */ }\n mediaRecorderRef.current = null;\n setIsListening(false);\n setIsTranscribing(false);\n };\n\n const stopListeningAndTranscribe = () => {\n usingWebSpeechRef.current = false;\n recognitionRef.current?.stop();\n recognitionRef.current = null;\n setIsListening(false);\n try { mediaRecorderRef.current?.stop(); } catch { /* ignore */ }\n };\n\n /**\n * Is the AI sheet the surface in charge right now?\n *\n * When it is, the dialog is hidden outright rather than dimmed behind it. The\n * two share `description` and `severity`, so leaving it on screen showed the\n * same report text, the same severity buttons and a second Send Report behind\n * a translucent overlay — one report wearing two faces. Nothing is lost by\n * hiding it: the state is shared, so \"Write it myself\" brings it straight\n * back with everything intact.\n *\n * RATING used to be excluded here. It no longer is: the sheet asks what this\n * is, so \"Rate us\" is one of the answers it has to be able to handle, and\n * bouncing someone back to the dialog for the one non-report tile would be a\n * surface switch mid-sentence.\n */\n const sheetUp = !!assist && assistOpen;\n\n /**\n * `display:none` already takes the dialog out of the tab order, but it is set\n * by React on the overlay while `inert`/`aria-hidden` go on the card itself —\n * so this also covers the frame where the sheet is mounting and the dialog\n * has not yet been hidden.\n */\n useEffect(() => {\n const el = modalRef.current;\n if (!el) return;\n if (sheetUp) {\n el.setAttribute(\"inert\", \"\");\n el.setAttribute(\"aria-hidden\", \"true\");\n } else {\n el.removeAttribute(\"inert\");\n el.removeAttribute(\"aria-hidden\");\n }\n }, [sheetUp, isOpen]);\n\n const handleClose = () => {\n stopVoice();\n setIsOpen(false);\n onClose?.();\n // A capture still running belongs to this report, not the next one.\n openGenRef.current += 1;\n pendingShotRef.current = null;\n setShotPending(false);\n // The preview and annotation overlays are full-viewport portals at the top of\n // the stacking order. Leaving their indices set on close leaves one of them\n // mounted over a dialog that is no longer there — the page stops accepting\n // typing or selection entirely, and the next open renders *underneath* it.\n closePreview();\n setAnnotatingIndex(null);\n setStep(1);\n setRating(0);\n setHoveredStar(0);\n setReportType(\"BUG\");\n setTypeChosen(false);\n setDuplicateIssueNumber(null);\n setDuplicateKind(\"duplicate\");\n setSimilarIssues(null);\n setPickedSimilar(null);\n setCheckingSimilar(false);\n setAttachingTo(null);\n setSeverity(null);\n setValidationError(null);\n setSelfReportFrom(null);\n setVoiceError(null);\n setIsEnhanced(false);\n setOriginalDescription(null);\n // A new report is a new conversation. Leaving `assistUsed` set would hide\n // the assistant for the rest of the page's life after one use.\n setAssistOpen(false);\n setAssistUsed(false);\n setAssistNotice(null);\n };\n\n const toggleVoice = async () => {\n if (isListening) {\n stopListeningAndTranscribe();\n return;\n }\n\n // Fresh run: nothing on screen came from voice yet.\n lastVoiceTextRef.current = null;\n hadWebSpeechRef.current = false;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const SpeechRec: (new () => any) | undefined = (typeof window !== \"undefined\")\n ? ((window as any).SpeechRecognition || (window as any).webkitSpeechRecognition)\n : undefined;\n\n // Get mic stream for MediaRecorder (Sarvam final accurate result)\n //\n // `navigator.mediaDevices` is absent outside a secure context and patchy in\n // some WebViews, so reaching straight for `.getUserMedia` throws a\n // TypeError carrying no usable `name`. Check for it first — but only give\n // up when Web Speech is missing too. Web Speech needs no recorder stream,\n // so it can still transcribe here; it just loses the Sarvam correction.\n let stream: MediaStream | null = null;\n const canRecord =\n typeof navigator !== \"undefined\" && !!navigator.mediaDevices?.getUserMedia;\n if (!canRecord && !SpeechRec) {\n setVoiceError(MIC_MESSAGES.insecure);\n return;\n }\n try {\n if (canRecord)\n stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n } catch (err) {\n // Bail on every cause we can name, and say which one it is.\n //\n // The old code returned only on a denial and let everything else fall\n // through to Web Speech — which starts by calling `setVoiceError(null)`,\n // wiping the message, and then reports its own `audio-capture` failure as\n // \"Microphone access denied\". A machine with no microphone at all was\n // told its permissions were the problem.\n const message = micErrorMessage(err);\n if (message) { setVoiceError(message); return; }\n // Unrecognised failure: Web Speech may still work without a recorder\n // stream, so try it rather than refusing outright.\n if (!SpeechRec) { setVoiceError(MIC_MESSAGES.generic); return; }\n }\n\n if (stream && transcribeAudio) {\n streamRef.current = stream;\n sarvamChunksRef.current = [];\n textBeforeVoiceRef.current = descriptionRef.current;\n\n const rec = new MediaRecorder(stream);\n mediaRecorderRef.current = rec;\n rec.ondataavailable = (e) => { if (e.data.size > 0) sarvamChunksRef.current.push(e.data); };\n rec.onstop = async () => {\n stream!.getTracks().forEach((t) => t.stop());\n if (streamRef.current === stream) streamRef.current = null;\n mediaRecorderRef.current = null;\n const chunks = sarvamChunksRef.current;\n sarvamChunksRef.current = [];\n if (!chunks.length || !transcribeAudio) return;\n setIsTranscribing(true);\n try {\n const blob = new Blob(chunks, { type: rec.mimeType || \"audio/webm\" });\n const text = await transcribeAudio(blob);\n if (text.trim()) {\n const live = descriptionRef.current;\n // No Web Speech (Firefox) means nothing has written a voice\n // baseline, so compare against the text this run started with —\n // otherwise typing during a Firefox recording is wiped here.\n const baseline =\n lastVoiceTextRef.current ?? textBeforeVoiceRef.current;\n const userEdited = live !== baseline;\n if (userEdited && hadWebSpeechRef.current) {\n // The field already holds the Web Speech preview plus whatever\n // the user typed around it. Overwriting from a snapshot would\n // delete the typing; appending would say the sentence twice. A\n // slightly rougher transcript is the better of the three.\n } else {\n // Replace the live Web Speech preview with the accurate Sarvam\n // result. When the user typed and there was no preview to\n // replace, their words are the base and Sarvam follows them.\n const base = userEdited ? live : textBeforeVoiceRef.current;\n const sep = base.trim() ? \" \" : \"\";\n setDescriptionFromVoice(base + sep + text.trim());\n setValidationError(null);\n setIsEnhanced(false);\n setOriginalDescription(null);\n }\n }\n } catch { /* keep Web Speech result on failure */ }\n setIsTranscribing(false);\n };\n rec.start();\n }\n\n if (SpeechRec) {\n setVoiceError(null);\n usingWebSpeechRef.current = true;\n hadWebSpeechRef.current = true;\n voiceBaseRef.current = descriptionRef.current;\n textBeforeVoiceRef.current = descriptionRef.current;\n const recognition = new SpeechRec();\n recognition.lang = \"en-IN\";\n recognition.interimResults = true;\n recognition.continuous = true;\n recognitionRef.current = recognition;\n\n recognition.onstart = () => setIsListening(true);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n recognition.onresult = (event: any) => {\n let finalText = \"\";\n let interimText = \"\";\n for (let i = event.resultIndex; i < event.results.length; i++) {\n const text = event.results[i][0].transcript;\n if (event.results[i].isFinal) finalText += text;\n else interimText += text;\n }\n rebaseVoiceOnUserEdits();\n if (finalText) {\n const sep = voiceBaseRef.current.trim() ? \" \" : \"\";\n voiceBaseRef.current += sep + finalText.trim();\n }\n const liveText = interimText\n ? voiceBaseRef.current + (voiceBaseRef.current.trim() ? \" \" : \"\") + interimText\n : voiceBaseRef.current;\n setDescriptionFromVoice(liveText);\n setValidationError(null);\n };\n\n recognition.onend = () => {\n if (usingWebSpeechRef.current && recognitionRef.current === recognition) {\n try { recognition.start(); } catch { /* ignore */ }\n } else {\n setIsListening(false);\n }\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n recognition.onerror = (event: any) => {\n if (event.error === \"aborted\" || event.error === \"no-speech\") return;\n // `audio-capture` is not a permission problem — it is the mic failing\n // to open at all — so it gets the hardware message, not the site-block\n // one. Sending a user with no microphone to their site settings is a\n // wild goose chase.\n setVoiceError(\n event.error === \"not-allowed\"\n ? MIC_MESSAGES.blocked\n : event.error === \"audio-capture\"\n ? MIC_MESSAGES.notFound\n : \"Speech recognition not available — try Chrome\",\n );\n usingWebSpeechRef.current = false;\n recognitionRef.current = null;\n setIsListening(false);\n };\n\n recognition.start();\n } else if (stream) {\n // Firefox: Sarvam-only, no live preview\n setVoiceError(null);\n setIsListening(true);\n }\n };\n\n /**\n * Disarm a pending push-to-talk hold.\n *\n * Anything that proves the user is typing rather than holding cancels it: a\n * second edit to the field, or a keystroke that isn't the space we armed on.\n * Without this the timer fired mid-sentence, and the fix-up it ran then\n * (delete a character, move the caret) landed on text the user had typed in\n * the meantime — every following keystroke went into the middle of a word.\n */\n const cancelPushToTalkArm = () => {\n if (!spaceTimerRef.current) return;\n clearTimeout(spaceTimerRef.current);\n spaceTimerRef.current = null;\n };\n\n /** Count edits during the hold window; the second one means \"still typing\". */\n const notePushToTalkEdit = () => {\n if (!spaceTimerRef.current) return;\n spaceEditsRef.current += 1;\n if (spaceEditsRef.current > 1) cancelPushToTalkArm();\n };\n\n const handleSpaceDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.code !== \"Space\") {\n // Any other key while armed — this is typing, not a hold.\n if (!e.metaKey && !e.ctrlKey && !e.altKey) cancelPushToTalkArm();\n return;\n }\n // Recording or already-committed to push-to-talk — swallow the space\n if (isListening || isPushToTalkRef.current) {\n e.preventDefault();\n return;\n }\n // Auto-repeat from a held key, or a timer already pending — let the browser\n // type normally; we only care about the first keydown of a hold.\n if (e.repeat || !transcribeAudio || isTranscribing || spaceTimerRef.current)\n return;\n // Only ever arm from an empty field.\n //\n // 400ms on the space bar is not a gesture, it's a pause: stopping to think\n // mid-sentence held the key long enough to swallow the space AND open the\n // mic, after which speech results rewrote what had been typed. Nobody\n // \"held space\" — they wrote a bug report. The hint that advertises this\n // (\"Hold Space to speak\") is a placeholder, so it is only on screen when\n // the field is empty; arming only there is exactly what was promised, and\n // it puts the trigger somewhere no sentence can reach it. Voice mid-report\n // is still one tap away on the mic button.\n if (e.currentTarget.value !== \"\") return;\n\n // Don't preventDefault: let the browser insert the space natively so the\n // cursor stays exactly where the user typed it. If the hold matures into\n // push-to-talk, strip that space back out below.\n //\n // No offset is captured here on purpose. The timer used to remember where\n // the caret was at keydown and edit there 400ms later; by then the user had\n // often typed on, so it deleted an unrelated space and dragged the caret\n // back into finished words. The hold now cancels the moment a second edit\n // or another key arrives, and the strip below reads the live caret.\n spaceEditsRef.current = 0;\n spaceTimerRef.current = setTimeout(() => {\n spaceTimerRef.current = null;\n isPushToTalkRef.current = true;\n const el = textareaRef.current;\n const caret = el?.selectionStart ?? null;\n // Only touch the field when the caret is still sitting right after the\n // space this hold typed. Anything else (a selection, a moved caret) is\n // left alone — a stray space beats scrambled words.\n if (\n el &&\n caret !== null &&\n caret === el.selectionEnd &&\n el.value[caret - 1] === \" \"\n ) {\n const cut = caret - 1;\n setDescription((prev) =>\n prev[cut] === \" \" ? prev.slice(0, cut) + prev.slice(cut + 1) : prev,\n );\n // toggleVoice() runs on this same tick and snapshots descriptionRef;\n // the state update hasn't landed yet, so keep the mirror honest.\n descriptionRef.current =\n descriptionRef.current.slice(0, cut) +\n descriptionRef.current.slice(cut + 1);\n requestAnimationFrame(() => {\n if (textareaRef.current) {\n textareaRef.current.selectionStart = cut;\n textareaRef.current.selectionEnd = cut;\n }\n });\n }\n void toggleVoice();\n }, 400);\n };\n\n const handleSpaceUp = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.code !== \"Space\") return;\n // Quick tap — space was already typed natively, nothing to do.\n cancelPushToTalkArm();\n if (isPushToTalkRef.current) {\n isPushToTalkRef.current = false;\n stopListeningAndTranscribe();\n }\n };\n\n const handleSubmit = async (opts?: {\n duplicateOf?: number;\n /** With `duplicateOf`: same problem, or a related request on that issue. */\n kind?: AttachKind;\n skipSimilar?: boolean;\n }) => {\n try {\n if (isSubmitting) return;\n\n // A rating takes the feedback path: the stars are the payload, the words\n // are optional, and nothing here reaches GitHub. The low-quality-text\n // guard is deliberately skipped — \"love it\" is a fine testimonial and a\n // useless bug report, and this branch is the former.\n if (isRating) {\n if (rating < 1) {\n setValidationError(\"Pick a star rating first.\");\n return;\n }\n if (!sendFeedback) return;\n\n setIsSubmitting(true);\n const result = await sendFeedback(rating, description.trim() || undefined);\n if (result?.success) {\n setSubmitted(true);\n setDescription(\"\");\n setRating(0);\n setTimeout(() => {\n setSubmitted(false);\n handleClose();\n }, 2000);\n } else {\n setValidationError(\"Could not send — please try again.\");\n }\n setIsSubmitting(false);\n return;\n }\n\n if (!description.trim()) return;\n\n const qualityError = isLowQualityText(description);\n if (qualityError) {\n setValidationError(qualityError);\n setStep(2);\n return;\n }\n\n // Severity is a real answer, not a pre-filled one. Gated here rather than\n // through `submitDisabled` so Send stays live and says why — a greyed-out\n // button with no message is the failure this replaced.\n if (showSeverity && reportType === \"BUG\" && !severity) {\n setValidationError(SEVERITY_REQUIRED);\n setStep(2);\n return;\n }\n\n // Read now, not off state after a setter: \"Add to #N\" picks the issue\n // and submits in the same click, before a re-render could deliver it.\n const duplicateOf = opts?.duplicateOf ?? duplicateIssueNumber;\n const attachKind: AttachKind = opts?.duplicateOf ? (opts.kind ?? \"duplicate\") : duplicateKind;\n\n // \"Is this already filed?\" — once, on the plain form. Not after the\n // assistant ran (it already walked the reporter through open issues), and\n // not when a duplicate is already picked. Anything short of a real match\n // inside SIMILAR_WAIT_MS sends the report as it always has.\n if (findSimilarIssues && !opts?.skipSimilar && !duplicateOf && !aiConversationId) {\n setIsSubmitting(true);\n setCheckingSimilar(true);\n const matches = await Promise.race([\n findSimilarIssues(description.trim()).catch(() => null),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), SIMILAR_WAIT_MS)),\n ]);\n setCheckingSimilar(false);\n if (matches && matches.length > 0) {\n setSimilarIssues(matches.slice(0, MAX_SIMILAR_SHOWN));\n // Nothing starts picked: a preselected row turns an unread tap into\n // a comment on the wrong issue.\n setPickedSimilar(null);\n setIsSubmitting(false);\n return;\n }\n }\n\n setIsSubmitting(true);\n // A page shot still being re-drawn gets a moment to make it in — worth\n // SHOT_WAIT_MS, not a report that never sends (#363).\n let shots = screenshots;\n const pending = pendingShotRef.current;\n if (pending) {\n const shot = await Promise.race([\n pending.catch(() => null),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), SHOT_WAIT_MS)),\n ]);\n if (shot && !shots.includes(shot)) {\n shots = [shot, ...shots.filter((s) => s !== pageShot)];\n }\n }\n const metadata: Record<string, string> = {};\n if (shots.length > 0) metadata.screenshots = JSON.stringify(shots);\n if (attachments.length > 0) metadata.attachments = JSON.stringify(attachments);\n if (showSeverity && reportType === \"BUG\" && severity) {\n metadata.severity = severity;\n }\n if (duplicateOf) {\n metadata.duplicateIssueNumber = String(duplicateOf);\n // Absent means the same problem — what every older server assumes.\n if (attachKind === \"related\") metadata.duplicateKind = \"related\";\n }\n if (aiConversationId) {\n metadata.aiConversationId = aiConversationId;\n }\n\n const result = await report(\n // The RATING branch returned above, so anything reaching here is a real\n // ReportType — the widened tile union can't leak into the report API.\n reportType as ReportType,\n description.trim(),\n Object.keys(metadata).length > 0 ? metadata : undefined,\n );\n\n if (result) {\n // Only when the server really attached. A pick it refused (issue closed\n // since) is filed as a new issue, and saying \"added to #N\" would be a lie.\n setAddedToIssue(duplicateOf && result.issueNumber === duplicateOf ? duplicateOf : null);\n setAddedAsRelated(!!duplicateOf && result.issueNumber === duplicateOf && attachKind === \"related\");\n const queued = result.status === \"QUEUED\" && !!result.message;\n setQueuedMessage(queued ? (result.message ?? null) : null);\n setSubmitted(true);\n setDescription(\"\");\n setScreenshots([]);\n setAttachments([]);\n // The dialog outlives the report. Without this, a second bug typed by\n // hand in the same session inherits the first one's chat and duplicate\n // match — and \"how many prompts per issue\" is measured off a chat that\n // wrote none of it.\n setAiConversationId(null);\n setDuplicateIssueNumber(null);\n setDuplicateKind(\"duplicate\");\n setSimilarIssues(null);\n setPickedSimilar(null);\n\n // A queued report carries a sentence worth reading; \"sent\" is a glance.\n setTimeout(() => {\n setSubmitted(false);\n setQueuedMessage(null);\n handleClose();\n }, queued ? 6000 : 2000);\n }\n setIsSubmitting(false);\n setAttachingTo(null);\n } catch {\n setIsSubmitting(false);\n setCheckingSimilar(false);\n setAttachingTo(null);\n }\n };\n\n if (!mounted) return null;\n\n return (\n <>\n {/* Keyframes for REC pulse — injected once when open */}\n {isOpen &&\n createPortal(\n <style>{`\n @keyframes gg-pulse{0%,100%{opacity:1}50%{opacity:0.35}}\n @keyframes gg-spin{to{transform:rotate(360deg)}}\n @keyframes gg-b1{0%,100%{height:3px}40%{height:13px}}\n @keyframes gg-b2{0%,100%{height:8px}50%{height:3px}}\n @keyframes gg-b3{0%,100%{height:4px}30%{height:14px}70%{height:5px}}\n @keyframes gg-b4{0%,100%{height:6px}60%{height:13px}}\n @keyframes gg-bug-crawl{0%,100%{transform:translateX(0) rotate(0deg)}20%{transform:translateX(-1.5px) rotate(-6deg)}40%{transform:translateX(1.5px) rotate(5deg)}60%{transform:translateX(-1px) rotate(-4deg)}80%{transform:translateX(1px) rotate(3deg)}}\n @keyframes gg-star-spin{0%,100%{transform:scale(1) rotate(0deg)}50%{transform:scale(1.15) rotate(15deg)}}\n @keyframes gg-ui-grow{0%,100%{transform:scaleY(1)}50%{transform:scaleY(1.12)}}\n @keyframes gg-perf-sweep{0%,100%{transform:rotate(0deg)}30%{transform:rotate(-12deg)}70%{transform:rotate(10deg)}}\n @keyframes gg-shield-pulse{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(1.08);opacity:.75}}\n @keyframes gg-question-shake{0%,100%{transform:rotate(0deg)}25%{transform:rotate(-7deg)}75%{transform:rotate(7deg)}}\n @keyframes gg-chat-tilt{0%,100%{transform:rotate(0deg) translateY(0)}50%{transform:rotate(-6deg) translateY(-2px)}}\n button[data-gg-type] > svg{transform-origin:center}\n button[data-gg-type=\"BUG\"] > svg{animation:gg-bug-crawl 2.2s ease-in-out infinite}\n button[data-gg-type=\"FEATURE_REQUEST\"] > svg{animation:gg-star-spin 2.6s ease-in-out infinite}\n button[data-gg-type=\"UI_IMPROVEMENT\"] > svg{animation:gg-ui-grow 1.8s ease-in-out infinite;transform-origin:bottom}\n button[data-gg-type=\"PERFORMANCE\"] > svg{animation:gg-perf-sweep 2.4s ease-in-out infinite}\n button[data-gg-type=\"SECURITY\"] > svg{animation:gg-shield-pulse 2.2s ease-in-out infinite;transform-origin:top}\n button[data-gg-type=\"QUESTION\"] > svg{animation:gg-question-shake 2s ease-in-out infinite}\n button[data-gg-type=\"OTHER\"] > svg{animation:gg-chat-tilt 2.2s ease-in-out infinite}\n /* Lift on hover, settle on press. Cheaper and steadier than doing it\n through React state, and :focus-visible keeps the ring off mouse users\n while leaving it for the arrow-key path. */\n button[data-gg-type]{transition:transform .15s ease,border-color .15s ease,box-shadow .15s ease,background-color .15s ease}\n button[data-gg-type]:hover{transform:translateY(-2px);box-shadow:0 6px 16px rgba(0,0,0,.18)}\n button[data-gg-type]:active{transform:translateY(0) scale(.985);box-shadow:none}\n button[data-gg-type]:focus-visible{outline:2px solid ${t.accent};outline-offset:2px}\n @keyframes gg-star-pop{0%{transform:scale(.6);opacity:0}60%{transform:scale(1.12)}100%{transform:scale(1);opacity:1}}\n button[data-gg-star]{transition:transform .12s ease}\n button[data-gg-star]:hover{transform:scale(1.18)}\n button[data-gg-star]:active{transform:scale(.94)}\n button[data-gg-star]:focus-visible{outline:2px solid #f59e0b;outline-offset:3px;border-radius:4px}\n `}</style>,\n document.body,\n )}\n {/* Report modal */}\n {isOpen &&\n createPortal(\n <div\n data-glitchgrab-layer=\"\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n pointerEvents: \"auto\",\n // Hidden, not unmounted, while the AI sheet is in charge — the\n // dialog's state IS the report, and unmounting would drop the\n // screenshots, attachments and step the reporter is on.\n display: sheetUp ? \"none\" : \"flex\",\n alignItems: sheet ? \"stretch\" : \"center\",\n justifyContent: sheet ? \"flex-end\" : \"center\",\n backgroundColor: \"rgba(0,0,0,0.5)\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n }}\n onClick={() => {\n if (previewIndex === null) handleClose();\n }}\n onPointerDown={(e) => e.stopPropagation()}\n onFocus={(e) => e.stopPropagation()}\n >\n <div\n ref={modalRef}\n // Hosts wait on `[role=\"dialog\"]` to know the dialog is up — without\n // it, a host's \"Opening…\" spinner sat out its own timeout long after\n // the dialog was on screen (#363).\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Report an issue\"\n onClick={(e) => e.stopPropagation()}\n style={{\n position: \"relative\",\n zIndex: 2147483647,\n width: sheet ? \"440px\" : \"420px\",\n maxWidth: sheet ? \"100%\" : \"calc(100% - 32px)\",\n maxHeight: sheet ? \"100dvh\" : \"calc(100dvh - 32px)\",\n ...(sheet ? { height: \"100dvh\", borderLeft: `1px solid ${t.inputBorder}` } : {}),\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: t.bg,\n borderRadius: sheet ? 0 : \"12px\",\n boxShadow: sheet\n ? \"0 20px 60px rgba(0, 0, 0, 0.35)\"\n : \"0 20px 60px rgba(0, 0, 0, 0.2), 0 4px 16px rgba(0, 0, 0, 0.1)\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n overflow: \"hidden\",\n color: t.text,\n isolation: \"isolate\",\n }}\n >\n {/* Header */}\n <div\n style={{\n flexShrink: 0,\n padding: \"16px 16px 12px\",\n borderBottom: `1px solid ${t.border}`,\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n }}\n >\n {/* Back leads to the type grid — nowhere to go with one type. */}\n {step > 1 && availableTypes.length > 1 && (\n <button\n type=\"button\"\n onClick={() => setStep((s) => (s - 1) as 1 | 2)}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"2px\",\n display: \"flex\",\n alignItems: \"center\",\n }}\n aria-label=\"Back\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n >\n <path\n d=\"M10 3L5 8L10 13\"\n stroke={t.textMuted}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n )}\n <span\n style={{\n fontSize: \"15px\",\n fontWeight: 600,\n color: t.text,\n }}\n >\n {step === 1 ? \"What's on your mind?\" : \"Tell us more\"}\n </span>\n </div>\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n }}\n >\n {step === 1 && (\n <span\n title=\"Press this anywhere to open Glitchgrab\"\n style={{\n fontSize: \"10px\",\n fontWeight: 600,\n lineHeight: 1,\n padding: \"3px 6px\",\n borderRadius: \"4px\",\n border: `1px solid ${t.inputBorder}`,\n background: t.inputBg,\n color: t.textMuted,\n whiteSpace: \"nowrap\",\n }}\n >\n {getShortcutLabel()}\n </span>\n )}\n <button\n type=\"button\"\n onClick={handleClose}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n aria-label=\"Close\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{ display: \"block\" }}\n >\n <path\n d=\"M4 4L12 12M12 4L4 12\"\n stroke={t.textMuted}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n {/* Two steps only exist when there is a type to pick. */}\n {availableTypes.length > 1 && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: \"0\",\n marginTop: \"12px\",\n }}\n >\n {[1, 2].map((s, i) => (\n <div\n key={s}\n style={{ display: \"flex\", alignItems: \"center\" }}\n >\n <div\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: s <= step ? t.accent : t.inputBorder,\n transition: \"background-color 0.2s ease\",\n }}\n />\n {i < 1 && (\n <div\n style={{\n width: \"40px\",\n height: \"2px\",\n backgroundColor:\n s < step ? t.accent : t.inputBorder,\n transition: \"background-color 0.2s ease\",\n }}\n />\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Body */}\n <div\n style={{\n padding: \"18px\",\n overflowY: \"auto\",\n flex: \"1 1 auto\",\n minHeight: 0,\n }}\n >\n {submitted ? (\n <div\n style={{\n textAlign: \"center\",\n padding: \"20px 0\",\n color: t.accent,\n fontSize: \"14px\",\n fontWeight: 500,\n }}\n >\n {queuedMessage ? (\n <span\n style={{\n // amber-500 reads on the dark panel, amber-700 on the light one\n color: isDark ? \"#f59e0b\" : \"#b45309\",\n fontWeight: 400,\n lineHeight: 1.5,\n }}\n >\n {queuedMessage}\n </span>\n ) : addedToIssue\n ? `Added to #${addedToIssue}${addedAsRelated ? \" as a related request\" : \"\"}. Thank you!`\n : `${getTypeLabel(reportType)} sent. Thank you!`}\n </div>\n ) : (\n <>\n {/* Step 1: Category */}\n {/* Rating hero — a compliment is a different act from filing\n a bug, so it gets its own row instead of hiding as the\n 8th identical tile. Clicking a star both sets it and\n advances, turning a 3-click flow into 1. */}\n {step === 1 && headerSlot ? (\n <div style={{ marginBottom: \"14px\" }}>{headerSlot}</div>\n ) : null}\n\n {step === 1 && sendFeedback && (\n <div\n style={{\n border: \"1px solid rgba(245,158,11,0.35)\",\n background: \"rgba(245,158,11,0.07)\",\n borderRadius: \"10px\",\n padding: \"14px 16px\",\n marginBottom: \"16px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: \"12px\",\n flexWrap: \"wrap\",\n }}\n onMouseLeave={() => setHoveredStar(0)}\n >\n <span\n style={{ fontSize: \"13px\", fontWeight: 600, color: t.text }}\n >\n How are we doing?\n </span>\n <span style={{ display: \"flex\", gap: \"4px\" }}>\n {[1, 2, 3, 4, 5].map((star) => {\n // `rating` is normally 0 here; it only shows through\n // when someone rated, hit Back, and returned.\n const filled = star <= (hoveredStar || rating);\n return (\n <button\n key={star}\n type=\"button\"\n data-gg-star={star}\n aria-label={`${star} star${star > 1 ? \"s\" : \"\"}`}\n onMouseEnter={() => setHoveredStar(star)}\n onFocus={() => setHoveredStar(star)}\n onClick={() => {\n setRating(star);\n setReportType(\"RATING\");\n setTypeChosen(true);\n setStep(2);\n }}\n style={{\n border: \"none\",\n background: \"transparent\",\n padding: 0,\n cursor: \"pointer\",\n lineHeight: 0,\n }}\n >\n <svg width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.4 6.8 19.1l1-5.8L3.5 9.2l5.9-.9L12 3z\"\n fill={filled ? \"#f59e0b\" : \"transparent\"}\n stroke=\"#f59e0b\"\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n );\n })}\n </span>\n </div>\n )}\n\n {step === 1 && sendFeedback && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"10px\",\n marginBottom: \"16px\",\n }}\n >\n <span style={{ flex: 1, height: \"1px\", background: t.border }} />\n <span style={{ fontSize: \"11px\", color: t.textMuted }}>\n or report something\n </span>\n <span style={{ flex: 1, height: \"1px\", background: t.border }} />\n </div>\n )}\n\n {/* The dialog screenshots the screen the moment it opens.\n Saying so here — with a way out — is the honest place to\n do it; step 2 was one screen too late to be a choice. */}\n {step === 1 && screenshots.length > 0 && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"10px\",\n marginBottom: \"14px\",\n padding: \"8px 10px\",\n border: `1px solid ${t.inputBorder}`,\n borderRadius: \"8px\",\n background: t.inputBg,\n }}\n >\n <img\n src={screenshots[0]}\n alt=\"\"\n style={{\n width: \"34px\",\n height: \"24px\",\n objectFit: \"cover\",\n borderRadius: \"4px\",\n border: `1px solid ${t.border}`,\n flexShrink: 0,\n }}\n />\n <span style={{ fontSize: \"11px\", color: t.textMuted, flex: 1 }}>\n Screenshot attached\n </span>\n <button\n type=\"button\"\n onClick={() => setScreenshots([])}\n aria-label=\"Remove screenshot\"\n style={{\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n cursor: \"pointer\",\n fontSize: \"15px\",\n lineHeight: 1,\n padding: \"2px 4px\",\n }}\n >\n ×\n </button>\n </div>\n )}\n\n {step === 1 && (\n <div\n ref={tileGridRef}\n onKeyDown={handleTileGridKeyDown}\n style={{\n display: \"grid\",\n gridTemplateColumns: \"1fr 1fr 1fr\",\n gap: \"10px\",\n }}\n >\n {availableTypes.map((type) => (\n <button\n key={type}\n type=\"button\"\n data-gg-type={type}\n onClick={() => {\n setReportType(type);\n setTypeChosen(true);\n setStep(2);\n }}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"9px\",\n padding: \"18px 10px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n background: t.inputBg,\n cursor: \"pointer\",\n color: t.text,\n fontFamily: \"inherit\",\n }}\n onMouseEnter={(e) => {\n (\n e.currentTarget as HTMLElement\n ).style.borderColor = t.accent;\n }}\n onMouseLeave={(e) => {\n (\n e.currentTarget as HTMLElement\n ).style.borderColor = t.inputBorder;\n }}\n >\n {getTypeIcon(type, t.accent, 22)}\n <span\n style={{\n fontSize: \"12px\",\n fontWeight: 600,\n textAlign: \"center\",\n lineHeight: \"1.2\",\n }}\n >\n {getTypeLabel(type)}\n </span>\n </button>\n ))}\n </div>\n )}\n\n {/* Step 2: Details */}\n {step === 2 && (\n <>\n {/* What you picked, still on screen and still changeable.\n Previously step 2 said only \"Tell us more\", so the\n only way to check or switch type was the Back arrow. */}\n <button\n type=\"button\"\n // One type means nothing to change it to — the chip is a label then.\n disabled={availableTypes.length === 1}\n onClick={() => setStep(1)}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"6px\",\n marginBottom: \"10px\",\n padding: \"4px 10px 4px 8px\",\n borderRadius: \"999px\",\n border: `1px solid ${isRating ? \"rgba(245,158,11,0.4)\" : t.inputBorder}`,\n background: isRating ? \"rgba(245,158,11,0.1)\" : t.inputBg,\n color: t.text,\n fontSize: \"11px\",\n fontWeight: 600,\n fontFamily: \"inherit\",\n cursor: availableTypes.length === 1 ? \"default\" : \"pointer\",\n }}\n >\n {getTypeIcon(reportType, isRating ? \"#f59e0b\" : t.accent, 13)}\n {getTypeLabel(reportType)}\n {availableTypes.length > 1 && (\n <span style={{ color: t.textMuted, fontWeight: 400 }}>· change</span>\n )}\n </button>\n\n {/* Stars carry the payload for a rating; the words below\n them are optional, so this sits above the textarea. */}\n {isRating && (\n <div\n style={{\n display: \"flex\",\n gap: \"6px\",\n marginBottom: \"12px\",\n }}\n onMouseLeave={() => setHoveredStar(0)}\n >\n {[1, 2, 3, 4, 5].map((star) => {\n const filled = star <= (hoveredStar || rating);\n return (\n <button\n key={star}\n type=\"button\"\n aria-label={`${star} star${star > 1 ? \"s\" : \"\"}`}\n onClick={() => {\n setRating(star);\n if (validationError) setValidationError(null);\n }}\n onMouseEnter={() => setHoveredStar(star)}\n style={{\n border: \"none\",\n background: \"transparent\",\n padding: 0,\n cursor: \"pointer\",\n lineHeight: 0,\n }}\n >\n <svg width=\"30\" height=\"30\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.4 6.8 19.1l1-5.8L3.5 9.2l5.9-.9L12 3z\"\n fill={filled ? \"#f59e0b\" : \"transparent\"}\n stroke={filled ? \"#f59e0b\" : t.inputBorder}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n );\n })}\n </div>\n )}\n {/* Entry point to the AI sheet (#330). The sheet itself\n renders in its own portal at the bottom of this\n component, not inline: a conversation crammed into a\n 420px card read like a form field, not a chat.\n Hidden for RATING — a star needs no help. */}\n {assist && !isRating && !assistUsed && (\n <button\n type=\"button\"\n onClick={() => {\n setAssistNotice(null);\n setTypeChosen(true);\n setAssistOpen(true);\n }}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"6px\",\n marginBottom: \"10px\",\n // 8px vertical keeps the tap target at ~32px.\n padding: \"8px 10px\",\n borderRadius: \"6px\",\n border: `1px solid ${t.accent}`,\n background: \"transparent\",\n color: t.accent,\n fontSize: \"12px\",\n fontWeight: 600,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n title=\"Answer a question or two and the assistant writes the report for you\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3zM19 15l.75 2.25L22 18l-2.25.75L19 21l-.75-2.25L16 18l2.25-.75L19 15z\"\n stroke={t.accent}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n Describe it with AI\n </button>\n )}\n <div style={{ position: \"relative\" }}>\n <textarea\n ref={textareaRef}\n value={description}\n onChange={(e) => {\n notePushToTalkEdit();\n setDescription(e.target.value);\n if (validationError) setValidationError(null);\n if (isEnhanced) {\n setIsEnhanced(false);\n setOriginalDescription(null);\n }\n }}\n placeholder={\n isTranscribing\n ? \"Transcribing your speech…\"\n : isListening\n ? \"Listening… speak now\"\n // `hasVoice` false once voice has failed: the\n // rotating placeholder advertises \"Hold Space\n // to speak\" directly above a line saying the\n // microphone is blocked.\n : getPlaceholder(reportType, placeholderIdx, !!transcribeAudio && !voiceError)\n }\n style={{\n width: \"100%\",\n minHeight: \"100px\",\n padding: enhanceText\n ? \"28px 12px 36px\"\n : transcribeAudio\n ? \"10px 12px 36px\"\n : \"10px 12px\",\n borderRadius: \"8px\",\n border: `1px solid ${isTranscribing ? \"#f59e0b\" : isListening ? t.accent : t.inputBorder}`,\n fontSize: \"14px\",\n fontFamily: \"inherit\",\n resize: \"none\",\n outline: \"none\",\n boxSizing: \"border-box\",\n color: t.text,\n backgroundColor: t.inputBg,\n transition: \"border-color 0.2s ease\",\n }}\n onKeyDown={handleSpaceDown}\n onKeyUp={handleSpaceUp}\n onFocus={(e) => {\n (\n e.target as HTMLTextAreaElement\n ).style.borderColor = t.accent;\n }}\n onBlur={(e) => {\n if (!isListening && !isTranscribing)\n (\n e.target as HTMLTextAreaElement\n ).style.borderColor = t.inputBorder;\n }}\n autoFocus\n />\n {/* Bottom-left: REC / Transcribing badge (same row as mic button) */}\n {(isListening || isTranscribing) && (\n <span\n style={{\n position: \"absolute\",\n bottom: \"10px\",\n left: \"10px\",\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"4px\",\n fontSize: \"10px\",\n fontWeight: 700,\n letterSpacing: \"0.04em\",\n color: isTranscribing ? \"#f59e0b\" : \"#ef4444\",\n pointerEvents: \"none\",\n zIndex: 1,\n }}\n >\n <span\n style={{\n width: \"6px\",\n height: \"6px\",\n borderRadius: \"50%\",\n backgroundColor: \"currentColor\",\n animation:\n \"gg-pulse 1.2s ease-in-out infinite\",\n display: \"inline-block\",\n flexShrink: 0,\n }}\n />\n {isTranscribing ? \"Transcribing…\" : \"REC\"}\n {isListening && !isTranscribing && (\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"flex-end\",\n gap: \"2px\",\n height: \"14px\",\n marginLeft: \"3px\",\n }}\n >\n {[\n { anim: \"gg-b1\", dur: \"0.6s\", delay: \"0s\" },\n {\n anim: \"gg-b2\",\n dur: \"0.5s\",\n delay: \"0.1s\",\n },\n {\n anim: \"gg-b3\",\n dur: \"0.7s\",\n delay: \"0.05s\",\n },\n {\n anim: \"gg-b4\",\n dur: \"0.55s\",\n delay: \"0.15s\",\n },\n ].map((b, i) => (\n <span\n key={i}\n style={{\n width: \"2.5px\",\n height: \"4px\",\n borderRadius: \"1px\",\n backgroundColor: \"#ef4444\",\n animation: `${b.anim} ${b.dur} ease-in-out ${b.delay} infinite`,\n display: \"inline-block\",\n alignSelf: \"center\",\n }}\n />\n ))}\n </span>\n )}\n </span>\n )}\n {/* Top-right: AI enhance */}\n {enhanceText && (\n <button\n type=\"button\"\n onClick={async () => {\n if (!description.trim() || isEnhancing) return;\n setIsEnhancing(true);\n try {\n const polished = await enhanceText(\n description,\n screenshots[0] ?? null,\n );\n if (polished && polished !== description) {\n setOriginalDescription(description);\n setDescription(polished);\n setIsEnhanced(true);\n if (validationError)\n setValidationError(null);\n }\n } finally {\n setIsEnhancing(false);\n }\n }}\n disabled={\n !description.trim() || isEnhancing || isEnhanced\n }\n style={{\n position: \"absolute\",\n top: \"6px\",\n right: \"6px\",\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"4px\",\n background: t.inputBg,\n border: \"none\",\n padding: \"2px 6px\",\n borderRadius: \"4px\",\n fontFamily: \"inherit\",\n fontSize: \"11px\",\n color: t.textMuted,\n cursor:\n !description.trim() || isEnhancing\n ? \"default\"\n : \"pointer\",\n opacity: !description.trim() ? 0.5 : 1,\n zIndex: 1,\n }}\n title=\"Polish grammar — preserves your meaning\"\n >\n <svg\n width=\"11\"\n height=\"11\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3zM19 15l.75 2.25L22 18l-2.25.75L19 21l-.75-2.25L16 18l2.25-.75L19 15z\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n {isEnhancing ? \"Enhancing...\" : \"AI enhance\"}\n </button>\n )}\n {/* Bottom-right: mic icon only, outlined */}\n {transcribeAudio && (\n <button\n type=\"button\"\n onClick={() => {\n void toggleVoice();\n }}\n title={\n isListening\n ? \"Stop recording\"\n : \"Speak your report\"\n }\n style={{\n position: \"absolute\",\n bottom: \"14px\",\n right: \"7px\",\n width: \"26px\",\n height: \"26px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n background: \"transparent\",\n border: `1.5px solid ${isListening ? \"#ef4444\" : t.inputBorder}`,\n borderRadius: \"6px\",\n color: isListening ? \"#ef4444\" : t.textMuted,\n cursor: \"pointer\",\n zIndex: 1,\n padding: 0,\n transition:\n \"border-color 0.2s ease, color 0.2s ease\",\n }}\n >\n {isListening ? (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <rect\n x=\"6\"\n y=\"6\"\n width=\"12\"\n height=\"12\"\n rx=\"2\"\n />\n </svg>\n ) : (\n <svg\n width=\"13\"\n height=\"13\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <rect\n x=\"9\"\n y=\"2\"\n width=\"6\"\n height=\"12\"\n rx=\"3\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n />\n <path\n d=\"M5 10a7 7 0 0014 0M12 19v3M9 22h6\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n />\n </svg>\n )}\n </button>\n )}\n </div>\n {/* Hidden once voice has failed: telling someone to\n hold Space to speak, directly above a line saying\n the microphone is blocked, advertises a gesture\n that cannot work. The error carries the mic story\n on its own until they retry. */}\n {transcribeAudio && !isListening && !isTranscribing && !voiceError && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"5px\",\n marginTop: \"5px\",\n fontSize: \"11px\",\n color: t.text,\n opacity: 0.55,\n userSelect: \"none\",\n }}\n >\n <svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\"/>\n </svg>\n Hold Space to speak — we'll transcribe it\n </div>\n )}\n {isEnhanced && originalDescription !== null && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n marginTop: \"6px\",\n padding: \"6px 8px\",\n borderRadius: \"6px\",\n background: isDark\n ? \"rgba(34,211,238,0.06)\"\n : \"rgba(8,145,178,0.05)\",\n border: `1px solid ${t.accent}40`,\n }}\n >\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{ flexShrink: 0 }}\n >\n <path\n d=\"M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z\"\n stroke={t.accent}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span\n style={{\n fontSize: \"11px\",\n color: t.textMuted,\n flex: 1,\n }}\n >\n AI enhanced\n </span>\n <button\n type=\"button\"\n onClick={() => {\n setIsEnhanced(false);\n setOriginalDescription(null);\n }}\n style={{\n padding: \"2px 8px\",\n borderRadius: \"4px\",\n border: `1px solid ${t.accent}`,\n background: t.accent,\n color: t.accentText,\n fontSize: \"11px\",\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n Keep\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setDescription(originalDescription);\n setIsEnhanced(false);\n setOriginalDescription(null);\n }}\n style={{\n padding: \"2px 8px\",\n borderRadius: \"4px\",\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"11px\",\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n Restore\n </button>\n </div>\n )}\n {/* Recovery instructions, not a one-word verdict —\n `lineHeight` and `maxWidth` so two sentences stay\n readable instead of running edge to edge. */}\n {voiceError && (\n <p\n role=\"alert\"\n style={{\n color: \"#ef4444\",\n fontSize: \"11px\",\n lineHeight: 1.5,\n marginTop: \"4px\",\n marginBottom: 0,\n }}\n >\n {voiceError}\n </p>\n )}\n\n {/* Why the assistant went away — a draft it wrote, a\n cap it hit, or a model that was down. Sits directly\n under the box it is talking about: a notice about\n the description that renders below Severity reads as\n being about Severity. */}\n {assistNotice && (\n <p\n style={{\n color: t.textMuted,\n fontSize: \"12px\",\n marginTop: \"6px\",\n marginBottom: 0,\n lineHeight: 1.5,\n }}\n >\n {assistNotice}\n </p>\n )}\n\n {/* Screenshot section — hidden for a rating. The dialog\n auto-captures the screen on open, and a testimonial\n has no reason to ship one (it may even be published\n publicly later). handleSubmit's rating branch never\n reads `screenshots`, so nothing leaks either way. */}\n {!isRating && (\n <div style={{ marginTop: \"10px\" }}>\n <span\n style={{\n fontSize: \"12px\",\n color: t.textMuted,\n marginBottom: \"6px\",\n display: \"block\",\n fontWeight: 500,\n }}\n >\n Attachments\n {screenshots.length + attachments.length > 0\n ? ` (${screenshots.length + attachments.length})`\n : \"\"}\n </span>\n {(screenshots.length > 0 || shotPending) && (\n <div\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: \"8px\",\n marginBottom: \"8px\",\n }}\n >\n {shotPending && (\n <div\n role=\"status\"\n aria-label=\"Capturing screenshot\"\n title=\"Capturing a screenshot of the page…\"\n style={{\n width: \"56px\",\n height: \"56px\",\n borderRadius: \"6px\",\n border: `1px dashed ${t.border}`,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"4px\",\n boxSizing: \"border-box\",\n fontSize: \"9px\",\n lineHeight: 1.2,\n textAlign: \"center\",\n color: t.textMuted,\n animation: \"gg-pulse 1.4s ease-in-out infinite\",\n }}\n >\n Capturing…\n </div>\n )}\n {screenshots.map((src, i) => (\n <div\n key={i}\n style={{\n position: \"relative\",\n width: \"56px\",\n height: \"56px\",\n }}\n >\n <img\n src={src}\n alt={`Screenshot ${i + 1}`}\n onClick={() => openPreview(i)}\n style={{\n width: \"100%\",\n height: \"100%\",\n borderRadius: \"6px\",\n border: `1px solid ${t.border}`,\n objectFit: \"cover\",\n objectPosition: \"top\",\n cursor: \"zoom-in\",\n display: \"block\",\n }}\n />\n <button\n type=\"button\"\n onClick={() =>\n setScreenshots((prev) =>\n prev.filter((_, idx) => idx !== i),\n )\n }\n aria-label={`Remove screenshot ${i + 1}`}\n style={{\n position: \"absolute\",\n top: \"-6px\",\n right: \"-6px\",\n width: \"17px\",\n height: \"17px\",\n borderRadius: \"50%\",\n border: \"none\",\n background: \"#ef4444\",\n color: \"#fff\",\n fontSize: \"11px\",\n lineHeight: 1,\n padding: 0,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <svg\n width=\"8\"\n height=\"8\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n >\n <path\n d=\"M1 1L9 9M9 1L1 9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n onClick={() => setAnnotatingIndex(i)}\n aria-label={`Annotate screenshot ${i + 1}`}\n title=\"Annotate\"\n style={{\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n width: \"24px\",\n height: \"24px\",\n borderRadius: \"50%\",\n border: \"none\",\n background: t.accent,\n color: t.accentText,\n padding: 0,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"0 2px 8px rgba(0,0,0,0.45)\",\n }}\n >\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n >\n <path\n d=\"M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z\"\n stroke=\"currentColor\"\n strokeWidth=\"2.2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n ))}\n </div>\n )}\n {attachments.length > 0 && (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"6px\",\n marginBottom: \"8px\",\n }}\n >\n {attachments.map((a, i) => (\n <div\n key={i}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n padding: \"6px 8px\",\n borderRadius: \"6px\",\n border: `1px solid ${t.border}`,\n }}\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{ flexShrink: 0, opacity: 0.6 }}\n >\n <path\n d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M14 2v6h6\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span\n style={{\n fontSize: \"11px\",\n color: t.text,\n flex: 1,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {a.name}\n </span>\n <span\n style={{ fontSize: \"10px\", color: t.textMuted }}\n >\n {(a.size / 1024).toFixed(0)}KB\n </span>\n <button\n type=\"button\"\n onClick={() =>\n setAttachments((prev) =>\n prev.filter((_, idx) => idx !== i),\n )\n }\n aria-label={`Remove ${a.name}`}\n style={{\n width: \"16px\",\n height: \"16px\",\n borderRadius: \"50%\",\n border: \"none\",\n background: \"#ef4444\",\n color: \"#fff\",\n fontSize: \"10px\",\n lineHeight: 1,\n padding: 0,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flexShrink: 0,\n }}\n >\n <svg\n width=\"8\"\n height=\"8\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n >\n <path\n d=\"M1 1L9 9M9 1L1 9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n ))}\n </div>\n )}\n {/* Drop zone — always available to add more */}\n <div\n onClick={() => fileInputRef.current?.click()}\n onDrop={(e) => {\n e.preventDefault();\n setScreenshotDragOver(false);\n addFiles(Array.from(e.dataTransfer.files));\n }}\n onDragOver={(e) => {\n e.preventDefault();\n setScreenshotDragOver(true);\n }}\n onDragLeave={() => setScreenshotDragOver(false)}\n style={{\n border: `1.5px dashed ${screenshotDragOver ? t.accent : t.inputBorder}`,\n borderRadius: \"8px\",\n padding:\n screenshots.length + attachments.length > 0\n ? \"8px 12px\"\n : \"18px 12px\",\n textAlign: \"center\",\n cursor: \"pointer\",\n background: screenshotDragOver\n ? isDark\n ? \"rgba(34,211,238,0.06)\"\n : \"rgba(8,145,178,0.04)\"\n : \"transparent\",\n transition:\n \"border-color 0.15s ease, background 0.15s ease\",\n }}\n >\n {screenshots.length + attachments.length > 0 ? (\n <p\n style={{\n margin: 0,\n fontSize: \"11px\",\n fontWeight: 500,\n color: t.textMuted,\n }}\n >\n {screenshotDragOver\n ? \"Drop to attach\"\n : \"+ Add more · Drag & drop · Paste\"}\n </p>\n ) : (\n <>\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{\n margin: \"0 auto 6px\",\n display: \"block\",\n opacity: 0.45,\n }}\n >\n <rect\n x=\"3\"\n y=\"3\"\n width=\"18\"\n height=\"18\"\n rx=\"2\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n />\n <circle\n cx=\"8.5\"\n cy=\"8.5\"\n r=\"1.5\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M21 15l-5-5L5 21\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <p\n style={{\n margin: 0,\n fontSize: \"12px\",\n fontWeight: 600,\n color: t.text,\n }}\n >\n {screenshotDragOver\n ? \"Drop to attach\"\n : \"Add screenshots or files\"}\n </p>\n <p\n style={{\n margin: \"3px 0 0\",\n fontSize: \"11px\",\n color: t.textMuted,\n }}\n >\n Images, PDF, DOC, XLS · Drag & drop · Paste\n ⌘V / Ctrl+V · Click to browse\n </p>\n </>\n )}\n </div>\n </div>\n )}\n\n {showSeverity && reportType === \"BUG\" && (\n <div style={{ marginTop: \"10px\" }}>\n <span\n style={{\n fontSize: \"12px\",\n color: t.textMuted,\n marginBottom: \"6px\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n }}\n >\n How bad is it?\n <span\n style={{\n color: severity\n ? t.textMuted\n : needsSeverity\n ? \"#ef4444\"\n : t.textMuted,\n fontSize: \"11px\",\n }}\n >\n {severity ? \"\" : \"· required\"}\n </span>\n </span>\n <div\n role=\"radiogroup\"\n aria-label=\"Severity\"\n style={{ display: \"flex\", gap: \"6px\" }}\n >\n {SEVERITY_LEVELS.map((s) => {\n const on = severity === s;\n return (\n <button\n key={s}\n type=\"button\"\n role=\"radio\"\n aria-checked={on}\n onClick={() => {\n setSeverity(s);\n if (validationError)\n setValidationError(null);\n }}\n style={{\n flex: 1,\n minWidth: 0,\n // 9px + 12px line + borders clears a 36px\n // tap target; 6px left it at ~29px.\n padding: \"9px 2px\",\n borderRadius: \"6px\",\n border: `1px solid ${\n on\n ? t.accent\n : needsSeverity\n ? \"#ef4444\"\n : t.inputBorder\n }`,\n background: on\n ? t.accent\n : \"transparent\",\n color: on ? t.accentText : t.text,\n fontSize: \"12px\",\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n whiteSpace: \"nowrap\",\n // Four labels where there were three: clip\n // rather than spill if a host squeezes the\n // dialog below ~260px.\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n transition: \"all 0.15s ease\",\n }}\n >\n {SEVERITY_LABELS[s]}\n </button>\n );\n })}\n </div>\n </div>\n )}\n {validationError && (\n <p\n style={{\n color: \"#ef4444\",\n fontSize: \"12px\",\n marginTop: \"6px\",\n }}\n >\n {validationError}\n </p>\n )}\n {similarIssues ? (\n // Same visual language as the assistant's \"Our team is\n // already on this\" card, so both routes to a duplicate\n // read as one feature.\n <div\n data-gg-similar=\"\"\n style={{\n marginTop: \"12px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"10px\",\n padding: \"12px\",\n borderRadius: \"10px\",\n border: \"1px solid rgba(245,158,11,0.4)\",\n backgroundColor: \"rgba(245,158,11,0.08)\",\n }}\n >\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"2px\" }}>\n {/* Theme text, not amber: amber on the tint is ~2:1 in light mode. */}\n <span style={{ color: t.text, fontWeight: 600, fontSize: \"13px\" }}>\n Our team may already have this, or something close\n </span>\n <span style={{ color: t.textMuted, fontSize: \"12px\", lineHeight: 1.5 }}>\n {similarIssues.length > 1\n ? \"Pick the one that matches. Same problem, or a different request for the same feature — it's added to that issue, so the team has it in one place.\"\n : \"Same problem, or a different request for the same feature? Pick it — it's added to that issue, so the team has it in one place.\"}\n </span>\n </div>\n {/* Title only, no link: an SDK reporter is a stranger to a\n private repo and the link would 404 for them. */}\n <div\n role=\"radiogroup\"\n aria-label=\"Existing issues\"\n style={{ display: \"flex\", flexDirection: \"column\", gap: \"6px\" }}\n >\n {similarIssues.map((issue) => {\n const picked = pickedSimilar === issue.number;\n return (\n <button\n key={issue.number}\n type=\"button\"\n role=\"radio\"\n aria-checked={picked}\n disabled={isSubmitting}\n onClick={() => setPickedSimilar(issue.number)}\n style={{\n display: \"flex\",\n alignItems: \"flex-start\",\n gap: \"10px\",\n width: \"100%\",\n minHeight: \"44px\",\n padding: \"9px 10px\",\n borderRadius: \"8px\",\n border: `1px solid ${picked ? t.accent : t.border}`,\n boxShadow: picked ? `0 0 0 1px ${t.accent}` : \"none\",\n backgroundColor: t.bg,\n color: t.text,\n textAlign: \"left\",\n cursor: isSubmitting ? \"not-allowed\" : \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n flexShrink: 0,\n marginTop: \"2px\",\n width: \"14px\",\n height: \"14px\",\n boxSizing: \"border-box\",\n borderRadius: \"50%\",\n border: `2px solid ${picked ? t.accent : t.textMuted}`,\n backgroundColor: picked ? t.accent : \"transparent\",\n boxShadow: picked ? `inset 0 0 0 2px ${t.bg}` : \"none\",\n }}\n />\n <span\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"3px\",\n minWidth: 0,\n }}\n >\n <span\n title={issue.title}\n style={{\n fontSize: \"12.5px\",\n lineHeight: 1.45,\n wordBreak: \"break-word\",\n overflow: \"hidden\",\n display: \"-webkit-box\",\n WebkitLineClamp: 3,\n WebkitBoxOrient: \"vertical\",\n }}\n >\n <span style={{ color: t.textMuted, fontWeight: 600 }}>\n #{issue.number}\n </span>{\" \"}\n {issue.title}\n </span>\n {issue.status && (\n <span style={{ fontSize: \"11.5px\", color: t.textMuted }}>\n {issue.status}\n </span>\n )}\n </span>\n </button>\n );\n })}\n </div>\n <button\n type=\"button\"\n disabled={isSubmitting || !pickedSimilar}\n onClick={() => {\n if (!pickedSimilar) return;\n setAttachingTo(pickedSimilar);\n setDuplicateIssueNumber(pickedSimilar);\n setDuplicateKind(\"duplicate\");\n void handleSubmit({ duplicateOf: pickedSimilar, kind: \"duplicate\" });\n }}\n style={{\n width: \"100%\",\n minHeight: \"40px\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor:\n isSubmitting || !pickedSimilar ? t.bgSecondary : t.accent,\n color: isSubmitting || !pickedSimilar ? t.textMuted : t.accentText,\n fontSize: \"14px\",\n fontWeight: 600,\n cursor: isSubmitting || !pickedSimilar ? \"not-allowed\" : \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n {typeof attachingTo === \"number\" && duplicateKind !== \"related\" ? (\n <>\n <ButtonSpinner />\n Adding to #{attachingTo}…\n </>\n ) : (\n pickedSimilar ? `Add to #${pickedSimilar}` : \"Pick the matching issue\"\n )}\n </button>\n {/* Not the same problem, but the same feature (practise_stack\n #1868 beside #1867). Only once a row is picked, so it always\n names the issue it writes to. */}\n {pickedSimilar && (\n <button\n type=\"button\"\n disabled={isSubmitting}\n onClick={() => {\n setAttachingTo(pickedSimilar);\n setDuplicateIssueNumber(pickedSimilar);\n setDuplicateKind(\"related\");\n void handleSubmit({ duplicateOf: pickedSimilar, kind: \"related\" });\n }}\n style={{\n width: \"100%\",\n minHeight: \"40px\",\n marginTop: \"-4px\",\n padding: \"9px 10px\",\n borderRadius: \"8px\",\n border: \"1px solid rgba(245,158,11,0.4)\",\n backgroundColor: \"transparent\",\n color: isSubmitting ? t.textMuted : t.text,\n fontSize: \"13px\",\n fontWeight: 600,\n cursor: isSubmitting ? \"not-allowed\" : \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n {typeof attachingTo === \"number\" && duplicateKind === \"related\" ? (\n <>\n <ButtonSpinner />\n Adding to #{attachingTo}…\n </>\n ) : (\n `Related request — add to #${pickedSimilar}`\n )}\n </button>\n )}\n <button\n type=\"button\"\n disabled={isSubmitting}\n onClick={() => {\n setAttachingTo(\"new\");\n void handleSubmit({ skipSimilar: true });\n }}\n style={{\n width: \"100%\",\n minHeight: \"40px\",\n marginTop: \"-4px\",\n padding: \"8px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor: \"transparent\",\n color: isSubmitting ? t.textMuted : t.text,\n fontSize: \"13px\",\n fontWeight: 500,\n textDecoration: \"underline\",\n textUnderlineOffset: \"3px\",\n cursor: isSubmitting ? \"not-allowed\" : \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n {attachingTo === \"new\" ? (\n <>\n <ButtonSpinner />\n Sending as new…\n </>\n ) : (\n \"No, mine is different — send as new\"\n )}\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n onClick={() => void handleSubmit()}\n disabled={submitDisabled}\n style={{\n marginTop: \"12px\",\n width: \"100%\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor: submitDisabled\n ? t.bgSecondary\n : t.accent,\n color: submitDisabled ? t.textMuted : t.accentText,\n fontSize: \"14px\",\n fontWeight: 600,\n cursor: submitDisabled ? \"not-allowed\" : \"pointer\",\n fontFamily: \"inherit\",\n transition: \"background-color 0.15s ease\",\n }}\n >\n {checkingSimilar ? (\n <>\n <ButtonSpinner />\n Checking for existing reports…\n </>\n ) : isSubmitting\n ? shotPending && !isRating\n ? \"Attaching screenshot…\"\n : \"Sending...\"\n : isRating\n ? \"Send Rating\"\n : \"Send Report\"}\n </button>\n )}\n </>\n )}\n </>\n )}\n </div>\n\n {/* Footer — who's reporting, and the attribution */}\n <div\n style={{\n padding: \"8px 16px 10px\",\n borderTop: `1px solid ${t.border}`,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: \"12px\",\n }}\n >\n <ReporterChip reporter={reporter} t={t} />\n {reportGlitchgrabProblem ? (\n <button\n type=\"button\"\n data-gg-self-report=\"\"\n onClick={() => {\n setSelfReportPrefill(\"\");\n setSelfReportFrom(\"form\");\n }}\n title=\"Something wrong with this reporter itself? Tell the Glitchgrab team.\"\n style={{\n fontSize: \"11px\",\n color: t.textMuted,\n whiteSpace: \"nowrap\",\n flexShrink: 0,\n border: \"none\",\n background: \"transparent\",\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n textDecoration: \"underline\",\n textUnderlineOffset: \"2px\",\n // A ~30px tap target without growing the footer.\n padding: \"9px 0\",\n margin: \"-9px 0\",\n }}\n >\n Problem with Glitchgrab?\n </button>\n ) : (\n <span\n style={{\n fontSize: \"11px\",\n color: t.textMuted,\n whiteSpace: \"nowrap\",\n flexShrink: 0,\n }}\n >\n Powered by Glitchgrab\n </span>\n )}\n </div>\n </div>\n </div>,\n document.body,\n )}\n\n {/* Hidden file input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={ATTACHMENT_ACCEPT}\n multiple\n onChange={handleFileUpload}\n style={{ display: \"none\" }}\n />\n\n {/* Full-screen screenshot preview */}\n {isOpen &&\n previewIndex !== null &&\n screenshots[previewIndex] &&\n createPortal(\n <div\n data-glitchgrab-layer=\"\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n backgroundColor: \"rgba(0,0,0,0.85)\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n cursor: \"pointer\",\n }}\n onClick={(e) => {\n e.stopPropagation();\n closePreview();\n }}\n onMouseDown={(e) => e.stopPropagation()}\n >\n <div\n ref={previewImgRef}\n style={{\n position: \"relative\",\n display: \"flex\",\n maxWidth: \"100%\",\n maxHeight: \"calc(100vh - 80px)\",\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div\n ref={previewScrollRef}\n onPointerDown={handlePanStart}\n onPointerMove={handlePanMove}\n onPointerUp={handlePanEnd}\n onPointerCancel={handlePanEnd}\n onClick={togglePreviewZoom}\n style={\n previewZoomed\n ? {\n // Fill the overlay so there is room to pan around a\n // full-resolution screenshot.\n width: \"calc(100vw - 32px)\",\n height: \"calc(100vh - 80px)\",\n overflow: \"auto\",\n borderRadius: \"8px\",\n touchAction: \"none\",\n cursor: \"grab\",\n }\n : { maxWidth: \"100%\", lineHeight: 0 }\n }\n >\n <img\n ref={previewImgElRef}\n src={screenshots[previewIndex]}\n alt=\"Screenshot preview\"\n onLoad={(e) =>\n setPreviewNatural({\n w: e.currentTarget.naturalWidth,\n h: e.currentTarget.naturalHeight,\n })\n }\n style={\n previewZoomed\n ? {\n // Natural size — one image pixel per CSS pixel.\n maxWidth: \"none\",\n maxHeight: \"none\",\n display: \"block\",\n cursor: \"zoom-out\",\n }\n : {\n maxWidth: \"100%\",\n maxHeight: \"calc(100vh - 80px)\",\n borderRadius: \"8px\",\n objectFit: \"contain\",\n cursor: canZoomPreview ? \"zoom-in\" : \"default\",\n display: \"block\",\n }\n }\n />\n </div>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setAnnotatingIndex(previewIndex);\n }}\n style={{\n position: \"absolute\",\n top: \"12px\",\n right: \"12px\",\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"6px\",\n padding: \"8px 14px\",\n borderRadius: \"999px\",\n border: \"none\",\n background: t.accent,\n color: t.accentText,\n fontSize: \"13px\",\n fontWeight: 700,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n boxShadow: \"0 4px 14px rgba(0,0,0,0.35)\",\n animation: \"gg-pulse 2s ease-in-out infinite\",\n }}\n >\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n Annotate\n </button>\n </div>\n <div\n style={{\n marginTop: \"12px\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"12px\",\n }}\n >\n <span\n style={{\n color: t.textMuted,\n fontSize: \"12px\",\n }}\n >\n {[\n screenshots.length > 1\n ? `${previewIndex + 1} / ${screenshots.length}`\n : null,\n canZoomPreview\n ? previewZoomed\n ? \"Drag to pan · click image to fit\"\n : \"Click image to zoom to full size\"\n : null,\n previewZoomed ? \"Esc to fit\" : \"Click outside to close\",\n ]\n .filter(Boolean)\n .join(\" · \")}\n </span>\n </div>\n </div>,\n document.body,\n )}\n\n {/* Annotation overlay */}\n {isOpen &&\n annotatingIndex !== null &&\n screenshots[annotatingIndex] &&\n createPortal(\n <AnnotationCanvas\n imageSrc={screenshots[annotatingIndex]}\n onCancel={() => setAnnotatingIndex(null)}\n onSave={(dataUrl) => {\n // Marking up the page shot keeps it the page shot.\n if (screenshots[annotatingIndex] === pageShot) setPageShot(dataUrl);\n setScreenshots((prev) =>\n prev.map((s, i) => (i === annotatingIndex ? dataUrl : s)),\n );\n setAnnotatingIndex(null);\n }}\n />,\n document.body,\n )}\n\n {/* \"Problem with Glitchgrab?\" (#366) — above the dialog AND the sheet,\n with its own send. Mounted after the sheet's portal, so at the same\n z-index it paints on top. */}\n {isOpen && selfReportFrom && reportGlitchgrabProblem && (\n <GlitchgrabProblemPanel\n send={reportGlitchgrabProblem}\n theme={layerTheme}\n surface={selfReportFrom}\n conversationId={aiConversationId}\n reportType={reportType}\n screenshots={screenshots}\n initialText={selfReportPrefill}\n onClose={() => setSelfReportFrom(null)}\n />\n )}\n\n {/* The AI sheet (#330) — its own layer, above the dialog. It owns the\n whole flow (chat → draft → Send) but NOT submission: `description`,\n `severity` and `handleSubmit` are this component's own, so there is\n exactly one submit path and the sheet cannot drift from it. */}\n {isOpen && sheetUp && (\n <AssistSheet\n assist={assist}\n theme={layerTheme}\n // Every image, not just the first: the auto page shot arrived at [0],\n // so passing that one meant a pasted picture never reached the model\n // however visibly it was attached (#352). The sheet sends the newest\n // few and shows the rest.\n screenshots={screenshots}\n pageShot={pageShot}\n onAddFiles={addFiles}\n onRemoveImage={(index) =>\n setScreenshots((prev) => prev.filter((_, i) => i !== index))\n }\n // Non-image attachments too (#1851): the assistant reads the text\n // ones, so a mockup attached on the form is part of the conversation.\n files={attachments}\n onRemoveFile={(index) =>\n setAttachments((prev) => prev.filter((_, i) => i !== index))\n }\n attachmentCount={screenshots.length + attachments.length}\n context={{ ...(assistContext ?? {}), reportType }}\n reportTypeLabel={getTypeLabel(reportType)}\n typePicked={typeChosen}\n currentTile={reportType}\n tiles={sendFeedback ? [...availableTypes, \"RATING\"] : availableTypes}\n onPickType={(tile) => {\n setReportType(tile);\n setTypeChosen(true);\n // Keep the dialog underneath in step with the sheet, so \"Write it\n // myself\" lands on the form for the tile that was just picked\n // rather than back on the grid.\n setStep(2);\n }}\n onDuplicateChange={(issueNumber, kind) => {\n setDuplicateIssueNumber(issueNumber);\n setDuplicateKind(issueNumber && kind === \"related\" ? \"related\" : \"duplicate\");\n }}\n onConversationChange={setAiConversationId}\n // The brief answered it: close everything rather than dropping them\n // back onto an empty form, which reads as \"file it anyway\".\n onFinish={handleClose}\n rating={rating}\n onRatingChange={(value) => {\n setRating(value);\n if (validationError) setValidationError(null);\n }}\n projectSlot={headerSlot}\n reporterName={reporter?.name ?? null}\n description={description}\n onDescriptionChange={(value) => {\n setDescription(value);\n if (validationError) setValidationError(null);\n }}\n severity={severity}\n onSeverityChange={(value) => {\n setSeverity(value);\n if (validationError) setValidationError(null);\n }}\n showSeverity={showSeverity}\n validationError={validationError}\n severityRefused={needsSeverity}\n isSubmitting={isSubmitting}\n submitted={submitted}\n onSend={() => void handleSubmit({ skipSimilar: true })}\n onReportGlitchgrabProblem={\n reportGlitchgrabProblem\n ? (prefill) => {\n setSelfReportPrefill(prefill ?? \"\");\n setSelfReportFrom(\"assist\");\n }\n : undefined\n }\n onDegrade={(message, retryable) => {\n setAssistOpen(false);\n // An hourly limit clears in minutes: keep the button so they can try\n // again on this report. Retiring it read as \"the AI threw me out\"\n // to a QA team sharing one office IP.\n if (!retryable) setAssistUsed(true);\n setAssistNotice(message);\n }}\n onClose={() => {\n setAssistOpen(false);\n // Closing by hand is not \"used up\" — someone who peeked and backed\n // out should still find the button where they left it. Only a\n // degrade that will not clear by itself (cap, outage) retires the\n // assistant for this report.\n requestAnimationFrame(() => textareaRef.current?.focus());\n }}\n />\n )}\n </>\n );\n}\n\n/* ─── Helpers ─── */\n\nfunction getPlaceholder(type: DialogTile, idx = 0, hasVoice = false): string {\n if (type === \"RATING\") return \"What made it good — or what let you down? (optional)\";\n if (hasVoice && idx === 1) return \"Hold Space to speak — we'll transcribe it\";\n switch (type) {\n case \"BUG\":\n return \"What went wrong? Describe it or paste an error...\";\n case \"FEATURE_REQUEST\":\n return \"Describe the feature you'd like...\";\n case \"UI_IMPROVEMENT\":\n return \"What looks off? Describe the visual issue...\";\n case \"PERFORMANCE\":\n return \"What's slow? Describe when it happens...\";\n case \"SECURITY\":\n return \"Describe the security concern...\";\n case \"QUESTION\":\n return \"What would you like to know?\";\n case \"OTHER\":\n return \"Tell us what's on your mind...\";\n }\n}\n\nfunction getTypeIcon(type: DialogTile, color: string, size = 24): ReactNode {\n const props = {\n width: size,\n height: size,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n style: { flexShrink: 0 } as CSSProperties,\n };\n switch (type) {\n case \"RATING\":\n return (\n <svg {...props}>\n <path\n d=\"M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.4 6.8 19.1l1-5.8L3.5 9.2l5.9-.9L12 3z\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n case \"BUG\":\n return (\n <svg {...props}>\n <path\n d=\"M8 2L6.5 3.5M16 2L17.5 3.5M3 9H7M17 9H21M12 2a5 5 0 015 5v4a5 5 0 01-10 0V7a5 5 0 015-5zM7 16l-2 3M17 16l2 3\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n case \"FEATURE_REQUEST\":\n return (\n <svg {...props}>\n <path\n d=\"M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2z\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n case \"UI_IMPROVEMENT\":\n return (\n <svg {...props}>\n <rect\n x=\"3\"\n y=\"3\"\n width=\"18\"\n height=\"18\"\n rx=\"2\"\n stroke={color}\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M3 9h18M9 21V9\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n case \"PERFORMANCE\":\n return (\n <svg {...props}>\n <path\n d=\"M12 21a9 9 0 100-18 9 9 0 000 18zM12 12l4-4M12 7v.01\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n case \"SECURITY\":\n return (\n <svg {...props}>\n <path\n d=\"M12 3l7 3v5c0 4.5-3 8.5-7 10-4-1.5-7-5.5-7-10V6l7-3z\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n case \"QUESTION\":\n return (\n <svg {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke={color} strokeWidth=\"1.5\" />\n <path\n d=\"M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3M12 17h.01\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n case \"OTHER\":\n return (\n <svg {...props}>\n <path\n d=\"M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2v10z\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n }\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { encodeScreenshot } from \"./image-encode\";\n\ntype Point = { x: number; y: number };\n\ntype Stroke =\n | { type: \"freehand\"; color: string; width: number; points: Point[] }\n | { type: \"circle\"; color: string; width: number; cx: number; cy: number; r: number };\n\nconst PALETTE = [\"#ef4444\", \"#f59e0b\", \"#22c55e\", \"#3b82f6\", \"#a855f7\", \"#ffffff\"];\n\nfunction drawStroke(ctx: CanvasRenderingContext2D, s: Stroke) {\n ctx.strokeStyle = s.color;\n ctx.lineWidth = s.width;\n ctx.lineCap = \"round\";\n ctx.lineJoin = \"round\";\n if (s.type === \"freehand\") {\n if (s.points.length < 2) return;\n ctx.beginPath();\n ctx.moveTo(s.points[0].x, s.points[0].y);\n for (let i = 1; i < s.points.length; i++) ctx.lineTo(s.points[i].x, s.points[i].y);\n ctx.stroke();\n } else {\n ctx.beginPath();\n ctx.arc(s.cx, s.cy, s.r, 0, Math.PI * 2);\n ctx.stroke();\n }\n}\n\ninterface AnnotationCanvasProps {\n imageSrc: string;\n onSave: (dataUrl: string) => void;\n onCancel: () => void;\n}\n\n/** Freehand + circle annotation overlay for a screenshot preview — draws directly on a canvas sized to the image's natural resolution, composited on save. */\nexport function AnnotationCanvas({ imageSrc, onSave, onCancel }: AnnotationCanvasProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const imgRef = useRef<HTMLImageElement | null>(null);\n const [ready, setReady] = useState(false);\n const [tool, setTool] = useState<\"pen\" | \"circle\">(\"pen\");\n const [color, setColor] = useState(PALETTE[0]);\n const [strokeWidth, setStrokeWidth] = useState(4);\n const [strokes, setStrokes] = useState<Stroke[]>([]);\n const [currentStroke, setCurrentStroke] = useState<Stroke | null>(null);\n\n useEffect(() => {\n const img = new Image();\n img.onload = () => {\n imgRef.current = img;\n const canvas = canvasRef.current;\n if (canvas) {\n canvas.width = img.naturalWidth;\n canvas.height = img.naturalHeight;\n }\n setReady(true);\n };\n img.src = imageSrc;\n }, [imageSrc]);\n\n useEffect(() => {\n if (!ready) return;\n const canvas = canvasRef.current;\n const img = imgRef.current;\n if (!canvas || !img) return;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\n for (const s of strokes) drawStroke(ctx, s);\n if (currentStroke) drawStroke(ctx, currentStroke);\n }, [ready, strokes, currentStroke]);\n\n const getPos = (e: React.PointerEvent<HTMLCanvasElement>): Point => {\n const canvas = e.currentTarget;\n const rect = canvas.getBoundingClientRect();\n return {\n x: ((e.clientX - rect.left) * canvas.width) / rect.width,\n y: ((e.clientY - rect.top) * canvas.height) / rect.height,\n };\n };\n\n const handlePointerDown = (e: React.PointerEvent<HTMLCanvasElement>) => {\n e.currentTarget.setPointerCapture(e.pointerId);\n const { x, y } = getPos(e);\n setCurrentStroke(\n tool === \"pen\"\n ? { type: \"freehand\", color, width: strokeWidth, points: [{ x, y }] }\n : { type: \"circle\", color, width: strokeWidth, cx: x, cy: y, r: 0 },\n );\n };\n\n const handlePointerMove = (e: React.PointerEvent<HTMLCanvasElement>) => {\n if (!currentStroke) return;\n const { x, y } = getPos(e);\n setCurrentStroke((prev) => {\n if (!prev) return prev;\n if (prev.type === \"freehand\") return { ...prev, points: [...prev.points, { x, y }] };\n return { ...prev, r: Math.hypot(x - prev.cx, y - prev.cy) };\n });\n };\n\n const handlePointerUp = () => {\n setCurrentStroke((prev) => {\n if (prev) setStrokes((s) => [...s, prev]);\n return null;\n });\n };\n\n const handleSave = () => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n // Annotating re-encodes an already-JPEG image, so quality is chosen by the\n // shared budget ladder rather than a fixed low value — a second lossy pass\n // at 0.85 was visibly degrading text.\n onSave(encodeScreenshot(canvas));\n };\n\n const iconBtn = (active = false): React.CSSProperties => ({\n width: \"30px\",\n height: \"30px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"6px\",\n border: `1.5px solid ${active ? \"#22d3ee\" : \"rgba(255,255,255,0.15)\"}`,\n background: active ? \"rgba(34,211,238,0.15)\" : \"transparent\",\n color: \"#fff\",\n cursor: \"pointer\",\n padding: 0,\n });\n\n return (\n <div\n data-glitchgrab-layer=\"\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n backgroundColor: \"rgba(0,0,0,0.9)\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n }}\n onClick={(e) => {\n e.stopPropagation();\n if (e.target === e.currentTarget) onCancel();\n }}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <canvas\n ref={canvasRef}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n style={{\n maxWidth: \"100%\",\n maxHeight: \"calc(100vh - 140px)\",\n borderRadius: \"8px\",\n touchAction: \"none\",\n cursor: \"crosshair\",\n display: \"block\",\n }}\n />\n\n <div\n style={{\n marginTop: \"14px\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n flexWrap: \"wrap\",\n justifyContent: \"center\",\n maxWidth: \"100%\",\n }}\n >\n <button type=\"button\" onClick={() => setTool(\"pen\")} style={iconBtn(tool === \"pen\")} title=\"Freehand\" aria-label=\"Freehand tool\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path d=\"M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n <button type=\"button\" onClick={() => setTool(\"circle\")} style={iconBtn(tool === \"circle\")} title=\"Circle\" aria-label=\"Circle tool\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"12\" r=\"8\" stroke=\"currentColor\" strokeWidth=\"1.8\" />\n </svg>\n </button>\n\n <div style={{ width: \"1px\", height: \"20px\", background: \"rgba(255,255,255,0.15)\" }} />\n\n {PALETTE.map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => setColor(c)}\n aria-label={`Color ${c}`}\n style={{\n width: \"22px\",\n height: \"22px\",\n borderRadius: \"50%\",\n background: c,\n border: color === c ? \"2px solid #22d3ee\" : \"2px solid rgba(255,255,255,0.3)\",\n cursor: \"pointer\",\n padding: 0,\n }}\n />\n ))}\n <input\n type=\"color\"\n value={color}\n onChange={(e) => setColor(e.target.value)}\n title=\"Custom color\"\n aria-label=\"Custom color\"\n style={{\n width: \"22px\",\n height: \"22px\",\n padding: 0,\n border: \"none\",\n background: \"none\",\n cursor: \"pointer\",\n }}\n />\n\n <div style={{ width: \"1px\", height: \"20px\", background: \"rgba(255,255,255,0.15)\" }} />\n\n <input\n type=\"range\"\n min={2}\n max={12}\n value={strokeWidth}\n onChange={(e) => setStrokeWidth(Number(e.target.value))}\n title=\"Stroke width\"\n aria-label=\"Stroke width\"\n style={{ width: \"70px\" }}\n />\n\n <div style={{ width: \"1px\", height: \"20px\", background: \"rgba(255,255,255,0.15)\" }} />\n\n <button\n type=\"button\"\n onClick={() => setStrokes((s) => s.slice(0, -1))}\n disabled={strokes.length === 0}\n style={{ ...iconBtn(), opacity: strokes.length === 0 ? 0.35 : 1 }}\n title=\"Undo\"\n aria-label=\"Undo\"\n >\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path d=\"M9 14L4 9l5-5M4 9h10a6 6 0 010 12h-2\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n <button\n type=\"button\"\n onClick={() => setStrokes([])}\n disabled={strokes.length === 0}\n style={{ ...iconBtn(), opacity: strokes.length === 0 ? 0.35 : 1 }}\n title=\"Clear all\"\n aria-label=\"Clear all\"\n >\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path d=\"M3 6h18M8 6V4a1 1 0 011-1h6a1 1 0 011 1v2m2 0v14a1 1 0 01-1 1H7a1 1 0 01-1-1V6h12z\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div style={{ marginTop: \"12px\", display: \"flex\", gap: \"8px\" }}>\n <button\n type=\"button\"\n onClick={onCancel}\n style={{\n padding: \"8px 16px\",\n borderRadius: \"8px\",\n border: \"1.5px solid rgba(255,255,255,0.2)\",\n background: \"transparent\",\n color: \"#fff\",\n fontSize: \"13px\",\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleSave}\n style={{\n padding: \"8px 16px\",\n borderRadius: \"8px\",\n border: \"none\",\n background: \"#22d3ee\",\n color: \"#09090b\",\n fontSize: \"13px\",\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n Save annotation\n </button>\n </div>\n </div>\n );\n}\n","/**\n * Screenshot encoding shared by the capture path and the annotation editor.\n *\n * Screenshots travel to `/api/v1/sdk/report` as base64 inside a JSON body, so\n * every extra pixel is billed against the serverless request-body limit\n * (~4.5 MB on Vercel). We want the sharpest image that still leaves room for a\n * second screenshot plus the rest of the payload, so encode at high quality\n * first and only step down when the result overshoots the budget.\n */\n\n/** Max length of a single screenshot data URL. Two of these still fit in one request. */\nexport const MAX_SCREENSHOT_DATA_URL_LENGTH = 1_800_000;\n\n/** Tried in order — the first one under budget wins. */\nconst QUALITY_LADDER = [0.92, 0.85, 0.75] as const;\n\n/** When even q0.75 overshoots: redraw at this factor, then re-run the ladder. */\nconst DOWNSCALE_FACTOR = 0.7;\n\n/**\n * Full resolution plus three downscales (0.7, 0.49, 0.34). One downscale used\n * to be the limit, and an image still over budget after it was returned over\n * budget — the cap was advisory for exactly the images it existed for.\n */\nconst MAX_ROUNDS = 4;\n\nfunction downscale(\n canvas: HTMLCanvasElement,\n factor: number,\n): HTMLCanvasElement | null {\n const next = document.createElement(\"canvas\");\n next.width = Math.max(1, Math.round(canvas.width * factor));\n next.height = Math.max(1, Math.round(canvas.height * factor));\n const ctx = next.getContext(\"2d\");\n if (!ctx) return null;\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = \"high\";\n ctx.drawImage(canvas, 0, 0, next.width, next.height);\n return next;\n}\n\n/**\n * JPEG-encode a canvas at the highest quality that fits the payload budget.\n * Resolution is preserved unless every quality step overshoots — losing pixels\n * is what made screenshots unreadable, so it is the last thing we give up.\n */\nexport function encodeScreenshot(\n canvas: HTMLCanvasElement,\n maxLength = MAX_SCREENSHOT_DATA_URL_LENGTH,\n): string {\n let current = canvas;\n let encoded = \"\";\n\n for (let round = 0; round < MAX_ROUNDS; round++) {\n for (const quality of QUALITY_LADDER) {\n encoded = current.toDataURL(\"image/jpeg\", quality);\n if (encoded.length <= maxLength) return encoded;\n }\n if (round === MAX_ROUNDS - 1) break;\n const smaller = downscale(current, DOWNSCALE_FACTOR);\n if (!smaller) break;\n current = smaller;\n }\n\n // Nothing fit. The smallest attempt beats no image; the sheet's total budget\n // decides whether it rides along.\n return encoded;\n}\n\nfunction readAsDataUrl(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n}\n\nasync function reencodeImageFile(file: File, maxLength: number): Promise<string | null> {\n if (typeof createImageBitmap !== \"function\") return null;\n const bitmap = await createImageBitmap(file);\n try {\n const canvas = document.createElement(\"canvas\");\n canvas.width = bitmap.width;\n canvas.height = bitmap.height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n // JPEG has no alpha channel — transparent pixels would come out black.\n ctx.fillStyle = \"#ffffff\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(bitmap, 0, 0);\n return encodeScreenshot(canvas, maxLength);\n } finally {\n bitmap.close?.();\n }\n}\n\n/**\n * An image the reporter attached or pasted, as a data URL held to the same\n * budget as a captured screenshot.\n *\n * These used to ride along exactly as read off disk. A retina PNG from the\n * clipboard is routinely 5–10 MB — over the request-body limit on its own — so\n * Vercel refused the assistant turn at the edge with a 413 before the route\n * ran: no log, no degrade message from the server, the sheet just closed.\n *\n * A file already under budget passes through untouched, so a small PNG crop\n * stays a sharp PNG. Anything that cannot be decoded here (no\n * `createImageBitmap`, a format the browser can't draw) comes back raw; the\n * sheet's total budget is the backstop for those.\n */\nexport async function encodeImageFile(\n file: File,\n maxLength = MAX_SCREENSHOT_DATA_URL_LENGTH,\n): Promise<string> {\n // A data URL is base64 (4 chars per 3 bytes) behind a short `data:…;base64,`\n // prefix, so the size is known before reading a byte.\n const rawLength = Math.ceil(file.size / 3) * 4 + 64;\n if (rawLength > maxLength) {\n try {\n const shrunk = await reencodeImageFile(file, maxLength);\n if (shrunk && shrunk.length < rawLength) return shrunk;\n } catch {\n // Fall through to the raw file — an unreadable image is still evidence.\n }\n }\n return readAsDataUrl(file);\n}\n","\"use client\";\n\nimport { useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type {\n AssistFile,\n AssistFn,\n AssistSheetEvent,\n AssistTurnResult,\n AttachKind,\n DialogTile,\n ReportSeverity,\n} from \"./types\";\nimport {\n MAX_ASSIST_FILE_CHARS,\n MAX_ASSIST_FILE_CHARS_EACH,\n MAX_ASSIST_FILES,\n MAX_ASSIST_IMAGE_CHARS,\n MAX_ASSIST_IMAGES,\n SEVERITY_LEVELS,\n SEVERITY_LABELS,\n} from \"./types\";\nimport {\n ASSIST_ATTACHMENT_ACCEPT,\n decodeTextDataUrl,\n isAssistReadableFile,\n} from \"./attachments\";\nimport { getTypeLabel } from \"./labels\";\nimport { ChatMarkdown } from \"./chat-markdown\";\n\n/**\n * The AI report assistant, as a sheet (#330).\n *\n * A right-hand drawer on a wide screen, a bottom sheet under 640px — the shape\n * every chat surface a reporter has ever used already has. It replaced an\n * in-dialog panel that technically worked and read like a form field: a\n * conversation crammed into 150px of a 420px card never felt like talking to\n * anyone.\n *\n * The sheet owns the whole flow — chat, then the draft, then Send. There is no\n * hand-back to the dialog, because a context switch at the exact moment someone\n * is finished is the worst possible time to move them.\n *\n * It does NOT own submission. `description`, `severity` and `onSend` are the\n * dialog's own state and handler passed straight through, so there is exactly\n * one submit path in this package and the sheet cannot drift from it.\n *\n * Every failure path ends the same way: `onDegrade` fires, the sheet closes,\n * and the plain form is there. Filing a bug never depends on a model.\n */\n\nexport interface AssistTheme {\n bg: string;\n bgSecondary: string;\n border: string;\n text: string;\n textMuted: string;\n inputBg: string;\n inputBorder: string;\n accent: string;\n accentText: string;\n}\n\ninterface ChatMessage {\n role: \"user\" | \"assistant\";\n content: string;\n /**\n * A draft the model wrote. Its `content` is the draft TEXT, not a \"here's\n * your report\" line — the model has to see what it wrote, or \"keep chatting\"\n * makes the reporter describe the whole thing again (#357).\n */\n kind?: \"report\";\n}\n\n/**\n * The images one turn can carry: newest first, at most `MAX_ASSIST_IMAGES`,\n * and never more than `MAX_ASSIST_IMAGE_CHARS` between them. An image that\n * would overflow is skipped rather than ending the pick, so a heavy paste costs\n * itself, not the small page shot behind it. Returned oldest-first, the order\n * the model reads them in.\n */\nfunction pickAssistImages(all: string[]): string[] {\n const picked: string[] = [];\n let total = 0;\n for (let i = all.length - 1; i >= 0 && picked.length < MAX_ASSIST_IMAGES; i--) {\n const shot = all[i];\n if (total + shot.length > MAX_ASSIST_IMAGE_CHARS) continue;\n picked.unshift(shot);\n total += shot.length;\n }\n return picked;\n}\n\n/** A non-image file attached to the report, as the dialog holds it. */\ninterface SheetFile {\n name: string;\n size: number;\n dataUrl: string;\n}\n\n/** Stable empty default, so the memo below does not re-decode every render. */\nconst NO_FILES: SheetFile[] = [];\n\n/**\n * The text files one turn can carry (#1851): readable types only, newest\n * first, at most `MAX_ASSIST_FILES` and `MAX_ASSIST_FILE_CHARS` between them,\n * each cut at `MAX_ASSIST_FILE_CHARS_EACH`. Returned oldest-first with each\n * file's index in `files`, so the strip marks exactly the ones sent.\n */\nfunction pickAssistFiles(files: SheetFile[]): { index: number; file: AssistFile }[] {\n const picked: { index: number; file: AssistFile }[] = [];\n let total = 0;\n for (let i = files.length - 1; i >= 0 && picked.length < MAX_ASSIST_FILES; i--) {\n const attached = files[i];\n if (!isAssistReadableFile(attached.name)) continue;\n const text = decodeTextDataUrl(attached.dataUrl);\n if (!text || !text.trim()) continue;\n const content = text.slice(0, MAX_ASSIST_FILE_CHARS_EACH);\n if (total + content.length > MAX_ASSIST_FILE_CHARS) continue;\n picked.unshift({ index: i, file: { name: attached.name, content } });\n total += content.length;\n }\n return picked;\n}\n\ninterface AssistSheetProps {\n assist: AssistFn;\n theme: AssistTheme;\n /**\n * Every image attached to the report, oldest first — the auto-captured page\n * shot, then anything pasted or picked in here. The newest that fit\n * `MAX_ASSIST_IMAGES` and `MAX_ASSIST_IMAGE_CHARS` go to the model\n * (`pickAssistImages`); the strip above the composer shows all of them, because a\n * paste that lands somewhere invisible reads as a paste that failed (#352).\n */\n screenshots: string[];\n /**\n * The shot the dialog captured itself when it opened, if it did. Every other\n * entry of `screenshots` was added by the reporter — and is usually the thing\n * they are complaining about, which may not be this page at all (#357).\n */\n pageShot?: string | null;\n /**\n * Add images or files from inside the sheet. The host owns both lists and\n * sorts them: images to `screenshots`, anything else to `files`.\n */\n onAddFiles?: (files: File[]) => void;\n /**\n * Every non-image file attached to the report, oldest first (#1851). The\n * text ones the assistant can read are sent with each turn; the rest (pdf,\n * docx) are shown so the reporter knows they are attached, and dimmed.\n */\n files?: SheetFile[];\n /** Take one file back off the report, by its index in `files`. */\n onRemoveFile?: (index: number) => void;\n /**\n * Take one image back off the report, by its index in `screenshots` (#360).\n * Without it a wrong paste could only be undone by leaving the sheet — and\n * the reporter had no idea the dialog behind it had a remove button.\n */\n onRemoveImage?: (index: number) => void;\n /** How many screenshots + files are attached, for the draft's summary line. */\n attachmentCount: number;\n /** Page URL / breadcrumbs / report type — whatever the host knows. */\n context: Record<string, unknown> | null;\n /** \"Bug Report\", \"Feature Request\", … — shown in the header. */\n reportTypeLabel: string;\n\n /**\n * The picker turn (#330 follow-up). ⌘⇧G now lands here instead of on the\n * dialog's tile grid, so the very first thing the sheet does is ask what\n * this is — as chips, not as a model turn. Deterministic, instant, and it\n * costs nothing from the project's monthly conversation cap.\n *\n * `typePicked` is true when the host already knows (a tile was clicked in\n * the dialog, or the host opened with a type), and the picker is skipped.\n */\n typePicked: boolean;\n /** What the dialog currently holds — decides whether a picked type is a\n * rating (stars, no model) or a report (chat). */\n currentTile: DialogTile;\n tiles: DialogTile[];\n onPickType: (tile: DialogTile) => void;\n\n /**\n * The rating step. A star needs no assistant, so this branch never calls the\n * model: stars + an optional line, straight down the host's FeedbackFn.\n * The submit path itself stays the dialog's — `onSend` is its `handleSubmit`,\n * which already routes a RATING through `FeedbackFn` instead of the report\n * API. The sheet never grows a second way to submit.\n */\n rating: number;\n onRatingChange: (value: number) => void;\n /** The host's \"Reporting to <project>\" line, reused verbatim. */\n projectSlot?: ReactNode;\n reporterName?: string | null;\n\n /** The dialog's description state. The draft box edits it in place. */\n description: string;\n onDescriptionChange: (value: string) => void;\n /** `null` until picked — the sheet never pre-selects one either (#353). */\n severity: ReportSeverity | null;\n onSeverityChange: (value: ReportSeverity) => void;\n showSeverity: boolean;\n /**\n * The dialog owns submission, so a refused send (no severity, low-quality\n * text) sets an error the reporter cannot see behind this sheet. Rendered\n * above Send.\n */\n validationError?: string | null;\n /**\n * True only when the refusal was ABOUT severity. Computed by the dialog,\n * which owns the error: painting the row red for a low-quality-text refusal\n * would point at the wrong field and teach people to ignore red.\n */\n severityRefused?: boolean;\n\n /**\n * Tells the dialog which issue to attach to, so its ONE submit path carries\n * the number into report metadata. Null clears it — the reporter kept typing\n * and it stopped looking like a duplicate. `kind` says whether it is the same\n * problem or a related request for that issue.\n */\n onDuplicateChange?: (issueNumber: number | null, kind?: AttachKind) => void;\n\n /**\n * Tells the dialog which chat this is, so its ONE submit path carries the id\n * into report metadata. That link is the only way to answer \"how many prompts\n * does a filed issue cost\" — a conversation with no report against it is one\n * that went nowhere, and that is a finding too.\n */\n onConversationChange?: (conversationId: string | null) => void;\n\n isSubmitting: boolean;\n submitted: boolean;\n onSend: () => void;\n\n /** `retryable`: the reason clears on its own, so the assistant is not retired. */\n onDegrade: (message: string, retryable?: boolean) => void;\n onClose: () => void;\n /**\n * Close the whole dialog, not just the sheet. Used when the brief answered\n * the question: dropping them back onto an empty report form after telling\n * them they are done would read as \"now file it anyway\".\n */\n onFinish?: () => void;\n /**\n * Opens the dialog's \"Problem with Glitchgrab?\" panel (#366). The sheet is\n * where the assistant goes wrong, so the way to say so lives here too — as a\n * link, and as a card when the assistant itself decides the chat is about\n * Glitchgrab. `prefill` is the reporter's own words, so they never retype.\n * Omitted when the host did not offer it.\n */\n onReportGlitchgrabProblem?: (prefill?: string) => void;\n}\n\n/**\n * Openers, not instructions. Someone who does not know what to type is the\n * whole reason this surface exists; a blank box helps them least.\n */\nconst STARTERS = [\n \"Something on this page is broken\",\n \"It did the wrong thing\",\n \"I wish it could…\",\n];\n\n/**\n * The check-back chip the prompt offers before the first report\n * (`apps/web/lib/ai-assist/prompt.ts`, pinned in `prompt.test.ts`). Tapping it\n * already confirmed the restatement, so the report it produces files itself\n * after a short countdown instead of asking for a second Send (#402). A plain\n * typed yes arms it too (`isAffirmativeReply`): reporters answer \"Is that right?\"\n * by typing \"yes\", and were then made to press Send on top of saying yes.\n */\nconst CONFIRM_OPTION = \"Yes, that's it\";\n\n/**\n * The assistant saying back what it understood (\"So you're saying… Is that\n * right?\"). The prompt pairs it with the \"Yes, that's it\" chip, but the model\n * does not always send the chip — and a yes to the question is the same answer\n * either way.\n */\nexport function isCheckBackQuestion(text: string): boolean {\n const t = text.trim();\n return (\n /^so,? you['’]?re saying\\b/i.test(t) ||\n /\\b(is that right|is that correct|did i get (that|it) right|have i got (that|it) right)\\s*\\??\\s*$/i.test(t)\n );\n}\n\n/**\n * A reply that is only a yes — \"yes\", \"yeah\", \"correct\", \"haan\", \"👍\". Anything\n * with more in it is a correction and must go back to the model, so the whole\n * message has to be the yes.\n */\nexport function isAffirmativeReply(text: string): boolean {\n return /^(y|ya|yah|yes|yess|yeah|yep|yup|ok|okay|sure|correct|right|exactly|confirm(ed)?|that['’]?s (it|right|correct)|yes,? that['’]?s (it|right)|haan|han|ha|ho|hmm yes|👍)[\\s.!👍]*$/i.test(\n text.trim(),\n );\n}\n\n/**\n * Seconds a confirmed draft stays on screen before it files itself (#402). The\n * reporter never read the draft before confirming — it is written after the\n * tap — so this is the window in which a wrong or injected draft gets stopped,\n * with the × beside the countdown (#406).\n */\nconst AUTO_FILE_SECONDS = 3;\n\nconst NARROW_QUERY = \"(max-width: 640px)\";\n\nfunction useIsNarrow(): boolean {\n const [narrow, setNarrow] = useState(false);\n useEffect(() => {\n try {\n const mq = window.matchMedia(NARROW_QUERY);\n setNarrow(mq.matches);\n const onChange = (e: MediaQueryListEvent) => setNarrow(e.matches);\n mq.addEventListener(\"change\", onChange);\n return () => mq.removeEventListener(\"change\", onChange);\n } catch {\n // Never crash a host page over a layout preference.\n }\n }, []);\n return narrow;\n}\n\nfunction Sparkle({ color, size = 14 }: { color: string; size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3zM19 15l.75 2.25L22 18l-2.25.75L19 21l-.75-2.25L16 18l2.25-.75L19 15z\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n\n/** Small round avatar so a transcript reads as two people, not one log. */\nfunction Avatar({\n who,\n theme: t,\n initials,\n}: {\n who: \"user\" | \"assistant\";\n theme: AssistTheme;\n /** The reporter's own initials. A stray \"Y\" for \"You\" reads as a typo. */\n initials?: string;\n}) {\n const isAi = who === \"assistant\";\n return (\n <span\n aria-hidden=\"true\"\n style={{\n flexShrink: 0,\n width: \"24px\",\n height: \"24px\",\n borderRadius: \"50%\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n marginTop: \"2px\",\n backgroundColor: isAi ? `${t.accent}22` : t.bgSecondary,\n border: `1px solid ${isAi ? t.accent : t.inputBorder}`,\n color: isAi ? t.accent : t.textMuted,\n fontSize: \"10px\",\n fontWeight: 700,\n }}\n >\n {isAi ? (\n <Sparkle color={t.accent} size={12} />\n ) : initials ? (\n initials\n ) : (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"8\" r=\"3.4\" stroke=\"currentColor\" strokeWidth=\"1.8\" />\n <path\n d=\"M5 20c0-3.6 3.1-5.6 7-5.6s7 2 7 5.6\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n />\n </svg>\n )}\n </span>\n );\n}\n\nexport function AssistSheet({\n assist,\n theme: t,\n screenshots,\n pageShot = null,\n onAddFiles,\n files = NO_FILES,\n onRemoveFile,\n onRemoveImage,\n attachmentCount,\n context,\n reportTypeLabel,\n typePicked,\n currentTile,\n tiles,\n onPickType,\n rating,\n onRatingChange,\n projectSlot,\n reporterName,\n description,\n onDescriptionChange,\n severity,\n onSeverityChange,\n showSeverity,\n validationError,\n severityRefused = false,\n onDuplicateChange,\n onConversationChange,\n isSubmitting,\n submitted,\n onSend,\n onDegrade,\n onClose,\n onFinish,\n onReportGlitchgrabProblem,\n}: AssistSheetProps) {\n const narrow = useIsNarrow();\n /** A send the dialog refused because nothing is picked yet — turns the row red. */\n /**\n * The picker mirrors the dialog's gate exactly — `showSeverity` AND a bug.\n * A feature request has no severity to give, and showing \"required\" on a\n * field the dialog will not ask for makes Send unexplainable.\n */\n const severityAsked = showSeverity && currentTile === \"BUG\";\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [input, setInput] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [conversationId, setConversationId] = useState<string | null>(null);\n /** Star hover preview — local, because it is pure presentation. */\n const [hoveredStar, setHoveredStar] = useState(0);\n /**\n * Tappable answers offered with the last question. Cleared the moment\n * anything is sent — a stale chip row invites answering a question that has\n * already moved on.\n */\n const [options, setOptions] = useState<string[]>([]);\n /**\n * The already-open issue this turned out to be. Server-validated, so the\n * number is safe to hand back on submit: the report is added to that issue\n * as a comment rather than opening a second one.\n */\n const [duplicate, setDuplicate] = useState<\n (NonNullable<AssistTurnResult[\"duplicate\"]> & { kind: AttachKind }) | null\n >(null);\n /** The assistant said \"this is about Glitchgrab, not this app\" (#366) — show the offer card. */\n const [glitchgrabOffer, setGlitchgrabOffer] = useState(false);\n /**\n * The brief answered it. Nothing is filed and the dialog closes — the whole\n * point of giving the assistant the project's guides is that some people\n * should never have to write a report at all.\n */\n const [solved, setSolved] = useState<string | null>(null);\n /**\n * A bug is asked how bad it is right after its type, before the chat (#402).\n * Asked once: a severity already picked on the form is not asked again.\n */\n const needsSeverity = (tile: DialogTile) => showSeverity && tile === \"BUG\" && !severity;\n /**\n * \"type\" → the picker chips, \"severity\" → how bad a bug is, \"rating\" →\n * stars, \"chat\" → the conversation, \"draft\" → the model's report, ready to\n * send. A sheet opened from the dialog's own \"Describe it with AI\" button\n * already knows its type and starts at \"chat\" (or \"severity\" for a bug);\n * ⌘⇧G starts at \"type\".\n */\n const [phase, setPhase] = useState<\n \"type\" | \"severity\" | \"rating\" | \"chat\" | \"draft\" | \"solved\"\n >(() =>\n !typePicked\n ? \"type\"\n : currentTile === \"RATING\"\n ? \"rating\"\n : needsSeverity(currentTile)\n ? \"severity\"\n : \"chat\",\n );\n /**\n * Seconds until a confirmed draft files itself (#402), null when nothing is\n * counting. Driven by the effect below, so closing the sheet, a degrade or\n * the dialog starting its own submit all stop it without a stray timer.\n */\n const [autoFileLeft, setAutoFileLeft] = useState<number | null>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n const draftRef = useRef<HTMLTextAreaElement>(null);\n /** Guards the seed below against React 18's double-invoked effects. */\n const seededRef = useRef(false);\n /** The opening turn is waiting for the severity answer (#402). */\n const seedPendingRef = useRef(false);\n /**\n * Clicks the server has not seen yet (#357). They ride along with the next\n * turn, or go on their own when the sheet is left — the moment someone gives\n * up on the assistant is exactly the click worth keeping.\n */\n const eventsRef = useRef<AssistSheetEvent[]>([]);\n /** The model's own last draft, to tell \"sent as drafted\" from \"edited\". */\n const aiDraftRef = useRef<string | null>(null);\n\n function logEvent(type: AssistSheetEvent[\"type\"], detail?: string) {\n eventsRef.current.push({ type, at: Date.now(), ...(detail ? { detail } : {}) });\n }\n\n function takeEvents(): AssistSheetEvent[] | undefined {\n if (eventsRef.current.length === 0) return undefined;\n const events = eventsRef.current;\n eventsRef.current = [];\n return events;\n }\n\n /**\n * Send pending clicks without a model turn. Fire-and-forget: the server\n * answers an empty `messages` with no model call and nothing counted, and\n * nobody waits on it. Needs a conversation to attach to — clicks before the\n * first reply have nowhere to go and ride with that reply instead.\n */\n function flushEvents() {\n if (!conversationId) return;\n const events = takeEvents();\n if (!events) return;\n try {\n void Promise.resolve(\n assist({ messages: [], conversationId, events, screenshots: [], context: null }),\n ).catch(() => {});\n } catch {\n // A host's fn threw synchronously. Losing a click log is fine.\n }\n }\n\n // What the next turn will actually send — the strip marks exactly these, so\n // an image dropped for size reads as unread, not just one dropped for count.\n const readShots = new Set(pickAssistImages(screenshots));\n // Decoding a mockup is not free, and this body re-runs on every keystroke.\n const sentFiles = useMemo(() => pickAssistFiles(files), [files]);\n const readFiles = new Set(sentFiles.map((f) => f.index));\n\n /** Every way out of the sheet that is not Send. */\n function leave(type: \"write_myself\" | \"closed\", detail?: string) {\n logEvent(type, detail);\n flushEvents();\n onClose();\n }\n\n useEffect(() => {\n const el = scrollRef.current;\n if (el) el.scrollTop = el.scrollHeight;\n }, [messages, busy, phase]);\n\n useEffect(() => {\n if (phase === \"draft\") draftRef.current?.focus();\n }, [phase]);\n\n useEffect(() => {\n if (autoFileLeft === null) return;\n // The dialog took over (Send pressed by hand) or the draft went away.\n if (isSubmitting || submitted || phase !== \"draft\") {\n setAutoFileLeft(null);\n return;\n }\n if (autoFileLeft <= 0) {\n sendDraft(true);\n return;\n }\n const id = setTimeout(() => setAutoFileLeft((n) => (n === null ? null : n - 1)), 1000);\n return () => clearTimeout(id);\n // `sendDraft` is re-created every render; the tick that reaches 0 renders\n // first, so it is always the current one.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [autoFileLeft, isSubmitting, submitted, phase]);\n\n /** The reporter touched the draft, so it is theirs to send now (#402). */\n function stopAutoFile(reason: string) {\n if (autoFileLeft === null) return;\n setAutoFileLeft(null);\n logEvent(\"auto_file_stopped\", reason);\n }\n\n /**\n * A turn that failed carried clicks with it. Put them back and flush them on\n * their own — the clicks right before an outage are exactly the ones worth\n * reading, and a cap/rate-limit degrade still accepts an events-only flush.\n */\n function degradeKeepingEvents(\n events: AssistSheetEvent[] | undefined,\n message: string,\n retryable?: boolean,\n ) {\n if (events) eventsRef.current = [...events, ...eventsRef.current];\n flushEvents();\n onDegrade(message, retryable);\n }\n\n /**\n * `autoFile`: this turn answers the check-back chip, so a plain report it\n * returns starts the countdown instead of waiting for Send (#402).\n */\n async function runTurn(history: ChatMessage[], autoFile = false) {\n setBusy(true);\n setAutoFileLeft(null);\n let result: AssistTurnResult;\n const events = takeEvents();\n try {\n // Held to a total budget, and no singular `screenshot` beside it: a body\n // over the request limit is refused at the edge with a 413 before the\n // route runs, and repeating the newest image is what tipped real turns\n // over it.\n const sent = pickAssistImages(screenshots);\n result = await assist({\n // `kind` only on drafts, so an older server sees the exact shape it\n // always did — it just learns the draft text now instead of a\n // placeholder line.\n messages: history.map((m) =>\n m.kind ? { role: m.role, content: m.content, kind: m.kind } : m,\n ),\n conversationId,\n screenshots: sent,\n // Only when there is something: an older server then sees the body\n // it always did.\n ...(sentFiles.length > 0 ? { files: sentFiles.map((f) => f.file) } : {}),\n context: {\n ...(context ?? {}),\n imageSources: sent.map((shot) => (pageShot && shot === pageShot ? \"page\" : \"attached\")),\n // Whether this dialog can open the #366 panel at all. A hint — the\n // server decides whether the model may offer it.\n canReportGlitchgrab: !!onReportGlitchgrabProblem,\n },\n events,\n });\n } catch {\n // AssistFn is documented as never-throwing, but a host is a host.\n degradeKeepingEvents(\n events,\n \"The assistant is unavailable — write your report below and send it as normal.\",\n );\n return;\n } finally {\n setBusy(false);\n }\n\n if (result.degraded) {\n degradeKeepingEvents(events, result.degraded, result.retryable === true);\n return;\n }\n if (result.conversationId) {\n setConversationId(result.conversationId);\n onConversationChange?.(result.conversationId);\n }\n\n // One card, one submit path for both: the SAME problem, or a related request\n // the model asked about. The server never sends both.\n const attach = result.duplicate\n ? { ...result.duplicate, kind: \"duplicate\" as const }\n : result.related\n ? { ...result.related, kind: \"related\" as const }\n : null;\n setDuplicate(attach);\n onDuplicateChange?.(attach?.number ?? null, attach?.kind);\n setGlitchgrabOffer(!!result.aboutGlitchgrab && !!onReportGlitchgrabProblem && !!result.question);\n\n if (result.solved) {\n setSolved(result.solved);\n setOptions([]);\n setPhase(\"solved\");\n return;\n }\n\n if (result.report) {\n onDescriptionChange(result.report);\n aiDraftRef.current = result.report;\n logEvent(\"draft_shown\");\n setMessages([...history, { role: \"assistant\", content: result.report, kind: \"report\" }]);\n setOptions([]);\n setPhase(\"draft\");\n // Never onto somebody else's issue: attaching to the wrong thread stays a\n // deliberate click. And never without a severity the dialog would refuse.\n if (autoFile && !attach && !(severityAsked && !severity)) {\n setAutoFileLeft(AUTO_FILE_SECONDS);\n }\n return;\n }\n if (result.question) {\n setMessages([...history, { role: \"assistant\", content: result.question }]);\n setOptions(result.options ?? []);\n return;\n }\n onDegrade(\"The assistant had nothing to add — write your report below and send it as normal.\");\n }\n\n // Whatever was already typed IS the first message. Making someone retype it\n // to \"start the chat\" would be the most annoying thing this feature could do.\n useEffect(() => {\n if (seededRef.current) return;\n seededRef.current = true;\n // Nothing to seed until we know what this is — the picker runs first, and\n // anything typed before it would be a report about an unknown thing.\n // A rating never calls the model, so whatever is in the box is a comment,\n // not the opening line of a conversation.\n if (!typePicked || currentTile === \"RATING\") return;\n // A bug answers \"how bad is it?\" first (#402); the opening turn waits.\n if (phase === \"severity\") {\n seedPendingRef.current = true;\n return;\n }\n seedFromDescription();\n // Intentionally once, on mount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n function seedFromDescription() {\n const seed = description.trim();\n if (!seed) return;\n const history: ChatMessage[] = [{ role: \"user\", content: seed }];\n setMessages(history);\n void runTurn(history);\n }\n\n function answerSeverity(value: ReportSeverity) {\n onSeverityChange(value);\n setPhase(\"chat\");\n if (seedPendingRef.current) {\n seedPendingRef.current = false;\n seedFromDescription();\n }\n }\n\n /** Typed into the composer: a plain yes to \"Is that right?\" counts as the tap. */\n function sendTyped(text: string) {\n const lastAssistant = [...messages].reverse().find((m) => m.role === \"assistant\");\n const checkingBack =\n options.includes(CONFIRM_OPTION) ||\n (lastAssistant?.kind !== \"report\" && isCheckBackQuestion(lastAssistant?.content ?? \"\"));\n send(text, checkingBack && isAffirmativeReply(text));\n }\n\n function send(text: string, autoFile = false) {\n const value = text.trim();\n if (!value || busy) return;\n setOptions([]);\n // Replying at all answers the offer — the card goes, the chat carries on.\n setGlitchgrabOffer(false);\n // Typed under a draft, it is a correction to that draft (#360 — the chat box\n // stays there, so asking for a change is just replying). Logged as\n // `keep_chatting`, the first number read when tuning the prompt.\n const underDraft = phase === \"draft\";\n if (underDraft) {\n const edited =\n aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();\n logEvent(\"keep_chatting\", edited ? \"after editing\" : undefined);\n setPhase(\"chat\");\n }\n const base = underDraft ? withCurrentDraft(messages) : messages;\n const history: ChatMessage[] = [...base, { role: \"user\", content: value }];\n setMessages(history);\n setInput(\"\");\n void runTurn(history, autoFile);\n }\n\n /**\n * One tap answers \"what do you want to do?\". RATING branches away from the\n * model entirely; every other tile drops into the conversation the sheet\n * already had.\n */\n function pickType(tile: DialogTile) {\n onPickType(tile);\n setPhase(tile === \"RATING\" ? \"rating\" : needsSeverity(tile) ? \"severity\" : \"chat\");\n }\n\n /**\n * The draft stays in the conversation — as the reporter last left it, hand\n * edits included — so the next message is read as a correction to it, not as\n * the start of a new report (#357).\n */\n function withCurrentDraft(history: ChatMessage[]): ChatMessage[] {\n const current = description.trim();\n const next = [...history];\n for (let i = next.length - 1; i >= 0; i--) {\n if (next[i].kind === \"report\") {\n if (current) next[i] = { ...next[i], content: current };\n break;\n }\n }\n return next;\n }\n\n /** `auto`: the countdown ran out, so nobody pressed Send — kept apart in the log. */\n function sendDraft(auto = false) {\n setAutoFileLeft(null);\n const edited = aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();\n logEvent(\"draft_sent\", auto ? \"auto-filed\" : edited ? \"edited\" : \"as drafted\");\n flushEvents();\n onSend();\n }\n\n const empty = phase === \"chat\" && messages.length === 0 && !busy;\n\n /**\n * The already-open issue, and where its fix stands. Shown beside the \"is it\n * the same problem?\" question and again above the draft — \"we know, we're on\n * it\" is the answer the reporter came for, so it is said before Send, not\n * after. `status` is the server's, off GitHub's milestone; never the model's.\n *\n * `title: false` beside the question, which already names the issue — the\n * card then adds only what the model cannot say: where the fix stands.\n */\n function renderKnownIssue({ title, footer }: { title: boolean; footer?: string }) {\n if (!duplicate) return null;\n return (\n <div\n data-gg-known-issue=\"\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"3px\",\n padding: \"9px 10px\",\n borderRadius: \"8px\",\n border: \"1px solid rgba(245,158,11,0.4)\",\n backgroundColor: \"rgba(245,158,11,0.08)\",\n fontSize: \"12px\",\n lineHeight: 1.5,\n minWidth: 0,\n }}\n >\n {/* Theme text, not amber: amber on the tint is ~2:1 in light mode. */}\n <span style={{ color: t.text, fontWeight: 600 }}>\n {duplicate.kind === \"related\"\n ? title\n ? \"Your request goes onto this issue\"\n : `Connected to #${duplicate.number}`\n : title\n ? \"Our team is already on this\"\n : `Our team is already on #${duplicate.number}`}\n </span>\n {title && (\n <span style={{ color: t.textMuted, wordBreak: \"break-word\" }}>\n #{duplicate.number} {duplicate.title}\n </span>\n )}\n {/* Where THAT issue's fix stands says nothing about a new request added\n to it — \"Fix expected by 18 Sep\" would read as a promise for theirs. */}\n {duplicate.status && duplicate.kind !== \"related\" && (\n <span style={{ color: t.text, fontWeight: 600 }}>{duplicate.status}</span>\n )}\n {footer && (\n <span style={{ color: t.textMuted }}>\n {duplicate.kind === \"related\"\n ? \"Added as a separate request on it, not a repeat — the team sees both.\"\n : footer}\n </span>\n )}\n </div>\n );\n }\n\n /** \"Naresh Bhosale\" → \"NB\". Blank when we were given no name at all. */\n const initials = (reporterName ?? \"\")\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((w) => w[0]?.toUpperCase() ?? \"\")\n .join(\"\");\n\n const panelStyle: React.CSSProperties = narrow\n ? {\n width: \"100%\",\n maxHeight: \"88dvh\",\n borderTopLeftRadius: \"16px\",\n borderTopRightRadius: \"16px\",\n animation: \"gg-sheet-up .22s cubic-bezier(.2,.8,.2,1)\",\n }\n : {\n width: \"440px\",\n maxWidth: \"100%\",\n height: \"100dvh\",\n borderLeft: `1px solid ${t.border}`,\n animation: \"gg-sheet-in .22s cubic-bezier(.2,.8,.2,1)\",\n };\n\n return createPortal(\n <>\n <style>{`\n @keyframes gg-sheet-in{from{transform:translateX(24px);opacity:0}to{transform:translateX(0);opacity:1}}\n @keyframes gg-sheet-up{from{transform:translateY(24px);opacity:0}to{transform:translateY(0);opacity:1}}\n @keyframes gg-sheet-fade{from{opacity:0}to{opacity:1}}\n @keyframes gg-autofile{from{transform:scaleX(0)}to{transform:scaleX(1)}}\n @keyframes gg-dot{0%,80%,100%{transform:translateY(0);opacity:.4}40%{transform:translateY(-3px);opacity:1}}\n [data-gg-sheet-send]:focus-visible,[data-gg-chip]:focus-visible,[data-gg-assist-remove]:focus-visible,[data-gg-stop-auto-file]:focus-visible{outline:2px solid currentColor;outline-offset:2px}\n `}</style>\n <div\n data-glitchgrab-layer=\"\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Describe your report with AI\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n display: \"flex\",\n alignItems: narrow ? \"flex-end\" : \"stretch\",\n justifyContent: narrow ? \"center\" : \"flex-end\",\n backgroundColor: \"rgba(0,0,0,0.5)\",\n animation: \"gg-sheet-fade .18s ease\",\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n }}\n onClick={() => leave(\"closed\")}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <div\n onClick={(e) => e.stopPropagation()}\n style={{\n ...panelStyle,\n display: \"flex\",\n flexDirection: \"column\",\n // A flex child defaults to min-width:auto, so a long chat bubble\n // grows the sheet past the viewport instead of wrapping inside it.\n // This is what keeps the bottom sheet on screen.\n minWidth: 0,\n maxWidth: \"100%\",\n boxSizing: \"border-box\",\n backgroundColor: t.bg,\n color: t.text,\n boxShadow: \"0 20px 60px rgba(0,0,0,.35)\",\n overflow: \"hidden\",\n isolation: \"isolate\",\n }}\n >\n {/* ── Header ─────────────────────────────────────────────── */}\n <div\n data-gg-sheet-header=\"\"\n style={{\n flexShrink: 0,\n padding: \"14px 16px\",\n borderBottom: `1px solid ${t.border}`,\n display: \"flex\",\n alignItems: \"flex-start\",\n justifyContent: \"space-between\",\n gap: \"12px\",\n minWidth: 0,\n }}\n >\n {/* No overflow:hidden here. The extension's project picker drops its\n search list out of this column, and clipping it left the list\n cut off under the search box with nothing to click (#380).\n minWidth:0 alone lets the column shrink; the picker ellipsizes\n its own label. */}\n <div style={{ minWidth: 0 }}>\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"7px\",\n fontSize: \"14px\",\n fontWeight: 600,\n }}\n >\n <Sparkle color={t.accent} />\n Describe it with AI\n <span\n style={{\n fontSize: \"10px\",\n fontWeight: 600,\n letterSpacing: \".04em\",\n textTransform: \"uppercase\",\n color: t.accent,\n border: `1px solid ${t.accent}55`,\n borderRadius: \"4px\",\n padding: \"1px 5px\",\n }}\n >\n Beta\n </span>\n </div>\n <div style={{ fontSize: \"11.5px\", color: t.textMuted, marginTop: \"3px\" }}>\n {/* The picker's own bubble asks the question — saying it again\n here reads as two prompts for one answer. */}\n {phase === \"type\" ? null : reportTypeLabel}\n {/* The severity step's chips are gone once answered — this is\n where the answer stays visible. */}\n {phase !== \"type\" && severityAsked && severity\n ? ` · ${SEVERITY_LABELS[severity]}`\n : null}\n {projectSlot ? <span style={{ marginLeft: \"6px\" }}>{projectSlot}</span> : null}\n </div>\n </div>\n {/* The way out of the assistant, on every width.\n This used to be a bare × on a phone, which reads as \"close the\n whole thing\" — so someone the assistant was not helping had no\n visible way to reach the form, only a way to give up. It is a\n switch, so it says what it switches to. */}\n <button\n type=\"button\"\n data-gg-write-myself=\"\"\n onClick={() => leave(\"write_myself\", `header, ${phase}`)}\n aria-label=\"Write it myself instead\"\n style={{\n flexShrink: 0,\n border: `1px solid ${t.inputBorder}`,\n borderRadius: \"999px\",\n background: \"transparent\",\n color: t.textMuted,\n cursor: \"pointer\",\n fontSize: \"11.5px\",\n lineHeight: 1,\n fontFamily: \"inherit\",\n whiteSpace: \"nowrap\",\n // ~32px tall either way — this is the escape hatch, not a hint.\n padding: \"9px 11px\",\n }}\n >\n Write it myself\n </button>\n </div>\n\n {/* ── Transcript ─────────────────────────────────────────── */}\n <div\n ref={scrollRef}\n style={{\n flex: 1,\n minHeight: narrow ? \"180px\" : 0,\n overflowY: \"auto\",\n padding: \"16px\",\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n {/* `marginTop: auto` is what pins a short transcript to the BOTTOM\n of a tall drawer, the way every chat surface behaves. Doing it\n with justify-content instead breaks scrolling once the\n conversation outgrows the panel. */}\n <div\n style={{\n marginTop: \"auto\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"12px\",\n minWidth: 0,\n }}\n >\n {phase === \"type\" && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"12px\" }}>\n <div style={{ display: \"flex\", gap: \"8px\" }}>\n <Avatar who=\"assistant\" theme={t} />\n <div\n style={{\n padding: \"9px 12px\",\n borderRadius: \"12px 12px 12px 4px\",\n backgroundColor: t.bgSecondary,\n fontSize: \"13px\",\n lineHeight: 1.55,\n maxWidth: \"88%\",\n }}\n >\n {reporterName ? `Hi ${reporterName.split(\" \")[0]} — w` : \"W\"}hat do you want to\n do? Pick one and I'll take it from there.\n </div>\n </div>\n <div\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: \"6px\",\n paddingLeft: \"32px\",\n }}\n >\n {tiles.map((tile) => {\n const rate = tile === \"RATING\";\n return (\n <button\n key={tile}\n type=\"button\"\n data-gg-chip=\"\"\n data-gg-tile={tile}\n onClick={() => pickType(tile)}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"5px\",\n // The rating is the only tile that isn't a report, so\n // it wears the star colour the dialog's hero row uses\n // rather than hiding among the report types.\n border: `1px solid ${rate ? \"rgba(245,158,11,0.5)\" : t.inputBorder}`,\n background: rate ? \"rgba(245,158,11,0.08)\" : \"transparent\",\n color: rate ? \"#f59e0b\" : t.textMuted,\n borderRadius: \"999px\",\n // 8px vertical keeps the tap target at ~32px.\n padding: \"8px 12px\",\n fontSize: \"12px\",\n fontWeight: rate ? 600 : 400,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n >\n {rate ? \"★ Rate us\" : getTypeLabel(tile)}\n </button>\n );\n })}\n </div>\n </div>\n )}\n\n {/* #402: one tap, right after \"Bug\", so a confirmed draft has\n everything the dialog needs to file it without a second stop. */}\n {phase === \"severity\" && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"12px\" }}>\n <div style={{ display: \"flex\", gap: \"8px\" }}>\n <Avatar who=\"assistant\" theme={t} />\n <div\n style={{\n padding: \"9px 12px\",\n borderRadius: \"12px 12px 12px 4px\",\n backgroundColor: t.bgSecondary,\n fontSize: \"13px\",\n lineHeight: 1.55,\n maxWidth: \"88%\",\n }}\n >\n How bad is it?\n </div>\n </div>\n <div\n role=\"radiogroup\"\n aria-label=\"Severity\"\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: \"6px\",\n paddingLeft: \"32px\",\n }}\n >\n {SEVERITY_LEVELS.map((s) => (\n <button\n key={s}\n type=\"button\"\n role=\"radio\"\n aria-checked={severity === s}\n data-gg-chip=\"\"\n data-gg-severity={s}\n onClick={() => answerSeverity(s)}\n style={{\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.textMuted,\n borderRadius: \"999px\",\n // Same as the picker and option chips — one chip size.\n padding: \"8px 12px\",\n fontSize: \"12px\",\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n >\n {SEVERITY_LABELS[s]}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {phase === \"rating\" && !submitted && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"12px\" }}>\n <div style={{ display: \"flex\", gap: \"8px\" }}>\n <Avatar who=\"assistant\" theme={t} />\n <div\n style={{\n padding: \"9px 12px\",\n borderRadius: \"12px 12px 12px 4px\",\n backgroundColor: t.bgSecondary,\n fontSize: \"13px\",\n lineHeight: 1.55,\n maxWidth: \"88%\",\n }}\n >\n How are we doing? Tap a star — the words are optional.\n </div>\n </div>\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"10px\",\n marginLeft: \"32px\",\n padding: \"12px\",\n borderRadius: \"12px\",\n border: \"1px solid rgba(245,158,11,0.4)\",\n backgroundColor: \"rgba(245,158,11,0.06)\",\n }}\n >\n <div style={{ display: \"flex\", gap: \"4px\" }} role=\"group\" aria-label=\"Rating\">\n {[1, 2, 3, 4, 5].map((star) => {\n const filled = star <= (hoveredStar || rating);\n return (\n <button\n key={star}\n type=\"button\"\n aria-label={`${star} star${star > 1 ? \"s\" : \"\"}`}\n aria-pressed={star <= rating}\n onClick={() => onRatingChange(star)}\n onMouseEnter={() => setHoveredStar(star)}\n onMouseLeave={() => setHoveredStar(0)}\n style={{\n border: \"none\",\n background: \"transparent\",\n padding: 0,\n cursor: \"pointer\",\n lineHeight: 0,\n }}\n >\n <svg width=\"30\" height=\"30\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.4 6.8 19.1l1-5.8L3.5 9.2l5.9-.9L12 3z\"\n fill={filled ? \"#f59e0b\" : \"transparent\"}\n stroke={filled ? \"#f59e0b\" : t.inputBorder}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n );\n })}\n </div>\n <textarea\n value={description}\n onChange={(e) => onDescriptionChange(e.target.value)}\n rows={3}\n placeholder=\"What made it good — or what let you down? (optional)\"\n style={{\n width: \"100%\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n backgroundColor: t.inputBg,\n color: t.text,\n fontSize: \"13px\",\n lineHeight: 1.5,\n fontFamily: \"inherit\",\n resize: \"vertical\",\n outline: \"none\",\n boxSizing: \"border-box\",\n }}\n />\n <button\n type=\"button\"\n onClick={() => setPhase(\"type\")}\n style={{\n alignSelf: \"flex-start\",\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"12px\",\n fontFamily: \"inherit\",\n // A bare text link is ~14px tall — half a thumb.\n padding: \"9px 0\",\n cursor: \"pointer\",\n textDecoration: \"underline\",\n }}\n >\n Report something instead\n </button>\n </div>\n </div>\n )}\n\n {empty && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"12px\" }}>\n <div style={{ display: \"flex\", gap: \"8px\" }}>\n <Avatar who=\"assistant\" theme={t} />\n <div\n style={{\n padding: \"9px 12px\",\n borderRadius: \"12px 12px 12px 4px\",\n backgroundColor: t.bgSecondary,\n fontSize: \"13px\",\n lineHeight: 1.55,\n maxWidth: \"88%\",\n }}\n >\n {reporterName ? `Hi ${reporterName.split(\" \")[0]} — t` : \"T\"}ell me what went\n wrong in your own words. I can already see your screenshot and what you clicked,\n so skip the boring parts.\n </div>\n </div>\n <div\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: \"6px\",\n paddingLeft: \"32px\",\n }}\n >\n {STARTERS.map((s) => (\n <button\n key={s}\n type=\"button\"\n data-gg-chip=\"\"\n onClick={() => {\n logEvent(\"starter_tap\", s);\n send(s);\n }}\n style={{\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.textMuted,\n borderRadius: \"999px\",\n padding: \"6px 11px\",\n fontSize: \"12px\",\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n >\n {s}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {messages.map((m, i) => {\n const mine = m.role === \"user\";\n if (m.kind === \"report\") {\n // While the draft card is up it shows the text itself, so the\n // bubble only points at it. Once they go back to chatting, the\n // draft stays readable in the transcript: they are correcting\n // it, and a correction to something you cannot see is a guess.\n const live = phase === \"draft\" && i === messages.length - 1;\n return (\n <div key={i} style={{ display: \"flex\", gap: \"8px\", minWidth: 0 }}>\n <Avatar who=\"assistant\" theme={t} />\n <div\n data-gg-draft-bubble=\"\"\n style={{\n maxWidth: \"82%\",\n minWidth: 0,\n padding: \"9px 12px\",\n borderRadius: \"12px 12px 12px 4px\",\n fontSize: \"13px\",\n lineHeight: 1.55,\n backgroundColor: t.bgSecondary,\n color: t.text,\n border: live ? \"none\" : `1px solid ${t.accent}66`,\n }}\n >\n {live ? (\n // #402: \"have a read\" beside a countdown reads as a\n // contradiction. Say what is about to happen instead.\n autoFileLeft !== null ? (\n \"Here's your report — I'll file it unless you want to change something.\"\n ) : (\n \"Here's your report — have a read.\"\n )\n ) : (\n <>\n <span\n style={{\n display: \"block\",\n fontSize: \"10px\",\n fontWeight: 700,\n letterSpacing: \".06em\",\n textTransform: \"uppercase\",\n color: t.accent,\n marginBottom: \"4px\",\n }}\n >\n Draft so far\n </span>\n <span\n style={{\n display: \"block\",\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n maxHeight: \"160px\",\n overflowY: \"auto\",\n color: t.textMuted,\n }}\n >\n {m.content}\n </span>\n </>\n )}\n </div>\n </div>\n );\n }\n return (\n <div\n key={i}\n style={{\n display: \"flex\",\n gap: \"8px\",\n minWidth: 0,\n flexDirection: mine ? \"row-reverse\" : \"row\",\n }}\n >\n <Avatar who={m.role} theme={t} initials={initials} />\n <div\n style={{\n maxWidth: \"82%\",\n minWidth: 0,\n padding: \"9px 12px\",\n borderRadius: mine ? \"12px 12px 4px 12px\" : \"12px 12px 12px 4px\",\n fontSize: \"13px\",\n lineHeight: 1.55,\n // Markdown owns the assistant's line breaks and lists.\n whiteSpace: mine ? \"pre-wrap\" : \"normal\",\n wordBreak: \"break-word\",\n backgroundColor: mine ? t.accent : t.bgSecondary,\n color: mine ? t.accentText : t.text,\n }}\n >\n {/* The reporter's own words stay literal — someone typing\n `**` meant the asterisks. */}\n {mine ? m.content : <ChatMarkdown text={m.content} theme={t} />}\n </div>\n </div>\n );\n })}\n\n {/* Answers to the question above, as chips. The assistant sends these\n when the reporter has said something it cannot act on (\"it could\n be better\") — re-asking \"what specifically?\" is what made that\n conversation go in circles. */}\n {/* The model thinks this is an open issue and is asking. The card\n sits with the question so \"is it the same problem?\" is answered\n looking at the actual issue — and its status. */}\n {duplicate && !busy && phase === \"chat\" && (\n <div style={{ paddingLeft: \"32px\", minWidth: 0 }}>\n {renderKnownIssue({ title: false })}\n </div>\n )}\n\n {/* #366 — the assistant thinks this is about Glitchgrab itself, not\n this app. Offered, never automatic: a wrong guess must not yank\n someone out of a real report. One tap sends it on with their own\n words already in the box; one tap says no and the chat goes on. */}\n {glitchgrabOffer && onReportGlitchgrabProblem && !busy && phase === \"chat\" && (\n <div style={{ paddingLeft: \"32px\", minWidth: 0 }}>\n <div\n data-gg-glitchgrab-offer=\"\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"8px\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.accent}55`,\n backgroundColor: `${t.accent}14`,\n fontSize: \"12px\",\n lineHeight: 1.5,\n }}\n >\n <span style={{ color: t.text, fontWeight: 600 }}>\n This is about Glitchgrab, not this app\n </span>\n <span style={{ color: t.textMuted }}>\n It goes to the team that builds this reporter, with your chat attached.\n </span>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"6px\" }}>\n <button\n type=\"button\"\n data-gg-glitchgrab-offer-send=\"\"\n onClick={() => {\n logEvent(\"glitchgrab_offer_tap\");\n setGlitchgrabOffer(false);\n onReportGlitchgrabProblem(\n messages\n .filter((m) => m.role === \"user\")\n .map((m) => m.content.trim())\n .filter(Boolean)\n .join(\"\\n\\n\"),\n );\n }}\n style={{\n padding: \"8px 12px\",\n borderRadius: \"999px\",\n border: \"none\",\n backgroundColor: t.accent,\n color: t.accentText,\n fontSize: \"12px\",\n fontWeight: 700,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n // Both stretch, so on a phone each wrapped line reads as\n // a choice rather than one button left stranded.\n flex: \"1 1 auto\",\n }}\n >\n Send to the Glitchgrab team\n </button>\n <button\n type=\"button\"\n data-gg-glitchgrab-offer-no=\"\"\n onClick={() => {\n logEvent(\"glitchgrab_offer_declined\");\n send(\"No — it's about this app, not the reporting tool\");\n }}\n style={{\n padding: \"8px 12px\",\n borderRadius: \"999px\",\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"12px\",\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n flex: \"1 1 auto\",\n }}\n >\n No, it's about this app\n </button>\n </div>\n </div>\n </div>\n )}\n\n {options.length > 0 && !busy && phase === \"chat\" && !glitchgrabOffer && (\n <div\n style={{\n display: \"flex\",\n // Long labels wrapped into a ragged row that always stranded\n // the last chip on a line of its own. Past ~24 characters\n // these stop being chips and become a choice list, so they\n // stack full width and read like one.\n flexDirection: options.some((o) => o.length > 24) ? \"column\" : \"row\",\n alignItems: options.some((o) => o.length > 24) ? \"stretch\" : \"flex-start\",\n flexWrap: \"wrap\",\n gap: \"6px\",\n paddingLeft: \"32px\",\n }}\n >\n {options.map((option) => (\n <button\n key={option}\n type=\"button\"\n data-gg-chip=\"\"\n data-gg-option=\"\"\n onClick={() => {\n logEvent(\"option_tap\", option);\n send(option, option === CONFIRM_OPTION);\n }}\n style={{\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.textMuted,\n borderRadius: \"999px\",\n // Same 8px as the picker chips — one tap target size in\n // this sheet, not two.\n padding: \"8px 12px\",\n fontSize: \"12px\",\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n textAlign: \"left\",\n }}\n >\n {option}\n </button>\n ))}\n </div>\n )}\n\n {busy && (\n <div style={{ display: \"flex\", gap: \"8px\" }} role=\"status\" aria-label=\"Thinking\">\n <Avatar who=\"assistant\" theme={t} />\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"4px\",\n padding: \"12px\",\n borderRadius: \"12px 12px 12px 4px\",\n backgroundColor: t.bgSecondary,\n }}\n >\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n style={{\n width: \"5px\",\n height: \"5px\",\n borderRadius: \"50%\",\n backgroundColor: t.textMuted,\n animation: `gg-dot 1.1s ease-in-out ${i * 0.15}s infinite`,\n }}\n />\n ))}\n </span>\n </div>\n )}\n\n {/* ── The draft ────────────────────────────────────────── */}\n {phase === \"draft\" && !submitted && (\n <div\n style={{\n border: `1px solid ${t.accent}`,\n borderRadius: \"12px\",\n backgroundColor: t.bgSecondary,\n padding: \"12px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"10px\",\n minWidth: 0,\n boxSizing: \"border-box\",\n }}\n >\n <span\n style={{\n fontSize: \"10px\",\n fontWeight: 700,\n letterSpacing: \".06em\",\n textTransform: \"uppercase\",\n color: t.accent,\n }}\n >\n {duplicate\n ? `What we'll add to #${duplicate.number}${duplicate.kind === \"related\" ? \" as a related request\" : \"\"} · edit anything`\n : \"Your report · edit anything\"}\n </span>\n\n {renderKnownIssue({\n title: true,\n footer: \"Your details will be added to it instead of opening a new issue.\",\n })}\n <textarea\n ref={draftRef}\n value={description}\n onChange={(e) => {\n stopAutoFile(\"edited the draft\");\n onDescriptionChange(e.target.value);\n }}\n rows={6}\n style={{\n width: \"100%\",\n minHeight: \"120px\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n backgroundColor: t.inputBg,\n color: t.text,\n fontSize: \"13px\",\n lineHeight: 1.55,\n fontFamily: \"inherit\",\n resize: \"vertical\",\n outline: \"none\",\n boxSizing: \"border-box\",\n }}\n />\n\n {/* Answered a step ago; while the countdown runs a second\n picker is only something to mis-tap. Stopping it brings the\n picker back so the answer can still be changed. */}\n {severityAsked && autoFileLeft === null && (\n <div>\n <span\n style={{\n fontSize: \"11.5px\",\n color: t.textMuted,\n display: \"block\",\n marginBottom: \"6px\",\n }}\n >\n How bad is it?\n {!severity && (\n <span\n style={{\n marginLeft: \"6px\",\n fontSize: \"11px\",\n color: severityRefused ? \"#ef4444\" : t.textMuted,\n }}\n >\n · required\n </span>\n )}\n </span>\n <div\n role=\"radiogroup\"\n aria-label=\"Severity\"\n style={{ display: \"flex\", gap: \"6px\" }}\n >\n {SEVERITY_LEVELS.map((s) => {\n const on = severity === s;\n return (\n <button\n key={s}\n type=\"button\"\n onClick={() => onSeverityChange(s)}\n role=\"radio\"\n aria-checked={on}\n style={{\n flex: 1,\n minWidth: 0,\n padding: \"8px 2px\",\n borderRadius: \"8px\",\n border: `1px solid ${\n on\n ? t.accent\n : severityRefused\n ? \"#ef4444\"\n : t.inputBorder\n }`,\n backgroundColor: on ? t.accent : \"transparent\",\n color: on ? t.accentText : t.textMuted,\n fontSize: \"12px\",\n fontWeight: 600,\n fontFamily: \"inherit\",\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n cursor: \"pointer\",\n }}\n >\n {SEVERITY_LABELS[s]}\n </button>\n );\n })}\n </div>\n </div>\n )}\n\n {attachmentCount > 0 && (\n <span style={{ fontSize: \"11.5px\", color: t.textMuted }}>\n {attachmentCount} {attachmentCount === 1 ? \"attachment\" : \"attachments\"} will be\n sent with this.\n </span>\n )}\n </div>\n )}\n\n {phase === \"solved\" && solved && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"12px\" }}>\n <div style={{ display: \"flex\", gap: \"8px\" }}>\n <Avatar who=\"assistant\" theme={t} />\n <div\n style={{\n padding: \"9px 12px\",\n borderRadius: \"12px 12px 12px 4px\",\n backgroundColor: t.bgSecondary,\n fontSize: \"13px\",\n lineHeight: 1.55,\n maxWidth: \"88%\",\n whiteSpace: \"pre-wrap\",\n }}\n >\n {solved}\n </div>\n </div>\n <span\n style={{ fontSize: \"11.5px\", color: t.textMuted, paddingLeft: \"32px\" }}\n >\n Nothing was filed — you are all set.\n </span>\n </div>\n )}\n\n {submitted && (\n <div\n style={{\n textAlign: \"center\",\n padding: \"24px 0\",\n color: t.accent,\n fontSize: \"14px\",\n fontWeight: 600,\n }}\n >\n {reportTypeLabel} sent. Thank you!\n </div>\n )}\n </div>\n </div>\n\n {/* ── Composer / Send ────────────────────────────────────── */}\n {/* The picker has nothing to compose — a chip IS the answer, and an\n input under it invites someone to type a type name we then have\n to parse. */}\n {!submitted && phase !== \"type\" && phase !== \"severity\" && (\n <div\n style={{\n flexShrink: 0,\n borderTop: `1px solid ${t.border}`,\n padding: \"12px 16px\",\n paddingBottom: narrow ? \"max(12px, env(safe-area-inset-bottom))\" : \"12px\",\n backgroundColor: t.bg,\n }}\n >\n {phase === \"solved\" ? (\n <button\n type=\"button\"\n data-gg-sheet-send=\"\"\n onClick={() => (onFinish ?? onClose)()}\n style={{\n width: \"100%\",\n padding: \"12px\",\n borderRadius: \"10px\",\n border: \"none\",\n backgroundColor: t.accent,\n color: t.accentText,\n fontSize: \"14px\",\n fontWeight: 700,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n >\n Done\n </button>\n ) : phase === \"rating\" ? (\n <button\n type=\"button\"\n data-gg-sheet-send=\"\"\n onClick={onSend}\n disabled={isSubmitting || rating < 1}\n style={{\n width: \"100%\",\n padding: \"12px\",\n borderRadius: \"10px\",\n border: \"none\",\n backgroundColor: isSubmitting || rating < 1 ? t.bgSecondary : \"#f59e0b\",\n color: isSubmitting || rating < 1 ? t.textMuted : \"#1a1a1a\",\n fontSize: \"14px\",\n fontWeight: 700,\n fontFamily: \"inherit\",\n cursor: isSubmitting || rating < 1 ? \"default\" : \"pointer\",\n }}\n >\n {isSubmitting ? \"Sending…\" : rating < 1 ? \"Pick a star first\" : \"Send Rating\"}\n </button>\n ) : (\n // Chat AND draft share this branch, so the chat box is the same\n // element on both sides of a draft landing — it stays put\n // instead of remounting, and a draft is something you can\n // still reply to (#360), not a form that replaced the chat.\n <>\n {/* Proof that a pasted image landed. ⌘V is handled by the\n dialog underneath, which used to swallow the picture into a\n strip hidden behind this sheet — indistinguishable from\n paste being unsupported (#352). */}\n {(screenshots.length > 0 || files.length > 0 || onAddFiles) && (\n <div\n style={{\n display: \"flex\",\n gap: \"8px\",\n alignItems: \"center\",\n flexWrap: \"wrap\",\n marginBottom: \"8px\",\n }}\n >\n {screenshots.map((shot, i) => {\n // Only some are actually sent (count and size caps), so\n // the rest are dimmed rather than hidden: \"it is attached\n // but the assistant is not looking at it\" is the true\n // statement.\n const read = readShots.has(shot);\n return (\n <div\n key={`${i}-${shot.slice(-16)}`}\n style={{\n position: \"relative\",\n width: \"40px\",\n height: \"40px\",\n flexShrink: 0,\n }}\n >\n <img\n src={shot}\n alt={read ? \"Attached image the assistant reads\" : \"Attached image\"}\n data-gg-assist-thumb=\"\"\n style={{\n display: \"block\",\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n borderRadius: \"8px\",\n border: `1px solid ${read ? t.accent : t.inputBorder}`,\n opacity: read ? 1 : 0.45,\n boxSizing: \"border-box\",\n }}\n />\n {/* #360: a wrong paste could not be taken back from\n in here, so reporters described \"the third\n screenshot\" in words instead. Same red × as the\n dialog's own strip. */}\n {onRemoveImage && (\n <button\n type=\"button\"\n data-gg-assist-remove=\"\"\n aria-label={`Remove image ${i + 1}`}\n title=\"Remove this image\"\n onClick={() => {\n stopAutoFile(\"changed attachments\");\n logEvent(\n \"image_removed\",\n pageShot && shot === pageShot ? \"page capture\" : \"attached\",\n );\n onRemoveImage(i);\n }}\n // 32px to tap, 20px to see: the dot stays small on a\n // 40px thumbnail, the target does not.\n style={{\n position: \"absolute\",\n top: \"-13px\",\n right: \"-13px\",\n width: \"32px\",\n height: \"32px\",\n border: \"none\",\n background: \"transparent\",\n padding: 0,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"50%\",\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: \"20px\",\n height: \"20px\",\n boxSizing: \"border-box\",\n borderRadius: \"50%\",\n border: `2px solid ${t.bg}`,\n background: \"#ef4444\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path\n d=\"M1 1L9 9M9 1L1 9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n </button>\n )}\n </div>\n );\n })}\n {/* #1851: a mockup attached on the form was invisible here,\n and the assistant asked about a page it never saw. A\n file it reads is outlined like a read image; one it\n cannot read is dimmed, and says why on hover. */}\n {files.map((file, i) => {\n const read = readFiles.has(i);\n const why = read\n ? \"the assistant reads this file\"\n : isAssistReadableFile(file.name)\n ? \"attached, but more than one message can carry, so the assistant is not reading it\"\n : \"attached to the report — the assistant can't read this kind of file\";\n return (\n <div\n key={`file-${i}-${file.name}`}\n data-gg-assist-file=\"\"\n data-gg-assist-file-read={read ? \"\" : undefined}\n title={`${file.name} — ${why}`}\n style={{\n position: \"relative\",\n height: \"40px\",\n maxWidth: \"170px\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n padding: \"0 10px\",\n borderRadius: \"8px\",\n border: `1px solid ${read ? t.accent : t.inputBorder}`,\n opacity: read ? 1 : 0.55,\n boxSizing: \"border-box\",\n flexShrink: 0,\n }}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\" style={{ flexShrink: 0 }}>\n <path\n d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z M14 2v6h6\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span\n style={{\n fontSize: \"11.5px\",\n color: t.text,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {file.name}\n </span>\n {onRemoveFile && (\n <button\n type=\"button\"\n data-gg-assist-remove-file=\"\"\n aria-label={`Remove file ${file.name}`}\n title=\"Remove this file\"\n onClick={() => {\n stopAutoFile(\"changed attachments\");\n logEvent(\"file_removed\", read ? \"read\" : \"not read\");\n onRemoveFile(i);\n }}\n style={{\n position: \"absolute\",\n top: \"-13px\",\n right: \"-13px\",\n width: \"32px\",\n height: \"32px\",\n border: \"none\",\n background: \"transparent\",\n padding: 0,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"50%\",\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: \"20px\",\n height: \"20px\",\n boxSizing: \"border-box\",\n borderRadius: \"50%\",\n border: `2px solid ${t.bg}`,\n background: \"#ef4444\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path\n d=\"M1 1L9 9M9 1L1 9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n </button>\n )}\n </div>\n );\n })}\n {onAddFiles && (\n <label\n data-gg-assist-attach=\"\"\n title=\"Attach an image or a file (html, json, log…) — or paste one\"\n style={{\n width: \"40px\",\n height: \"40px\",\n borderRadius: \"8px\",\n border: `1px dashed ${t.inputBorder}`,\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: t.textMuted,\n fontSize: \"18px\",\n cursor: \"pointer\",\n flexShrink: 0,\n }}\n >\n +\n <input\n type=\"file\"\n accept={ASSIST_ATTACHMENT_ACCEPT}\n multiple\n onChange={(e) => {\n const picked = Array.from(e.target.files ?? []);\n if (picked.length) {\n stopAutoFile(\"changed attachments\");\n const images = picked.filter((f) => f.type.startsWith(\"image/\")).length;\n if (images) logEvent(\"image_added\", String(images));\n if (picked.length > images) {\n logEvent(\"file_added\", String(picked.length - images));\n }\n onAddFiles(picked);\n }\n // Same file twice in a row fires no change event\n // unless the input is cleared.\n e.target.value = \"\";\n }}\n style={{ display: \"none\" }}\n />\n </label>\n )}\n {readShots.size < screenshots.length && (\n <span style={{ color: t.textMuted, fontSize: \"11px\" }}>\n {readShots.size} of {screenshots.length} read\n </span>\n )}\n </div>\n )}\n <div style={{ display: \"flex\", gap: \"8px\", alignItems: \"flex-end\" }}>\n <textarea\n value={input}\n onChange={(e) => {\n // Typing a change under the draft — it must not file mid-sentence.\n stopAutoFile(\"typing a change\");\n setInput(e.target.value);\n }}\n onKeyDown={(e) => {\n // Enter sends, Shift+Enter breaks the line — the rule\n // every chat surface uses, so nobody has to learn it.\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n sendTyped(input);\n }\n }}\n placeholder={\n phase === \"draft\" ? \"Anything to change? Tell me here…\" : \"Type your answer…\"\n }\n rows={1}\n disabled={busy}\n autoFocus\n style={{\n flex: 1,\n minHeight: \"42px\",\n maxHeight: \"120px\",\n padding: \"11px 12px\",\n borderRadius: \"10px\",\n border: `1px solid ${t.inputBorder}`,\n backgroundColor: t.inputBg,\n color: t.text,\n fontSize: \"13px\",\n lineHeight: 1.4,\n fontFamily: \"inherit\",\n resize: \"none\",\n outline: \"none\",\n boxSizing: \"border-box\",\n }}\n />\n <button\n type=\"button\"\n data-gg-sheet-send=\"\"\n onClick={() => sendTyped(input)}\n disabled={busy || !input.trim()}\n aria-label=\"Send message\"\n data-gg-send-message=\"\"\n style={{\n flexShrink: 0,\n width: \"42px\",\n height: \"42px\",\n borderRadius: \"10px\",\n border: \"none\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: busy || !input.trim() ? t.bgSecondary : t.accent,\n color: busy || !input.trim() ? t.textMuted : t.accentText,\n cursor: busy || !input.trim() ? \"default\" : \"pointer\",\n }}\n >\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n {/* Paper plane, nose to the RIGHT. Direction is the\n entire meaning of this icon — get it backwards and it\n reads as \"back\", which is the opposite action. */}\n <path\n d=\"M3 20.5L21.5 12 3 3.5V10l12 2-12 2v6.5z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>\n </div>\n {phase === \"draft\" && (\n <>\n {validationError && (\n <p\n style={{\n margin: \"8px 0 0\",\n color: \"#ef4444\",\n fontSize: \"12px\",\n }}\n >\n {validationError}\n </p>\n )}\n {autoFileLeft !== null ? (\n // #402: \"Yes, that's it\" was the confirmation. The draft\n // files itself unless they stop it — the bar shows how\n // long is left, the button sends now, the × on its right\n // stops it (#406). Stopping keeps the draft: Send Report\n // comes back, and closing the sheet drops it.\n <div style={{ display: \"flex\", gap: \"8px\", marginTop: \"8px\" }}>\n <button\n type=\"button\"\n data-gg-sheet-send=\"\"\n data-gg-auto-file=\"\"\n onClick={() => sendDraft()}\n style={{\n flex: 1,\n minWidth: 0,\n position: \"relative\",\n overflow: \"hidden\",\n padding: \"12px\",\n borderRadius: \"10px\",\n border: \"none\",\n backgroundColor: t.accent,\n color: t.accentText,\n fontSize: \"14px\",\n fontWeight: 700,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n position: \"absolute\",\n inset: 0,\n backgroundColor: \"rgba(255,255,255,0.22)\",\n transformOrigin: \"left\",\n animation: `gg-autofile ${AUTO_FILE_SECONDS}s linear forwards`,\n }}\n />\n <span style={{ position: \"relative\" }}>Filing in {autoFileLeft}s…</span>\n </button>\n <button\n type=\"button\"\n data-gg-stop-auto-file=\"\"\n onClick={() => stopAutoFile(\"pressed stop\")}\n aria-label=\"Stop — don't send\"\n title=\"Stop — don't send\"\n style={{\n flexShrink: 0,\n width: \"44px\",\n borderRadius: \"10px\",\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.text,\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: \"pointer\",\n }}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n strokeWidth=\"2.25\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n data-gg-sheet-send=\"\"\n onClick={() => sendDraft()}\n disabled={isSubmitting || !description.trim()}\n style={{\n width: \"100%\",\n marginTop: \"8px\",\n padding: \"12px\",\n borderRadius: \"10px\",\n border: \"none\",\n backgroundColor:\n isSubmitting || !description.trim() ? t.bgSecondary : t.accent,\n color: isSubmitting || !description.trim() ? t.textMuted : t.accentText,\n fontSize: \"14px\",\n fontWeight: 700,\n fontFamily: \"inherit\",\n cursor: isSubmitting || !description.trim() ? \"default\" : \"pointer\",\n }}\n >\n {isSubmitting\n ? \"Sending…\"\n : duplicate\n ? `Add to #${duplicate.number}`\n : \"Send Report\"}\n </button>\n )}\n </>\n )}\n </>\n )}\n\n {/* The moment people actually give up is two replies into a\n conversation that is not landing — not while looking at the\n header. Offer the form there, in as many words. */}\n {phase === \"chat\" && messages.length > 0 && (\n <button\n type=\"button\"\n data-gg-write-myself=\"\"\n onClick={() => leave(\"write_myself\", \"footer\")}\n style={{\n display: \"block\",\n margin: \"8px auto 0\",\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"11.5px\",\n fontFamily: \"inherit\",\n padding: \"6px 8px\",\n cursor: \"pointer\",\n }}\n >\n Not getting it? Fill the form yourself →\n </button>\n )}\n\n {/* #366 — the assistant itself is what went wrong. That report\n belongs to Glitchgrab, not to the project behind this sheet. */}\n {/* Hidden while the offer card is up — it says the same thing, bigger. */}\n {onReportGlitchgrabProblem && phase !== \"solved\" && !glitchgrabOffer && (\n <button\n type=\"button\"\n data-gg-self-report=\"\"\n onClick={() => onReportGlitchgrabProblem()}\n style={{\n display: \"block\",\n // ~32px tap target; the negative margins keep the composer\n // from growing to make room for it.\n margin: \"-2px auto -8px\",\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"11.5px\",\n fontFamily: \"inherit\",\n padding: \"10px 8px\",\n cursor: \"pointer\",\n textDecoration: \"underline\",\n textUnderlineOffset: \"2px\",\n }}\n >\n Assistant misbehaving? Tell Glitchgrab\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n </>,\n document.body,\n );\n}\n","// Minimal type surface ReportDialog needs — kept separate from the SDK's\n// full types.ts (which also covers auto-capture/breadcrumbs, irrelevant here).\n\nexport type ReportType =\n | \"BUG\"\n | \"FEATURE_REQUEST\"\n | \"UI_IMPROVEMENT\"\n | \"PERFORMANCE\"\n | \"SECURITY\"\n | \"QUESTION\"\n | \"OTHER\";\n\n/**\n * What the user can pick on step 1. A superset of `ReportType`: `RATING` is a\n * tile, not a report type — it never reaches the report API or GitHub, it saves\n * a star rating through `FeedbackFn` instead. Kept out of `ReportType` so the\n * report endpoint's validated enum stays exactly what it was.\n */\nexport type DialogTile = ReportType | \"RATING\";\n\nexport type ReportSeverity = \"low\" | \"medium\" | \"high\" | \"critical\";\n\n/**\n * The picker's order, left to right. Kept next to the union so a new level\n * can't be added to the type and forgotten in the two pickers that render it\n * (the dialog's own row and the assist sheet's).\n *\n * Mirrored server-side by `SEVERITY_VALUES` in `apps/web/lib/severity.ts`,\n * which rejects anything outside it — add a level in both, or the button files\n * a 400.\n */\nexport const SEVERITY_LEVELS: readonly ReportSeverity[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"critical\",\n];\n\n/**\n * Display text. The buttons used to render the raw union value through\n * `text-transform: capitalize`, which meant the label and the GitHub label\n * (`severity:<value>`) could never diverge — fine until a level needs wording\n * the label can't carry.\n */\nexport const SEVERITY_LABELS: Record<ReportSeverity, string> = {\n low: \"Low\",\n medium: \"Medium\",\n high: \"High\",\n critical: \"Critical\",\n};\n\nexport interface ReportResult {\n success: boolean;\n reportId?: string;\n issueUrl?: string;\n issueNumber?: number;\n title?: string;\n intent?: string;\n message?: string;\n /** \"QUEUED\" when saved but not filed yet — the repo lost GitHub access. */\n status?: string;\n}\n\n/**\n * Who the dialog says is filing the report. Hosts resolve this differently —\n * the SDK from its `session` prop, the extension and GlitchRecord from the\n * server-side `ExtensionSession` identity — so the dialog takes it as data and\n * never guesses.\n *\n * `null`/omitted renders the anonymous state rather than nothing: a reporter\n * who believes they're signed in and isn't would otherwise file a report with\n * no way to be followed up, and never know.\n */\nexport interface ReportReporter {\n name?: string | null;\n email?: string | null;\n avatarUrl?: string | null;\n /** Optional role suffix, e.g. \"tester\" — shown next to the name */\n role?: string | null;\n}\n\n/** The function a host (SDK or extension) supplies to actually submit a report. */\nexport type ReportFn = (\n type: ReportType,\n description: string,\n metadata?: Record<string, string>\n) => Promise<ReportResult | null>;\n\n/**\n * Saves a 1–5 star rating. Supplying this is what makes the `RATING` tile\n * appear — a host with no feedback wiring (GlitchRecord desktop today) simply\n * doesn't show it rather than showing a tile that fails on submit.\n */\nexport type FeedbackFn = (\n rating: number,\n message?: string\n) => Promise<{ success: boolean } | null>;\n\n/** Optional: polish description text. Never throws — returns original text on failure. */\nexport type EnhanceTextFn = (text: string, screenshot?: string | null) => Promise<string>;\n\n/**\n * One turn of the AI report assistant (#330).\n *\n * `question` and `report` are mutually exclusive: the assistant is either still\n * asking, or it has written the description. `degraded` is set when the\n * assistant cannot help right now — over the project's monthly cap, rate\n * limited, model down, or simply switched off. That is not an error state: the\n * panel closes, the message is shown once, and the plain form the dialog has\n * always had takes over. Filing a report must never depend on a model.\n */\nexport interface AssistTurnResult {\n conversationId: string | null;\n question: string | null;\n /**\n * Tappable answers to `question`. Sent when the reporter has said something\n * too vague to act on — \"it could be better\" — and the assistant read\n * candidates off the screenshot instead of asking them to phrase it again.\n * Empty when it asked an open question.\n */\n options?: string[];\n report: string | null;\n /**\n * An issue that is already open for this exact problem. Server-validated\n * against the repo's real open issues, so the number is safe to send back:\n * the report is added to that issue as a comment instead of opening another.\n *\n * `status` is where the fix stands, worded by the server off GitHub's own\n * milestone and assignees — \"Fix expected by 18 Sep (v1.8).\" Never from the\n * model. Absent from servers older than it.\n */\n duplicate?: { number: number; title: string; url: string; status?: string } | null;\n /**\n * An open issue this is a DIFFERENT requirement for, in the same feature. The\n * assistant asks whether to add it there; yes → a comment marked as a related\n * request. Server-validated like `duplicate`, never set together with it.\n * Top-level on purpose: a host that predates it ignores it and files a new\n * issue, instead of posting new work as \"another report of this\".\n */\n related?: { number: number; title: string; url: string; status?: string } | null;\n /**\n * The project's own brief answered it and the reporter confirmed. Nothing is\n * filed — the sheet shows this line and the dialog closes. Someone whose\n * problem already had an answer leaves with the answer, not a ticket number.\n */\n solved?: string | null;\n /**\n * The assistant thinks this is a problem with Glitchgrab itself, not the\n * project (#366). The sheet offers to send it to the Glitchgrab team —\n * only when the host passed `reportGlitchgrabProblem`.\n */\n aboutGlitchgrab?: boolean;\n degraded?: string | null;\n /**\n * With `degraded`: the reason clears on its own (an hourly rate limit), so the\n * dialog keeps the assistant button for this report instead of retiring it.\n * A monthly cap or an outage leaves this unset. Absent from older hosts, which\n * then retire the assistant exactly as before.\n */\n retryable?: boolean;\n}\n\n/**\n * How many images ride along with one assistant turn.\n *\n * Capped rather than unbounded: every image is vision tokens against the\n * repo's monthly conversation cap, and a reporter who drags in eight shots\n * would spend the project's month on one bug. The newest win — the picture\n * someone just pasted is the one they are talking about.\n */\nexport const MAX_ASSIST_IMAGES = 3;\n\n/**\n * Total characters of image data one assistant turn may carry.\n *\n * Vercel refuses a request body over ~4.5 MB at the edge with a 413, before the\n * route runs — so the server never gets to answer `degrade`, nothing is logged,\n * and the sheet simply closes. Images are nearly the whole body; this leaves\n * about a megabyte for the conversation, context and events.\n */\nexport const MAX_ASSIST_IMAGE_CHARS = 3_500_000;\n\n/**\n * A text file the reporter attached, decoded for the assistant (#1851) — an\n * HTML mockup, a JSON export, a log. Images go in `screenshots`; binaries (pdf,\n * docx) are not read.\n */\nexport interface AssistFile {\n name: string;\n content: string;\n}\n\n/** Files one assistant turn may carry. The newest win, like images. */\nexport const MAX_ASSIST_FILES = 3;\n\n/**\n * Characters of file text one turn may carry in total, and per file. Sized to\n * fit the megabyte `MAX_ASSIST_IMAGE_CHARS` leaves under the request limit. The\n * server caps again and shows the model an outline plus an excerpt, so this\n * bounds the request body, not how much the model reads.\n */\nexport const MAX_ASSIST_FILE_CHARS = 300_000;\nexport const MAX_ASSIST_FILE_CHARS_EACH = 200_000;\n\n/**\n * Something the reporter did in the sheet, as opposed to something they typed\n * (#357). Kept so the team can see where a conversation stopped working —\n * \"keep chatting\" after a draft, \"write it myself\", a chip tapped.\n */\nexport interface AssistSheetEvent {\n type:\n | \"draft_shown\"\n | \"keep_chatting\"\n | \"write_myself\"\n | \"option_tap\"\n | \"starter_tap\"\n | \"image_added\"\n | \"image_removed\"\n | \"file_added\"\n | \"file_removed\"\n | \"draft_sent\"\n | \"auto_file_stopped\"\n | \"closed\"\n | \"glitchgrab_offer_tap\"\n | \"glitchgrab_offer_declined\";\n detail?: string;\n /** Epoch ms on the reporter's clock. */\n at: number;\n}\n\nexport interface AssistTurnParams {\n /**\n * The conversation so far. An assistant message with `kind: \"report\"` is a\n * draft the reporter was shown, its `content` the draft as they last left it\n * — so \"keep chatting\" revises the draft instead of starting over (#357).\n * Empty on an events-only flush.\n */\n messages: { role: \"user\" | \"assistant\"; content: string; kind?: \"report\" }[];\n conversationId: string | null;\n /**\n * Sheet clicks since the last call. Hosts forward params verbatim, so this\n * needs no host code; the server stores it against the conversation.\n */\n events?: AssistSheetEvent[];\n /**\n * Images the model reads — the auto-captured page shot plus anything the\n * reporter pasted or attached, newest last, at most `MAX_ASSIST_IMAGES` and\n * `MAX_ASSIST_IMAGE_CHARS` between them.\n */\n screenshots?: string[];\n /**\n * @deprecated Superseded by `screenshots`, and no longer sent by the sheet:\n * repeating the newest image doubled the heaviest part of the body and pushed\n * turns past the request-size limit. The server still reads it from SDK\n * builds that predate `screenshots`.\n */\n screenshot?: string | null;\n /**\n * Text files attached to the report (html, json, log…), decoded, newest last,\n * at most `MAX_ASSIST_FILES` (#1851). Omitted when there are none, so a host\n * or server that predates it sees the exact body it always did.\n */\n files?: AssistFile[];\n /**\n * Page URL, visited pages, breadcrumbs, report type. Host-supplied. The sheet\n * adds `imageSources` — \"page\" | \"attached\" per entry of `screenshots` — so\n * the model can tell the screen they were on from what they pasted (#357).\n */\n context?: Record<string, unknown> | null;\n}\n\n/**\n * Runs one assistant turn. Supplied by the host (SDK / extension /\n * GlitchRecord), because only the host knows how to authenticate. Must never\n * throw — a failure comes back as `degraded`.\n */\nexport type AssistFn = (params: AssistTurnParams) => Promise<AssistTurnResult>;\n\n/**\n * Why a report is added to an open issue instead of opening one: the SAME\n * problem (`duplicate`), or a different requirement for the same feature the\n * reporter chose to keep on that issue (`related`).\n */\nexport type AttachKind = \"duplicate\" | \"related\";\n\n/** An already-open issue the plain form's duplicate check matched. */\nexport interface SimilarIssue {\n number: number;\n title: string;\n url: string;\n /**\n * Where the fix stands, worded by the server off GitHub's milestone and\n * assignees — the same line the assistant's duplicate card shows. Absent from\n * hosts or servers that predate it.\n */\n status?: string;\n}\n\n/**\n * \"Is this already filed?\" — asked when the plain form's Send is pressed.\n *\n * Deterministic on the server (word overlap on the repo's open issues, no\n * model), so it can sit in front of Send without making filing depend on a\n * model. Hosts return `[]` when the project has it off and `null` on any\n * failure; the dialog treats both as \"send now\". Must never throw.\n */\nexport type FindSimilarIssuesFn = (description: string) => Promise<SimilarIssue[] | null>;\n\n/** What the dialog hands the host when someone reports a problem with Glitchgrab itself (#366). */\nexport interface GlitchgrabProblemParams {\n description: string;\n /** Where they were when it went wrong — the plain form, or the AI sheet. */\n surface: \"form\" | \"assist\";\n /**\n * The assistant chat, if there was one. The server checks it belongs to the\n * host's project, then puts the full transcript in the issue.\n */\n conversationId: string | null;\n /** The tile they were filing — \"BUG\", \"FEATURE_REQUEST\", … */\n reportType: string;\n /** Every image attached to the report, page shot first, as data URLs. */\n screenshots: string[];\n}\n\n/**\n * Sends a report about the report dialog itself to the Glitchgrab team, never\n * to the host project. Supplying it adds \"Problem with Glitchgrab?\" to the\n * dialog footer and the AI sheet; omitting it leaves both exactly as they were.\n * The SDK passes it only when the project's owner switched it on.\n */\nexport type GlitchgrabProblemFn = (\n params: GlitchgrabProblemParams\n) => Promise<ReportResult | null>;\n","/**\n * File types the report dialog offers in its picker. Mirrors the server-side\n * allowlist in `apps/web/lib/attachments-constants.ts` — the server is the\n * authority, this list only shapes the native file dialog.\n *\n * Text-like files (html, json, log…) are previewed in the GitHub issue body and\n * stored whole on the CDN as plain text; binaries (pdf, docx…) are committed to\n * the repo attachments branch.\n */\nconst TEXT_ATTACHMENT_EXTENSIONS = [\n \".html\",\n \".htm\",\n \".txt\",\n \".md\",\n \".json\",\n \".xml\",\n \".log\",\n \".yml\",\n \".yaml\",\n \".csv\",\n \".har\",\n \".js\",\n \".mjs\",\n \".cjs\",\n \".ts\",\n \".tsx\",\n \".jsx\",\n \".css\",\n \".scss\",\n \".py\",\n \".sh\",\n] as const;\n\nconst BINARY_ATTACHMENT_EXTENSIONS = [\".pdf\", \".doc\", \".docx\", \".xls\", \".xlsx\", \".zip\"] as const;\n\nexport const ATTACHMENT_ACCEPT = [\n \"image/*\",\n ...TEXT_ATTACHMENT_EXTENSIONS,\n ...BINARY_ATTACHMENT_EXTENSIONS,\n].join(\",\");\n\n/**\n * The AI sheet's picker (#1851): images, and the text files the assistant can\n * read. Binaries stay on the dialog's own picker — offering a PDF in a chat\n * that cannot read it would promise something the assistant does not do.\n */\nexport const ASSIST_ATTACHMENT_ACCEPT = [\"image/*\", ...TEXT_ATTACHMENT_EXTENSIONS].join(\",\");\n\n/** True for a file the assistant reads as text. Judged by name, like the server. */\nexport function isAssistReadableFile(name: string): boolean {\n const lower = name.toLowerCase();\n return TEXT_ATTACHMENT_EXTENSIONS.some((ext) => lower.endsWith(ext));\n}\n\n/**\n * The dialog holds attachments as `readAsDataURL` output. Back to text, UTF-8,\n * so an HTML mockup with \"—\" or Marathi in it reaches the model intact. Null on\n * anything that is not a data URL — never throws.\n */\nexport function decodeTextDataUrl(dataUrl: string): string | null {\n try {\n if (!dataUrl.startsWith(\"data:\")) return null;\n const comma = dataUrl.indexOf(\",\");\n if (comma < 0) return null;\n const meta = dataUrl.slice(5, comma);\n const payload = dataUrl.slice(comma + 1);\n if (!meta.endsWith(\";base64\")) return decodeURIComponent(payload);\n const binary = atob(payload);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder(\"utf-8\").decode(bytes);\n } catch {\n return null;\n }\n}\n","import type { DialogTile } from \"./types\";\n\n/**\n * The human name of a tile.\n *\n * Lives here rather than inside `report-dialog` because the AI sheet now shows\n * the same tiles as its first turn (#330 follow-up). Two copies of this list\n * would drift the moment a type is added, and the reporter would see one name\n * in the dialog and a different one in the chat.\n */\nexport function getTypeLabel(type: DialogTile): string {\n switch (type) {\n case \"RATING\":\n return \"Rating\";\n case \"BUG\":\n return \"Bug Report\";\n case \"FEATURE_REQUEST\":\n return \"Feature Request\";\n case \"UI_IMPROVEMENT\":\n return \"UI Improvement\";\n case \"PERFORMANCE\":\n return \"Performance\";\n case \"SECURITY\":\n return \"Security\";\n case \"QUESTION\":\n return \"Question\";\n case \"OTHER\":\n return \"Other\";\n }\n}\n","\"use client\";\n\nimport type { CSSProperties, ReactNode } from \"react\";\n\n/**\n * The markdown the assistant writes in a chat bubble, rendered as formatting\n * instead of literal `**` and `#`.\n *\n * Blocks: paragraphs, headings, bullet / numbered / task lists (nested),\n * > quotes, fenced code, tables, rules. Inline: bold, italic, ~~strike~~,\n * `code`, links, bare URLs, backslash escapes.\n *\n * Hand-rolled on purpose. This ships inside the SDK, whose only dependency\n * beyond React is html2canvas-pro, and a markdown library would be the largest\n * thing in the bundle to format a chat reply.\n *\n * Output is React elements, never HTML. The reply is model output built from\n * page content, attached files and project notes — all untrusted — so a string\n * reaching `innerHTML` is an injection path. Links are `http(s)` only, and an\n * image is shown as a link, never loaded: an `<img>` pointed anywhere by\n * injected text is a tracking pixel inside the host's page.\n *\n * Every block gets explicit inline styles, and headings are `div`s: the SDK\n * renders inside someone else's page, and their global `h2` / `ul` / `table`\n * CSS would otherwise restyle our bubble.\n *\n * No lookbehind in any pattern: Safari before 16.4 throws on it at parse time,\n * and a module that fails to load takes the host app with it.\n */\n\n/** The slice of `AssistTheme` this paints with — declared here, not imported, so\n * this module and assist-sheet do not import each other. */\ntype MdTheme = { accent: string; bg: string; border: string; textMuted: string };\n\n// ─── Inline ────────────────────────────────────────────────────────────────\n\nconst CODE = /`([^`\\n]+)`/y;\nconst MD_LINK = /\\[([^\\]\\n]*)\\]\\((https?:\\/\\/[^\\s)]+)\\)/y;\nconst BOLD_STAR = /\\*\\*(\\S(?:[^\\n]*?\\S)?)\\*\\*/y;\nconst BOLD_UNDER = /__(\\S(?:[^\\n]*?\\S)?)__/y;\nconst ITALIC_STAR = /\\*(\\S(?:[^*\\n]*?\\S)?)\\*/y;\nconst ITALIC_UNDER = /_(\\S(?:[^_\\n]*?\\S)?)_/y;\nconst STRIKE = /~~(\\S(?:[^\\n]*?\\S)?)~~/y;\nconst FULL_URL = /https?:\\/\\/[^\\s<>]+/y;\n// A bare domain only counts with a path — \"glitchgrab.dev/guides\" is a link,\n// \"sms.ts\" is a file name. Lowercase only, so \"Next.js/React\" stays prose.\nconst BARE_URL = /(?:[a-z0-9-]+\\.)+[a-z]{2,24}\\/[^\\s<>]*/y;\n\nconst WORD = /[A-Za-z0-9]/;\nconst URL_EDGE = /[A-Za-z0-9@./-]/;\nconst TRAILING_PUNCT = /[.,;:!?'\")\\]*_~]+$/;\nconst ESCAPABLE = \"\\\\`*_{}[]()#+-.!|~>\";\n\nconst MONO = \"ui-monospace, SFMono-Regular, Menlo, Consolas, monospace\";\n\nfunction at(re: RegExp, text: string, i: number): RegExpExecArray | null {\n re.lastIndex = i;\n return re.exec(text);\n}\n\nfunction isSafeHref(href: string): boolean {\n try {\n const { protocol } = new URL(href);\n return protocol === \"http:\" || protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\nfunction renderInline(text: string, theme: MdTheme, key: string): ReactNode[] {\n const out: ReactNode[] = [];\n let plain = \"\";\n let i = 0;\n\n const flush = () => {\n if (plain) out.push(plain);\n plain = \"\";\n };\n const link = (href: string, label: ReactNode, k: string) => (\n <a\n key={k}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer nofollow\"\n title={href}\n style={{\n color: \"inherit\",\n textDecoration: \"underline\",\n textDecorationColor: theme.accent,\n textUnderlineOffset: \"2px\",\n wordBreak: \"break-word\",\n }}\n >\n {label}\n </a>\n );\n\n while (i < text.length) {\n const ch = text[i];\n const prev = i > 0 ? text[i - 1] : \"\";\n const k = `${key}.${i}`;\n let m: RegExpExecArray | null;\n\n if (ch === \"\\\\\" && i + 1 < text.length && ESCAPABLE.includes(text[i + 1])) {\n plain += text[i + 1];\n i += 2;\n continue;\n }\n\n if (ch === \"`\" && (m = at(CODE, text, i))) {\n flush();\n out.push(\n <code\n key={k}\n style={{\n fontFamily: MONO,\n fontSize: \"0.92em\",\n padding: \"1px 4px\",\n borderRadius: \"4px\",\n backgroundColor: theme.bg,\n border: `1px solid ${theme.border}`,\n wordBreak: \"break-word\",\n }}\n >\n {m[1]}\n </code>\n );\n i += m[0].length;\n continue;\n }\n\n //  — shown as a link to the image, never loaded.\n const image = ch === \"!\" && text[i + 1] === \"[\";\n if ((ch === \"[\" || image) && (m = at(MD_LINK, text, image ? i + 1 : i)) && isSafeHref(m[2])) {\n flush();\n const label = m[1] ? renderInline(m[1], theme, k) : m[2];\n out.push(link(m[2], label, k));\n i += m[0].length + (image ? 1 : 0);\n continue;\n }\n\n if (ch === \"~\" && text[i + 1] === \"~\" && (m = at(STRIKE, text, i))) {\n flush();\n out.push(<del key={k}>{renderInline(m[1], theme, k)}</del>);\n i += m[0].length;\n continue;\n }\n\n if ((ch === \"*\" || ch === \"_\") && !WORD.test(prev)) {\n const double = text[i + 1] === ch;\n const bold = double ? at(ch === \"*\" ? BOLD_STAR : BOLD_UNDER, text, i) : null;\n const italic = bold ? null : at(ch === \"*\" ? ITALIC_STAR : ITALIC_UNDER, text, i);\n m = bold ?? italic;\n // `snake_case_name` and `2*3*4` are not emphasis: the closing mark must\n // not run straight into a word either.\n if (m && !WORD.test(text[i + m[0].length] ?? \"\")) {\n flush();\n const inner = renderInline(m[1], theme, k);\n out.push(\n bold ? (\n <strong key={k} style={{ fontWeight: 700 }}>\n {inner}\n </strong>\n ) : (\n <em key={k} style={{ fontStyle: \"italic\" }}>\n {inner}\n </em>\n )\n );\n i += m[0].length;\n continue;\n }\n }\n\n if (!URL_EDGE.test(prev)) {\n m = ch === \"h\" ? at(FULL_URL, text, i) : null;\n const bare = m ? null : /[a-z0-9]/.test(ch) ? at(BARE_URL, text, i) : null;\n const raw = m?.[0] ?? bare?.[0];\n if (raw) {\n const shown = raw.replace(TRAILING_PUNCT, \"\");\n const href = m ? shown : `https://${shown}`;\n if (shown.includes(\"/\") && isSafeHref(href)) {\n flush();\n out.push(link(href, shown, k));\n i += shown.length;\n continue;\n }\n }\n }\n\n plain += ch;\n i += 1;\n }\n\n flush();\n return out;\n}\n\n// ─── Blocks ────────────────────────────────────────────────────────────────\n\nconst FENCE = /^\\s{0,3}(`{3,}|~{3,})/;\nconst HEADING = /^\\s{0,3}(#{1,6})\\s+(.+?)(?:\\s+#+)?\\s*$/;\nconst RULE = /^\\s{0,3}([-*_])(?:\\s*\\1){2,}\\s*$/;\nconst QUOTE = /^\\s{0,3}>\\s?(.*)$/;\nconst LIST_ITEM = /^(\\s*)([-*+]|\\d{1,9}[.)])\\s+(.*)$/;\nconst TABLE_SEP = /^\\s*\\|?\\s*:?-+:?\\s*(?:\\|\\s*:?-+:?\\s*)*\\|?\\s*$/;\nconst TASK = /^\\[([ xX])\\]\\s+(.*)$/;\n\nconst STACK: CSSProperties = {\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"6px\",\n minWidth: 0,\n};\n\n/** Splits a table row on unescaped pipes, dropping the outer ones. */\nfunction splitRow(line: string): string[] {\n let s = line.trim();\n if (s.startsWith(\"|\")) s = s.slice(1);\n if (s.endsWith(\"|\") && !s.endsWith(\"\\\\|\")) s = s.slice(0, -1);\n const cells: string[] = [];\n let cell = \"\";\n for (let i = 0; i < s.length; i++) {\n if (s[i] === \"\\\\\" && s[i + 1] === \"|\") {\n cell += \"|\";\n i++;\n } else if (s[i] === \"|\") {\n cells.push(cell.trim());\n cell = \"\";\n } else {\n cell += s[i];\n }\n }\n cells.push(cell.trim());\n return cells;\n}\n\nfunction tableAt(lines: string[], i: number): string[] | null {\n const head = lines[i];\n const sep = lines[i + 1];\n if (!head?.includes(\"|\") || !sep?.includes(\"|\") || !TABLE_SEP.test(sep)) return null;\n const aligns = splitRow(sep);\n return aligns.length === splitRow(head).length ? aligns : null;\n}\n\nfunction startsBlock(lines: string[], i: number): boolean {\n const line = lines[i];\n return (\n FENCE.test(line) ||\n HEADING.test(line) ||\n RULE.test(line) ||\n QUOTE.test(line) ||\n LIST_ITEM.test(line) ||\n tableAt(lines, i) !== null\n );\n}\n\nfunction renderBlocks(lines: string[], theme: MdTheme, key: string): ReactNode[] {\n const out: ReactNode[] = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n const k = `${key}-${i}`;\n let m: RegExpExecArray | null;\n\n if (!line.trim()) {\n i++;\n continue;\n }\n\n if ((m = FENCE.exec(line))) {\n const fence = m[1];\n const body: string[] = [];\n i++;\n while (i < lines.length) {\n const t = lines[i].trim();\n if (t.length >= fence.length && [...t].every((c) => c === fence[0])) break;\n body.push(lines[i]);\n i++;\n }\n i++; // the closing fence, or past the end when the model never closed it\n out.push(\n <pre\n key={k}\n style={{\n margin: 0,\n padding: \"8px 10px\",\n borderRadius: \"6px\",\n backgroundColor: theme.bg,\n border: `1px solid ${theme.border}`,\n overflowX: \"auto\",\n maxWidth: \"100%\",\n fontFamily: MONO,\n fontSize: \"12px\",\n lineHeight: 1.5,\n whiteSpace: \"pre\",\n }}\n >\n <code style={{ fontFamily: \"inherit\" }}>{body.join(\"\\n\")}</code>\n </pre>\n );\n continue;\n }\n\n if ((m = HEADING.exec(line))) {\n const level = m[1].length;\n out.push(\n <div\n key={k}\n role=\"heading\"\n aria-level={level}\n style={{\n fontWeight: 700,\n fontSize: level === 1 ? \"1.15em\" : level === 2 ? \"1.08em\" : \"1em\",\n lineHeight: 1.35,\n }}\n >\n {renderInline(m[2], theme, k)}\n </div>\n );\n i++;\n continue;\n }\n\n if (RULE.test(line)) {\n out.push(<div key={k} role=\"separator\" style={{ borderTop: `1px solid ${theme.border}` }} />);\n i++;\n continue;\n }\n\n if (QUOTE.test(line)) {\n const inner: string[] = [];\n while (i < lines.length && (m = QUOTE.exec(lines[i]))) {\n inner.push(m[1]);\n i++;\n }\n out.push(\n <blockquote\n key={k}\n style={{\n ...STACK,\n margin: 0,\n paddingLeft: \"10px\",\n // `border` is near the bubble's own colour; the bar vanished.\n borderLeft: `3px solid ${theme.accent}66`,\n color: theme.textMuted,\n }}\n >\n {renderBlocks(inner, theme, k)}\n </blockquote>\n );\n continue;\n }\n\n const aligns = tableAt(lines, i);\n if (aligns) {\n const head = splitRow(line);\n const rows: string[][] = [];\n i += 2;\n while (i < lines.length && lines[i].trim() && lines[i].includes(\"|\")) {\n rows.push(splitRow(lines[i]));\n i++;\n }\n const align = (c: number): CSSProperties[\"textAlign\"] => {\n const a = aligns[c] ?? \"\";\n if (a.startsWith(\":\") && a.endsWith(\":\")) return \"center\";\n return a.endsWith(\":\") ? \"right\" : \"left\";\n };\n const cell = (c: number): CSSProperties => ({\n border: `1px solid ${theme.border}`,\n padding: \"4px 8px\",\n textAlign: align(c),\n verticalAlign: \"top\",\n });\n out.push(\n <div key={k} style={{ overflowX: \"auto\", maxWidth: \"100%\" }}>\n <table style={{ borderCollapse: \"collapse\", fontSize: \"12px\", margin: 0 }}>\n <thead>\n <tr>\n {head.map((h, c) => (\n <th key={c} style={{ ...cell(c), fontWeight: 600, backgroundColor: theme.bg }}>\n {renderInline(h, theme, `${k}h${c}`)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.map((row, r) => (\n <tr key={r}>\n {head.map((_, c) => (\n <td key={c} style={cell(c)}>\n {renderInline(row[c] ?? \"\", theme, `${k}r${r}c${c}`)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n continue;\n }\n\n if ((m = LIST_ITEM.exec(line))) {\n const baseIndent = m[1].length;\n const ordered = /\\d/.test(m[2]);\n const start = ordered ? parseInt(m[2], 10) : 1;\n const items: string[][] = [];\n\n while (i < lines.length) {\n const l = lines[i];\n const lm = LIST_ITEM.exec(l);\n const indent = l.length - l.trimStart().length;\n if (lm && indent <= baseIndent + 1) {\n if (/\\d/.test(lm[2]) !== ordered) break;\n items.push([lm[3]]);\n i++;\n continue;\n }\n const current = items[items.length - 1];\n if (!l.trim()) {\n // A blank line ends the list unless more of it follows.\n const next = lines[i + 1];\n const nextIndent = next ? next.length - next.trimStart().length : 0;\n if (next?.trim() && (nextIndent > baseIndent + 1 || LIST_ITEM.test(next))) {\n current.push(\"\");\n i++;\n continue;\n }\n break;\n }\n if (indent > baseIndent + 1) {\n // Content indent: strip what belongs to this list's own marker, so a\n // nested list comes out at the left edge of the item.\n current.push(l.slice(Math.min(indent, baseIndent + 2)));\n i++;\n continue;\n }\n break;\n }\n\n const ListTag = ordered ? \"ol\" : \"ul\";\n out.push(\n <ListTag\n key={k}\n start={ordered && start !== 1 ? start : undefined}\n style={{\n margin: 0,\n paddingLeft: \"20px\",\n listStyleType: ordered ? \"decimal\" : \"disc\",\n listStylePosition: \"outside\",\n }}\n >\n {items.map((itemLines, n) => {\n const ik = `${k}i${n}`;\n const task = TASK.exec(itemLines[0]);\n const body = task ? [task[2], ...itemLines.slice(1)] : itemLines;\n const box = task ? (\n <span aria-hidden=\"true\" style={{ marginRight: \"6px\" }}>\n {task[1] === \" \" ? \"☐\" : \"☑\"}\n </span>\n ) : null;\n const simple = body.filter((x) => x.trim()).length === 1;\n return (\n <li\n key={ik}\n style={{\n display: \"list-item\",\n marginTop: n ? \"3px\" : 0,\n paddingLeft: \"2px\",\n listStyleType: task ? \"none\" : undefined,\n }}\n >\n {simple ? (\n <>\n {box}\n {renderInline(body[0], theme, ik)}\n </>\n ) : (\n <div style={STACK}>\n {box ? (\n <div>\n {box}\n {renderInline(body[0], theme, ik)}\n </div>\n ) : null}\n {renderBlocks(box ? body.slice(1) : body, theme, ik)}\n </div>\n )}\n </li>\n );\n })}\n </ListTag>\n );\n continue;\n }\n\n // Paragraph: runs until a blank line or the start of another block. A\n // single line break stays a line break — this is chat, not a document.\n const para: string[] = [];\n while (i < lines.length && lines[i].trim() && !(para.length && startsBlock(lines, i))) {\n para.push(lines[i].trim());\n i++;\n }\n out.push(\n <div key={k}>\n {para.flatMap((p, n) => {\n const inline = renderInline(p, theme, `${k}p${n}`);\n return n ? [<br key={`${k}br${n}`} />, ...inline] : inline;\n })}\n </div>\n );\n }\n\n return out;\n}\n\nexport function ChatMarkdown({ text, theme }: { text: string; theme: MdTheme }) {\n return <div style={STACK}>{renderBlocks(text.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\"), theme, \"md\")}</div>;\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { AssistTheme } from \"./assist-sheet\";\nimport { encodeImageFile } from \"./image-encode\";\nimport type { GlitchgrabProblemFn } from \"./types\";\n\n/**\n * \"Problem with Glitchgrab?\" (#366).\n *\n * Someone reporting a bug in a customer's app hits a problem with the reporter\n * itself — the assistant loops, a button does nothing. That report belongs to\n * Glitchgrab, not to the project behind the dialog, so it gets its own small\n * layer on top of everything with its own send, instead of hijacking the\n * dialog's one submit path. The report underneath is never touched: closing\n * this panel lands them exactly where they were.\n */\n\nconst FONT = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif';\nconst FAILED = \"Couldn't send it. Try again in a moment.\";\n\n/** The server keeps the first 5 (`lib/glitchgrab-self-report.ts`); past that the button hides. */\nexport const MAX_SELF_REPORT_IMAGES = 5;\n\ninterface GlitchgrabProblemPanelProps {\n send: GlitchgrabProblemFn;\n theme: AssistTheme;\n surface: \"form\" | \"assist\";\n conversationId: string | null;\n reportType: string;\n /**\n * The report's images — what the panel starts with. Adding or removing one in\n * the panel changes only what goes to Glitchgrab, never the report underneath.\n */\n screenshots: string[];\n /** Opening text — the reporter's own chat words when the assistant offered this. */\n initialText?: string;\n onClose: () => void;\n}\n\n/**\n * \"your AI chat, what you did on this page and 2 screenshots\".\n *\n * Said before Send because none of it is the reporter's to give away silently:\n * it is their session on someone else's product, leaving that product.\n */\nexport function describeSentAlong(hasChat: boolean, screenshotCount: number): string {\n const parts = [\n ...(hasChat ? [\"your AI chat\"] : []),\n \"what you did on this page\",\n ...(screenshotCount > 0\n ? [`${screenshotCount} screenshot${screenshotCount === 1 ? \"\" : \"s\"}`]\n : []),\n ];\n if (parts.length === 1) return parts[0];\n return `${parts.slice(0, -1).join(\", \")} and ${parts[parts.length - 1]}`;\n}\n\nexport function GlitchgrabProblemPanel({\n send,\n theme: t,\n surface,\n conversationId,\n reportType,\n screenshots,\n initialText = \"\",\n onClose,\n}: GlitchgrabProblemPanelProps) {\n const [text, setText] = useState(initialText);\n const [busy, setBusy] = useState(false);\n const [sent, setSent] = useState(false);\n const [error, setError] = useState<string | null>(null);\n // The panel's own copy. #375: a reporter showing us the problem had no way to\n // add the screenshot of it — the report's images went along unseen.\n const [images, setImages] = useState<string[]>(() =>\n screenshots.slice(0, MAX_SELF_REPORT_IMAGES),\n );\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const fileRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n inputRef.current?.focus();\n }, []);\n\n // Same budget as the dialog's own attachments: a retina paste alone can be\n // over the request-body limit.\n const addImages = useCallback((files: File[]) => {\n const picked = files.filter((file) => file.type.startsWith(\"image/\"));\n if (!picked.length) return;\n void Promise.all(picked.map((file) => encodeImageFile(file).catch(() => null))).then(\n (encoded) => {\n const added = encoded.filter((url): url is string => !!url);\n if (added.length) {\n setImages((prev) => [...prev, ...added].slice(0, MAX_SELF_REPORT_IMAGES));\n }\n },\n );\n }, []);\n\n // A pasted image belongs to this panel. Window + capture runs before the\n // dialog's own paste handler on window; without stopping it there the image\n // lands on the report underneath, where the reporter never sees it arrive.\n // Immediate, not plain stopPropagation: an event targeted at window itself\n // still runs every other window listener after a plain stop.\n useEffect(() => {\n const onPaste = (e: ClipboardEvent) => {\n try {\n const items = e.clipboardData?.items;\n if (!items) return;\n const files: File[] = [];\n for (let i = 0; i < items.length; i++) {\n if (items[i].kind !== \"file\") continue;\n const file = items[i].getAsFile();\n if (file) files.push(file);\n }\n if (!files.length) return;\n e.preventDefault();\n e.stopImmediatePropagation();\n addImages(files);\n } catch {\n // An unreadable clipboard is just a paste that did nothing.\n }\n };\n window.addEventListener(\"paste\", onPaste, true);\n return () => window.removeEventListener(\"paste\", onPaste, true);\n }, [addImages]);\n\n // Escape closes this layer and nothing else. Window + capture runs before the\n // dialog's own Escape handler on document; stopping it here keeps the report\n // underneath open — closing that would throw away the very draft this panel\n // promises to leave alone.\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n e.stopPropagation();\n onClose();\n };\n window.addEventListener(\"keydown\", onKey, true);\n return () => window.removeEventListener(\"keydown\", onKey, true);\n }, [onClose]);\n\n const submit = async () => {\n const description = text.trim();\n if (!description || busy) return;\n setBusy(true);\n setError(null);\n try {\n const result = await send({\n description,\n surface,\n conversationId,\n reportType,\n screenshots: images,\n });\n if (result?.success) setSent(true);\n else setError(result?.message || FAILED);\n } catch {\n setError(FAILED);\n } finally {\n setBusy(false);\n }\n };\n\n const canSend = !!text.trim() && !busy;\n\n const secondaryButton = {\n padding: \"10px 14px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.text,\n fontSize: \"13px\",\n fontWeight: 600,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n } as const;\n\n const primaryButton = (enabled: boolean) =>\n ({\n padding: \"10px 14px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor: enabled ? t.accent : t.bgSecondary,\n color: enabled ? t.accentText : t.textMuted,\n fontSize: \"13px\",\n fontWeight: 700,\n fontFamily: \"inherit\",\n cursor: enabled ? \"pointer\" : \"default\",\n }) as const;\n\n return createPortal(\n // No close on backdrop click: a stray click would throw away what they typed.\n // `data-glitchgrab-layer` exempts this from the dialog's anti-focus-trap\n // sweep, which sets `inert` on every other role=\"dialog\" on the page —\n // without it the panel renders but cannot be typed into.\n <div\n data-glitchgrab-layer=\"\"\n data-gg-self-report-panel=\"\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"gg-self-report-title\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n backgroundColor: \"rgba(0,0,0,0.55)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n boxSizing: \"border-box\",\n fontFamily: FONT,\n }}\n >\n <div\n style={{\n width: \"100%\",\n maxWidth: \"420px\",\n boxSizing: \"border-box\",\n backgroundColor: t.bg,\n color: t.text,\n border: `1px solid ${t.border}`,\n borderRadius: \"12px\",\n boxShadow: \"0 20px 50px rgba(0,0,0,0.5)\",\n padding: \"18px\",\n }}\n >\n {sent ? (\n <>\n <div id=\"gg-self-report-title\" style={{ fontSize: \"15px\", fontWeight: 600 }}>\n Sent to the Glitchgrab team\n </div>\n <p style={{ margin: \"6px 0 16px\", fontSize: \"13px\", lineHeight: 1.5, color: t.textMuted }}>\n Thanks — we'll look into it. Your report is still open behind this, exactly as\n you left it.\n </p>\n <button\n type=\"button\"\n data-gg-self-report-done=\"\"\n onClick={onClose}\n style={{ ...primaryButton(true), width: \"100%\" }}\n >\n Back to your report\n </button>\n </>\n ) : (\n <>\n <div\n style={{\n display: \"flex\",\n alignItems: \"flex-start\",\n justifyContent: \"space-between\",\n gap: \"12px\",\n }}\n >\n <div id=\"gg-self-report-title\" style={{ fontSize: \"15px\", fontWeight: 600 }}>\n Problem with Glitchgrab?\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n style={{\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"18px\",\n lineHeight: 1,\n cursor: \"pointer\",\n padding: \"4px 6px\",\n margin: \"-4px -6px 0 0\",\n }}\n >\n ×\n </button>\n </div>\n <p style={{ margin: \"6px 0 12px\", fontSize: \"13px\", lineHeight: 1.5, color: t.textMuted }}>\n This goes to the people who build this reporter — not to this project's team.\n Tell us what went wrong: the AI chat, a button, anything.\n </p>\n\n <textarea\n ref={inputRef}\n data-gg-self-report-input=\"\"\n value={text}\n onChange={(e) => {\n setText(e.target.value);\n if (error) setError(null);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n void submit();\n }\n }}\n rows={4}\n placeholder=\"e.g. The assistant kept asking the same question and never wrote a draft\"\n style={{\n width: \"100%\",\n boxSizing: \"border-box\",\n resize: \"vertical\",\n padding: \"10px 12px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n backgroundColor: t.inputBg,\n color: t.text,\n fontSize: \"14px\",\n lineHeight: 1.45,\n fontFamily: \"inherit\",\n outline: \"none\",\n }}\n />\n\n <div\n data-gg-self-report-images=\"\"\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n alignItems: \"center\",\n gap: \"8px\",\n marginTop: \"10px\",\n }}\n >\n {images.map((src, i) => (\n <div key={i} style={{ position: \"relative\", width: \"48px\", height: \"48px\" }}>\n <img\n src={src}\n alt={`Screenshot ${i + 1}`}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n display: \"block\",\n boxSizing: \"border-box\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n }}\n />\n <button\n type=\"button\"\n data-gg-self-report-remove-image=\"\"\n aria-label={`Remove screenshot ${i + 1}`}\n title=\"Don't send this one\"\n onClick={() => setImages((prev) => prev.filter((_, j) => j !== i))}\n style={{\n position: \"absolute\",\n top: \"-13px\",\n right: \"-13px\",\n width: \"32px\",\n height: \"32px\",\n border: \"none\",\n background: \"transparent\",\n padding: 0,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"50%\",\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: \"20px\",\n height: \"20px\",\n boxSizing: \"border-box\",\n borderRadius: \"50%\",\n border: `2px solid ${t.bg}`,\n background: \"#ef4444\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path\n d=\"M1 1L9 9M9 1L1 9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n </button>\n </div>\n ))}\n {images.length < MAX_SELF_REPORT_IMAGES && (\n <button\n type=\"button\"\n data-gg-self-report-attach=\"\"\n aria-label=\"Add screenshot\"\n title=\"Add a screenshot — or paste one\"\n onClick={() => fileRef.current?.click()}\n style={{\n height: \"48px\",\n padding: \"0 12px\",\n boxSizing: \"border-box\",\n borderRadius: \"8px\",\n border: `1px dashed ${t.inputBorder}`,\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"12.5px\",\n fontWeight: 600,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n >\n {/* Short once thumbnails fill the row, or on a phone it wraps\n onto a line of its own. */}\n {images.length >= 3 ? \"+ Add\" : \"+ Add screenshot\"}\n </button>\n )}\n <input\n ref={fileRef}\n type=\"file\"\n accept=\"image/*\"\n multiple\n data-gg-self-report-file=\"\"\n onChange={(e) => {\n addImages(Array.from(e.target.files ?? []));\n // The same file twice in a row fires no change unless cleared.\n e.target.value = \"\";\n }}\n style={{ display: \"none\" }}\n />\n </div>\n\n <p\n data-gg-self-report-includes=\"\"\n style={{ margin: \"8px 0 0\", fontSize: \"11.5px\", lineHeight: 1.45, color: t.textMuted }}\n >\n Also sent, so we can see what happened:{\" \"}\n {describeSentAlong(conversationId !== null, images.length)}.\n </p>\n {error && (\n <p role=\"alert\" style={{ margin: \"8px 0 0\", fontSize: \"12px\", color: \"#ef4444\" }}>\n {error}\n </p>\n )}\n\n <div style={{ display: \"flex\", justifyContent: \"flex-end\", gap: \"8px\", marginTop: \"14px\" }}>\n <button type=\"button\" onClick={onClose} style={secondaryButton}>\n Cancel\n </button>\n <button\n type=\"button\"\n data-gg-self-report-send=\"\"\n onClick={() => void submit()}\n disabled={!canSend}\n style={primaryButton(canSend)}\n >\n {busy ? \"Sending…\" : \"Send to Glitchgrab\"}\n </button>\n </div>\n </>\n )}\n </div>\n </div>,\n document.body,\n );\n}\n","/**\n * The global keyboard shortcut that opens the Glitchgrab report dialog.\n * Single source of truth — the provider's keydown handler and every label\n * rendered anywhere (SDK dialog, host app UI) derive from this.\n */\n\n/** Server-safe label. Used during SSR and as the non-Mac label. */\nexport const GLITCHGRAB_SHORTCUT = \"Ctrl+Shift+G\";\n\n/** Mac label, using the platform's modifier glyphs. */\nexport const GLITCHGRAB_SHORTCUT_MAC = \"⌘⇧G\";\n\n/** True when running on a Mac-like platform. Always false on the server. */\nfunction isMac(): boolean {\n try {\n if (typeof navigator === \"undefined\") return false;\n return /Mac|iPhone|iPad|iPod/i.test(navigator.platform || navigator.userAgent);\n } catch {\n return false;\n }\n}\n\n/**\n * OS-aware label for the report-dialog shortcut — `⌘⇧G` on Mac,\n * `Ctrl+Shift+G` elsewhere. Returns the non-Mac label on the server, so\n * render it client-side (or after mount) to avoid a hydration mismatch.\n */\nexport function getShortcutLabel(): string {\n return isMac() ? GLITCHGRAB_SHORTCUT_MAC : GLITCHGRAB_SHORTCUT;\n}\n\n/** True when the keyboard event matches the report-dialog shortcut. */\nexport function matchesShortcut(e: KeyboardEvent): boolean {\n return (\n (e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === \"g\"\n );\n}\n","/**\n * Default screenshot capture for hosts that embed the dialog in the page being\n * reported (the SDK). Standalone hosts inject their own — see\n * `ReportDialogProps.captureScreenshot`.\n *\n * html2canvas does not photograph the page, it re-draws it from computed CSS,\n * and that re-draw drifts from what the reporter actually sees: in one\n * production report every border fell back to Tailwind's preflight\n * `border: 0 solid` (solid, currentColor), so a dark dashboard came out ringed\n * in white and a dashed box came out solid. A screenshot that disagrees with\n * the screen is worse than none — the developer ends up debugging the capture.\n *\n * So where the browser can hand over the tab's real pixels, take those, and\n * keep html2canvas as the fallback for everywhere it can't.\n */\n\nimport { encodeScreenshot } from \"./image-encode\";\n\n/** Capture at the display's own density, capped — beyond 2× the payload grows faster than the legibility. */\nconst MAX_SCALE = 2;\n\n/** A frame that never arrives must not hold the dialog closed. */\nconst FRAME_TIMEOUT_MS = 3000;\n\n/**\n * Ceiling on everything after the reporter clicked Allow. `waitForFrame` has\n * its own timeout but `video.play()` does not, and an await that never settles\n * never reaches the `finally` that stops the stream — the \"Sharing this tab\"\n * bar would then outlive the report (#364, not reproduced: a static page stops\n * in ~140ms in real Chromium). Bounded here so no await in the path can do it.\n */\nconst GRAB_TIMEOUT_MS = FRAME_TIMEOUT_MS + 2000;\n\n/**\n * Chromium-only members of the `getDisplayMedia` options. Not in lib.dom yet;\n * other engines ignore unknown keys, so passing them is harmless.\n */\ntype TabCaptureOptions = DisplayMediaStreamOptions & {\n preferCurrentTab?: boolean;\n selfBrowserSurface?: \"include\" | \"exclude\";\n surfaceSwitching?: \"include\" | \"exclude\";\n monitorTypeSurfaces?: \"include\" | \"exclude\";\n};\n\ntype FrameCallbackVideo = HTMLVideoElement & {\n requestVideoFrameCallback?: (callback: () => void) => number;\n};\n\n/**\n * Only Chromium offers \"this tab\" as a one-click Allow. Safari and Firefox\n * would open a full screen/window picker instead — a worse experience than the\n * re-draw, and one that invites sharing the whole desktop — so they go straight\n * to html2canvas. `CaptureController` ships only in Chromium, which makes it a\n * stand-in for \"honours preferCurrentTab\" without sniffing the user agent.\n */\nexport function canCaptureTabPixels(): boolean {\n try {\n return (\n typeof navigator !== \"undefined\" &&\n typeof navigator.mediaDevices?.getDisplayMedia === \"function\" &&\n typeof (globalThis as { CaptureController?: unknown }).CaptureController !== \"undefined\"\n );\n } catch {\n return false;\n }\n}\n\n/** `HTMLMediaElement.HAVE_CURRENT_DATA` — a frame is decoded and drawable. */\nconst HAVE_CURRENT_DATA = 2;\n\n/** Resolves true once a frame is decoded, false if none arrived in time. */\nfunction waitForFrame(video: FrameCallbackVideo): Promise<boolean> {\n // play() usually resolves with the first frame already decoded — use it.\n // Waiting for the *next* one stalls: tab capture only emits a frame when the\n // page repaints, so on a page that isn't moving it may never come (measured:\n // a static page sat out the full timeout at 1× and fell back every time).\n if (video.readyState >= HAVE_CURRENT_DATA && video.videoWidth > 0) {\n return Promise.resolve(true);\n }\n return new Promise((resolve) => {\n const timer = setTimeout(() => resolve(false), FRAME_TIMEOUT_MS);\n const done = () => {\n clearTimeout(timer);\n resolve(true);\n };\n if (typeof video.requestVideoFrameCallback === \"function\") {\n video.requestVideoFrameCallback(done);\n } else if (video.readyState >= 2) {\n done();\n } else {\n video.addEventListener(\"loadeddata\", done, { once: true });\n }\n });\n}\n\nasync function grabFrame(stream: MediaStream): Promise<HTMLCanvasElement | null> {\n const video = document.createElement(\"video\") as FrameCallbackVideo;\n video.muted = true;\n video.playsInline = true;\n video.srcObject = stream;\n try {\n await video.play();\n if (!(await waitForFrame(video))) return null;\n if (!video.videoWidth || !video.videoHeight) return null;\n\n const maxWidth = Math.max(1, window.innerWidth) * MAX_SCALE;\n const factor = Math.min(1, maxWidth / video.videoWidth);\n const canvas = document.createElement(\"canvas\");\n canvas.width = Math.round(video.videoWidth * factor);\n canvas.height = Math.round(video.videoHeight * factor);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n ctx.drawImage(video, 0, 0, canvas.width, canvas.height);\n return canvas;\n } finally {\n video.srcObject = null;\n }\n}\n\n/**\n * The tab's real pixels via `getDisplayMedia({ preferCurrentTab })`.\n *\n * Chrome asks \"Allow this site to see this tab?\" on every call — that prompt is\n * the price of an exact image. Must be called inside the click (or keypress)\n * that opened the dialog: the browser refuses without a user gesture, which is\n * why the dialog captures before its first await.\n *\n * Returns null — never throws — on a refusal, an unsupported browser, a\n * missing `display-capture` permission policy, or anything other than a tab.\n */\nexport async function captureViaTabPixels(): Promise<string | null> {\n if (!canCaptureTabPixels()) return null;\n\n let stream: MediaStream | null = null;\n try {\n const options: TabCaptureOptions = {\n video: { displaySurface: \"browser\" } as MediaTrackConstraints,\n audio: false,\n preferCurrentTab: true,\n selfBrowserSurface: \"include\",\n surfaceSwitching: \"exclude\",\n monitorTypeSurfaces: \"exclude\",\n };\n stream = await navigator.mediaDevices.getDisplayMedia(options);\n\n // The picker can still offer a window or a whole screen. This image goes to\n // the host app's issue tracker, so anything beyond the host's own tab —\n // another app, a password manager, a chat — must never be encoded.\n const surface = (\n stream.getVideoTracks()[0]?.getSettings() as { displaySurface?: string } | undefined\n )?.displaySurface;\n if (surface && surface !== \"browser\") return null;\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timedOut = new Promise<null>((resolve) => {\n timer = setTimeout(() => resolve(null), GRAB_TIMEOUT_MS);\n });\n const canvas = await Promise.race([grabFrame(stream), timedOut]).finally(() =>\n clearTimeout(timer)\n );\n return canvas ? encodeScreenshot(canvas) : null;\n } catch {\n return null;\n } finally {\n // Stop at once — the \"sharing this tab\" indicator should last as long as\n // one frame takes, not as long as the dialog stays open.\n stream?.getTracks().forEach((track) => track.stop());\n }\n}\n\n/**\n * Longest one image may hold up the re-draw. html2canvas waits 15s per image by\n * default, and `useCORS` re-fetches every cross-origin one — a list of avatars\n * on a slow line kept the capture running for most of a minute (#363). An image\n * that misses this is left out of the screenshot; the page around it is not.\n */\nconst IMAGE_TIMEOUT_MS = 3000;\n\n/**\n * Our own dialog, sheet and overlays. The SDK opens the dialog before the\n * re-draw finishes (#363), so without this the page shot would show the dialog\n * sitting on top of the page it is meant to be a picture of.\n */\nfunction isGlitchgrabLayer(el: Element): boolean {\n return el.hasAttribute(\"data-glitchgrab-layer\");\n}\n\n/** Re-draw the viewport from the DOM. Needs no permission; not always faithful. */\nexport async function captureViaHtml2Canvas(): Promise<string | null> {\n try {\n const { default: html2canvas } = await import(\"html2canvas-pro\");\n const scale = Math.min(Math.max(window.devicePixelRatio || 1, 1), MAX_SCALE);\n const canvas = await html2canvas(document.body, {\n scale,\n logging: false,\n useCORS: true,\n allowTaint: true,\n imageTimeout: IMAGE_TIMEOUT_MS,\n ignoreElements: isGlitchgrabLayer,\n x: window.scrollX,\n y: window.scrollY,\n width: window.innerWidth,\n height: window.innerHeight,\n windowWidth: window.innerWidth,\n windowHeight: window.innerHeight,\n });\n return encodeScreenshot(canvas);\n } catch {\n return null;\n }\n}\n\n/**\n * The capture already running, if any. One ⌘⇧G on an SDK page with the\n * extension installed opened the dialog twice — both keydown listeners fired —\n * and each open asked Chrome for the tab: two share prompts for one report\n * (#364). An open that arrives mid-capture gets the same image instead.\n */\nlet inFlight: Promise<string | null> | null = null;\n\nexport interface CaptureOptions {\n /**\n * Called the moment the capture falls back to the DOM re-draw — the point at\n * which the dialog can open (#363). Real pixels are taken before the dialog\n * is on screen, or the frame would show it; the re-draw leaves our own layers\n * out, so it doesn't have to wait. On a slow CPU and a long page the re-draw\n * took seconds, and the dialog used to stay closed for all of them.\n */\n onRedraw?: () => void;\n}\n\n/**\n * Resolves once the browser has painted, so a dialog opened in `onRedraw` is on\n * screen before html2canvas takes the main thread. Capped, because a hidden tab\n * never paints.\n */\nfunction nextPaint(): Promise<void> {\n return new Promise((resolve) => {\n const cap = setTimeout(resolve, 100);\n if (typeof requestAnimationFrame !== \"function\") return;\n requestAnimationFrame(() =>\n setTimeout(() => {\n clearTimeout(cap);\n resolve();\n }, 0)\n );\n });\n}\n\n/**\n * Real pixels first, the re-draw when those aren't available. A refused prompt\n * still yields a screenshot — the reporter said no to screen sharing, not to\n * filing the report.\n *\n * `getDisplayMedia` is still reached synchronously on a fresh call: the async\n * body runs up to its first await before this returns.\n */\nexport function captureDefaultScreenshot(options?: CaptureOptions): Promise<string | null> {\n if (inFlight) return inFlight;\n inFlight = (async () => {\n const pixels = await captureViaTabPixels();\n if (pixels) return pixels;\n if (options?.onRedraw) {\n try {\n options.onRedraw();\n } catch {\n // The caller's problem — the screenshot still gets taken.\n }\n await nextPaint();\n }\n return captureViaHtml2Canvas();\n })().finally(() => {\n inFlight = null;\n });\n return inFlight;\n}\n","import type { AssistTurnResult } from \"./types\";\n\n/**\n * Turning the `/api/v1/ai/report-chat` response into what the sheet renders —\n * one copy for every host.\n *\n * The SDK, the Chrome extension and GlitchRecord each mapped it by hand, and\n * GlitchRecord's copy kept only question/report: its sheet never got the\n * \"Yes, that's it\" chip, \"our team is already on #N\", or an answer from the\n * project's guides. A field added here reaches all three.\n *\n * React-free on purpose: GlitchRecord's Electron main process imports it.\n */\n\n/** Shown when the assistant cannot be reached — the plain form takes over. */\nexport const ASSIST_OFFLINE_MESSAGE =\n \"The assistant is unavailable — write your report below and send it as normal.\";\n\nexport function assistOffline(): AssistTurnResult {\n return { conversationId: null, question: null, report: null, degraded: ASSIST_OFFLINE_MESSAGE };\n}\n\ntype IssueRef = { number: number; title: string; url: string; status?: string };\n\ninterface ReportChatEnvelope {\n success?: boolean;\n error?: string;\n retryable?: boolean;\n data?: {\n conversationId?: string | null;\n question?: string | null;\n options?: unknown;\n report?: string | null;\n duplicate?: IssueRef | null;\n related?: IssueRef | null;\n solved?: string | null;\n aboutGlitchgrab?: boolean;\n };\n}\n\n/**\n * @param ok `response.ok`\n * @param body the parsed JSON body, or `null` when it was not JSON\n */\nexport function toAssistTurnResult(ok: boolean, body: unknown): AssistTurnResult {\n const envelope = (body ?? null) as ReportChatEnvelope | null;\n if (!ok || !envelope?.success) {\n return {\n ...assistOffline(),\n // The server words why (cap, rate limit, switched off). An hourly limit\n // keeps the assistant button for this report.\n degraded: envelope?.error ?? ASSIST_OFFLINE_MESSAGE,\n retryable: envelope?.retryable === true,\n };\n }\n const d = envelope.data ?? {};\n return {\n conversationId: d.conversationId ?? null,\n question: d.question ?? null,\n options: Array.isArray(d.options)\n ? d.options.filter((o): o is string => typeof o === \"string\")\n : [],\n report: d.report ?? null,\n duplicate: d.duplicate ?? null,\n related: d.related ?? null,\n solved: d.solved ?? null,\n aboutGlitchgrab: d.aboutGlitchgrab === true,\n degraded: null,\n };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\n\n/**\n * Demo booking, rendered inside the host app.\n *\n * The customer embeds Glitchgrab, and their visitors book a demo without ever\n * leaving the page — no redirect to a scheduling site, no separate brand in the\n * middle of a sales moment. The SDK token identifies the project, so the server\n * knows whose calendar to read and where to file the recording afterwards.\n *\n * Styled inline for the same reason the report dialog is: this renders inside\n * someone else's stylesheet and must not inherit from it or fight it.\n */\n\ninterface Slot {\n startsAt: string;\n endsAt: string;\n}\n\ntype Step = \"slots\" | \"details\" | \"code\" | \"done\";\n\nconst t = {\n bg: \"#141414\",\n surface: \"#1c1c1c\",\n border: \"#2a2a2a\",\n text: \"#e5e5e5\",\n muted: \"#9aa0a6\",\n accent: \"#3b82f6\",\n danger: \"#f87171\",\n};\n\n/** The visitor's own zone — a demo confirmed in the wrong one is the worst bug this can have. */\nfunction localZone(): string {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone;\n } catch {\n return \"UTC\";\n }\n}\n\nfunction dayKey(iso: string): string {\n return new Date(iso).toDateString();\n}\n\nfunction formatDay(iso: string): string {\n return new Date(iso).toLocaleDateString(undefined, {\n weekday: \"short\",\n day: \"numeric\",\n month: \"short\",\n });\n}\n\nfunction formatTime(iso: string): string {\n return new Date(iso).toLocaleTimeString(undefined, { hour: \"2-digit\", minute: \"2-digit\" });\n}\n\nexport function BookingDialog({\n token,\n baseUrl,\n open,\n onClose,\n}: {\n token: string;\n baseUrl: string;\n open: boolean;\n onClose: () => void;\n}) {\n const [step, setStep] = useState<Step>(\"slots\");\n const [slots, setSlots] = useState<Slot[] | null>(null);\n const [heading, setHeading] = useState<{ title: string; description: string | null }>({\n title: \"Book a demo\",\n description: null,\n });\n /** Set when the project has a WhatsApp code — the second way in. */\n const [whatsappUrl, setWhatsappUrl] = useState<string | null>(null);\n const [selected, setSelected] = useState<Slot | null>(null);\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [note, setNote] = useState(\"\");\n const [code, setCode] = useState(\"\");\n const [bookingId, setBookingId] = useState<string | null>(null);\n const [meetUrl, setMeetUrl] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const headers = useMemo(\n () => ({ Authorization: `Bearer ${token}`, \"Content-Type\": \"application/json\" }),\n [token]\n );\n\n const loadSlots = useCallback(async () => {\n setError(null);\n setSlots(null);\n try {\n const from = new Date().toISOString();\n const to = new Date(Date.now() + 21 * 86400_000).toISOString();\n const res = await fetch(\n `${baseUrl}/api/v1/sdk/booking/availability?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`,\n { headers }\n );\n const json = await res.json();\n if (!json.success) {\n setError(json.error ?? \"Couldn't load available times\");\n setSlots([]);\n return;\n }\n setSlots(json.data.slots ?? []);\n setHeading({ title: json.data.title, description: json.data.description });\n setWhatsappUrl(json.data.whatsappUrl ?? null);\n } catch {\n setError(\"Couldn't reach the booking service\");\n setSlots([]);\n }\n }, [baseUrl, headers]);\n\n useEffect(() => {\n if (!open) return;\n // Reset every open: a dialog that reopens showing last week's chosen slot\n // and a half-filled form is worse than one that starts clean.\n setStep(\"slots\");\n setSelected(null);\n setCode(\"\");\n setBookingId(null);\n setError(null);\n void loadSlots();\n }, [open, loadSlots]);\n\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", onKey, true);\n return () => document.removeEventListener(\"keydown\", onKey, true);\n }, [open, onClose]);\n\n if (!open) return null;\n\n const byDay = new Map<string, Slot[]>();\n for (const slot of slots ?? []) {\n const key = dayKey(slot.startsAt);\n byDay.set(key, [...(byDay.get(key) ?? []), slot]);\n }\n\n async function startBooking() {\n if (!selected) return;\n setBusy(true);\n setError(null);\n try {\n const res = await fetch(`${baseUrl}/api/v1/sdk/booking`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n name,\n email,\n phone,\n note,\n startsAt: selected.startsAt,\n timezone: localZone(),\n }),\n });\n const json = await res.json();\n if (!json.success) {\n setError(json.error ?? \"Couldn't hold that slot\");\n return;\n }\n setBookingId(json.data.bookingId);\n setStep(\"code\");\n } catch {\n setError(\"Couldn't reach the booking service\");\n } finally {\n setBusy(false);\n }\n }\n\n async function confirmBooking() {\n if (!bookingId) return;\n setBusy(true);\n setError(null);\n try {\n const res = await fetch(`${baseUrl}/api/v1/sdk/booking/verify`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ bookingId, code }),\n });\n const json = await res.json();\n if (!json.success) {\n setError(json.error ?? \"Couldn't confirm that code\");\n return;\n }\n setMeetUrl(json.data.meetUrl);\n setStep(\"done\");\n } catch {\n setError(\"Couldn't reach the booking service\");\n } finally {\n setBusy(false);\n }\n }\n\n const canSubmitDetails = name.trim() && email.includes(\"@\") && phone.replace(/\\D/g, \"\").length >= 8;\n\n return (\n <div\n onClick={(e) => {\n if (e.target === e.currentTarget) onClose();\n }}\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483000,\n background: \"rgba(0,0,0,.6)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 16,\n fontFamily: \"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n }}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={heading.title}\n style={{\n width: \"min(440px, 100%)\",\n maxHeight: \"min(660px, 90vh)\",\n display: \"flex\",\n flexDirection: \"column\",\n background: t.bg,\n color: t.text,\n borderRadius: 16,\n boxShadow: \"0 20px 60px rgba(0,0,0,.55)\",\n overflow: \"hidden\",\n }}\n >\n <div\n style={{\n padding: \"16px 18px\",\n borderBottom: `1px solid ${t.border}`,\n display: \"flex\",\n alignItems: \"flex-start\",\n justifyContent: \"space-between\",\n gap: 12,\n }}\n >\n <div>\n <div style={{ fontSize: 15, fontWeight: 600 }}>{heading.title}</div>\n {heading.description && (\n <div style={{ fontSize: 12, color: t.muted, marginTop: 2 }}>{heading.description}</div>\n )}\n </div>\n <button\n onClick={onClose}\n aria-label=\"Close\"\n style={{ border: 0, background: \"transparent\", color: t.muted, fontSize: 20, cursor: \"pointer\", lineHeight: 1 }}\n >\n ×\n </button>\n </div>\n\n <div style={{ padding: 18, overflowY: \"auto\", flex: \"1 1 auto\" }}>\n {error && (\n <div style={{ color: t.danger, fontSize: 12, marginBottom: 12, lineHeight: 1.5 }}>{error}</div>\n )}\n\n {step === \"slots\" && (\n <>\n {whatsappUrl && (\n <a\n href={whatsappUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n style={{\n display: \"block\",\n marginBottom: 16,\n padding: \"10px 14px\",\n borderRadius: 10,\n border: `1px solid ${t.border}`,\n background: t.surface,\n color: t.text,\n fontSize: 13,\n textDecoration: \"none\",\n }}\n >\n 💬 Rather book on WhatsApp?\n <span style={{ display: \"block\", fontSize: 11, color: t.muted, marginTop: 2 }}>\n We'll ask the same questions in chat.\n </span>\n </a>\n )}\n {slots === null && <div style={{ color: t.muted, fontSize: 13 }}>Finding times…</div>}\n {slots?.length === 0 && !error && (\n <div style={{ color: t.muted, fontSize: 13 }}>No times available right now.</div>\n )}\n {[...byDay.entries()].map(([day, daySlots]) => (\n <div key={day} style={{ marginBottom: 18 }}>\n <div style={{ fontSize: 11, color: t.muted, marginBottom: 8, textTransform: \"uppercase\", letterSpacing: \".6px\" }}>\n {formatDay(daySlots[0].startsAt)}\n </div>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 8 }}>\n {daySlots.map((slot) => (\n <button\n key={slot.startsAt}\n onClick={() => {\n setSelected(slot);\n setStep(\"details\");\n }}\n style={{\n padding: \"8px 14px\",\n borderRadius: 999,\n border: `1px solid ${t.border}`,\n background: t.surface,\n color: t.text,\n fontSize: 13,\n cursor: \"pointer\",\n }}\n >\n {formatTime(slot.startsAt)}\n </button>\n ))}\n </div>\n </div>\n ))}\n </>\n )}\n\n {step === \"details\" && selected && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 10 }}>\n <div style={{ fontSize: 13, color: t.muted }}>\n {formatDay(selected.startsAt)} · {formatTime(selected.startsAt)}\n {\" · \"}\n <button\n onClick={() => setStep(\"slots\")}\n style={{ border: 0, background: \"transparent\", color: t.accent, cursor: \"pointer\", fontSize: 13, padding: 0 }}\n >\n change\n </button>\n </div>\n <Field label=\"Your name\" value={name} onChange={setName} />\n <Field label=\"Email\" value={email} onChange={setEmail} type=\"email\" />\n <Field\n label=\"Mobile number\"\n value={phone}\n onChange={setPhone}\n type=\"tel\"\n hint=\"We send a code here to confirm, then a reminder before the call.\"\n />\n <Field label=\"Anything we should know? (optional)\" value={note} onChange={setNote} />\n <button\n onClick={startBooking}\n disabled={!canSubmitDetails || busy}\n style={primaryStyle(!canSubmitDetails || busy)}\n >\n {busy ? \"Sending code…\" : \"Send verification code\"}\n </button>\n </div>\n )}\n\n {step === \"code\" && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 10 }}>\n <div style={{ fontSize: 13, color: t.muted, lineHeight: 1.5 }}>\n We sent a 4-digit code to your phone. Your slot is held for 10 minutes.\n </div>\n <Field label=\"Code\" value={code} onChange={setCode} />\n <button\n onClick={confirmBooking}\n disabled={code.trim().length < 4 || busy}\n style={primaryStyle(code.trim().length < 4 || busy)}\n >\n {busy ? \"Confirming…\" : \"Confirm booking\"}\n </button>\n </div>\n )}\n\n {step === \"done\" && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 10 }}>\n <div style={{ fontSize: 15, fontWeight: 600 }}>You're booked.</div>\n <div style={{ fontSize: 13, color: t.muted, lineHeight: 1.6 }}>\n {selected && `${formatDay(selected.startsAt)} at ${formatTime(selected.startsAt)}. `}\n A calendar invite is on its way to {email}, and we'll send a WhatsApp reminder\n before the call.\n </div>\n {meetUrl && (\n <a href={meetUrl} target=\"_blank\" rel=\"noreferrer\" style={{ ...primaryStyle(false), textAlign: \"center\", textDecoration: \"none\" }}>\n Open the meeting link\n </a>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nfunction primaryStyle(disabled: boolean) {\n return {\n marginTop: 4,\n padding: \"10px 16px\",\n borderRadius: 999,\n border: 0,\n background: disabled ? \"#2a2a2a\" : t.accent,\n color: disabled ? \"#6b7280\" : \"#fff\",\n fontSize: 14,\n fontWeight: 500,\n cursor: disabled ? \"default\" : \"pointer\",\n } as const;\n}\n\nfunction Field({\n label,\n value,\n onChange,\n type = \"text\",\n hint,\n}: {\n label: string;\n value: string;\n onChange: (v: string) => void;\n type?: string;\n hint?: string;\n}) {\n return (\n <label style={{ display: \"block\", fontSize: 11, color: t.muted }}>\n {label}\n <input\n type={type}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n style={{\n display: \"block\",\n width: \"100%\",\n boxSizing: \"border-box\",\n marginTop: 4,\n padding: \"9px 12px\",\n background: t.surface,\n color: t.text,\n border: `1px solid ${t.border}`,\n borderRadius: 8,\n fontSize: 13,\n outline: \"none\",\n }}\n />\n {hint && <div style={{ marginTop: 4, fontSize: 10, color: t.muted }}>{hint}</div>}\n </label>\n );\n}\n","/**\n * Unhandled rejection reasons are not always `Error` instances. A rejection with\n * a plain object reason used to stringify to `\"[object Object]\"` — a title and a\n * body with no message, no stack and nothing to triage.\n *\n * `describeRejection` extracts the most useful *stable* message it can, plus the\n * `.stack` when one exists (cross-realm errors from extensions and iframes fail\n * `instanceof Error` but still carry a usable stack), plus a serialized dump of\n * the whole reason for the report metadata.\n */\n\n/** Max length of the serialized reason stored in report metadata. */\nconst DETAILS_MAX_LENGTH = 1000;\n\n/** Max length of a message rung promoted into `errorMessage`. */\nconst MESSAGE_MAX_LENGTH = 200;\n\nexport interface RejectionDescription {\n /** Short, stable message — safe to hash for dedup and to slice into an issue title. */\n message: string;\n /** Stack trace when the reason carries one, regardless of `instanceof Error`. */\n stack?: string;\n /** Full serialized reason for `metadata.rejectionReason`. Empty when unavailable. */\n details?: string;\n}\n\n/** A rejection with neither a message nor a stack cannot be triaged by anyone. */\nexport function isUnactionableRejection(description: RejectionDescription): boolean {\n if (description.stack) return false;\n const message = description.message.trim();\n return message === \"\" || message === \"[object Object]\";\n}\n\nfunction readString(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n if (trimmed === \"\" || trimmed === \"[object Object]\") return undefined;\n return trimmed.slice(0, MESSAGE_MAX_LENGTH);\n}\n\n/** `.code`/`.status` are often numbers — accept those, but never objects. */\nfunction readScalar(value: unknown): string | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) return String(value);\n return readString(value);\n}\n\nfunction readStack(reason: unknown): string | undefined {\n try {\n const stack = (reason as { stack?: unknown } | null)?.stack;\n return typeof stack === \"string\" && stack.trim() !== \"\" ? stack : undefined;\n } catch {\n // Getters can throw — a missing stack is better than a crash.\n return undefined;\n }\n}\n\n/** `JSON.stringify` throws on circular refs and BigInt, and on throwing getters. */\nfunction serialize(reason: unknown): string | undefined {\n try {\n const seen = new WeakSet<object>();\n const json = JSON.stringify(reason, (_key, value) => {\n if (typeof value === \"bigint\") return `${value}n`;\n if (typeof value === \"object\" && value !== null) {\n if (seen.has(value)) return \"[Circular]\";\n seen.add(value);\n }\n return value;\n });\n if (!json || json === \"{}\" || json === \"null\") return undefined;\n return json.slice(0, DETAILS_MAX_LENGTH);\n } catch {\n return undefined;\n }\n}\n\n/** Max own keys listed when falling back to a shape description. */\nconst SHAPE_MAX_KEYS = 5;\n\n/**\n * Last resort when no stable field exists: name the reason's keys, not its values.\n * Stable across occurrences, so the dedup signature still collapses repeats.\n */\nfunction describeShape(reason: unknown): string {\n try {\n const keys = Object.keys(reason as object);\n if (keys.length === 0) return \"\";\n const listed = keys.slice(0, SHAPE_MAX_KEYS).join(\", \");\n const suffix = keys.length > SHAPE_MAX_KEYS ? \", …\" : \"\";\n return `Rejected object: ${listed}${suffix}`.slice(0, MESSAGE_MAX_LENGTH);\n } catch {\n return \"\";\n }\n}\n\n/** Max length of a resource URL appended to an event message. */\nconst EVENT_URL_MAX_LENGTH = 120;\n\n/**\n * Events cross realm boundaries (iframes, extensions) and fail `instanceof`,\n * and `Event` is undefined outside the DOM. Duck-type instead: every event\n * carries a string `type` and a boolean `isTrusted`.\n */\nfunction isEventLike(reason: unknown): boolean {\n try {\n if (typeof Event !== \"undefined\" && reason instanceof Event) return true;\n const source = reason as { type?: unknown; isTrusted?: unknown } | null;\n return typeof source?.type === \"string\" && typeof source?.isTrusted === \"boolean\";\n } catch {\n return false;\n }\n}\n\n/**\n * A promise rejected with a DOM Event — a script/img/media `onerror`, an\n * IndexedDB request, a third-party embed — carries no `.message` and no\n * `.stack`. Its only own key in Chrome is `isTrusted`, so the shape fallback\n * produced \"Rejected object: isTrusted\": a report naming nothing at all.\n *\n * The event's own `type` and `target` say which resource failed, so read those\n * instead. The URL is stripped of its query and hash — a cache-busting param\n * would otherwise give every occurrence a unique dedup signature.\n */\nfunction describeEvent(reason: unknown): string {\n const parts: string[] = [];\n\n try {\n const source = reason as { constructor?: { name?: string }; type?: unknown };\n const name = source.constructor?.name || \"Event\";\n parts.push(`${name} (\"${String(source.type ?? \"\")}\")`);\n } catch {\n parts.push(\"Event\");\n }\n\n try {\n const target = (reason as { target?: unknown }).target as\n | (Element & { src?: string; href?: string; currentSrc?: string })\n | null\n | undefined;\n const tag = target?.tagName?.toLowerCase();\n if (tag) parts.push(`from <${tag}>`);\n const url =\n readString(target?.currentSrc) ?? readString(target?.src) ?? readString(target?.href);\n if (url) parts.push(`— ${url.split(/[?#]/)[0].slice(0, EVENT_URL_MAX_LENGTH)}`);\n } catch {\n // Cross-origin or detached targets throw on access — the type alone still\n // beats a key list.\n }\n\n return parts.join(\" \").slice(0, MESSAGE_MAX_LENGTH);\n}\n\nexport function describeRejection(reason: unknown): RejectionDescription {\n try {\n if (reason instanceof Error) {\n return {\n message: reason.message || reason.name || \"\",\n stack: reason.stack,\n };\n }\n\n const stack = readStack(reason);\n\n if (typeof reason === \"string\") {\n return { message: readString(reason) ?? \"\", stack };\n }\n if (typeof reason === \"number\" || typeof reason === \"boolean\") {\n return { message: String(reason), stack };\n }\n if (reason === null || reason === undefined) {\n return { message: \"\" };\n }\n\n const source = reason as Record<string, unknown>;\n const nestedError = source.error;\n\n // Stable rungs first — these keep the dedup signature and the issue title\n // meaningful. A volatile JSON dump would defeat both.\n const message =\n readString(source.message) ??\n readString(nestedError) ??\n readString((nestedError as { message?: unknown } | null | undefined)?.message) ??\n readScalar(source.code) ??\n readString(source.name) ??\n readScalar(source.status) ??\n readString(source.statusText) ??\n \"\";\n\n const details = serialize(reason);\n\n // No stable rung — describe the reason by its key *shape*, never by its values.\n // `errorMessage` feeds computeSignature, so a message carrying volatile fields\n // (requestId, timestamps) would give every occurrence a unique signature and\n // defeat dedup entirely. The values still travel in `details`.\n //\n // An event is the one shapeless reason worth reporting: its type and target\n // name the failing resource, so it gets a real message and stays actionable.\n return {\n message:\n message || (isEventLike(reason) ? describeEvent(reason) : describeShape(reason)),\n stack,\n details,\n };\n } catch {\n // Never throw out of the SDK — an empty description is dropped upstream.\n return { message: \"\" };\n }\n}\n","/**\n * The global keyboard shortcut that opens the Glitchgrab report dialog.\n * Single source of truth — the provider's keydown handler and every label\n * rendered anywhere (SDK dialog, host app UI) derive from this.\n */\n\n/** Server-safe label. Used during SSR and as the non-Mac label. */\nexport const GLITCHGRAB_SHORTCUT = \"Ctrl+Shift+G\";\n\n/** Mac label, using the platform's modifier glyphs. */\nexport const GLITCHGRAB_SHORTCUT_MAC = \"⌘⇧G\";\n\n/** True when running on a Mac-like platform. Always false on the server. */\nfunction isMac(): boolean {\n try {\n if (typeof navigator === \"undefined\") return false;\n return /Mac|iPhone|iPad|iPod/i.test(navigator.platform || navigator.userAgent);\n } catch {\n return false;\n }\n}\n\n/**\n * OS-aware label for the report-dialog shortcut — `⌘⇧G` on Mac,\n * `Ctrl+Shift+G` elsewhere. Returns the non-Mac label on the server, so\n * render it client-side (or after mount) to avoid a hydration mismatch.\n */\nexport function getShortcutLabel(): string {\n return isMac() ? GLITCHGRAB_SHORTCUT_MAC : GLITCHGRAB_SHORTCUT;\n}\n\n/** True when the keyboard event matches the report-dialog shortcut. */\nexport function matchesShortcut(e: KeyboardEvent): boolean {\n return (\n (e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === \"g\"\n );\n}\n","\"use client\";\n\nimport { useState, type CSSProperties, type ReactNode } from \"react\";\nimport type { ReportButtonProps } from \"./types\";\nimport { useGlitchgrab } from \"./provider\";\n\n/** Safe version of useGlitchgrab that returns null when outside provider */\nfunction useGlitchgrabSafe() {\n try {\n return useGlitchgrab();\n } catch {\n return null;\n }\n}\n\n/**\n * Optional trigger button for opening the report dialog.\n *\n * The dialog itself lives inside `GlitchgrabProvider` — you don't need this component\n * unless you want a visible trigger button. You can also open the dialog programmatically\n * via `useGlitchgrab().openReportDialog()`.\n *\n * @example\n * ```tsx\n * // Use the default floating button\n * <ReportButton />\n *\n * // Use your own trigger\n * <ReportButton>\n * {({ onClick }) => <button onClick={onClick}>Report</button>}\n * </ReportButton>\n *\n * // Or skip ReportButton entirely and use the hook\n * const { openReportDialog } = useGlitchgrab();\n * <button onClick={() => openReportDialog()}>Report</button>\n * ```\n */\nexport function ReportButton({\n position = \"bottom-right\",\n label = \"Report Bug\",\n className,\n children,\n}: ReportButtonProps & {\n children?: (props: { onClick: () => void; capturing: boolean }) => ReactNode;\n}) {\n const [capturing, setCapturing] = useState(false);\n const glitchgrab = useGlitchgrabSafe();\n\n if (!glitchgrab) return null;\n\n const handleClick = async () => {\n setCapturing(true);\n glitchgrab.openReportDialog();\n setCapturing(false);\n };\n\n // Custom trigger via render prop\n if (children) {\n return <>{children({ onClick: handleClick, capturing })}</>;\n }\n\n // Default floating button\n const isTop = position?.startsWith(\"top\") ?? false;\n const isLeft = position?.endsWith(\"left\") ?? false;\n\n const positionStyles: CSSProperties = {\n ...(isLeft ? { left: \"16px\" } : { right: \"16px\" }),\n ...(isTop ? { top: \"16px\" } : { bottom: \"16px\" }),\n };\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={capturing}\n className={className}\n style={{\n position: \"fixed\",\n ...positionStyles,\n zIndex: 99999,\n padding: \"10px 18px\",\n borderRadius: \"24px\",\n border: \"none\",\n backgroundColor: \"#18181b\",\n color: \"#fafafa\",\n fontSize: \"14px\",\n fontWeight: 500,\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n cursor: capturing ? \"wait\" : \"pointer\",\n boxShadow:\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1)\",\n transition: \"transform 0.15s ease, box-shadow 0.15s ease\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n opacity: capturing ? 0.7 : 1,\n }}\n onMouseEnter={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1.05)\";\n }}\n onMouseLeave={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1)\";\n }}\n aria-label={label}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{ flexShrink: 0 }}\n >\n <path\n d=\"M8 1C4.134 1 1 4.134 1 8s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zm0 12.5a.75.75 0 110-1.5.75.75 0 010 1.5zm.75-3.5a.75.75 0 01-1.5 0V5a.75.75 0 011.5 0v5z\"\n fill=\"currentColor\"\n />\n </svg>\n {capturing ? \"Capturing...\" : label}\n </button>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useGlitchgrab } from \"./provider\";\n\n/**\n * Trigger for the demo booking dialog.\n *\n * The dialog itself lives in `GlitchgrabProvider`; this is only a convenience.\n * Most hosts will want their own button in their own design, which is what the\n * render prop is for — or skip this entirely and call\n * `useGlitchgrab().openBookingDialog()`.\n *\n * @example\n * ```tsx\n * <BookDemoButton />\n *\n * <BookDemoButton>\n * {({ onClick }) => <MyCta onClick={onClick}>Talk to us</MyCta>}\n * </BookDemoButton>\n * ```\n */\nexport function BookDemoButton({\n label = \"Book a demo\",\n className,\n children,\n}: {\n label?: string;\n className?: string;\n children?: (props: { onClick: () => void }) => ReactNode;\n}) {\n const { openBookingDialog } = useGlitchgrab();\n\n if (children) return <>{children({ onClick: openBookingDialog })}</>;\n\n return (\n <button\n type=\"button\"\n onClick={openBookingDialog}\n className={className}\n style={\n className\n ? undefined\n : {\n padding: \"10px 18px\",\n borderRadius: 999,\n border: 0,\n background: \"#3b82f6\",\n color: \"#fff\",\n fontSize: 14,\n fontWeight: 500,\n cursor: \"pointer\",\n }\n }\n >\n {label}\n </button>\n );\n}\n","\"use client\";\n\nimport type { CSSProperties, ReactNode } from \"react\";\nimport type { FeedbackButtonProps } from \"./types\";\nimport { useGlitchgrab } from \"./provider\";\n\n/** Safe version of useGlitchgrab that returns null when outside provider */\nfunction useGlitchgrabSafe() {\n try {\n return useGlitchgrab();\n } catch {\n return null;\n }\n}\n\n/**\n * Trigger for the built-in feedback dialog (stars + message).\n *\n * The dialog itself lives inside `GlitchgrabProvider` — this is only the visible\n * trigger. Open it programmatically with `useGlitchgrab().openFeedbackDialog()`,\n * or skip the dialog entirely and call `sendFeedback(rating, message)` from your\n * own UI.\n *\n * @example\n * ```tsx\n * // Default floating button\n * <FeedbackButton />\n *\n * // Your own trigger\n * <FeedbackButton>\n * {({ onClick }) => <button onClick={onClick}>Rate us</button>}\n * </FeedbackButton>\n * ```\n */\nexport function FeedbackButton({\n position = \"bottom-left\",\n label = \"Feedback\",\n className,\n children,\n}: FeedbackButtonProps & {\n children?: (props: { onClick: () => void }) => ReactNode;\n}) {\n const glitchgrab = useGlitchgrabSafe();\n\n if (!glitchgrab) return null;\n\n const handleClick = () => glitchgrab.openFeedbackDialog();\n\n if (children) {\n return <>{children({ onClick: handleClick })}</>;\n }\n\n const isTop = position?.startsWith(\"top\") ?? false;\n const isLeft = position?.endsWith(\"left\") ?? false;\n\n const positionStyles: CSSProperties = {\n ...(isLeft ? { left: \"16px\" } : { right: \"16px\" }),\n ...(isTop ? { top: \"16px\" } : { bottom: \"16px\" }),\n };\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n className={className}\n style={{\n position: \"fixed\",\n ...positionStyles,\n zIndex: 99999,\n padding: \"10px 18px\",\n borderRadius: \"24px\",\n border: \"none\",\n backgroundColor: \"#18181b\",\n color: \"#fafafa\",\n fontSize: \"14px\",\n fontWeight: 500,\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n cursor: \"pointer\",\n boxShadow:\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1)\",\n transition: \"transform 0.15s ease, box-shadow 0.15s ease\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n }}\n onMouseEnter={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1.05)\";\n }}\n onMouseLeave={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1)\";\n }}\n aria-label={label}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{ flexShrink: 0 }}\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 2.5l2.9 5.9 6.5.9-4.7 4.6 1.1 6.5L12 17.4l-5.8 3 1.1-6.5L2.6 9.3l6.5-.9L12 2.5z\"\n fill=\"currentColor\"\n />\n </svg>\n {label}\n </button>\n );\n}\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\n\nexport interface GlitchgrabReport {\n id: string;\n source: string;\n status: string;\n rawInput: string | null;\n reporterPrimaryKey: string;\n reporterName: string;\n reporterEmail: string | null;\n reporterPhone: string | null;\n pageUrl: string | null;\n createdAt: string;\n /** Number of comments on the linked GitHub issue (0 if no issue) */\n commentCount: number;\n issue: {\n githubNumber: number;\n githubUrl: string;\n title: string;\n labels: string[];\n severity: string | null;\n githubState: string | null;\n } | null;\n}\n\nconst BASE_URL = \"https://glitchgrab.dev\";\n\n/**\n * Hook to fetch bug reports for a specific user.\n *\n * ```tsx\n * const { reports, isLoading, error, refetch } = useGlitchgrabReports({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * userId: session.user.id,\n * });\n * ```\n */\nexport function useGlitchgrabReports({\n token,\n userId,\n limit = 100,\n}: {\n token: string;\n userId: string;\n /** Max results (default 100, max 100) */\n limit?: number;\n}): {\n reports: GlitchgrabReport[];\n isLoading: boolean;\n isFetching: boolean;\n error: string | null;\n refetch: () => Promise<void>;\n} {\n const [reports, setReports] = useState<GlitchgrabReport[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const fetchReports = useCallback(async () => {\n if (!token || !userId) {\n setIsLoading(false);\n return;\n }\n\n setIsFetching(true);\n setError(null);\n\n try {\n const res = await fetch(\n `${BASE_URL}/api/v1/sdk/reports?reporterPrimaryKey=${encodeURIComponent(userId)}&limit=${limit}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n const data = await res.json();\n\n if (data.success) {\n setReports(data.data ?? []);\n } else {\n setError(data.error ?? \"Failed to fetch reports\");\n }\n } catch {\n setError(\"Network error\");\n } finally {\n setIsLoading(false);\n setIsFetching(false);\n }\n }, [token, userId, limit]);\n\n useEffect(() => {\n fetchReports();\n }, [fetchReports]);\n\n return { reports, isLoading, isFetching, error, refetch: fetchReports };\n}\n\n/**\n * Standalone fetcher — use with TanStack Query or any data fetching library.\n *\n * ```tsx\n * const { data } = useQuery({\n * queryKey: [\"glitchgrab-reports\", userId],\n * queryFn: () => fetchGlitchgrabReports({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * userId: session.user.id,\n * }),\n * });\n * ```\n */\nexport async function fetchGlitchgrabReports({\n token,\n userId,\n limit = 100,\n}: {\n token: string;\n userId: string;\n limit?: number;\n}): Promise<GlitchgrabReport[]> {\n const res = await fetch(\n `${BASE_URL}/api/v1/sdk/reports?reporterPrimaryKey=${encodeURIComponent(userId)}&limit=${limit}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n const data = await res.json();\n if (!data.success) throw new Error(data.error ?? \"Failed to fetch reports\");\n return data.data ?? [];\n}\n\n// ─── Report Actions ─────────────────────────────────────\n\nasync function reportAction(\n token: string,\n reportId: string,\n body: Record<string, string>\n): Promise<void> {\n const res = await fetch(`${BASE_URL}/api/v1/reports/${reportId}/actions`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok || !data.success) throw new Error(data.error ?? \"Action failed\");\n}\n\n/**\n * Hook to manage report actions with loading/error states.\n *\n * ```tsx\n * const { approve, reject, close, isPending, error } = useGlitchgrabActions({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * onSuccess: () => refetch(),\n * onError: (err) => toast.error(err.message),\n * });\n *\n * <button onClick={() => approve(reportId)} disabled={isPending}>\n * {isPending ? \"...\" : \"Approve\"}\n * </button>\n * ```\n */\nexport function useGlitchgrabActions({\n token,\n onSuccess,\n onError,\n}: {\n token: string;\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n}) {\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const run = useCallback(\n async (reportId: string, body: Record<string, string>) => {\n setIsPending(true);\n setError(null);\n try {\n await reportAction(token, reportId, body);\n onSuccess?.();\n } catch (e) {\n const err = e instanceof Error ? e : new Error(\"Action failed\");\n setError(err.message);\n onError?.(err);\n } finally {\n setIsPending(false);\n }\n },\n [token, onSuccess, onError]\n );\n\n return {\n approve: (reportId: string) => run(reportId, { action: \"label\", label: \"approved\" }),\n reject: (reportId: string) => run(reportId, { action: \"label\", label: \"rejected\" }),\n close: (reportId: string) => run(reportId, { action: \"close\" }),\n reopen: (reportId: string) => run(reportId, { action: \"reopen\" }),\n label: (reportId: string, label: string) => run(reportId, { action: \"label\", label }),\n unlabel: (reportId: string, label: string) => run(reportId, { action: \"unlabel\", label }),\n isPending,\n error,\n };\n}\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { GlitchgrabFeedback } from \"./types\";\n\nconst DEFAULT_BASE_URL = \"https://glitchgrab.dev\";\n\nexport interface FeedbackQuery {\n token: string;\n /** Only entries the repo owner published — use this for a public testimonials wall */\n approvedOnly?: boolean;\n /** Only this end-user's feedback (their primary key in your DB) */\n userId?: string;\n /** Floor on the star rating, 1–5 */\n minRating?: number;\n /** Max results (default 50, max 100) */\n limit?: number;\n baseUrl?: string;\n}\n\nfunction buildUrl({\n approvedOnly,\n userId,\n minRating,\n limit = 50,\n baseUrl,\n}: Omit<FeedbackQuery, \"token\">): string {\n const params = new URLSearchParams({ limit: String(limit) });\n if (approvedOnly) params.set(\"approved\", \"true\");\n if (userId) params.set(\"reporterPrimaryKey\", userId);\n if (minRating) params.set(\"minRating\", String(minRating));\n return `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/sdk/feedback?${params.toString()}`;\n}\n\n/**\n * Standalone fetcher — use with TanStack Query or any data fetching library.\n *\n * ```tsx\n * const { data } = useQuery({\n * queryKey: [\"testimonials\"],\n * queryFn: () => fetchGlitchgrabFeedback({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * approvedOnly: true,\n * minRating: 4,\n * }),\n * });\n * ```\n */\nexport async function fetchGlitchgrabFeedback(\n query: FeedbackQuery\n): Promise<GlitchgrabFeedback[]> {\n const res = await fetch(buildUrl(query), {\n headers: { Authorization: `Bearer ${query.token}` },\n });\n const data = await res.json();\n if (!data.success) throw new Error(data.error ?? \"Failed to fetch feedback\");\n return data.data ?? [];\n}\n\n/**\n * Hook to read back the feedback your end-users left — render it as a\n * testimonials wall, or show a user their own past ratings.\n *\n * ```tsx\n * const { feedback, isLoading, error, refetch } = useGlitchgrabFeedback({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * approvedOnly: true,\n * });\n * ```\n */\nexport function useGlitchgrabFeedback(query: FeedbackQuery): {\n feedback: GlitchgrabFeedback[];\n isLoading: boolean;\n isFetching: boolean;\n error: string | null;\n refetch: () => Promise<void>;\n} {\n const { token, approvedOnly, userId, minRating, limit, baseUrl } = query;\n\n const [feedback, setFeedback] = useState<GlitchgrabFeedback[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const load = useCallback(async () => {\n if (!token) {\n setIsLoading(false);\n return;\n }\n\n setIsFetching(true);\n setError(null);\n\n try {\n const data = await fetchGlitchgrabFeedback({\n token,\n approvedOnly,\n userId,\n minRating,\n limit,\n baseUrl,\n });\n setFeedback(data);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Network error\");\n } finally {\n setIsLoading(false);\n setIsFetching(false);\n }\n }, [token, approvedOnly, userId, minRating, limit, baseUrl]);\n\n useEffect(() => {\n load();\n }, [load]);\n\n return { feedback, isLoading, isFetching, error, refetch: load };\n}\n"],"mappings":"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","names":["GLITCHGRAB_SHORTCUT","GLITCHGRAB_SHORTCUT_MAC","getShortcutLabel","import_react","e","appContext","t","import_react","import_react_dom","import_jsx_runtime","jsx","t","jsxs","useState","useEffect","useRef","history","Fragment","e","createPortal","jsx","rgb","t","useState","useEffect","jsxs","words","sendFeedback","enhanceText","findSimilarIssues","transcribeAudio","useRef","_a","useMemo","e","result","Fragment","createPortal","import_react","import_jsx_runtime","_a","seen","GLITCHGRAB_SHORTCUT","GLITCHGRAB_SHORTCUT_MAC","isMac","getShortcutLabel","import_jsx_runtime","DEFAULT_BASE_URL","maxBreadcrumbs","release","appContext","responseBodyOrigins","captureError","setContext","setContexts","addBreadcrumb","GLITCHGRAB_SHORTCUT","getShortcutLabel","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","useGlitchgrabSafe","import_react","import_react","DEFAULT_BASE_URL"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/error-boundary.tsx","../../report-ui/src/assist-response.ts","../src/redact.ts","../src/breadcrumbs.ts","../src/runtime.ts","../src/app-context.ts","../src/utils.ts","../src/dedup.ts","../src/capture.ts","../../report-ui/src/report-dialog.tsx","../../report-ui/src/annotation-canvas.tsx","../../report-ui/src/image-encode.ts","../../report-ui/src/assist-sheet.tsx","../../report-ui/src/types.ts","../../report-ui/src/attachments.ts","../../report-ui/src/labels.ts","../../report-ui/src/chat-markdown.tsx","../../report-ui/src/glitchgrab-problem.tsx","../../report-ui/src/shortcut.ts","../../report-ui/src/capture.ts","../../report-ui/src/host-theme.ts","../../report-ui/src/assist-response.ts","../src/booking-dialog.tsx","../src/rejection.ts","../src/shortcut.ts","../src/report-button.tsx","../src/book-demo-button.tsx","../src/feedback-button.tsx","../src/use-reports.ts","../src/use-feedback.ts"],"sourcesContent":["\"use client\";\n\n// ─── Core (required) ─────────────────────────────────────\nexport { GlitchgrabProvider, useGlitchgrab } from \"./provider\";\n\n// ─── Optional Components ─────────────────────────────────\nexport { ReportButton } from \"./report-button\";\nexport { BookDemoButton } from \"./book-demo-button\";\nexport { FeedbackButton } from \"./feedback-button\";\nexport { GlitchgrabErrorBoundary } from \"./error-boundary\";\n\n// ─── Caught-error reporting ──────────────────────────────\n// Standalone form for call sites outside the provider tree (global-error.tsx)\n// or outside React entirely. Inside the tree, prefer useGlitchgrab().captureError.\nexport { captureError } from \"./capture\";\n\n// ─── App context ─────────────────────────────────────────\n// Key-values attached to every report (orgId, plan, feature flags). Standalone\n// form so non-React code can set them; also on useGlitchgrab().\nexport {\n setContext,\n setContexts,\n getAppContext,\n clearAppContext,\n} from \"./app-context\";\n\n// ─── Hooks ──────────────────────────────────────────────\nexport { useGlitchgrabReports, fetchGlitchgrabReports, useGlitchgrabActions } from \"./use-reports\";\nexport type { GlitchgrabReport } from \"./use-reports\";\nexport { useGlitchgrabFeedback, fetchGlitchgrabFeedback } from \"./use-feedback\";\nexport type { FeedbackQuery } from \"./use-feedback\";\n\n// ─── Breadcrumbs ─────────────────────────────────────────\nexport {\n addBreadcrumb,\n getBreadcrumbs,\n clearBreadcrumbs,\n initBreadcrumbs,\n} from \"./breadcrumbs\";\n\n// ─── Keyboard shortcut ───────────────────────────────────\nexport {\n GLITCHGRAB_SHORTCUT,\n GLITCHGRAB_SHORTCUT_MAC,\n getShortcutLabel,\n matchesShortcut,\n} from \"./shortcut\";\n\n// ─── Utilities ───────────────────────────────────────────\nexport { sanitizeUrl, captureContext, captureDeviceInfo, sendReport, sendFeedback, enhanceText } from \"./utils\";\nexport { computeSignature, shouldSkipDuplicate, clearDedupCache } from \"./dedup\";\n\n// ─── Types ───────────────────────────────────────────────\nexport type {\n CaptureErrorOptions,\n GlitchgrabConfig,\n GlitchgrabProviderProps,\n ReportPayload,\n ReportResult,\n ReportType,\n ReportSeverity,\n CapturedContext,\n DeviceInfo,\n RuntimeInfo,\n Breadcrumb,\n BreadcrumbType,\n UseGlitchgrabReturn,\n ReportButtonProps,\n FeedbackButtonProps,\n FeedbackPayload,\n FeedbackResult,\n GlitchgrabFeedback,\n GlitchgrabSession,\n} from \"./types\";\n","\"use client\";\n\nimport {\n createContext,\n useContext,\n useRef,\n useEffect,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport type {\n CaptureErrorOptions,\n FeedbackResult,\n GlitchgrabProviderProps,\n UseGlitchgrabReturn,\n ReportPayload,\n ReportResult,\n ReportType,\n} from \"./types\";\nimport { GlitchgrabErrorBoundary } from \"./error-boundary\";\nimport { ReportDialog, type GlitchgrabProblemParams } from \"@glitchgrab/report-ui\";\nimport { BookingDialog } from \"./booking-dialog\";\nimport { sanitizeUrl, captureContext, contextMetadata, sendReport, sendFeedback, captureDeviceInfo, enhanceText, assistTurn, findSimilarIssues, transcribeAudio, type EnhanceContext } from \"./utils\";\nimport {\n setContext as setContextInternal,\n setContexts as setContextsInternal,\n setRelease,\n} from \"./app-context\";\nimport { incrementErrorCount } from \"./runtime\";\nimport { computeSignature, shouldSkipDuplicate } from \"./dedup\";\nimport { describeRejection, isUnactionableRejection } from \"./rejection\";\nimport {\n captureError as captureErrorStandalone,\n matchesIgnorePatterns,\n registerCaptureConfig,\n} from \"./capture\";\nimport { GLITCHGRAB_SHORTCUT, getShortcutLabel, matchesShortcut } from \"./shortcut\";\nimport {\n initBreadcrumbs,\n addBreadcrumb as addBreadcrumbInternal,\n getBreadcrumbs,\n} from \"./breadcrumbs\";\n\nconst DEFAULT_BASE_URL = \"https://glitchgrab.dev\";\n\nconst GlitchgrabContext = createContext<UseGlitchgrabReturn | null>(null);\n\n/**\n * Hook to access Glitchgrab in your components.\n *\n * @example\n * ```tsx\n * const { reportBug, report, captureError, addBreadcrumb } = useGlitchgrab();\n *\n * // Report a bug\n * reportBug(\"Login button crashes on mobile\");\n *\n * // Report an error your own boundary already caught (e.g. app/error.tsx)\n * captureError(error, { digest: error.digest, boundary: \"next-app-router\" });\n *\n * // Report a feature request\n * report(\"FEATURE_REQUEST\", \"Add dark mode\");\n *\n * // Add a custom breadcrumb\n * addBreadcrumb(\"User clicked checkout\", { cartItems: \"3\" });\n * ```\n */\nexport function useGlitchgrab(): UseGlitchgrabReturn {\n const ctx = useContext(GlitchgrabContext);\n if (!ctx) {\n throw new Error(\"useGlitchgrab must be used within a GlitchgrabProvider\");\n }\n return ctx;\n}\n\nfunction GlitchgrabProviderInner({\n token,\n session: sessionProp,\n baseUrl,\n onError,\n onReportSent,\n breadcrumbs: enableBreadcrumbs = true,\n maxBreadcrumbs = 50,\n children,\n fallback,\n types,\n showSeverity,\n ignoreErrors,\n release,\n context: appContext,\n responseBodyOrigins,\n}: GlitchgrabProviderProps) {\n const visitedPagesRef = useRef<string[]>([]);\n\n // Hosts build `session` inline from their auth hook, so it is a new object on\n // every host render. Keyed on what it says instead: an unchanged session no\n // longer tears down and re-adds the error listeners, or rebuilds every\n // callback that reads it (#363).\n const sessionKey = sessionProp\n ? [\n sessionProp.userId,\n sessionProp.name,\n sessionProp.email,\n sessionProp.phone,\n sessionProp.avatarUrl,\n sessionProp.image,\n ]\n .map((v) => (v == null ? \"\" : String(v)))\n .join(\"\\u0000\")\n : \"\";\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const session = useMemo(() => sessionProp, [sessionKey]);\n\n // Same reasoning as the capture config below: written during render so a crash\n // on a child's first render still reports which build it came from.\n setRelease(release);\n if (appContext) setContextsInternal(appContext);\n\n // Publish config for the standalone `captureError` export.\n //\n // Written in the render body, not an effect: a crash during a child's *initial*\n // render unwinds to the framework boundary (Next's `error.tsx`) before any effect\n // commits, so an effect-based registration would leave `captureError` unconfigured\n // for exactly the case it exists to cover. The write is idempotent, so React's\n // strict-mode double-invoke and discarded renders are harmless. Never torn down on\n // unmount — `global-error.tsx` replaces the root layout, provider tree included.\n registerCaptureConfig({\n token,\n baseUrl,\n session,\n ignoreErrors,\n getVisitedPages: () => visitedPagesRef.current,\n onError,\n onReportSent,\n });\n\n // Initialize breadcrumbs\n useEffect(() => {\n if (enableBreadcrumbs) {\n initBreadcrumbs(maxBreadcrumbs, { responseBodyOrigins });\n }\n // Keyed on the joined origins, not the array — callers pass this inline, and\n // a fresh array identity each render would re-run the effect every render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enableBreadcrumbs, maxBreadcrumbs, responseBodyOrigins?.join(\",\")]);\n\n // Track page visits\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n\n const trackPage = () => {\n try {\n const sanitized = sanitizeUrl(window.location.href);\n const pages = visitedPagesRef.current;\n if (pages[pages.length - 1] !== sanitized) {\n pages.push(sanitized);\n if (pages.length > 20) {\n pages.splice(0, pages.length - 20);\n }\n }\n } catch {\n // Silently fail\n }\n };\n\n trackPage();\n const handlePopState = () => trackPage();\n window.addEventListener(\"popstate\", handlePopState);\n\n const origPushState = history.pushState.bind(history);\n const origReplaceState = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n origPushState(...args);\n trackPage();\n };\n history.replaceState = function (...args) {\n origReplaceState(...args);\n trackPage();\n };\n\n return () => {\n window.removeEventListener(\"popstate\", handlePopState);\n history.pushState = origPushState;\n history.replaceState = origReplaceState;\n };\n } catch {\n // Never crash\n }\n }, []);\n\n // Unhandled errors and rejections — skip in development\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n if (process.env.NODE_ENV === \"development\") return;\n\n // Matches chrome-extension://, safari-extension://, moz-extension://\n const EXTENSION_ORIGIN_RE = /\\b(?:chrome|safari|moz)-extension:\\/\\//;\n\n // Well-known extension-injected noise that carries no extension origin in\n // filename/stack, so EXTENSION_ORIGIN_RE can't catch it. Not app bugs.\n const KNOWN_NOISE_RE = [\n /Object Not Found Matching Id:\\d+, MethodName:update, ParamCount:\\d+/,\n ];\n\n const matchesIgnore = (message: string): boolean => {\n if (KNOWN_NOISE_RE.some((pattern) => pattern.test(message))) return true;\n return matchesIgnorePatterns(message, ignoreErrors);\n };\n\n const handleError = (event: ErrorEvent) => {\n try {\n // Ignore opaque cross-origin script errors — the browser masks these with no\n // stack, no filename, and no error object, so there is nothing actionable to report.\n const isOpaqueCrossOrigin =\n event.message === \"Script error.\" ||\n event.message === \"Script error\" ||\n (!event.error && !event.filename);\n if (isOpaqueCrossOrigin) {\n return;\n }\n\n // Caller-supplied ignore patterns — known-noisy signatures (e.g. browser\n // extension bridge errors) that aren't app bugs.\n if (matchesIgnore(event.message)) {\n return;\n }\n\n // Ignore benign ResizeObserver warnings — these are triggered by UI libraries\n // (Radix, cmdk, etc.) and are not actionable bugs.\n if (\n event.message === \"ResizeObserver loop completed with undelivered notifications.\" ||\n event.message === \"ResizeObserver loop limit exceeded\"\n ) {\n return;\n }\n\n // Ignore errors thrown by browser extensions — crypto wallets, ad blockers,\n // and other extensions run in the page's JS context but are not part of the app.\n if (\n (event.filename && EXTENSION_ORIGIN_RE.test(event.filename)) ||\n (event.error?.stack && EXTENSION_ORIGIN_RE.test(event.error.stack))\n ) {\n return;\n }\n // Counted before the snapshot, so a report says which error in the run\n // it was — the fifth crash reads very differently from the first.\n incrementErrorCount();\n const context = captureContext(visitedPagesRef.current);\n const sig = computeSignature({\n errorMessage: event.message,\n pageUrl: context.url,\n errorStack: event.error?.stack,\n });\n if (shouldSkipDuplicate(sig)) return;\n const payload: ReportPayload = {\n token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: event.message,\n errorStack: event.error?.stack,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n ...contextMetadata(context),\n filename: event.filename ?? \"\",\n lineno: String(event.lineno ?? \"\"),\n colno: String(event.colno ?? \"\"),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n },\n };\n sendReport(payload, baseUrl).then((result) => {\n if (result && onReportSent) onReportSent(result);\n });\n if (onError && event.error) onError(event.error);\n } catch {\n // Silently fail\n }\n };\n\n const handleRejection = (event: PromiseRejectionEvent) => {\n try {\n const reason = event.reason;\n // Non-Error reasons used to stringify to \"[object Object]\", discarding\n // every field and every chance of a stack.\n const description = describeRejection(reason);\n const errMsg = description.message;\n const errStack = description.stack;\n\n // Ignore generic cross-origin script errors.\n if (errMsg === \"Script error.\" || errMsg === \"Script error\") {\n return;\n }\n\n // Caller-supplied ignore patterns — known-noisy signatures (e.g. browser\n // extension bridge errors) that aren't app bugs.\n if (matchesIgnore(errMsg)) {\n return;\n }\n\n // Ignore unhandled rejections where the call chain passes through a browser\n // extension — these are the extension's own failures, not the app's.\n if (errStack && EXTENSION_ORIGIN_RE.test(errStack)) return;\n\n // No message and no stack — nothing a human or an AI could triage. Reporting\n // it only produces issues titled \"[object Object]\".\n if (isUnactionableRejection(description)) return;\n\n // Snapshot only once the rejection has survived every filter — an\n // ignored rejection must not inflate errorCount for the next report.\n incrementErrorCount();\n const context = captureContext(visitedPagesRef.current);\n\n const sig = computeSignature({\n errorMessage: errMsg,\n pageUrl: context.url,\n errorStack: errStack,\n });\n if (shouldSkipDuplicate(sig)) return;\n const payload: ReportPayload = {\n token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage: errMsg,\n errorStack: errStack,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n ...contextMetadata(context),\n type: \"unhandledrejection\",\n ...(description.details ? { rejectionReason: description.details } : {}),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n },\n };\n sendReport(payload, baseUrl).then((result) => {\n if (result && onReportSent) onReportSent(result);\n });\n if (onError && reason instanceof Error) onError(reason);\n } catch {\n // Silently fail\n }\n };\n\n window.addEventListener(\"error\", handleError);\n window.addEventListener(\"unhandledrejection\", handleRejection);\n\n return () => {\n window.removeEventListener(\"error\", handleError);\n window.removeEventListener(\"unhandledrejection\", handleRejection);\n };\n } catch {\n // Never crash\n }\n }, [token, baseUrl, onError, onReportSent, session, ignoreErrors]);\n\n const report = useCallback(\n async (\n type: ReportType,\n description: string,\n metadata?: Record<string, string>\n ): Promise<ReportResult | null> => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const payload: ReportPayload = {\n token,\n source: \"SDK_USER_REPORT\",\n type,\n description,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n ...contextMetadata(context),\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n ...metadata,\n },\n };\n const result = await sendReport(payload, baseUrl);\n if (result && onReportSent) onReportSent(result);\n return result;\n } catch {\n return null;\n }\n },\n [token, baseUrl, onReportSent, session]\n );\n\n const reportBug = useCallback(\n (description: string, metadata?: Record<string, string>) =>\n report(\"BUG\", description, metadata),\n [report]\n );\n\n /**\n * \"Problem with Glitchgrab?\" (#366) — a report about the dialog itself, sent\n * to Glitchgrab's own repo with the same session a host report carries:\n * pages visited, breadcrumbs, device info and the dialog's screenshots. Only\n * wired when the project owner opted in, because it leaves their project.\n */\n const reportGlitchgrabProblem = useCallback(\n async (params: GlitchgrabProblemParams): Promise<ReportResult | null> => {\n try {\n const context = captureContext(visitedPagesRef.current);\n const body = JSON.stringify({\n ...params,\n pageUrl: context.url,\n userAgent: context.userAgent,\n deviceInfo: context.deviceInfo ?? undefined,\n visitedPages: context.visitedPages,\n breadcrumbs: context.breadcrumbs,\n ...(session?.userId ? { reporterId: session.userId } : {}),\n ...(session?.name ? { reporterName: String(session.name) } : {}),\n ...(session?.email ? { reporterEmail: String(session.email) } : {}),\n });\n const res = await fetch(`${baseUrl}/api/v1/sdk/glitchgrab-report`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", Authorization: `Bearer ${token}` },\n body,\n // keepalive caps the body at 64KB — screenshots blow past it.\n ...(body.length < 60_000 ? { keepalive: true } : {}),\n });\n const json = (await res.json().catch(() => null)) as {\n success?: boolean;\n error?: string;\n data?: Omit<ReportResult, \"success\">;\n } | null;\n if (!res.ok || !json?.success) {\n return { success: false, message: json?.error ?? \"Couldn't send it\" };\n }\n return { success: true, ...json.data };\n } catch {\n return null;\n }\n },\n [token, baseUrl, session]\n );\n\n const feedback = useCallback(\n async (\n rating: number,\n message?: string,\n metadata?: Record<string, string>\n ): Promise<FeedbackResult | null> => {\n try {\n const context = captureContext(visitedPagesRef.current);\n return await sendFeedback(\n {\n token,\n rating,\n message,\n pageUrl: context.url,\n userAgent: context.userAgent,\n metadata: {\n timestamp: context.timestamp,\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n ...metadata,\n },\n },\n baseUrl\n );\n } catch {\n return null;\n }\n },\n [token, baseUrl, session]\n );\n\n // One dialog, not two — this opens the same report dialog straight onto its\n // RATING tile. A user answering \"what's on your mind?\" shouldn't have to know\n // in advance whether their thought is a bug or a compliment.\n const openFeedbackDialog = useCallback(() => {\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(\n new CustomEvent(\"glitchgrab:open-report\", { detail: { type: \"RATING\" } })\n );\n }\n }, []);\n\n // Stable identity — the documented usage puts this in a `useEffect` dep array.\n // Reads config from the module registry, which this render already refreshed.\n const captureError = useCallback(\n (error: unknown, options?: CaptureErrorOptions) => {\n captureErrorStandalone(error, options);\n },\n []\n );\n\n const setContext = useCallback((key: string, value: unknown) => {\n setContextInternal(key, value);\n }, []);\n\n const setContexts = useCallback((values: Record<string, unknown>) => {\n setContextsInternal(values);\n }, []);\n\n const addBreadcrumb = useCallback(\n (message: string, data?: Record<string, string>) => {\n addBreadcrumbInternal(\"custom\", message, data);\n },\n []\n );\n\n /**\n * Who the host's server vouched for (`signSession` in `glitchgrab/server`).\n * Sent with every paid browser call — AI chat, enhance, similar issues, voice —\n * so a project with signed users on can tell its own users from someone who\n * lifted the token out of the bundle.\n */\n const signedUserId = session?.userId;\n const signature = typeof session?.signature === \"string\" ? session.signature : null;\n const identity = useMemo(\n () => ({ userId: signedUserId ?? null, signature }),\n [signedUserId, signature]\n );\n\n const enhance = useCallback(\n async (text: string, screenshot?: string | null): Promise<string> => {\n try {\n const ctx = captureContext(visitedPagesRef.current);\n const context: EnhanceContext = {\n url: ctx.url,\n visitedPages: ctx.visitedPages.slice(-5),\n breadcrumbs: ctx.breadcrumbs.slice(-10).map((b) => ({ type: b.type, message: b.message })),\n };\n return await enhanceText(text, token, baseUrl, screenshot, context, identity);\n } catch {\n return text;\n }\n },\n [token, baseUrl, identity]\n );\n\n /**\n * One assistant turn. Carries the same session context the enhance button\n * sends — the page, where they had been, what they clicked — because that is\n * most of what a developer would have asked for anyway.\n */\n const assist = useCallback(\n async (params: {\n messages: { role: \"user\" | \"assistant\"; content: string }[];\n conversationId: string | null;\n /** Every image on the report, newest last (#352). */\n screenshots?: string[];\n /** @deprecated Sent beside `screenshots` for older server builds. */\n screenshot?: string | null;\n context?: Record<string, unknown> | null;\n }) => {\n const ctx = captureContext(visitedPagesRef.current);\n return assistTurn(\n {\n ...params,\n // Same identity the report itself carries, from the same prop.\n reporter: session\n ? {\n key: session.userId,\n name: session.name ? String(session.name) : null,\n email: session.email ? String(session.email) : null,\n ...(signature ? { signature } : {}),\n }\n : undefined,\n context: {\n ...(params.context ?? {}),\n url: ctx.url,\n visitedPages: ctx.visitedPages.slice(-5),\n breadcrumbs: ctx.breadcrumbs\n .slice(-25)\n .map((b) => ({ type: b.type, message: b.message })),\n },\n },\n token,\n baseUrl\n );\n },\n [token, baseUrl, session]\n );\n\n // Plain form's \"is this already filed?\" on Send. Wired beside `assist`\n // because the owner's AI-assist switch is its consent too; the server\n // re-checks that switch on every call.\n const findSimilar = useCallback(\n (description: string) => findSimilarIssues(description, token, baseUrl, identity),\n [token, baseUrl, identity]\n );\n\n const transcribe = useCallback(\n async (blob: Blob): Promise<string> => {\n try {\n return await transcribeAudio(blob, token, baseUrl, identity);\n } catch {\n return \"\";\n }\n },\n [token, baseUrl, identity]\n );\n\n const openReportDialog = useCallback((options?: { description?: string; type?: ReportType }) => {\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(new CustomEvent(\"glitchgrab:open-report\", { detail: options }));\n }\n }, []);\n\n /**\n * Tell the Chrome extension this page already has a report dialog.\n *\n * The extension binds the same shortcut on every page that ISN'T running the\n * SDK — someone else's dashboard, a staging site, a video call — so a bug can\n * be filed anywhere. Without a marker it cannot tell those apart, and a host\n * app that embeds the SDK would open two dialogs on one keystroke.\n *\n * An attribute rather than a global: content scripts run in an isolated\n * world and cannot see page JavaScript, but they do share the DOM.\n */\n useEffect(() => {\n try {\n if (typeof document === \"undefined\") return;\n document.documentElement.setAttribute(\"data-glitchgrab-sdk\", \"1\");\n return () => document.documentElement.removeAttribute(\"data-glitchgrab-sdk\");\n } catch {\n // Never crash\n }\n }, []);\n\n /**\n * Which project this app's reports go to.\n *\n * Fixed for the SDK — one token, one repo — but until now invisible, and\n * invisible is indistinguishable from wrong to whoever is about to press\n * send. Shown read-only for the same reason it is not a dropdown: an end\n * user of the host app has no business choosing, or even seeing, which other\n * projects exist.\n */\n const [projectName, setProjectName] = useState<string | null>(null);\n\n /**\n * Whether this project's owner turned the AI report assistant on (#330).\n * Starts false so the dialog never flashes an affordance it may not keep, and\n * is only ever a UI hint — /api/v1/ai/report-chat re-checks the same column\n * on every call.\n */\n const [aiAssist, setAiAssist] = useState(false);\n\n /**\n * Whether the owner switched on \"Problem with Glitchgrab?\" (#366). Same\n * contract as `aiAssist`: starts false, a UI hint only —\n * /api/v1/sdk/glitchgrab-report re-checks the column on every call.\n */\n const [glitchgrabReport, setGlitchgrabReport] = useState(false);\n\n /**\n * The owner's signed-users mode. A UI hint like `aiAssist` — every paid route\n * re-checks the signature itself. Absent on older servers, which read as OFF.\n */\n const [signedUsers, setSignedUsers] = useState<\"OFF\" | \"WARN\" | \"ENFORCE\">(\"OFF\");\n\n /**\n * Enforced and this user is unsigned: the AI features would only answer\n * \"unsigned\", so they are not offered. The plain report form still files —\n * a missing signature must never cost the host a bug report.\n */\n const aiBlockedUnsigned = signedUsers === \"ENFORCE\" && !signature;\n\n /**\n * Demo booking, opened from the host app's own \"Book a demo\" button.\n *\n * State lives here rather than in the button so a host can trigger it from\n * anywhere — a pricing table, a nav item, the end of a blog post — without\n * every one of those places owning a dialog.\n */\n const [bookingOpen, setBookingOpen] = useState(false);\n const openBookingDialog = useCallback(() => setBookingOpen(true), []);\n\n useEffect(() => {\n let cancelled = false;\n fetch(`${baseUrl}/api/v1/sdk/project`, {\n headers: { Authorization: `Bearer ${token}` },\n })\n .then((r) => (r.ok ? r.json() : null))\n .then((json) => {\n if (cancelled || !json?.success || !json.data?.name) return;\n setProjectName(json.data.name as string);\n setAiAssist(json.data.aiAssist === true);\n setGlitchgrabReport(json.data.glitchgrabReport === true);\n const mode = json.data.signedUsers;\n setSignedUsers(mode === \"WARN\" || mode === \"ENFORCE\" ? mode : \"OFF\");\n })\n .catch(() => {\n // The dialog simply omits the line — never block reporting on it.\n });\n return () => { cancelled = true; };\n }, [baseUrl, token]);\n\n // Tell the developer, not the end user: once per mode change, development only.\n useEffect(() => {\n try {\n if (signedUsers === \"OFF\" || signature || !session) return;\n if (typeof process === \"undefined\" || process.env?.NODE_ENV !== \"development\") return;\n console.warn(\n signedUsers === \"ENFORCE\"\n ? \"[glitchgrab] This project enforces signed users and `session.signature` is missing — AI features are hidden. Sign it on your server with signSession() from \\\"glitchgrab/server\\\".\"\n : \"[glitchgrab] This project warns on unsigned users and `session.signature` is missing. Sign it on your server with signSession() from \\\"glitchgrab/server\\\" before the owner switches to Enforce.\"\n );\n } catch {\n // Never crash\n }\n }, [signedUsers, signature, session]);\n\n // Global keyboard shortcut: Cmd+Shift+G (Mac) / Ctrl+Shift+G (Windows/Linux)\n useEffect(() => {\n try {\n if (typeof window === \"undefined\") return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (matchesShortcut(e)) {\n e.preventDefault();\n openReportDialog();\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n } catch {\n // Never crash\n }\n }, [openReportDialog]);\n\n // Who the dialog shows as the reporter. `session` is the SDK's identity\n // primitive; the avatar is read off the extra fields GlitchgrabSession allows,\n // since auth libraries name it `image` (NextAuth) or `avatarUrl`.\n const reporter = useMemo(() => {\n if (!session) return null;\n const avatar = session.avatarUrl ?? session.image;\n return {\n name: session.name,\n email: session.email,\n avatarUrl: typeof avatar === \"string\" ? avatar : null,\n };\n }, [session]);\n\n // Starts as the non-Mac label so SSR and the first client render agree,\n // then resolves to the real platform label after mount.\n const [shortcutLabel, setShortcutLabel] = useState(GLITCHGRAB_SHORTCUT);\n useEffect(() => {\n setShortcutLabel(getShortcutLabel());\n }, []);\n\n return (\n <GlitchgrabContext.Provider\n value={{\n token,\n baseUrl: baseUrl ?? DEFAULT_BASE_URL,\n reportBug,\n report,\n captureError,\n setContext,\n setContexts,\n sendFeedback: feedback,\n openFeedbackDialog,\n addBreadcrumb,\n openReportDialog,\n openBookingDialog,\n enhanceText: enhance,\n shortcutLabel,\n }}\n >\n <GlitchgrabErrorBoundary\n token={token}\n baseUrl={baseUrl}\n session={session}\n onError={onError}\n fallback={fallback}\n visitedPages={visitedPagesRef.current}\n >\n {children}\n </GlitchgrabErrorBoundary>\n <BookingDialog\n token={token}\n baseUrl={baseUrl ?? DEFAULT_BASE_URL}\n open={bookingOpen}\n onClose={() => setBookingOpen(false)}\n />\n <ReportDialog\n report={report}\n sendFeedback={feedback}\n // enhance-text on a token needs the owner's AI-assist switch now, so\n // the link is only offered where it can answer.\n enhanceText={aiAssist && !aiBlockedUnsigned ? enhance : undefined}\n assist={aiAssist && !aiBlockedUnsigned ? assist : undefined}\n findSimilarIssues={aiAssist && !aiBlockedUnsigned ? findSimilar : undefined}\n reportGlitchgrabProblem={glitchgrabReport ? reportGlitchgrabProblem : undefined}\n transcribeAudio={aiBlockedUnsigned ? undefined : transcribe}\n types={types}\n showSeverity={showSeverity}\n reporter={reporter}\n headerSlot={\n projectName ? (\n <div style={{ fontSize: 11, color: \"#9aa0a6\" }}>\n Reporting to <strong style={{ color: \"#e5e5e5\" }}>{projectName}</strong>\n </div>\n ) : null\n }\n />\n </GlitchgrabContext.Provider>\n );\n}\n\nexport function GlitchgrabProvider(props: GlitchgrabProviderProps) {\n // No token = passthrough (SDK disabled)\n if (!props.token) return <>{props.children}</>;\n\n const resolvedProps = {\n ...props,\n baseUrl: props.baseUrl || DEFAULT_BASE_URL,\n };\n\n try {\n return <GlitchgrabProviderInner {...resolvedProps} />;\n } catch {\n return <>{props.children}</>;\n }\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { GlitchgrabSession } from \"./types\";\nimport { sendReport } from \"./utils\";\nimport { buildCapturedErrorPayload } from \"./capture\";\n\ninterface ErrorBoundaryProps {\n token: string;\n baseUrl?: string;\n session?: GlitchgrabSession | null;\n onError?: (error: Error) => void;\n fallback?: React.ReactNode;\n visitedPages: string[];\n children: React.ReactNode;\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n}\n\nexport class GlitchgrabErrorBoundary extends React.Component<\n ErrorBoundaryProps,\n ErrorBoundaryState\n> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(): ErrorBoundaryState {\n return { hasError: true };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n try {\n // Same payload shape and dedup as `captureError` — this boundary is just\n // another caught-error source. Config comes from props, not the module\n // registry, so the boundary works standalone (it's exported on its own).\n // No `ignoreErrors` by design: those are a provider prop this component\n // cannot see when mounted directly by a host app.\n const payload = buildCapturedErrorPayload(\n error,\n { componentStack: errorInfo.componentStack ?? undefined },\n {\n token: this.props.token,\n baseUrl: this.props.baseUrl,\n session: this.props.session,\n getVisitedPages: () => this.props.visitedPages,\n },\n \"GlitchgrabErrorBoundary\"\n );\n\n if (payload) {\n sendReport(payload, this.props.baseUrl);\n }\n\n if (this.props.onError) {\n this.props.onError(error);\n }\n } catch {\n // Never crash the host app\n }\n }\n\n render(): React.ReactNode {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n // Re-render children — allows recovery from transient errors\n return this.props.children;\n }\n\n return this.props.children;\n }\n}\n","import type { AssistTurnResult } from \"./types\";\n\n/**\n * Turning the `/api/v1/ai/report-chat` response into what the sheet renders —\n * one copy for every host.\n *\n * The SDK, the Chrome extension and GlitchRecord each mapped it by hand, and\n * GlitchRecord's copy kept only question/report: its sheet never got the\n * \"Yes, that's it\" chip, \"our team is already on #N\", or an answer from the\n * project's guides. A field added here reaches all three.\n *\n * React-free on purpose: GlitchRecord's Electron main process imports it.\n */\n\n/** Shown when the assistant cannot be reached — the plain form takes over. */\nexport const ASSIST_OFFLINE_MESSAGE =\n \"The assistant is unavailable — write your report below and send it as normal.\";\n\nexport function assistOffline(): AssistTurnResult {\n return { conversationId: null, question: null, report: null, degraded: ASSIST_OFFLINE_MESSAGE };\n}\n\ntype IssueRef = { number: number; title: string; url: string; status?: string };\n\ninterface ReportChatEnvelope {\n success?: boolean;\n error?: string;\n retryable?: boolean;\n data?: {\n conversationId?: string | null;\n question?: string | null;\n options?: unknown;\n report?: string | null;\n duplicate?: IssueRef | null;\n related?: IssueRef | null;\n solved?: string | null;\n aboutGlitchgrab?: boolean;\n };\n}\n\n/**\n * @param ok `response.ok`\n * @param body the parsed JSON body, or `null` when it was not JSON\n */\nexport function toAssistTurnResult(ok: boolean, body: unknown): AssistTurnResult {\n const envelope = (body ?? null) as ReportChatEnvelope | null;\n if (!ok || !envelope?.success) {\n return {\n ...assistOffline(),\n // The server words why (cap, rate limit, switched off). An hourly limit\n // keeps the assistant button for this report.\n degraded: envelope?.error ?? ASSIST_OFFLINE_MESSAGE,\n retryable: envelope?.retryable === true,\n };\n }\n const d = envelope.data ?? {};\n return {\n conversationId: d.conversationId ?? null,\n question: d.question ?? null,\n options: Array.isArray(d.options)\n ? d.options.filter((o): o is string => typeof o === \"string\")\n : [],\n report: d.report ?? null,\n duplicate: d.duplicate ?? null,\n related: d.related ?? null,\n solved: d.solved ?? null,\n aboutGlitchgrab: d.aboutGlitchgrab === true,\n degraded: null,\n };\n}\n","/**\n * Redaction for anything scraped off the wire. Error response bodies are the\n * one place the SDK copies server output verbatim, and servers echo back tokens,\n * emails and password-reset links in their error envelopes.\n */\n\nconst SENSITIVE_KEY_RE =\n /(pass|pwd|secret|token|auth|session|cookie|credential|apikey|api_key|access_key|private|signature|otp|pin|cvv|card|ssn|aadhaar|pan)/i;\n\nconst EMAIL_RE = /[\\w.+-]+@[\\w-]+\\.[\\w.-]+/g;\nconst JWT_RE = /\\beyJ[\\w-]{8,}\\.[\\w-]{8,}\\.[\\w-]{8,}\\b/g;\nconst BEARER_RE = /\\b(bearer\\s+)[\\w-.~+/]{12,}=*/gi;\n\n/** Longest error body kept. Enough for a stack or a validation list, not a page. */\nexport const MAX_BODY_LENGTH = 500;\n\nfunction redactString(value: string): string {\n return value\n .replace(JWT_RE, \"[REDACTED]\")\n .replace(BEARER_RE, \"$1[REDACTED]\")\n .replace(EMAIL_RE, \"[REDACTED_EMAIL]\");\n}\n\nfunction redactValue(value: unknown, depth: number): unknown {\n if (depth > 4) return \"[DEPTH]\";\n if (value === null || value === undefined) return value;\n if (typeof value === \"string\") return redactString(value);\n if (typeof value === \"number\" || typeof value === \"boolean\") return value;\n if (Array.isArray(value)) return value.slice(0, 20).map((v) => redactValue(v, depth + 1));\n if (typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [key, inner] of Object.entries(value as Record<string, unknown>)) {\n out[key] = SENSITIVE_KEY_RE.test(key) ? \"[REDACTED]\" : redactValue(inner, depth + 1);\n }\n return out;\n }\n return String(value);\n}\n\n/**\n * Redact and truncate a response body for breadcrumb metadata.\n * JSON is walked key-by-key so sensitive fields are dropped by name; anything\n * else is treated as opaque text and only pattern-scrubbed. Never throws.\n */\nexport function redactBody(body: string, maxLength: number = MAX_BODY_LENGTH): string {\n try {\n const trimmed = body.trim();\n if (!trimmed) return \"\";\n\n let result: string;\n try {\n result = JSON.stringify(redactValue(JSON.parse(trimmed), 0));\n } catch {\n // Not JSON — HTML error pages, plain text, stack dumps.\n result = redactString(trimmed);\n }\n\n return result.length > maxLength ? `${result.slice(0, maxLength)}…[truncated]` : result;\n } catch {\n return \"\";\n }\n}\n","import type { Breadcrumb, BreadcrumbType } from \"./types\";\nimport { redactBody } from \"./redact\";\n\nconst MAX_DEFAULT = 50;\n\nlet breadcrumbs: Breadcrumb[] = [];\nlet maxBreadcrumbs = MAX_DEFAULT;\nlet initialized = false;\n\n/**\n * Extra origins whose error bodies may be captured. Same-origin is always\n * allowed; everything else must be listed explicitly.\n */\nlet responseBodyOrigins: string[] = [];\n\nexport interface BreadcrumbOptions {\n /**\n * Additional origins to capture error response bodies from, e.g.\n * `[\"https://api.myapp.com\"]`. Same-origin requests are always captured.\n */\n responseBodyOrigins?: string[];\n}\n\n/**\n * Error response bodies are only read for endpoints the host app owns.\n *\n * A 422 from your own API echoes your own validation errors. A 422 from Stripe,\n * Auth0 or an analytics vendor echoes whatever *they* chose to put in it — dates\n * of birth, phone numbers, addresses — under field names no key-based redactor\n * can anticipate. That body would end up in a GitHub issue. Same-origin is the\n * line that separates \"our error shape\" from \"someone else's payload\"; anything\n * beyond it has to be named explicitly.\n */\nfunction mayCaptureBody(url: string): boolean {\n try {\n if (typeof window === \"undefined\") return false;\n const origin = new URL(url, window.location.href).origin;\n if (origin === window.location.origin) return true;\n return responseBodyOrigins.includes(origin);\n } catch {\n return false;\n }\n}\n\nexport function initBreadcrumbs(max?: number, options?: BreadcrumbOptions) {\n // Applied before the early return so a later provider can widen the allowlist\n // even though the interceptors are only installed once.\n if (options?.responseBodyOrigins?.length) {\n responseBodyOrigins = Array.from(\n new Set([...responseBodyOrigins, ...options.responseBodyOrigins])\n );\n }\n if (initialized) return;\n maxBreadcrumbs = max ?? MAX_DEFAULT;\n\n try {\n if (typeof window === \"undefined\") return;\n interceptConsole();\n interceptFetch();\n interceptXhr();\n interceptNavigation();\n interceptClicks();\n initialized = true;\n } catch {\n // Never crash\n }\n}\n\nexport function addBreadcrumb(\n type: BreadcrumbType,\n message: string,\n data?: Record<string, string>\n) {\n try {\n breadcrumbs.push({\n type,\n message: message.slice(0, 200),\n timestamp: new Date().toISOString(),\n data,\n });\n if (breadcrumbs.length > maxBreadcrumbs) {\n breadcrumbs = breadcrumbs.slice(-maxBreadcrumbs);\n }\n } catch {\n // Never crash\n }\n}\n\nexport function getBreadcrumbs(): Breadcrumb[] {\n return [...breadcrumbs];\n}\n\nexport function clearBreadcrumbs() {\n breadcrumbs = [];\n}\n\n/** Test-only — reset the cross-origin body allowlist. */\nexport function clearResponseBodyOrigins() {\n responseBodyOrigins = [];\n}\n\n// ─── Console Interception ────────────────────────────────\n\nfunction interceptConsole() {\n const origLog = console.log;\n const origWarn = console.warn;\n const origError = console.error;\n\n console.log = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[log] ${argsToString(args)}`);\n origLog.apply(console, args);\n };\n\n console.warn = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[warn] ${argsToString(args)}`);\n origWarn.apply(console, args);\n };\n\n console.error = function (...args: unknown[]) {\n addBreadcrumb(\"console\", `[error] ${argsToString(args)}`);\n origError.apply(console, args);\n };\n}\n\n/** Longest text a console breadcrumb keeps. */\nconst CONSOLE_TEXT_MAX = 200;\n\nfunction argsToString(args: unknown[]): string {\n try {\n return args\n .map((a) => {\n if (typeof a === \"string\") return a.slice(0, CONSOLE_TEXT_MAX);\n if (a instanceof Error) return a.message;\n try {\n return previewJson(a, CONSOLE_TEXT_MAX);\n } catch {\n return String(a);\n }\n })\n .join(\" \")\n .slice(0, CONSOLE_TEXT_MAX);\n } catch {\n return \"[unknown]\";\n }\n}\n\n/**\n * `JSON.stringify`, but it stops writing once the output passes `max`.\n *\n * Every console call in the host app runs through here, on the host's own\n * thread. `JSON.stringify` cannot stop early, so logging a 5,000-row array — or\n * a DOM node, whose React fiber links back into the whole tree — serialised all\n * of it to keep 200 characters (#363). For plain data the output is identical\n * to `JSON.stringify` up to the cut; a cycle is written as \"[Circular]\" instead\n * of throwing.\n */\nexport function previewJson(value: unknown, max: number): string {\n let out = \"\";\n const path = new WeakSet<object>();\n\n const write = (input: unknown, inArray: boolean): void => {\n if (out.length > max) return;\n let v = input;\n if (v !== null && typeof v === \"object\" && typeof (v as { toJSON?: unknown }).toJSON === \"function\") {\n v = (v as { toJSON: () => unknown }).toJSON();\n }\n if (v === null) {\n out += \"null\";\n return;\n }\n switch (typeof v) {\n case \"string\":\n out += JSON.stringify(v.length > max ? v.slice(0, max) : v);\n return;\n case \"number\":\n out += Number.isFinite(v) ? String(v) : \"null\";\n return;\n case \"boolean\":\n case \"bigint\":\n out += String(v);\n return;\n case \"object\":\n break;\n default:\n // undefined, functions and symbols: dropped from objects, null in arrays.\n if (inArray) out += \"null\";\n return;\n }\n\n const obj = v as object;\n if (path.has(obj)) {\n out += '\"[Circular]\"';\n return;\n }\n path.add(obj);\n if (Array.isArray(obj)) {\n out += \"[\";\n for (let i = 0; i < obj.length && out.length <= max; i++) {\n if (i > 0) out += \",\";\n write(obj[i], true);\n }\n out += \"]\";\n } else {\n out += \"{\";\n let first = true;\n for (const key in obj) {\n if (out.length > max) break;\n if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;\n const child = (obj as Record<string, unknown>)[key];\n if (child === undefined || typeof child === \"function\" || typeof child === \"symbol\") continue;\n out += `${first ? \"\" : \",\"}${JSON.stringify(key)}:`;\n first = false;\n write(child, false);\n }\n out += \"}\";\n }\n // Only a cycle is circular — the same object twice in one value is not.\n path.delete(obj);\n };\n\n write(value, false);\n return out;\n}\n\n// ─── HTTP Interception ───────────────────────────────────\n\n/**\n * Read the body of a failed response without consuming it. `clone()` is what\n * makes this safe — the app still gets an unread body. Only non-2xx responses\n * are read: a \"→ 500\" with no cause is not worth the breadcrumb it's written on,\n * but cloning every successful response would double-buffer real traffic.\n */\nasync function readErrorBody(response: Response, url: string): Promise<string> {\n try {\n if (response.ok) return \"\";\n if (!mayCaptureBody(url)) return \"\";\n const text = await response.clone().text();\n return redactBody(text);\n } catch {\n return \"\";\n }\n}\n\nfunction interceptFetch() {\n const origFetch = window.fetch;\n\n (window.fetch as (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>) = async function (input, init) {\n const url =\n typeof input === \"string\"\n ? input\n : input instanceof URL\n ? input.toString()\n : input instanceof Request\n ? input.url\n : String(input);\n const method = init?.method ?? \"GET\";\n const start = Date.now();\n\n try {\n const response = await origFetch(\n input as Parameters<typeof origFetch>[0],\n init,\n );\n const body = await readErrorBody(response, url);\n addBreadcrumb(\"api\", `${method} ${url.slice(0, 100)} → ${response.status}`, {\n method,\n status: String(response.status),\n duration: `${Date.now() - start}ms`,\n ...(body ? { responseBody: body } : {}),\n });\n return response;\n } catch (err) {\n addBreadcrumb(\"api\", `${method} ${url.slice(0, 100)} → FAILED`, {\n method,\n error: err instanceof Error ? err.message : \"unknown\",\n duration: `${Date.now() - start}ms`,\n });\n throw err;\n }\n };\n}\n\n/**\n * axios, and every library built on it, uses XMLHttpRequest in the browser — not\n * fetch. Without this patch an axios-based app records zero API breadcrumbs and\n * every report arrives with no idea which request preceded the crash.\n */\nfunction interceptXhr() {\n if (typeof XMLHttpRequest === \"undefined\") return;\n\n const origOpen = XMLHttpRequest.prototype.open;\n const origSend = XMLHttpRequest.prototype.send;\n\n interface TrackedXhr extends XMLHttpRequest {\n __ggMethod?: string;\n __ggUrl?: string;\n __ggStart?: number;\n __ggListening?: boolean;\n }\n\n // The listener is attached on open(), not send(): open() is where the method\n // and URL become known, and an XHR that is opened and then aborted before send\n // still deserves the breadcrumb.\n //\n // XHR objects are reusable — open/send/open/send on one instance is legal, and\n // a library may call open() twice before sending. Attaching per open() would\n // leave a stale listener that fires on the *next* request's loadend and writes\n // a breadcrumb with the previous method and URL. One listener per instance,\n // reading __ggMethod/__ggUrl live, avoids that: it always describes the request\n // that actually just finished.\n XMLHttpRequest.prototype.open = function (\n this: TrackedXhr,\n method: string,\n url: string | URL,\n ...rest: unknown[]\n ) {\n try {\n this.__ggMethod = method;\n this.__ggUrl = typeof url === \"string\" ? url : url.toString();\n\n const record = () => {\n try {\n const recordedMethod = this.__ggMethod ?? \"GET\";\n const recordedUrl = (this.__ggUrl ?? \"\").slice(0, 100);\n const duration = `${Date.now() - (this.__ggStart ?? Date.now())}ms`;\n\n // status 0 means the request never completed — offline, CORS, aborted.\n if (!this.status) {\n addBreadcrumb(\"api\", `${recordedMethod} ${recordedUrl} → FAILED`, {\n method: recordedMethod,\n duration,\n });\n return;\n }\n\n const failed = this.status < 200 || this.status >= 300;\n const body = failed && mayCaptureBody(this.__ggUrl ?? \"\") ? readXhrBody(this) : \"\";\n addBreadcrumb(\"api\", `${recordedMethod} ${recordedUrl} → ${this.status}`, {\n method: recordedMethod,\n status: String(this.status),\n duration,\n ...(body ? { responseBody: body } : {}),\n });\n } catch {\n // Never crash\n }\n };\n\n if (!this.__ggListening) {\n this.__ggListening = true;\n this.addEventListener(\"loadend\", record);\n }\n } catch {\n // Never crash\n }\n return (origOpen as unknown as (...args: unknown[]) => void).apply(this, [\n method,\n url,\n ...rest,\n ]);\n } as typeof XMLHttpRequest.prototype.open;\n\n XMLHttpRequest.prototype.send = function (this: TrackedXhr, ...args: unknown[]) {\n try {\n this.__ggStart = Date.now();\n } catch {\n // Never crash\n }\n return (origSend as unknown as (...args: unknown[]) => void).apply(this, args);\n } as typeof XMLHttpRequest.prototype.send;\n}\n\n/**\n * `responseText` throws on a `responseType` of \"blob\"/\"arraybuffer\"/\"json\" —\n * reading it defensively keeps a binary download from breaking the breadcrumb.\n */\nfunction readXhrBody(xhr: XMLHttpRequest): string {\n try {\n if (xhr.responseType && xhr.responseType !== \"text\" && xhr.responseType !== \"json\") return \"\";\n const raw = xhr.responseType === \"json\" ? JSON.stringify(xhr.response) : xhr.responseText;\n return raw ? redactBody(raw) : \"\";\n } catch {\n return \"\";\n }\n}\n\n// ─── Navigation Interception ─────────────────────────────\n\nfunction interceptNavigation() {\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n\n history.pushState = function (...args) {\n origPush(...args);\n addBreadcrumb(\"navigation\", `Navigate to ${window.location.pathname}`);\n };\n\n history.replaceState = function (...args) {\n origReplace(...args);\n addBreadcrumb(\"navigation\", `Replace to ${window.location.pathname}`);\n };\n\n window.addEventListener(\"popstate\", () => {\n addBreadcrumb(\"navigation\", `Back/Forward to ${window.location.pathname}`);\n });\n}\n\n// ─── Click Interception ──────────────────────────────────\n\n/** Longest label a click breadcrumb keeps. */\nconst CLICK_TEXT_MAX = 50;\n\n/** Text nodes read before giving up on finding `max` visible characters. */\nconst CLICK_TEXT_NODE_LIMIT = 500;\n\n/**\n * The first `max` characters of an element's text, without building all of it.\n *\n * A click lands on whatever is under the pointer — often a table row, a card\n * grid or a layout wrapper. `textContent` on that joins every text node below\n * it, so each click in a long list built a string of the entire list to keep\n * 50 characters of it, inside the click itself (#363).\n */\nexport function leadingText(el: Node, max: number): string {\n let text = \"\";\n let visited = 0;\n const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);\n while (\n text.trimStart().length < max &&\n visited++ < CLICK_TEXT_NODE_LIMIT &&\n walker.nextNode()\n ) {\n text += walker.currentNode.nodeValue ?? \"\";\n }\n return text.trim().slice(0, max);\n}\n\nfunction interceptClicks() {\n document.addEventListener(\n \"click\",\n (e) => {\n try {\n const target = e.target as HTMLElement;\n const tag = target.tagName?.toLowerCase();\n const text = target instanceof Node ? leadingText(target, CLICK_TEXT_MAX) : \"\";\n const id = target.id ? `#${target.id}` : \"\";\n const cls = target.className && typeof target.className === \"string\"\n ? `.${target.className.split(\" \")[0]}`\n : \"\";\n\n addBreadcrumb(\"click\", `Click ${tag}${id}${cls} \"${text}\"`);\n } catch {\n // Never crash\n }\n },\n { capture: true }\n );\n}\n","import type { RuntimeInfo } from \"./types\";\n\n/**\n * Runtime health at the moment of the crash. `deviceInfo` says what the machine\n * is; this says what shape it was in — a leak that ran the heap to its ceiling,\n * a 2G connection that starved a fetch, a bug that only shows up after ten\n * minutes on the page or on the fifth error in a row.\n */\n\nconst pageLoadedAt = Date.now();\nlet errorCount = 0;\n\n/** Bumped by every auto-captured error so a report says which one in the run it was. */\nexport function incrementErrorCount(): number {\n errorCount += 1;\n return errorCount;\n}\n\n/** Test-only — reset the per-session counter. */\nexport function resetErrorCount(): void {\n errorCount = 0;\n}\n\ninterface MemoryCapableWindow {\n memory?: { usedJSHeapSize?: number; jsHeapSizeLimit?: number };\n}\n\ninterface NetworkInformation {\n effectiveType?: string;\n downlink?: number;\n rtt?: number;\n saveData?: boolean;\n}\n\nconst toMb = (bytes: number | undefined): number | undefined =>\n typeof bytes === \"number\" ? Math.round((bytes / 1048576) * 10) / 10 : undefined;\n\nexport function captureRuntimeInfo(): RuntimeInfo | null {\n try {\n if (typeof window === \"undefined\") return null;\n\n // Chromium-only, and absent entirely under cross-origin isolation.\n const memory = (performance as unknown as MemoryCapableWindow)?.memory;\n // Chromium + Android only.\n const connection = (navigator as unknown as { connection?: NetworkInformation })?.connection;\n\n return {\n timeOnPageMs: Date.now() - pageLoadedAt,\n errorCount,\n visibility: typeof document !== \"undefined\" ? document.visibilityState : \"unknown\",\n ...(memory\n ? {\n jsHeapUsedMb: toMb(memory.usedJSHeapSize),\n jsHeapLimitMb: toMb(memory.jsHeapSizeLimit),\n }\n : {}),\n ...(connection\n ? {\n connectionType: connection.effectiveType,\n downlinkMbps: connection.downlink,\n rttMs: connection.rtt,\n saveData: connection.saveData,\n }\n : {}),\n };\n } catch {\n return null;\n }\n}\n","/**\n * App-owned context: key-values the host app attaches once and every report\n * carries thereafter — orgId, plan, role, active feature flags. The SDK cannot\n * guess these, and they are usually the difference between \"a crash\" and \"a\n * crash for enterprise tenants on the new billing flow\".\n *\n * Module-level, not React state, so it survives the provider unmount that\n * `global-error.tsx` causes and is readable from non-React call sites.\n */\n\nconst MAX_KEYS = 30;\nconst MAX_VALUE_LENGTH = 200;\n\nlet appContext: Record<string, string> = {};\nlet release: string | undefined;\n\nfunction coerce(value: unknown): string {\n if (typeof value === \"string\") return value.slice(0, MAX_VALUE_LENGTH);\n if (value === null || value === undefined) return \"\";\n try {\n return JSON.stringify(value).slice(0, MAX_VALUE_LENGTH);\n } catch {\n return String(value).slice(0, MAX_VALUE_LENGTH);\n }\n}\n\n/**\n * Attach one key-value to every future report. Passing `null`/`undefined`\n * removes the key — so a value that goes away (user logs out of an org) stops\n * being reported instead of going stale.\n */\nexport function setContext(key: string, value: unknown): void {\n try {\n if (!key) return;\n if (value === null || value === undefined) {\n delete appContext[key];\n return;\n }\n if (!(key in appContext) && Object.keys(appContext).length >= MAX_KEYS) return;\n appContext[key] = coerce(value);\n } catch {\n // Never crash the host app\n }\n}\n\n/** Set several keys at once. Merges — it does not replace what's already set. */\nexport function setContexts(values: Record<string, unknown>): void {\n try {\n for (const [key, value] of Object.entries(values ?? {})) setContext(key, value);\n } catch {\n // Never crash the host app\n }\n}\n\nexport function getAppContext(): Record<string, string> {\n return { ...appContext };\n}\n\nexport function clearAppContext(): void {\n appContext = {};\n}\n\n/**\n * The build this crash came from. Explicit `release` prop wins; otherwise the\n * standard Vercel/Next build env vars, which bundlers inline at build time.\n */\nexport function setRelease(value: string | undefined): void {\n if (value) release = value;\n}\n\nexport function getRelease(): string | undefined {\n if (release) return release;\n try {\n const fromEnv =\n process.env.NEXT_PUBLIC_APP_VERSION ||\n process.env.NEXT_PUBLIC_RELEASE ||\n process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA;\n return fromEnv || undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Test-only — reset release resolution between cases. */\nexport function clearRelease(): void {\n release = undefined;\n}\n","import type {\n CapturedContext,\n DeviceInfo,\n FeedbackPayload,\n FeedbackResult,\n ReportPayload,\n ReportResult,\n} from \"./types\";\n// The React-free subpath: utils.ts is also bundled into `glitchgrab/server`.\nimport { assistOffline, toAssistTurnResult } from \"@glitchgrab/report-ui/assist-response\";\nimport type { AssistTurnResult } from \"@glitchgrab/report-ui\";\nimport { getBreadcrumbs } from \"./breadcrumbs\";\nimport { captureRuntimeInfo } from \"./runtime\";\nimport { getAppContext, getRelease } from \"./app-context\";\n\nconst SENSITIVE_PARAMS = [\n \"token\", \"key\", \"secret\", \"password\", \"passwd\", \"auth\", \"authorization\",\n \"session\", \"sessionid\", \"session_id\", \"api_key\", \"apikey\", \"access_token\",\n \"refresh_token\", \"client_secret\", \"code\", \"state\", \"nonce\", \"credential\", \"private\",\n];\n\nexport function sanitizeUrl(url: string): string {\n try {\n const parsed = new URL(url);\n const params = new URLSearchParams(parsed.search);\n let modified = false;\n for (const key of Array.from(params.keys())) {\n if (SENSITIVE_PARAMS.some((s) => key.toLowerCase().includes(s))) {\n params.set(key, \"[REDACTED]\");\n modified = true;\n }\n }\n if (modified) parsed.search = params.toString();\n return parsed.toString();\n } catch {\n return url.split(\"?\")[0] ?? url;\n }\n}\n\nexport function captureDeviceInfo(): DeviceInfo | null {\n try {\n if (typeof window === \"undefined\") return null;\n return {\n screenWidth: screen.width,\n screenHeight: screen.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n platform: navigator.platform ?? \"unknown\",\n language: navigator.language ?? \"unknown\",\n online: navigator.onLine,\n colorScheme: window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\",\n devicePixelRatio: window.devicePixelRatio ?? 1,\n };\n } catch {\n return null;\n }\n}\n\nexport function captureContext(visitedPages: string[]): CapturedContext {\n try {\n return {\n url: sanitizeUrl(typeof window !== \"undefined\" ? window.location.href : \"\"),\n userAgent: typeof navigator !== \"undefined\" ? navigator.userAgent : \"\",\n timestamp: new Date().toISOString(),\n visitedPages: visitedPages.map(sanitizeUrl),\n breadcrumbs: getBreadcrumbs(),\n deviceInfo: captureDeviceInfo(),\n runtime: captureRuntimeInfo(),\n appContext: getAppContext(),\n release: getRelease(),\n };\n } catch {\n return {\n url: \"\",\n userAgent: \"\",\n timestamp: new Date().toISOString(),\n visitedPages: [],\n breadcrumbs: [],\n deviceInfo: null,\n runtime: null,\n appContext: {},\n };\n }\n}\n\n/**\n * Metadata every report carries regardless of how it was raised — release,\n * runtime health, and the host app's own context. One builder so a user-filed\n * report and an auto-captured crash describe the same world; the payload sites\n * only add what is specific to them.\n *\n * App context is prefixed so a key named `timestamp` or `status` can't quietly\n * overwrite a field the dashboard relies on.\n */\nexport function contextMetadata(context: CapturedContext): Record<string, string> {\n try {\n const runtime = context.runtime;\n const appContext = Object.entries(context.appContext ?? {}).reduce<Record<string, string>>(\n (acc, [key, value]) => {\n acc[`ctx_${key}`] = value;\n return acc;\n },\n {}\n );\n\n return {\n ...(context.release ? { release: context.release } : {}),\n ...(runtime\n ? {\n timeOnPageMs: String(runtime.timeOnPageMs),\n errorCount: String(runtime.errorCount),\n visibility: runtime.visibility,\n ...(runtime.jsHeapUsedMb !== undefined\n ? { jsHeapUsedMb: String(runtime.jsHeapUsedMb) }\n : {}),\n ...(runtime.jsHeapLimitMb !== undefined\n ? { jsHeapLimitMb: String(runtime.jsHeapLimitMb) }\n : {}),\n ...(runtime.connectionType ? { connectionType: runtime.connectionType } : {}),\n ...(runtime.downlinkMbps !== undefined\n ? { downlinkMbps: String(runtime.downlinkMbps) }\n : {}),\n ...(runtime.rttMs !== undefined ? { rttMs: String(runtime.rttMs) } : {}),\n ...(runtime.saveData !== undefined ? { saveData: String(runtime.saveData) } : {}),\n }\n : {}),\n ...appContext,\n };\n } catch {\n return {};\n }\n}\n\nexport const DEFAULT_BASE_URL = \"https://glitchgrab.dev\";\nconst MAX_RETRIES = 3;\nconst RETRY_BASE_MS = 500;\n\n/**\n * Send a report and return the result.\n * Never throws — returns null on failure.\n */\nexport async function sendReport(\n payload: ReportPayload,\n baseUrl?: string\n): Promise<ReportResult | null> {\n try {\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/sdk/report`;\n const body = JSON.stringify(payload);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${payload.token}`,\n };\n\n // keepalive has a 64KB body limit in browsers — skip it for large payloads (e.g., screenshots)\n const useKeepalive = body.length < 60_000;\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n ...(useKeepalive ? { keepalive: true } : {}),\n });\n\n if (response.ok) {\n const envelope = (await response.json()) as {\n success: boolean;\n data?: Omit<ReportResult, \"success\">;\n };\n return { success: envelope.success, ...(envelope.data ?? {}) };\n }\n\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return null;\n }\n } catch {\n // Will retry\n }\n\n if (attempt < MAX_RETRIES - 1) {\n await new Promise((resolve) =>\n setTimeout(resolve, RETRY_BASE_MS * Math.pow(2, attempt))\n );\n }\n }\n\n // Fallback: sendBeacon (fire-and-forget, no result)\n if (typeof navigator !== \"undefined\" && navigator.sendBeacon) {\n try {\n navigator.sendBeacon(url, new Blob([body], { type: \"application/json\" }));\n } catch {\n // Silently fail\n }\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Save a star rating your end-user left about your app.\n * Never throws — returns null on failure.\n *\n * Unlike `sendReport`, this is always a deliberate user action with a dialog\n * open in front of them, so it retries on transient failure but skips the\n * sendBeacon fallback: the caller needs a real result to show a thank-you.\n */\nexport async function sendFeedback(\n payload: FeedbackPayload,\n baseUrl?: string\n): Promise<FeedbackResult | null> {\n try {\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/sdk/feedback`;\n const body = JSON.stringify(payload);\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${payload.token}`,\n },\n body,\n });\n\n if (response.ok) {\n const envelope = (await response.json()) as {\n success: boolean;\n data?: Omit<FeedbackResult, \"success\">;\n };\n return { success: envelope.success, ...(envelope.data ?? {}) };\n }\n\n // 4xx other than rate limiting is a caller mistake — retrying won't help.\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return null;\n }\n } catch {\n // Will retry\n }\n\n if (attempt < MAX_RETRIES - 1) {\n await new Promise((resolve) =>\n setTimeout(resolve, RETRY_BASE_MS * Math.pow(2, attempt))\n );\n }\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\nexport interface EnhanceContext {\n url?: string;\n visitedPages?: string[];\n breadcrumbs?: Array<{ type: string; message: string }>;\n}\n\n/**\n * The signed-in user as the host's server vouched for them (`signSession`).\n *\n * Rides in the request BODY, never a header: every token route sets its own\n * CORS allow-list of headers, so a new header would fail preflight on all of\n * them. Omitted entirely when there is no signature — an unsigned id proves\n * nothing, and the server reads its absence as \"unsigned\".\n */\nexport interface SignedIdentity {\n userId?: string | null;\n signature?: string | null;\n}\n\n/** `{ userId, signature }` to spread into a JSON body, or nothing. */\nexport function signedFields(identity?: SignedIdentity | null): { userId?: string; signature?: string } {\n if (!identity?.signature || !identity.userId) return {};\n return { userId: identity.userId, signature: identity.signature };\n}\n\n/**\n * Polish raw description text via the Glitchgrab AI enhance endpoint.\n * Returns the polished text on success, or the original text on any failure.\n * Never throws.\n */\nexport async function enhanceText(\n text: string,\n token: string,\n baseUrl?: string,\n screenshot?: string | null,\n context?: EnhanceContext | null,\n identity?: SignedIdentity | null\n): Promise<string> {\n try {\n const trimmed = text.trim();\n if (!trimmed) return text;\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/ai/enhance-text`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n text: trimmed,\n ...(screenshot ? { screenshot } : {}),\n ...(context ? { context } : {}),\n ...signedFields(identity),\n }),\n });\n if (!response.ok) return text;\n const envelope = (await response.json()) as {\n success: boolean;\n data?: { text?: string };\n };\n if (envelope?.success && typeof envelope.data?.text === \"string\") {\n return envelope.data.text;\n }\n return text;\n } catch {\n return text;\n }\n}\n\n/**\n * \"Is this already filed?\" for the report dialog's plain form. Asked when Send\n * is pressed; a match lets the reporter add to the open issue instead of\n * opening a second one.\n *\n * `[]` when the project has it off, `null` on any failure — the dialog sends\n * straight away on either. Never throws.\n */\nexport async function findSimilarIssues(\n description: string,\n token: string,\n baseUrl?: string,\n identity?: SignedIdentity | null\n): Promise<{ number: number; title: string; url: string; status?: string }[] | null> {\n try {\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/reports/similar`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ text: description, ...signedFields(identity) }),\n });\n const envelope = (await response.json().catch(() => null)) as {\n success?: boolean;\n data?: { enabled?: boolean; matches?: { number: number; title: string; url: string; status?: string }[] };\n } | null;\n if (!response.ok || !envelope?.success) return null;\n if (!envelope.data?.enabled) return [];\n return Array.isArray(envelope.data.matches) ? envelope.data.matches : [];\n } catch {\n return null;\n }\n}\n\n/**\n * One turn of the AI report assistant (#330).\n *\n * Same never-throw contract as everything else in the SDK: a failure comes back\n * as `degraded` and the dialog quietly falls back to the plain form. An\n * end-user of the host app must never see a Glitchgrab error, and must never be\n * blocked from filing a bug because a model was busy.\n */\nexport async function assistTurn(\n params: {\n messages: { role: \"user\" | \"assistant\"; content: string }[];\n conversationId: string | null;\n screenshot?: string | null;\n context?: Record<string, unknown> | null;\n /**\n * Who the host app says is logged in, from the provider's `session` prop.\n * Stored against the conversation so a chat and the report it produced\n * agree on who filed — one SDK token covers every end user of the host app,\n * so without this every stranger's chat looks like the same person.\n */\n reporter?: {\n key?: string | null;\n name?: string | null;\n email?: string | null;\n /** `signSession()` output for `key`; absent when the host did not sign. */\n signature?: string | null;\n };\n },\n token: string,\n baseUrl?: string\n): Promise<AssistTurnResult> {\n const offline = assistOffline();\n try {\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/ai/report-chat`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify(params),\n });\n // One mapping for every host (packages/report-ui/src/assist-response.ts):\n // the server's degrade reason passes through, and nothing the sheet renders\n // is dropped.\n return toAssistTurnResult(response.ok, await response.json().catch(() => null));\n } catch {\n return offline;\n }\n}\n\n/**\n * Send an audio Blob to the Glitchgrab STT proxy (which calls Sarvam).\n * Returns the transcript string, or \"\" on any failure. Never throws.\n */\nexport async function transcribeAudio(\n blob: Blob,\n token: string,\n baseUrl?: string,\n identity?: SignedIdentity | null\n): Promise<string> {\n try {\n if (blob.size === 0) return \"\";\n const url = `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/sdk/stt`;\n const form = new FormData();\n form.append(\"file\", blob, \"audio.webm\");\n const signed = signedFields(identity);\n if (signed.userId && signed.signature) {\n form.append(\"userId\", signed.userId);\n form.append(\"signature\", signed.signature);\n }\n const response = await fetch(url, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${token}` },\n body: form,\n });\n if (!response.ok) return \"\";\n const envelope = (await response.json()) as {\n success: boolean;\n data?: { transcript?: string };\n };\n if (envelope?.success && typeof envelope.data?.transcript === \"string\") {\n return envelope.data.transcript;\n }\n return \"\";\n } catch {\n return \"\";\n }\n}\n","const DEFAULT_WINDOW_MS = 5 * 60 * 1000;\nconst MAX_ENTRIES = 100;\n\nconst seen = new Map<string, number>();\n\nfunction hashString(input: string): string {\n let h1 = 0xdeadbeef ^ 0;\n let h2 = 0x41c6ce57 ^ 0;\n for (let i = 0; i < input.length; i++) {\n const ch = input.charCodeAt(i);\n h1 = Math.imul(h1 ^ ch, 2654435761);\n h2 = Math.imul(h2 ^ ch, 1597334677);\n }\n h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);\n h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);\n return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);\n}\n\nfunction topStackFrame(stack: string | undefined): string {\n if (!stack) return \"\";\n const lines = stack.split(\"\\n\");\n for (const line of lines) {\n const t = line.trim();\n if (t.startsWith(\"at \") || t.includes(\"@\")) {\n return t;\n }\n }\n return \"\";\n}\n\nfunction stripUrlQuery(url: string | undefined): string {\n if (!url) return \"\";\n try {\n const u = new URL(url);\n return `${u.origin}${u.pathname}`;\n } catch {\n const q = url.indexOf(\"?\");\n return q === -1 ? url : url.slice(0, q);\n }\n}\n\nexport function computeSignature(params: {\n errorMessage: string | undefined;\n pageUrl: string | undefined;\n errorStack?: string | undefined;\n /**\n * Next.js error digest. Production strips server-boundary errors to a generic\n * message with no useful stack, so without the digest every distinct server\n * crash on one page collapses into a single signature.\n */\n digest?: string | undefined;\n}): string {\n const msg = params.errorMessage?.trim() ?? \"\";\n const page = stripUrlQuery(params.pageUrl);\n const frame = topStackFrame(params.errorStack);\n const digest = params.digest?.trim() ?? \"\";\n return hashString(digest ? `${msg}|${page}|${frame}|${digest}` : `${msg}|${page}|${frame}`);\n}\n\nexport function shouldSkipDuplicate(\n signature: string,\n windowMs: number = DEFAULT_WINDOW_MS,\n now: number = Date.now()\n): boolean {\n const last = seen.get(signature);\n if (last !== undefined && now - last < windowMs) {\n return true;\n }\n seen.set(signature, now);\n\n if (seen.size > MAX_ENTRIES) {\n const cutoff = now - windowMs;\n for (const [sig, ts] of seen) {\n if (ts < cutoff) seen.delete(sig);\n }\n if (seen.size > MAX_ENTRIES) {\n const excess = seen.size - MAX_ENTRIES;\n const keys = Array.from(seen.keys()).slice(0, excess);\n for (const k of keys) seen.delete(k);\n }\n }\n return false;\n}\n\nexport function clearDedupCache(): void {\n seen.clear();\n}\n","import type {\n CaptureErrorOptions,\n GlitchgrabSession,\n ReportPayload,\n ReportResult,\n} from \"./types\";\nimport { captureContext, contextMetadata, sendReport } from \"./utils\";\nimport { computeSignature, shouldSkipDuplicate } from \"./dedup\";\nimport { incrementErrorCount } from \"./runtime\";\n\n/**\n * Config the provider publishes so `captureError` works from call sites that\n * cannot reach React context — most importantly `app/global-error.tsx`, which\n * replaces the root layout and therefore renders *outside* the provider tree.\n */\nexport interface CaptureConfig {\n token: string;\n baseUrl?: string;\n session?: GlitchgrabSession | null;\n ignoreErrors?: (string | RegExp)[];\n /**\n * Read the current visitedPages. A getter, not the array itself: `global-error.tsx`\n * unmounts the provider, and the next provider to mount allocates a fresh ref — a\n * captured array reference would go orphaned and report an empty history for exactly\n * the crashes this module exists to file.\n */\n getVisitedPages: () => string[];\n onError?: (error: Error) => void;\n onReportSent?: (result: ReportResult) => void;\n}\n\nlet config: CaptureConfig | null = null;\n\n/**\n * Called from the provider's render body (not an effect) so the config exists\n * before children render. A crash during a child's *initial* render unwinds to\n * the framework boundary before any effect commits — registering in an effect\n * would leave `captureError` unconfigured for exactly the case it exists for.\n *\n * Never cleared on unmount: `global-error.tsx` tears down the provider tree.\n */\nexport function registerCaptureConfig(next: CaptureConfig): void {\n config = next;\n}\n\n/** Test-only — reset the module registry between cases. */\nexport function clearCaptureConfig(): void {\n config = null;\n}\n\nexport function matchesIgnorePatterns(\n message: string,\n patterns: (string | RegExp)[] | undefined\n): boolean {\n if (!patterns || patterns.length === 0) return false;\n return patterns.some((pattern) =>\n pattern instanceof RegExp ? pattern.test(message) : message.includes(pattern)\n );\n}\n\nfunction sessionMetadata(session: GlitchgrabSession | null | undefined): Record<string, string> {\n return {\n ...(session?.userId ? { sessionUserId: session.userId } : {}),\n ...(session?.name ? { sessionUserName: String(session.name) } : {}),\n ...(session?.email ? { sessionUserEmail: String(session.email) } : {}),\n ...(session?.phone ? { sessionUserPhone: String(session.phone) } : {}),\n };\n}\n\n/**\n * Build an `SDK_AUTO` payload from an already-caught error, applying dedup.\n * Returns `null` when the error should not be sent (ignored or duplicate).\n */\nexport function buildCapturedErrorPayload(\n error: unknown,\n options: CaptureErrorOptions | undefined,\n cfg: CaptureConfig,\n capturedBy: string = \"captureError\"\n): ReportPayload | null {\n const err = error instanceof Error ? error : undefined;\n const errorMessage = err ? err.message : String(error);\n if (!errorMessage) return null;\n\n if (matchesIgnorePatterns(errorMessage, cfg.ignoreErrors)) return null;\n\n // Counted before the snapshot so the report says which error in the run it is —\n // \"errorCount: 7\" on a first-seen signature means six crashes already preceded it.\n incrementErrorCount();\n const context = captureContext(cfg.getVisitedPages());\n const digest =\n options?.digest ??\n (typeof (error as { digest?: unknown })?.digest === \"string\"\n ? (error as { digest: string }).digest\n : undefined);\n\n const sig = computeSignature({\n errorMessage,\n pageUrl: context.url,\n errorStack: err?.stack,\n digest,\n });\n if (shouldSkipDuplicate(sig)) return null;\n\n return {\n token: cfg.token,\n source: \"SDK_AUTO\",\n type: \"BUG\",\n errorMessage,\n errorStack: err?.stack,\n componentStack: options?.componentStack ?? undefined,\n pageUrl: context.url,\n userAgent: context.userAgent,\n breadcrumbs: context.breadcrumbs,\n deviceInfo: context.deviceInfo ?? undefined,\n metadata: {\n timestamp: context.timestamp,\n visitedPages: JSON.stringify(context.visitedPages),\n capturedBy,\n ...contextMetadata(context),\n ...(options?.boundary ? { boundary: options.boundary } : {}),\n ...(digest ? { digest } : {}),\n ...sessionMetadata(cfg.session),\n ...options?.metadata,\n },\n };\n}\n\n/**\n * Report an error your app already caught — a framework error boundary\n * (`app/error.tsx`, `app/global-error.tsx`, React Router `errorElement`, Remix\n * `ErrorBoundary`), a `componentDidCatch`, or a `try/catch` you want filed.\n *\n * These never reach `window.onerror`, so provider auto-capture cannot see them.\n *\n * Fire-and-forget. Never throws, never blocks the fallback UI render. No-ops if\n * no `GlitchgrabProvider` has rendered yet (nothing to authenticate with).\n *\n * @example\n * ```tsx\n * // app/global-error.tsx — renders outside the provider tree\n * \"use client\";\n * import { captureError } from \"glitchgrab\";\n *\n * export default function GlobalError({ error }: { error: Error & { digest?: string } }) {\n * useEffect(() => {\n * captureError(error, { digest: error.digest, boundary: \"next-global-error\" });\n * }, [error]);\n * return <html><body><p>Something went wrong</p></body></html>;\n * }\n * ```\n */\nexport function captureError(error: unknown, options?: CaptureErrorOptions): void {\n try {\n const cfg = config;\n if (!cfg?.token) return;\n\n const payload = buildCapturedErrorPayload(error, options, cfg);\n if (!payload) return;\n\n void sendReport(payload, cfg.baseUrl).then((result) => {\n if (result && cfg.onReportSent) cfg.onReportSent(result);\n });\n\n if (cfg.onError && error instanceof Error) cfg.onError(error);\n } catch {\n // Never crash the host app\n }\n}\n","\"use client\";\n\nimport {\n useState,\n useRef,\n useEffect,\n useMemo,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { AnnotationCanvas } from \"./annotation-canvas\";\nimport { AssistSheet } from \"./assist-sheet\";\nimport { GlitchgrabProblemPanel } from \"./glitchgrab-problem\";\nimport { getShortcutLabel } from \"./shortcut\";\nimport { getTypeLabel } from \"./labels\";\nimport { ATTACHMENT_ACCEPT } from \"./attachments\";\nimport { captureDefaultScreenshot, type CaptureOptions } from \"./capture\";\nimport { encodeImageFile } from \"./image-encode\";\nimport type {\n ReportType,\n ReportSeverity,\n DialogTile,\n ReportFn,\n FeedbackFn,\n EnhanceTextFn,\n AssistFn,\n FindSimilarIssuesFn,\n SimilarIssue,\n AttachKind,\n ReportReporter,\n GlitchgrabProblemFn,\n} from \"./types\";\nimport { SEVERITY_LEVELS, SEVERITY_LABELS } from \"./types\";\nimport { detectDark, detectHostAccent } from \"./host-theme\";\n\n/** Shown when Send is pressed on a bug report with no severity picked (#353). */\nconst SEVERITY_REQUIRED = \"Pick how bad it is before sending.\";\n\n/** How long Send waits for a page shot that is still being re-drawn (#363). */\nconst SHOT_WAIT_MS = 3000;\n\n/**\n * How long Send waits on \"is this already filed?\". Past this the report goes\n * out as a new issue — a slow GitHub list must never cost someone their report.\n */\nconst SIMILAR_WAIT_MS = 2500;\n\n/** More than three and the reporter stops reading and sends a new one anyway. */\nconst MAX_SIMILAR_SHOWN = 3;\n\n/** Inline spinner for a button waiting on the network. `gg-spin` lives in the dialog's style block. */\nfunction ButtonSpinner() {\n return (\n <span\n aria-hidden=\"true\"\n style={{\n display: \"inline-block\",\n width: \"11px\",\n height: \"11px\",\n marginRight: \"6px\",\n verticalAlign: \"-1px\",\n border: \"2px solid currentColor\",\n borderRightColor: \"transparent\",\n borderRadius: \"50%\",\n animation: \"gg-spin .7s linear infinite\",\n }}\n />\n );\n}\n\n/** First letters of the first two words — \"Naresh Bhosale\" → \"NB\". */\nfunction initialsOf(name: string): string {\n return name\n .trim()\n .split(/\\s+/)\n .slice(0, 2)\n .map((part) => part[0]?.toUpperCase() ?? \"\")\n .join(\"\");\n}\n\n/**\n * Who this report will be filed as. Anonymous is shown, never hidden — a\n * reporter who assumes they're signed in and isn't would otherwise file\n * something nobody can follow up on, and find out only when no one replies.\n */\nfunction ReporterChip({\n reporter,\n t,\n}: {\n reporter: ReportReporter | null | undefined;\n t: ReturnType<typeof getTheme>;\n}) {\n // An avatar URL that 404s, or one a host's CSP blocks, must not leave an empty\n // circle — fall back to the same initials/glyph as if none had been given.\n const [avatarFailed, setAvatarFailed] = useState(false);\n const avatarUrl = reporter?.avatarUrl || \"\";\n useEffect(() => {\n setAvatarFailed(false);\n }, [avatarUrl]);\n\n const name = reporter?.name?.trim() || \"\";\n const isAnonymous = !name;\n const initials = isAnonymous ? \"\" : initialsOf(name);\n // \"Anonymous\", not \"Not signed in\": `session` is optional in the SDK and many\n // report surfaces are public, so an unauthenticated reporter is a normal state,\n // not an error to flag on every single report.\n const label = isAnonymous ? \"Anonymous\" : name;\n const title = isAnonymous\n ? \"No reporter identity was passed to Glitchgrab — this report won't be attributed to anyone\"\n : [name, reporter?.email, reporter?.role].filter(Boolean).join(\" · \");\n const showAvatarImage = !!avatarUrl && !avatarFailed;\n\n return (\n <span\n title={title}\n style={{ display: \"flex\", alignItems: \"center\", gap: \"6px\", minWidth: 0 }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: \"18px\",\n height: \"18px\",\n flexShrink: 0,\n borderRadius: \"50%\",\n overflow: \"hidden\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"8px\",\n fontWeight: 700,\n letterSpacing: \"0.02em\",\n background: isAnonymous ? t.inputBg : t.accent,\n color: isAnonymous ? t.textMuted : t.accentText,\n border: `1px solid ${isAnonymous ? t.inputBorder : \"transparent\"}`,\n }}\n >\n {showAvatarImage ? (\n <img\n src={avatarUrl}\n alt=\"\"\n width={18}\n height={18}\n onError={() => setAvatarFailed(true)}\n style={{ width: \"100%\", height: \"100%\", objectFit: \"cover\" }}\n />\n ) : initials ? (\n initials\n ) : (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 16 16\" fill=\"none\">\n <circle cx=\"8\" cy=\"5.5\" r=\"2.75\" stroke=\"currentColor\" strokeWidth=\"1.4\" />\n <path\n d=\"M2.75 13.5c0-2.35 2.35-3.75 5.25-3.75s5.25 1.4 5.25 3.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.4\"\n strokeLinecap=\"round\"\n />\n </svg>\n )}\n </span>\n <span\n style={{\n fontSize: \"11px\",\n color: t.textMuted,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {label}\n {reporter?.role ? ` · ${reporter.role}` : \"\"}\n </span>\n </span>\n );\n}\n\nfunction getTheme(dark: boolean) {\n const hostAccent = detectHostAccent();\n const defaults = dark\n ? {\n bg: \"#1c1c1e\",\n bgSecondary: \"#27272a\",\n border: \"#2c2c2e\",\n text: \"#fafafa\",\n textMuted: \"#a1a1aa\",\n accent: \"#22d3ee\",\n accentText: \"#09090b\",\n inputBg: \"#27272a\",\n inputBorder: \"#3f3f46\",\n }\n : {\n bg: \"#ffffff\",\n bgSecondary: \"#f4f4f5\",\n border: \"#e4e4e7\",\n text: \"#18181b\",\n textMuted: \"#71717a\",\n accent: \"#0891b2\",\n accentText: \"#ffffff\",\n inputBg: \"#fafafa\",\n inputBorder: \"#d4d4d8\",\n };\n\n if (hostAccent) {\n defaults.accent = hostAccent.accent;\n defaults.accentText = hostAccent.accentText;\n }\n\n return defaults;\n}\n\n/** Validate that report text is meaningful — rejects gibberish, throwaway words, random chars */\nfunction isLowQualityText(text: string): string | null {\n const trimmed = text.trim();\n if (!trimmed) return null;\n\n // Exact throwaway words\n const throwaway =\n /^(done|ok|yes|no|hi|hello|hey|test|testing|asdf|qwerty|abc|xyz|foo|bar|baz|lol|lmao|idk|bruh|nice|cool|wow|sup|yo|nah|yep|nope|thanks|thx|ty|k|kk|hmm|hm|na|mm|mhm|aight|bet|gg|wp|rip|omg|pls|plz)$/i;\n if (throwaway.test(trimmed)) {\n return \"Please describe the actual issue you're experiencing\";\n }\n\n // Repeated characters (aaaaaaa, !!!!!!!)\n if (/(.)\\1{4,}/.test(trimmed)) {\n return \"Please provide a meaningful description\";\n }\n\n const letters = trimmed.replace(/[^a-zA-Z]/g, \"\");\n if (letters.length >= 4) {\n // Very low vowel ratio (bkdfghjklmn...)\n const vowels = letters.replace(/[^aeiouAEIOU]/g, \"\").length;\n const vowelRatio = vowels / letters.length;\n if (vowelRatio < 0.08) {\n return \"That doesn't look like a valid description\";\n }\n\n // Keyboard mashing: single word with no real English pattern\n // Detects strings like \"asdfasfsdad\", \"jkljklfsdf\", \"qwertyuio\"\n // Real words have max 3-4 consecutive consonants; gibberish has long runs\n if (/[^aeiou\\s]{5,}/i.test(letters)) {\n const words = trimmed.split(/\\s+/);\n // Only flag if it's a single \"word\" — multi-word text is likely real\n if (words.length <= 2) {\n return \"That doesn't look like a valid description\";\n }\n }\n\n // Check if it looks like a random permutation of a few chars (asdfasfsdad)\n if (letters.length >= 6) {\n const uniqueChars = new Set(letters.toLowerCase()).size;\n const uniqueRatio = uniqueChars / letters.length;\n // Real English has ~0.6-0.9 unique ratio for short text; gibberish reuses few chars\n if (uniqueRatio < 0.4 && trimmed.split(/\\s+/).length <= 2) {\n return \"That doesn't look like a valid description\";\n }\n }\n }\n\n // Single short word that isn't a known tech term\n const words = trimmed.split(/\\s+/).filter((w) => w.length > 0);\n if (words.length === 1 && trimmed.length < 10) {\n const techTerms =\n /^(crash|error|bug|fail|broken|slow|freeze|lag|404|500|null|undefined|nan|timeout|overflow|leak|cors|oom)$/i;\n if (!techTerms.test(trimmed)) {\n return \"Please provide more detail about the issue\";\n }\n }\n\n return null;\n}\n\ninterface ReportDialogProps {\n report: ReportFn;\n /**\n * Saves a star rating. Passing it adds the `RATING` tile to step 1 — a\n * testimonial lives in the same dialog as a bug report because from the\n * user's side it's the same question (\"what's on your mind?\"), even though it\n * takes a completely different path server-side (feedback row, never a GitHub\n * issue). Omit it and the tile never appears.\n */\n sendFeedback?: FeedbackFn;\n enhanceText?: EnhanceTextFn;\n /**\n * Runs one turn of the AI report assistant (#330). Supplying it adds a\n * \"Describe it with AI\" affordance above the description box; omitting it\n * leaves the dialog exactly as it was. The assistant is an EXTRA mode, never\n * a replacement — the plain form stays present and usable throughout, and\n * the assistant closes itself the moment it cannot help.\n *\n * Hosts pass this only when the project has it switched on: the SDK reads\n * `aiAssist` off /api/v1/sdk/project. The server re-checks the same column on\n * every call, so this prop is a UI hint and not a permission.\n */\n assist?: AssistFn;\n /**\n * \"Is this already filed?\", asked when the plain form's Send is pressed. A\n * match shows \"Our team may already have this\" — pickable rows and \"Add to #N\" (the\n * report becomes a comment on that issue, through the same submit path the\n * assistant's duplicate uses) or \"No, mine is different\". No match, `null`, or\n * no answer within `SIMILAR_WAIT_MS` → sent exactly as before. Omit it and\n * Send never waits.\n *\n * Skipped when the assistant was used — it already checked open issues with\n * the reporter, and asking twice is the dialog arguing with itself.\n */\n findSimilarIssues?: FindSimilarIssuesFn;\n /**\n * Session facts handed to the assistant — page URL, pages visited, recent\n * clicks and API calls. The host owns this because only the host has it: the\n * SDK keeps breadcrumbs, the extension has the tab, GlitchRecord has neither.\n */\n assistContext?: Record<string, unknown> | null;\n transcribeAudio?: (blob: Blob) => Promise<string>;\n types?: ReportType[];\n showSeverity?: boolean;\n /**\n * Overrides how the initial/retake screenshot is captured. Defaults to\n * `captureDefaultScreenshot` (correct for the SDK, embedded in the host\n * page): the tab's real pixels on Chromium, html2canvas-pro over\n * `document.body` everywhere else — see `capture.ts`. It is called before\n * the dialog's first await, so the browser still sees the user's click.\n * Standalone hosts must inject their own — the current tab / `document.body`\n * there is the host's OWN tiny window, not the thing being reported:\n * - Chrome extension → `chrome.tabs.captureVisibleTab`\n * - GlitchRecord desktop → `webContents.capturePage` of the GlitchRecord\n * window the reporter was in (its Report Bug files GlitchRecord's own bugs)\n * Return `null` to open without a screenshot. The dialog opens when this\n * resolves, or earlier if it calls `options.onRedraw` — the default does on\n * its html2canvas path, then fills the strip when the re-draw lands (#363).\n */\n captureScreenshot?: (options?: CaptureOptions) => Promise<string | null>;\n /**\n * Who the report will be attributed to. Omit or pass `null` and the footer\n * says \"Not signed in\" rather than showing nothing — silence there reads as\n * \"you're signed in\", which is the failure worth preventing.\n */\n reporter?: ReportReporter | null;\n /**\n * Called when the dialog closes itself (the × or Escape).\n *\n * Hosts that mount this inside something of their own — the extension puts it\n * in a full-page iframe — otherwise have no way to know it is gone, and are\n * left with an invisible overlay still swallowing every click on the page.\n */\n onClose?: () => void;\n /**\n * Rendered at the top of step 1, inside the dialog.\n *\n * For hosts that must ask something the dialog itself knows nothing about —\n * the Chrome extension has to pick WHICH project a bug belongs to, because\n * unlike an SDK embedded in one app it could be reporting on anything. Left\n * outside, that question needed its own panel wrapped around this one, and\n * two stacked cards read as a bug in the bug reporter.\n */\n headerSlot?: ReactNode;\n /**\n * \"Problem with Glitchgrab?\" (#366). Supplying it swaps the footer's\n * \"Powered by Glitchgrab\" for a link, and adds the same link to the AI sheet,\n * both opening a small panel that files into Glitchgrab's own repo — never\n * the host's. The report underneath stays open and untouched.\n *\n * The SDK passes it only when the project owner switched it on; the Chrome\n * extension always does, because its reporters are Glitchgrab testers.\n */\n reportGlitchgrabProblem?: GlitchgrabProblemFn;\n /**\n * `\"modal\"` (default): the form is a centred card over the host page — the\n * SDK and the extension. `\"sheet\"`: the form is a right-side panel, like the\n * AI sheet, so the page being reported stays in view beside it — for a host\n * that opens the report over its own screen (GlitchRecord's Report Bug).\n */\n layout?: \"modal\" | \"sheet\";\n}\n\n/**\n * Recovery copy for every way the microphone can refuse to open.\n *\n * Every one of these ends with a way forward, because the field below still\n * accepts typing: a blocked mic must never read like a blocked report.\n */\nexport const MIC_MESSAGES = {\n blocked:\n \"Microphone is blocked for this site. Allow it in your browser's site settings, then reload this page. You can type your report instead.\",\n notFound:\n \"No microphone found. Connect one and try again, or type your report instead.\",\n inUse:\n \"Microphone is in use by another app. Close it and try again, or type your report instead.\",\n unusable:\n \"This microphone can't be used for recording. Pick another one in your system sound settings.\",\n insecure:\n \"Voice needs a secure (https) connection. Type your report instead.\",\n generic:\n \"Couldn't start the microphone. Try again, or type your report instead.\",\n} as const;\n\n/**\n * Turn a `getUserMedia` rejection into something the reporter can act on.\n *\n * \"Microphone access denied\" was a dead end: it is also what the browser says\n * when the origin holds a *persisted* block, and no code on this side can lift\n * that — only the user can, in site settings, and Chrome then needs a reload\n * before the new setting reaches the page. So the denied copy names both steps.\n *\n * Deliberately host-neutral. This dialog also renders inside the Chrome\n * extension and inside GlitchRecord, where \"the lock icon in the address bar\"\n * points at nothing.\n *\n * `null` means \"not a cause we recognise\" — the caller may still fall through\n * to Web Speech, which can succeed where the recorder stream did not.\n */\nexport const micErrorMessage = (err: unknown): string | null => {\n const name =\n typeof err === \"object\" && err !== null && \"name\" in err\n ? String((err as { name: unknown }).name)\n : \"\";\n switch (name) {\n case \"NotAllowedError\":\n case \"PermissionDeniedError\":\n case \"SecurityError\":\n return MIC_MESSAGES.blocked;\n case \"NotFoundError\":\n case \"DevicesNotFoundError\":\n return MIC_MESSAGES.notFound;\n case \"NotReadableError\":\n case \"TrackStartError\":\n return MIC_MESSAGES.inUse;\n case \"OverconstrainedError\":\n case \"ConstraintNotSatisfiedError\":\n return MIC_MESSAGES.unusable;\n default:\n return null;\n }\n};\n\n/**\n * The report dialog — rendered inside GlitchgrabProvider automatically.\n * Opens via the `glitchgrab:open-report` custom event (triggered by `openReportDialog()`).\n */\nexport function ReportDialog({\n report,\n sendFeedback,\n enhanceText,\n assist,\n findSimilarIssues,\n assistContext = null,\n transcribeAudio,\n types,\n showSeverity = true,\n captureScreenshot = captureDefaultScreenshot,\n reporter,\n onClose,\n headerSlot,\n reportGlitchgrabProblem,\n layout = \"modal\",\n}: ReportDialogProps) {\n const sheet = layout === \"sheet\";\n const [isEnhancing, setIsEnhancing] = useState(false);\n\n /**\n * AI assistant (#330). Closed until asked for, and one-way: once it degrades\n * or hands over a description it does not reopen itself. `assistNotice` is\n * why it went away, shown once under the box so the reporter is never left\n * wondering where the button went.\n */\n const [assistOpen, setAssistOpen] = useState(false);\n const [assistNotice, setAssistNotice] = useState<string | null>(null);\n const [assistUsed, setAssistUsed] = useState(false);\n /** Which surface opened the \"Problem with Glitchgrab?\" panel (#366); null = closed. */\n const [selfReportFrom, setSelfReportFrom] = useState<\"form\" | \"assist\" | null>(null);\n /** What the panel opens with — the reporter's chat words when the assistant offered it. */\n const [selfReportPrefill, setSelfReportPrefill] = useState(\"\");\n /**\n * Has anyone actually said what this report is?\n *\n * `reportType` has always defaulted to \"BUG\", which was fine while the tile\n * grid was the first thing anyone saw. Now that ⌘⇧G opens the assistant\n * first, that default would silently file a rating request as a bug — so the\n * sheet asks, and this is how it knows whether it still has to.\n */\n const [typeChosen, setTypeChosen] = useState(false);\n /**\n * The already-open issue the assistant matched this report to (#330\n * follow-up). Held here rather than in the sheet because `handleSubmit` is\n * the one submit path — the number rides in report metadata and the server\n * re-validates it, so a comment replaces the second identical issue.\n */\n const [duplicateIssueNumber, setDuplicateIssueNumber] = useState<number | null>(null);\n /**\n * Why it goes onto that issue: the SAME problem, or a different requirement\n * for the same feature the reporter chose to keep there (practise_stack #1868\n * beside #1867). Only `related` is sent — the server's comment then says it is\n * new work that closing the issue does not cover.\n */\n const [duplicateKind, setDuplicateKind] = useState<AttachKind>(\"duplicate\");\n /** The last report went on as a related request — the success line says so. */\n const [addedAsRelated, setAddedAsRelated] = useState(false);\n /**\n * What the plain form's duplicate check matched when Send was pressed.\n * Non-null swaps the Send button for the \"Our team may already have this\" card. `attachingTo` is\n * the choice now sending, so only that button spins.\n */\n const [similarIssues, setSimilarIssues] = useState<SimilarIssue[] | null>(null);\n const [checkingSimilar, setCheckingSimilar] = useState(false);\n const [attachingTo, setAttachingTo] = useState<number | \"new\" | null>(null);\n /** The row picked in that card. Starts on the best match — the button still names the number. */\n const [pickedSimilar, setPickedSimilar] = useState<number | null>(null);\n /** The open issue the last report was added to, for the success line. */\n const [addedToIssue, setAddedToIssue] = useState<number | null>(null);\n /**\n * The assistant chat that produced this description, if one did. Rides along\n * in metadata so the server can join the filed report back to the chat.\n */\n const [aiConversationId, setAiConversationId] = useState<string | null>(null);\n const [isEnhanced, setIsEnhanced] = useState(false);\n const [originalDescription, setOriginalDescription] = useState<string | null>(\n null,\n );\n const [isListening, setIsListening] = useState(false);\n const [isTranscribing, setIsTranscribing] = useState(false);\n const [voiceError, setVoiceError] = useState<string | null>(null);\n const [screenshotDragOver, setScreenshotDragOver] = useState(false);\n // Prevent hydration mismatch — render nothing until after hydration\n const [mounted, setMounted] = useState(false);\n useEffect(() => {\n setMounted(true);\n }, []);\n\n const [isOpen, setIsOpen] = useState(false);\n const [description, setDescription] = useState(\"\");\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n // Set when the server saved the report but could not file it yet — GitHub\n // refused access (status QUEUED). \"Bug sent\" would be a lie about an issue.\n const [queuedMessage, setQueuedMessage] = useState<string | null>(null);\n const [screenshots, setScreenshots] = useState<string[]>([]);\n /**\n * Which entry of `screenshots` this dialog captured itself on open. Anything\n * else was pasted or picked by the reporter, and the assistant is told so —\n * a WhatsApp screenshot pasted on the dashboard is about WhatsApp, not the\n * dashboard (#357). Matched by value, so removing or reordering is safe.\n */\n const [pageShot, setPageShot] = useState<string | null>(null);\n /**\n * The page shot is still being re-drawn (#363). The dialog no longer waits\n * for it: it opens at once, the strip shows a placeholder, and Send gives it\n * SHOT_WAIT_MS to make it in.\n */\n const [shotPending, setShotPending] = useState(false);\n const pendingShotRef = useRef<Promise<string | null> | null>(null);\n /**\n * Bumped on close. A capture that settles after its dialog closed carries a\n * stale number and is dropped — it belongs to a report nobody is writing.\n */\n const openGenRef = useRef(0);\n const [attachments, setAttachments] = useState<\n { name: string; size: number; dataUrl: string }[]\n >([]);\n const [previewIndex, setPreviewIndex] = useState<number | null>(null);\n const [annotatingIndex, setAnnotatingIndex] = useState<number | null>(null);\n // Lightbox zoom: false = fit to screen, true = 100% natural size with pan.\n const [previewZoomed, setPreviewZoomed] = useState(false);\n const [previewNatural, setPreviewNatural] = useState<{\n w: number;\n h: number;\n } | null>(null);\n const previewScrollRef = useRef<HTMLDivElement>(null);\n const previewImgElRef = useRef<HTMLImageElement>(null);\n const panRef = useRef<{\n x: number;\n y: number;\n left: number;\n top: number;\n moved: boolean;\n } | null>(null);\n // Fraction of the image the user clicked, so zooming in keeps that spot centred.\n const zoomAnchorRef = useRef<{ fx: number; fy: number } | null>(null);\n\n // Every preview opens fit-to-screen, so zoom state is reset alongside the\n // index rather than by an effect chasing it.\n const resetPreviewZoom = () => {\n setPreviewZoomed(false);\n setPreviewNatural(null);\n zoomAnchorRef.current = null;\n };\n const openPreview = (i: number) => {\n resetPreviewZoom();\n setPreviewIndex(i);\n };\n const closePreview = () => {\n resetPreviewZoom();\n setPreviewIndex(null);\n };\n const fileInputRef = useRef<HTMLInputElement>(null);\n const modalRef = useRef<HTMLDivElement>(null);\n const previewImgRef = useRef<HTMLDivElement>(null);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const recognitionRef = useRef<any>(null);\n const voiceBaseRef = useRef(\"\");\n const usingWebSpeechRef = useRef(false);\n const textBeforeVoiceRef = useRef(\"\");\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const streamRef = useRef<MediaStream | null>(null);\n const sarvamChunksRef = useRef<Blob[]>([]);\n const spaceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const isPushToTalkRef = useRef(false);\n // Edits seen since the space that armed push-to-talk. The space itself lands\n // as one native change; a second means the user is still typing, not holding.\n const spaceEditsRef = useRef(0);\n // Live mirror of `description` for the voice callbacks, which fire outside\n // React's render and would otherwise read the value captured when listening\n // started — see `rebaseVoiceOnUserEdits`.\n const descriptionRef = useRef(\"\");\n // The exact text voice last wrote into the field. Anything else in there is\n // the user's own typing.\n const lastVoiceTextRef = useRef<string | null>(null);\n // Did this run get a live Web Speech preview? Decides whether the Sarvam\n // result replaces text on screen or defers to it.\n const hadWebSpeechRef = useRef(false);\n\n // A host focus trap — Radix `FocusScope` inside a Dialog, DropdownMenu, Select,\n // or any other library doing the same — keeps document-level `focusin`/`focusout`\n // listeners that yank focus straight back into its own container. While one is\n // live, GlitchGrab's textarea is unusable: clicks land, but typing and\n // drag-select do nothing, because focus never stays where the user put it.\n //\n // `inert` is the counter: focusing *into* an inert subtree is a no-op, so the\n // trap's grab fails silently instead of fighting us for the caret. Re-applied\n // by a MutationObserver rather than snapshotted once at open — a host layer\n // that mounts after GlitchGrab (a prompt fired by a late query, a menu still\n // mounted through its close animation) would otherwise keep its trap.\n useEffect(() => {\n if (!isOpen) return;\n\n const HOST_LAYERS =\n '[role=\"dialog\"],[role=\"alertdialog\"],[role=\"menu\"],[role=\"listbox\"]';\n // Only the ones *we* set inert get it removed again on cleanup — a host that\n // was already inert must stay that way.\n const inerted = new Set<HTMLElement>();\n\n const applyInert = () => {\n document.querySelectorAll<HTMLElement>(HOST_LAYERS).forEach((el) => {\n // Our own layers, and anything wrapping them, must stay interactive.\n if (el.closest(\"[data-glitchgrab-layer]\")) return;\n if (el.querySelector(\"[data-glitchgrab-layer]\")) return;\n if (inerted.has(el) || el.hasAttribute(\"inert\")) return;\n el.setAttribute(\"inert\", \"\");\n inerted.add(el);\n });\n };\n\n applyInert();\n\n const observer = new MutationObserver((mutations) => {\n // Attribute-only churn (a `data-state` flip, a class swap) can't introduce a\n // layer we haven't seen, so skip the query unless nodes actually moved.\n const structural = mutations.some(\n (m) => m.addedNodes.length > 0 || m.removedNodes.length > 0,\n );\n if (structural) applyInert();\n });\n observer.observe(document.body, { childList: true, subtree: true });\n\n return () => {\n observer.disconnect();\n inerted.forEach((el) => el.removeAttribute(\"inert\"));\n };\n }, [isOpen]);\n\n // Stepper state\n const [step, setStep] = useState<1 | 2>(1);\n const [reportType, setReportType] = useState<DialogTile>(\"BUG\");\n /**\n * `null` until the reporter picks. It used to default to \"medium\", which put\n * a lit-up button on screen that nobody had chosen — so every report arrived\n * `severity:medium` and the field told triage nothing (#353).\n */\n const [severity, setSeverity] = useState<ReportSeverity | null>(null);\n const [validationError, setValidationError] = useState<string | null>(null);\n const [placeholderIdx, setPlaceholderIdx] = useState(0);\n /** 0 = nothing picked yet. Only meaningful while the RATING tile is selected. */\n const [rating, setRating] = useState(0);\n const [hoveredStar, setHoveredStar] = useState(0);\n\n const isRating = reportType === \"RATING\";\n\n // A rating is gated on the stars, not the words — the message is optional.\n const submitDisabled = isSubmitting || (isRating ? rating < 1 : !description.trim());\n\n /**\n * The picker turns red only after a send was actually refused for it — an\n * untouched form that already looks like an error trains people to ignore it.\n */\n const needsSeverity =\n validationError === SEVERITY_REQUIRED &&\n showSeverity &&\n reportType === \"BUG\" &&\n !severity;\n\n // RATING is deliberately NOT a tile: it gets the hero row above the grid, so\n // the stars are one click away instead of three, and its icon can't be\n // confused with Feature Request's star.\n // OTHER is gone from the default set: the rating hero is now the home for\n // \"general feedback\", and the two side by side asked the same question twice.\n // Hosts that still want it can pass it explicitly via `types`.\n const availableTypes: DialogTile[] = types ?? [\n \"BUG\",\n \"FEATURE_REQUEST\",\n \"UI_IMPROVEMENT\",\n \"PERFORMANCE\",\n \"SECURITY\",\n \"QUESTION\",\n ];\n\n const tileGridRef = useRef<HTMLDivElement>(null);\n\n /**\n * Step-1 shortcuts. Digits 1–5 set the rating and go straight to the message\n * box; letters jump to the tile they start with (b=bug, f=feature, u=ui,\n * p=performance, s=security, q=question).\n *\n * Digits are the rating rather than the tiles because the two would collide,\n * and the hero is the primary action — tiles are still one keystroke away by\n * letter, plus arrows and Tab.\n */\n useEffect(() => {\n if (!isOpen || step !== 1) return;\n const onKey = (e: KeyboardEvent) => {\n // Never hijack a key someone is typing into a field.\n const el = e.target as HTMLElement | null;\n const tag = el?.tagName;\n if (tag === \"INPUT\" || tag === \"TEXTAREA\" || el?.isContentEditable) return;\n if (e.metaKey || e.ctrlKey || e.altKey) return;\n\n if (sendFeedback && /^[1-5]$/.test(e.key)) {\n e.preventDefault();\n setRating(Number(e.key));\n setReportType(\"RATING\");\n setTypeChosen(true);\n setStep(2);\n return;\n }\n\n const letter = e.key.toLowerCase();\n if (!/^[a-z]$/.test(letter)) return;\n const match = availableTypes.find(\n (type) => getTypeLabel(type).toLowerCase().startsWith(letter)\n );\n if (match) {\n e.preventDefault();\n setReportType(match);\n setTypeChosen(true);\n setStep(2);\n }\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n // `availableTypes` is rebuilt each render; its contents are what matter.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, step, sendFeedback, availableTypes.join(\",\")]);\n\n /**\n * Arrow keys walk the tile grid, so the whole picker works without a mouse.\n * Two columns, so up/down is ±2 and left/right is ±1; Enter and Space are\n * left to the buttons themselves.\n */\n const handleTileGridKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n const keys = [\"ArrowRight\", \"ArrowLeft\", \"ArrowDown\", \"ArrowUp\"];\n if (!keys.includes(e.key)) return;\n const tiles = Array.from(\n tileGridRef.current?.querySelectorAll<HTMLButtonElement>(\"button[data-gg-type]\") ?? []\n );\n if (tiles.length === 0) return;\n e.preventDefault();\n const current = tiles.indexOf(document.activeElement as HTMLButtonElement);\n const delta =\n e.key === \"ArrowRight\" ? 1 : e.key === \"ArrowLeft\" ? -1 : e.key === \"ArrowDown\" ? 2 : -2;\n // From \"nothing focused\", the first arrow press should land on the first\n // tile rather than jumping into the middle of the grid.\n const next = current === -1 ? 0 : Math.min(Math.max(current + delta, 0), tiles.length - 1);\n tiles[next]?.focus();\n };\n\n // Once per open. Computed-style reads force a style recalc on the host page,\n // and this used to run on every host re-render while the dialog sat closed.\n const isDark = useMemo(() => (isOpen ? detectDark() : true), [isOpen]);\n const t = getTheme(isDark);\n /** The slice of the theme the layers above the dialog (AI sheet, #366 panel) paint with. */\n const layerTheme = {\n bg: t.bg,\n bgSecondary: t.bgSecondary,\n border: t.border,\n text: t.text,\n textMuted: t.textMuted,\n inputBg: t.inputBg,\n inputBorder: t.inputBorder,\n accent: t.accent,\n accentText: t.accentText,\n };\n\n // Zooming only earns its place when the screenshot holds more pixels than the\n // fit-to-screen view can show.\n const canZoomPreview =\n previewNatural !== null &&\n typeof window !== \"undefined\" &&\n (previewNatural.w > window.innerWidth - 32 ||\n previewNatural.h > window.innerHeight - 80);\n\n const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {\n const files = e.target.files;\n if (!files || files.length === 0) return;\n addFiles(Array.from(files));\n e.target.value = \"\";\n };\n\n const addFiles = (files: File[]) => {\n // Images are held to the screenshot budget — a raw retina paste alone can\n // exceed the request-body limit. All in one update, in the order dropped.\n const images = files.filter((file) => file.type.startsWith(\"image/\"));\n if (images.length > 0) {\n void Promise.all(images.map((file) => encodeImageFile(file).catch(() => null))).then(\n (encoded) => {\n const added = encoded.filter((url): url is string => !!url);\n if (added.length > 0) setScreenshots((prev) => [...prev, ...added]);\n },\n );\n }\n files\n .filter((file) => !file.type.startsWith(\"image/\"))\n .forEach((file) => {\n const reader = new FileReader();\n reader.onload = () => {\n setAttachments((prev) => [\n ...prev,\n { name: file.name, size: file.size, dataUrl: reader.result as string },\n ]);\n };\n reader.readAsDataURL(file);\n });\n };\n\n const handleOpen = async () => {\n const gen = openGenRef.current;\n setSubmitted(false);\n // Belt to `handleClose`'s braces: every open starts on the form, never on a\n // preview or annotator left over from last time. Asserted here rather than\n // only on close so it holds however the dialog was dismissed.\n closePreview();\n setAnnotatingIndex(null);\n if (availableTypes.length === 1) {\n setReportType(availableTypes[0]);\n setTypeChosen(true);\n setStep(2);\n }\n const show = () => {\n if (gen !== openGenRef.current) return;\n // The assistant is the front door now, not a button inside the form: ⌘⇧G\n // opens the sheet, which asks what this is before anything else. The tile\n // grid is still exactly one tap away (\"Write it myself\"), and a project\n // without the assistant — or one whose assistant degraded earlier in this\n // page's life — opens on the grid the way it always did.\n if (assist && !assistUsed) setAssistOpen(true);\n setIsOpen(true);\n };\n // Called before the first await, so the browser still sees the click.\n const capture = captureScreenshot({\n onRedraw: () => {\n if (gen !== openGenRef.current) return;\n setShotPending(true);\n show();\n },\n });\n pendingShotRef.current = capture;\n const previousPageShot = pageShot;\n const shot = await capture.catch(() => null);\n if (gen !== openGenRef.current) return;\n pendingShotRef.current = null;\n setShotPending(false);\n setPageShot(shot ?? null);\n // Merged, not replaced: the dialog may have been open while the re-draw\n // ran, and the reporter may have pasted an image. Only the last open's page\n // shot goes — it shows the page as it was then.\n if (shot) {\n setScreenshots((prev) => [\n shot,\n ...prev.filter((s) => s !== shot && s !== previousPageShot),\n ]);\n }\n show();\n };\n\n // Listen for programmatic open via openReportDialog()\n useEffect(() => {\n const handler = (e: Event) => {\n if (isOpen) return;\n const detail = (e as CustomEvent).detail;\n if (detail?.description) setDescription(detail.description);\n if (detail?.type) {\n setReportType(detail.type);\n setTypeChosen(true);\n setStep(2);\n }\n handleOpen();\n };\n window.addEventListener(\"glitchgrab:open-report\", handler);\n return () => window.removeEventListener(\"glitchgrab:open-report\", handler);\n }, [isOpen, handleOpen]);\n\n // Close on Escape\n useEffect(() => {\n if (!isOpen) return;\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n // Escape unwinds one layer at a time, topmost first:\n // annotate → zoom → preview → dialog. Annotate has to lead — it renders\n // above the preview, so skipping it would close the layer *underneath*\n // the one the user is looking at and strand the canvas on screen.\n if (annotatingIndex !== null) setAnnotatingIndex(null);\n else if (previewZoomed) setPreviewZoomed(false);\n else if (previewIndex !== null) closePreview();\n else handleClose();\n }\n };\n document.addEventListener(\"keydown\", handleEsc);\n return () => document.removeEventListener(\"keydown\", handleEsc);\n }, [isOpen, previewIndex, previewZoomed, annotatingIndex]);\n\n // Close screenshot preview on outside click. Registered in the CAPTURE phase\n // so it fires before the host page's own outside-click handlers (e.g. Radix\n // DismissableLayer) can stop the event from ever bubbling to our onClick.\n useEffect(() => {\n if (previewIndex === null || annotatingIndex !== null) return;\n const handlePointerDown = (e: PointerEvent) => {\n if (!previewImgRef.current?.contains(e.target as Node)) {\n closePreview();\n }\n };\n document.addEventListener(\"pointerdown\", handlePointerDown, true);\n return () =>\n document.removeEventListener(\"pointerdown\", handlePointerDown, true);\n }, [previewIndex, annotatingIndex]);\n\n // After zooming in, scroll so the point the user clicked is centred.\n useEffect(() => {\n const el = previewScrollRef.current;\n if (!previewZoomed || !el) return;\n const anchor = zoomAnchorRef.current ?? { fx: 0.5, fy: 0.5 };\n el.scrollLeft = anchor.fx * el.scrollWidth - el.clientWidth / 2;\n el.scrollTop = anchor.fy * el.scrollHeight - el.clientHeight / 2;\n }, [previewZoomed]);\n\n // Lives on the scroll container, not the <img>: while panning we hold pointer\n // capture on the container, and Chrome retargets the resulting click there\n // too — a handler on the image would never fire in the zoomed state.\n const togglePreviewZoom = (e: React.MouseEvent<HTMLDivElement>) => {\n e.stopPropagation();\n // A drag that panned the image must not also flip the zoom state.\n if (panRef.current?.moved) return;\n if (!previewZoomed && !canZoomPreview) return;\n const img = previewImgElRef.current;\n if (!previewZoomed && img) {\n const rect = img.getBoundingClientRect();\n zoomAnchorRef.current = {\n fx: (e.clientX - rect.left) / rect.width,\n fy: (e.clientY - rect.top) / rect.height,\n };\n }\n setPreviewZoomed((z) => !z);\n };\n\n const handlePanStart = (e: React.PointerEvent<HTMLDivElement>) => {\n const el = previewScrollRef.current;\n if (!previewZoomed || !el) return;\n panRef.current = {\n x: e.clientX,\n y: e.clientY,\n left: el.scrollLeft,\n top: el.scrollTop,\n moved: false,\n };\n el.setPointerCapture(e.pointerId);\n };\n\n const handlePanMove = (e: React.PointerEvent<HTMLDivElement>) => {\n const el = previewScrollRef.current;\n const start = panRef.current;\n if (!el || !start) return;\n const dx = e.clientX - start.x;\n const dy = e.clientY - start.y;\n if (Math.abs(dx) > 4 || Math.abs(dy) > 4) start.moved = true;\n el.scrollLeft = start.left - dx;\n el.scrollTop = start.top - dy;\n };\n\n const handlePanEnd = (e: React.PointerEvent<HTMLDivElement>) => {\n const el = previewScrollRef.current;\n const moved = panRef.current?.moved ?? false;\n try {\n el?.releasePointerCapture(e.pointerId);\n } catch {\n /* pointer already released */\n }\n // Keep `moved` readable through the click that follows this pointerup.\n if (moved) {\n panRef.current = { x: 0, y: 0, left: 0, top: 0, moved: true };\n setTimeout(() => {\n panRef.current = null;\n }, 0);\n } else {\n panRef.current = null;\n }\n };\n\n // Paste files from clipboard (Cmd+V / Ctrl+V) when dialog is open. Images land\n // in the screenshot strip, any other pasted file becomes an attachment. Plain\n // text is untouched so typing into the textarea still pastes normally.\n useEffect(() => {\n if (!isOpen) return;\n const handlePaste = (e: ClipboardEvent) => {\n try {\n const items = e.clipboardData?.items;\n if (!items) return;\n const pasted: File[] = [];\n for (let i = 0; i < items.length; i++) {\n if (items[i].kind !== \"file\") continue;\n const file = items[i].getAsFile();\n if (file) pasted.push(file);\n }\n if (pasted.length > 0) {\n e.preventDefault();\n addFiles(pasted);\n }\n } catch {\n // silently fail\n }\n };\n window.addEventListener(\"paste\", handlePaste);\n return () => window.removeEventListener(\"paste\", handlePaste);\n }, [isOpen]);\n\n useEffect(() => {\n if (!isOpen || !transcribeAudio) return;\n const id = setInterval(() => {\n setPlaceholderIdx((i) => (i + 1) % 2);\n }, 3000);\n return () => clearInterval(id);\n }, [isOpen, transcribeAudio]);\n\n // Voice callbacks fire outside React's render, so they need the current text,\n // not the text that was on screen when listening started.\n useEffect(() => {\n descriptionRef.current = description;\n }, [description]);\n\n /**\n * Adopt the user's own typing as the base voice appends to.\n *\n * `voiceBaseRef` is a snapshot taken when listening started. Every speech\n * result rewrote the whole field from that snapshot, so a sentence typed\n * while the mic was open vanished on the next word recognised. If the field\n * no longer holds what voice last wrote, the difference is the user's, and\n * the next result appends to it instead of replacing it.\n */\n const rebaseVoiceOnUserEdits = () => {\n const live = descriptionRef.current;\n // Before voice has written anything, the field's own starting text is the\n // baseline; after that it's whatever voice put there last.\n const baseline = lastVoiceTextRef.current ?? textBeforeVoiceRef.current;\n if (live === baseline) return;\n voiceBaseRef.current = live;\n textBeforeVoiceRef.current = live;\n };\n\n /** Write voice output and remember it, so later edits are detectable. */\n const setDescriptionFromVoice = (text: string) => {\n lastVoiceTextRef.current = text;\n descriptionRef.current = text;\n setDescription(text);\n };\n\n const stopVoice = () => {\n usingWebSpeechRef.current = false;\n recognitionRef.current?.stop();\n recognitionRef.current = null;\n sarvamChunksRef.current = [];\n const stream = streamRef.current;\n streamRef.current = null;\n stream?.getTracks().forEach((t) => t.stop());\n try { mediaRecorderRef.current?.stop(); } catch { /* ignore */ }\n mediaRecorderRef.current = null;\n setIsListening(false);\n setIsTranscribing(false);\n };\n\n const stopListeningAndTranscribe = () => {\n usingWebSpeechRef.current = false;\n recognitionRef.current?.stop();\n recognitionRef.current = null;\n setIsListening(false);\n try { mediaRecorderRef.current?.stop(); } catch { /* ignore */ }\n };\n\n /**\n * Is the AI sheet the surface in charge right now?\n *\n * When it is, the dialog is hidden outright rather than dimmed behind it. The\n * two share `description` and `severity`, so leaving it on screen showed the\n * same report text, the same severity buttons and a second Send Report behind\n * a translucent overlay — one report wearing two faces. Nothing is lost by\n * hiding it: the state is shared, so \"Write it myself\" brings it straight\n * back with everything intact.\n *\n * RATING used to be excluded here. It no longer is: the sheet asks what this\n * is, so \"Rate us\" is one of the answers it has to be able to handle, and\n * bouncing someone back to the dialog for the one non-report tile would be a\n * surface switch mid-sentence.\n */\n const sheetUp = !!assist && assistOpen;\n\n /**\n * `display:none` already takes the dialog out of the tab order, but it is set\n * by React on the overlay while `inert`/`aria-hidden` go on the card itself —\n * so this also covers the frame where the sheet is mounting and the dialog\n * has not yet been hidden.\n */\n useEffect(() => {\n const el = modalRef.current;\n if (!el) return;\n if (sheetUp) {\n el.setAttribute(\"inert\", \"\");\n el.setAttribute(\"aria-hidden\", \"true\");\n } else {\n el.removeAttribute(\"inert\");\n el.removeAttribute(\"aria-hidden\");\n }\n }, [sheetUp, isOpen]);\n\n const handleClose = () => {\n stopVoice();\n setIsOpen(false);\n onClose?.();\n // A capture still running belongs to this report, not the next one.\n openGenRef.current += 1;\n pendingShotRef.current = null;\n setShotPending(false);\n // The preview and annotation overlays are full-viewport portals at the top of\n // the stacking order. Leaving their indices set on close leaves one of them\n // mounted over a dialog that is no longer there — the page stops accepting\n // typing or selection entirely, and the next open renders *underneath* it.\n closePreview();\n setAnnotatingIndex(null);\n setStep(1);\n setRating(0);\n setHoveredStar(0);\n setReportType(\"BUG\");\n setTypeChosen(false);\n setDuplicateIssueNumber(null);\n setDuplicateKind(\"duplicate\");\n setSimilarIssues(null);\n setPickedSimilar(null);\n setCheckingSimilar(false);\n setAttachingTo(null);\n setSeverity(null);\n setValidationError(null);\n setSelfReportFrom(null);\n setVoiceError(null);\n setIsEnhanced(false);\n setOriginalDescription(null);\n // A new report is a new conversation. Leaving `assistUsed` set would hide\n // the assistant for the rest of the page's life after one use.\n setAssistOpen(false);\n setAssistUsed(false);\n setAssistNotice(null);\n };\n\n const toggleVoice = async () => {\n if (isListening) {\n stopListeningAndTranscribe();\n return;\n }\n\n // Fresh run: nothing on screen came from voice yet.\n lastVoiceTextRef.current = null;\n hadWebSpeechRef.current = false;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const SpeechRec: (new () => any) | undefined = (typeof window !== \"undefined\")\n ? ((window as any).SpeechRecognition || (window as any).webkitSpeechRecognition)\n : undefined;\n\n // Get mic stream for MediaRecorder (Sarvam final accurate result)\n //\n // `navigator.mediaDevices` is absent outside a secure context and patchy in\n // some WebViews, so reaching straight for `.getUserMedia` throws a\n // TypeError carrying no usable `name`. Check for it first — but only give\n // up when Web Speech is missing too. Web Speech needs no recorder stream,\n // so it can still transcribe here; it just loses the Sarvam correction.\n let stream: MediaStream | null = null;\n const canRecord =\n typeof navigator !== \"undefined\" && !!navigator.mediaDevices?.getUserMedia;\n if (!canRecord && !SpeechRec) {\n setVoiceError(MIC_MESSAGES.insecure);\n return;\n }\n try {\n if (canRecord)\n stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n } catch (err) {\n // Bail on every cause we can name, and say which one it is.\n //\n // The old code returned only on a denial and let everything else fall\n // through to Web Speech — which starts by calling `setVoiceError(null)`,\n // wiping the message, and then reports its own `audio-capture` failure as\n // \"Microphone access denied\". A machine with no microphone at all was\n // told its permissions were the problem.\n const message = micErrorMessage(err);\n if (message) { setVoiceError(message); return; }\n // Unrecognised failure: Web Speech may still work without a recorder\n // stream, so try it rather than refusing outright.\n if (!SpeechRec) { setVoiceError(MIC_MESSAGES.generic); return; }\n }\n\n if (stream && transcribeAudio) {\n streamRef.current = stream;\n sarvamChunksRef.current = [];\n textBeforeVoiceRef.current = descriptionRef.current;\n\n const rec = new MediaRecorder(stream);\n mediaRecorderRef.current = rec;\n rec.ondataavailable = (e) => { if (e.data.size > 0) sarvamChunksRef.current.push(e.data); };\n rec.onstop = async () => {\n stream!.getTracks().forEach((t) => t.stop());\n if (streamRef.current === stream) streamRef.current = null;\n mediaRecorderRef.current = null;\n const chunks = sarvamChunksRef.current;\n sarvamChunksRef.current = [];\n if (!chunks.length || !transcribeAudio) return;\n setIsTranscribing(true);\n try {\n const blob = new Blob(chunks, { type: rec.mimeType || \"audio/webm\" });\n const text = await transcribeAudio(blob);\n if (text.trim()) {\n const live = descriptionRef.current;\n // No Web Speech (Firefox) means nothing has written a voice\n // baseline, so compare against the text this run started with —\n // otherwise typing during a Firefox recording is wiped here.\n const baseline =\n lastVoiceTextRef.current ?? textBeforeVoiceRef.current;\n const userEdited = live !== baseline;\n if (userEdited && hadWebSpeechRef.current) {\n // The field already holds the Web Speech preview plus whatever\n // the user typed around it. Overwriting from a snapshot would\n // delete the typing; appending would say the sentence twice. A\n // slightly rougher transcript is the better of the three.\n } else {\n // Replace the live Web Speech preview with the accurate Sarvam\n // result. When the user typed and there was no preview to\n // replace, their words are the base and Sarvam follows them.\n const base = userEdited ? live : textBeforeVoiceRef.current;\n const sep = base.trim() ? \" \" : \"\";\n setDescriptionFromVoice(base + sep + text.trim());\n setValidationError(null);\n setIsEnhanced(false);\n setOriginalDescription(null);\n }\n }\n } catch { /* keep Web Speech result on failure */ }\n setIsTranscribing(false);\n };\n rec.start();\n }\n\n if (SpeechRec) {\n setVoiceError(null);\n usingWebSpeechRef.current = true;\n hadWebSpeechRef.current = true;\n voiceBaseRef.current = descriptionRef.current;\n textBeforeVoiceRef.current = descriptionRef.current;\n const recognition = new SpeechRec();\n recognition.lang = \"en-IN\";\n recognition.interimResults = true;\n recognition.continuous = true;\n recognitionRef.current = recognition;\n\n recognition.onstart = () => setIsListening(true);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n recognition.onresult = (event: any) => {\n let finalText = \"\";\n let interimText = \"\";\n for (let i = event.resultIndex; i < event.results.length; i++) {\n const text = event.results[i][0].transcript;\n if (event.results[i].isFinal) finalText += text;\n else interimText += text;\n }\n rebaseVoiceOnUserEdits();\n if (finalText) {\n const sep = voiceBaseRef.current.trim() ? \" \" : \"\";\n voiceBaseRef.current += sep + finalText.trim();\n }\n const liveText = interimText\n ? voiceBaseRef.current + (voiceBaseRef.current.trim() ? \" \" : \"\") + interimText\n : voiceBaseRef.current;\n setDescriptionFromVoice(liveText);\n setValidationError(null);\n };\n\n recognition.onend = () => {\n if (usingWebSpeechRef.current && recognitionRef.current === recognition) {\n try { recognition.start(); } catch { /* ignore */ }\n } else {\n setIsListening(false);\n }\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n recognition.onerror = (event: any) => {\n if (event.error === \"aborted\" || event.error === \"no-speech\") return;\n // `audio-capture` is not a permission problem — it is the mic failing\n // to open at all — so it gets the hardware message, not the site-block\n // one. Sending a user with no microphone to their site settings is a\n // wild goose chase.\n setVoiceError(\n event.error === \"not-allowed\"\n ? MIC_MESSAGES.blocked\n : event.error === \"audio-capture\"\n ? MIC_MESSAGES.notFound\n : \"Speech recognition not available — try Chrome\",\n );\n usingWebSpeechRef.current = false;\n recognitionRef.current = null;\n setIsListening(false);\n };\n\n recognition.start();\n } else if (stream) {\n // Firefox: Sarvam-only, no live preview\n setVoiceError(null);\n setIsListening(true);\n }\n };\n\n /**\n * Disarm a pending push-to-talk hold.\n *\n * Anything that proves the user is typing rather than holding cancels it: a\n * second edit to the field, or a keystroke that isn't the space we armed on.\n * Without this the timer fired mid-sentence, and the fix-up it ran then\n * (delete a character, move the caret) landed on text the user had typed in\n * the meantime — every following keystroke went into the middle of a word.\n */\n const cancelPushToTalkArm = () => {\n if (!spaceTimerRef.current) return;\n clearTimeout(spaceTimerRef.current);\n spaceTimerRef.current = null;\n };\n\n /** Count edits during the hold window; the second one means \"still typing\". */\n const notePushToTalkEdit = () => {\n if (!spaceTimerRef.current) return;\n spaceEditsRef.current += 1;\n if (spaceEditsRef.current > 1) cancelPushToTalkArm();\n };\n\n const handleSpaceDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.code !== \"Space\") {\n // Any other key while armed — this is typing, not a hold.\n if (!e.metaKey && !e.ctrlKey && !e.altKey) cancelPushToTalkArm();\n return;\n }\n // Recording or already-committed to push-to-talk — swallow the space\n if (isListening || isPushToTalkRef.current) {\n e.preventDefault();\n return;\n }\n // Auto-repeat from a held key, or a timer already pending — let the browser\n // type normally; we only care about the first keydown of a hold.\n if (e.repeat || !transcribeAudio || isTranscribing || spaceTimerRef.current)\n return;\n // Only ever arm from an empty field.\n //\n // 400ms on the space bar is not a gesture, it's a pause: stopping to think\n // mid-sentence held the key long enough to swallow the space AND open the\n // mic, after which speech results rewrote what had been typed. Nobody\n // \"held space\" — they wrote a bug report. The hint that advertises this\n // (\"Hold Space to speak\") is a placeholder, so it is only on screen when\n // the field is empty; arming only there is exactly what was promised, and\n // it puts the trigger somewhere no sentence can reach it. Voice mid-report\n // is still one tap away on the mic button.\n if (e.currentTarget.value !== \"\") return;\n\n // Don't preventDefault: let the browser insert the space natively so the\n // cursor stays exactly where the user typed it. If the hold matures into\n // push-to-talk, strip that space back out below.\n //\n // No offset is captured here on purpose. The timer used to remember where\n // the caret was at keydown and edit there 400ms later; by then the user had\n // often typed on, so it deleted an unrelated space and dragged the caret\n // back into finished words. The hold now cancels the moment a second edit\n // or another key arrives, and the strip below reads the live caret.\n spaceEditsRef.current = 0;\n spaceTimerRef.current = setTimeout(() => {\n spaceTimerRef.current = null;\n isPushToTalkRef.current = true;\n const el = textareaRef.current;\n const caret = el?.selectionStart ?? null;\n // Only touch the field when the caret is still sitting right after the\n // space this hold typed. Anything else (a selection, a moved caret) is\n // left alone — a stray space beats scrambled words.\n if (\n el &&\n caret !== null &&\n caret === el.selectionEnd &&\n el.value[caret - 1] === \" \"\n ) {\n const cut = caret - 1;\n setDescription((prev) =>\n prev[cut] === \" \" ? prev.slice(0, cut) + prev.slice(cut + 1) : prev,\n );\n // toggleVoice() runs on this same tick and snapshots descriptionRef;\n // the state update hasn't landed yet, so keep the mirror honest.\n descriptionRef.current =\n descriptionRef.current.slice(0, cut) +\n descriptionRef.current.slice(cut + 1);\n requestAnimationFrame(() => {\n if (textareaRef.current) {\n textareaRef.current.selectionStart = cut;\n textareaRef.current.selectionEnd = cut;\n }\n });\n }\n void toggleVoice();\n }, 400);\n };\n\n const handleSpaceUp = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.code !== \"Space\") return;\n // Quick tap — space was already typed natively, nothing to do.\n cancelPushToTalkArm();\n if (isPushToTalkRef.current) {\n isPushToTalkRef.current = false;\n stopListeningAndTranscribe();\n }\n };\n\n const handleSubmit = async (opts?: {\n duplicateOf?: number;\n /** With `duplicateOf`: same problem, or a related request on that issue. */\n kind?: AttachKind;\n skipSimilar?: boolean;\n }) => {\n try {\n if (isSubmitting) return;\n\n // A rating takes the feedback path: the stars are the payload, the words\n // are optional, and nothing here reaches GitHub. The low-quality-text\n // guard is deliberately skipped — \"love it\" is a fine testimonial and a\n // useless bug report, and this branch is the former.\n if (isRating) {\n if (rating < 1) {\n setValidationError(\"Pick a star rating first.\");\n return;\n }\n if (!sendFeedback) return;\n\n setIsSubmitting(true);\n const result = await sendFeedback(rating, description.trim() || undefined);\n if (result?.success) {\n setSubmitted(true);\n setDescription(\"\");\n setRating(0);\n setTimeout(() => {\n setSubmitted(false);\n handleClose();\n }, 2000);\n } else {\n setValidationError(\"Could not send — please try again.\");\n }\n setIsSubmitting(false);\n return;\n }\n\n if (!description.trim()) return;\n\n const qualityError = isLowQualityText(description);\n if (qualityError) {\n setValidationError(qualityError);\n setStep(2);\n return;\n }\n\n // Severity is a real answer, not a pre-filled one. Gated here rather than\n // through `submitDisabled` so Send stays live and says why — a greyed-out\n // button with no message is the failure this replaced.\n if (showSeverity && reportType === \"BUG\" && !severity) {\n setValidationError(SEVERITY_REQUIRED);\n setStep(2);\n return;\n }\n\n // Read now, not off state after a setter: \"Add to #N\" picks the issue\n // and submits in the same click, before a re-render could deliver it.\n const duplicateOf = opts?.duplicateOf ?? duplicateIssueNumber;\n const attachKind: AttachKind = opts?.duplicateOf ? (opts.kind ?? \"duplicate\") : duplicateKind;\n\n // \"Is this already filed?\" — once, on the plain form. Not after the\n // assistant ran (it already walked the reporter through open issues), and\n // not when a duplicate is already picked. Anything short of a real match\n // inside SIMILAR_WAIT_MS sends the report as it always has.\n if (findSimilarIssues && !opts?.skipSimilar && !duplicateOf && !aiConversationId) {\n setIsSubmitting(true);\n setCheckingSimilar(true);\n const matches = await Promise.race([\n findSimilarIssues(description.trim()).catch(() => null),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), SIMILAR_WAIT_MS)),\n ]);\n setCheckingSimilar(false);\n if (matches && matches.length > 0) {\n setSimilarIssues(matches.slice(0, MAX_SIMILAR_SHOWN));\n // Nothing starts picked: a preselected row turns an unread tap into\n // a comment on the wrong issue.\n setPickedSimilar(null);\n setIsSubmitting(false);\n return;\n }\n }\n\n setIsSubmitting(true);\n // A page shot still being re-drawn gets a moment to make it in — worth\n // SHOT_WAIT_MS, not a report that never sends (#363).\n let shots = screenshots;\n const pending = pendingShotRef.current;\n if (pending) {\n const shot = await Promise.race([\n pending.catch(() => null),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), SHOT_WAIT_MS)),\n ]);\n if (shot && !shots.includes(shot)) {\n shots = [shot, ...shots.filter((s) => s !== pageShot)];\n }\n }\n const metadata: Record<string, string> = {};\n if (shots.length > 0) metadata.screenshots = JSON.stringify(shots);\n if (attachments.length > 0) metadata.attachments = JSON.stringify(attachments);\n if (showSeverity && reportType === \"BUG\" && severity) {\n metadata.severity = severity;\n }\n if (duplicateOf) {\n metadata.duplicateIssueNumber = String(duplicateOf);\n // Absent means the same problem — what every older server assumes.\n if (attachKind === \"related\") metadata.duplicateKind = \"related\";\n }\n if (aiConversationId) {\n metadata.aiConversationId = aiConversationId;\n }\n\n const result = await report(\n // The RATING branch returned above, so anything reaching here is a real\n // ReportType — the widened tile union can't leak into the report API.\n reportType as ReportType,\n description.trim(),\n Object.keys(metadata).length > 0 ? metadata : undefined,\n );\n\n if (result) {\n // Only when the server really attached. A pick it refused (issue closed\n // since) is filed as a new issue, and saying \"added to #N\" would be a lie.\n setAddedToIssue(duplicateOf && result.issueNumber === duplicateOf ? duplicateOf : null);\n setAddedAsRelated(!!duplicateOf && result.issueNumber === duplicateOf && attachKind === \"related\");\n const queued = result.status === \"QUEUED\" && !!result.message;\n setQueuedMessage(queued ? (result.message ?? null) : null);\n setSubmitted(true);\n setDescription(\"\");\n setScreenshots([]);\n setAttachments([]);\n // The dialog outlives the report. Without this, a second bug typed by\n // hand in the same session inherits the first one's chat and duplicate\n // match — and \"how many prompts per issue\" is measured off a chat that\n // wrote none of it.\n setAiConversationId(null);\n setDuplicateIssueNumber(null);\n setDuplicateKind(\"duplicate\");\n setSimilarIssues(null);\n setPickedSimilar(null);\n\n // A queued report carries a sentence worth reading; \"sent\" is a glance.\n setTimeout(() => {\n setSubmitted(false);\n setQueuedMessage(null);\n handleClose();\n }, queued ? 6000 : 2000);\n }\n setIsSubmitting(false);\n setAttachingTo(null);\n } catch {\n setIsSubmitting(false);\n setCheckingSimilar(false);\n setAttachingTo(null);\n }\n };\n\n if (!mounted) return null;\n\n return (\n <>\n {/* Keyframes for REC pulse — injected once when open */}\n {isOpen &&\n createPortal(\n <style>{`\n @keyframes gg-pulse{0%,100%{opacity:1}50%{opacity:0.35}}\n @keyframes gg-spin{to{transform:rotate(360deg)}}\n @keyframes gg-b1{0%,100%{height:3px}40%{height:13px}}\n @keyframes gg-b2{0%,100%{height:8px}50%{height:3px}}\n @keyframes gg-b3{0%,100%{height:4px}30%{height:14px}70%{height:5px}}\n @keyframes gg-b4{0%,100%{height:6px}60%{height:13px}}\n @keyframes gg-bug-crawl{0%,100%{transform:translateX(0) rotate(0deg)}20%{transform:translateX(-1.5px) rotate(-6deg)}40%{transform:translateX(1.5px) rotate(5deg)}60%{transform:translateX(-1px) rotate(-4deg)}80%{transform:translateX(1px) rotate(3deg)}}\n @keyframes gg-star-spin{0%,100%{transform:scale(1) rotate(0deg)}50%{transform:scale(1.15) rotate(15deg)}}\n @keyframes gg-ui-grow{0%,100%{transform:scaleY(1)}50%{transform:scaleY(1.12)}}\n @keyframes gg-perf-sweep{0%,100%{transform:rotate(0deg)}30%{transform:rotate(-12deg)}70%{transform:rotate(10deg)}}\n @keyframes gg-shield-pulse{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(1.08);opacity:.75}}\n @keyframes gg-question-shake{0%,100%{transform:rotate(0deg)}25%{transform:rotate(-7deg)}75%{transform:rotate(7deg)}}\n @keyframes gg-chat-tilt{0%,100%{transform:rotate(0deg) translateY(0)}50%{transform:rotate(-6deg) translateY(-2px)}}\n button[data-gg-type] > svg{transform-origin:center}\n button[data-gg-type=\"BUG\"] > svg{animation:gg-bug-crawl 2.2s ease-in-out infinite}\n button[data-gg-type=\"FEATURE_REQUEST\"] > svg{animation:gg-star-spin 2.6s ease-in-out infinite}\n button[data-gg-type=\"UI_IMPROVEMENT\"] > svg{animation:gg-ui-grow 1.8s ease-in-out infinite;transform-origin:bottom}\n button[data-gg-type=\"PERFORMANCE\"] > svg{animation:gg-perf-sweep 2.4s ease-in-out infinite}\n button[data-gg-type=\"SECURITY\"] > svg{animation:gg-shield-pulse 2.2s ease-in-out infinite;transform-origin:top}\n button[data-gg-type=\"QUESTION\"] > svg{animation:gg-question-shake 2s ease-in-out infinite}\n button[data-gg-type=\"OTHER\"] > svg{animation:gg-chat-tilt 2.2s ease-in-out infinite}\n /* Lift on hover, settle on press. Cheaper and steadier than doing it\n through React state, and :focus-visible keeps the ring off mouse users\n while leaving it for the arrow-key path. */\n button[data-gg-type]{transition:transform .15s ease,border-color .15s ease,box-shadow .15s ease,background-color .15s ease}\n button[data-gg-type]:hover{transform:translateY(-2px);box-shadow:0 6px 16px rgba(0,0,0,.18)}\n button[data-gg-type]:active{transform:translateY(0) scale(.985);box-shadow:none}\n button[data-gg-type]:focus-visible{outline:2px solid ${t.accent};outline-offset:2px}\n @keyframes gg-star-pop{0%{transform:scale(.6);opacity:0}60%{transform:scale(1.12)}100%{transform:scale(1);opacity:1}}\n button[data-gg-star]{transition:transform .12s ease}\n button[data-gg-star]:hover{transform:scale(1.18)}\n button[data-gg-star]:active{transform:scale(.94)}\n button[data-gg-star]:focus-visible{outline:2px solid #f59e0b;outline-offset:3px;border-radius:4px}\n `}</style>,\n document.body,\n )}\n {/* Report modal */}\n {isOpen &&\n createPortal(\n <div\n data-glitchgrab-layer=\"\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n pointerEvents: \"auto\",\n // Hidden, not unmounted, while the AI sheet is in charge — the\n // dialog's state IS the report, and unmounting would drop the\n // screenshots, attachments and step the reporter is on.\n display: sheetUp ? \"none\" : \"flex\",\n alignItems: sheet ? \"stretch\" : \"center\",\n justifyContent: sheet ? \"flex-end\" : \"center\",\n backgroundColor: \"rgba(0,0,0,0.5)\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n }}\n onClick={() => {\n if (previewIndex === null) handleClose();\n }}\n onPointerDown={(e) => e.stopPropagation()}\n onFocus={(e) => e.stopPropagation()}\n >\n <div\n ref={modalRef}\n // Hosts wait on `[role=\"dialog\"]` to know the dialog is up — without\n // it, a host's \"Opening…\" spinner sat out its own timeout long after\n // the dialog was on screen (#363).\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Report an issue\"\n onClick={(e) => e.stopPropagation()}\n style={{\n position: \"relative\",\n zIndex: 2147483647,\n width: sheet ? \"440px\" : \"420px\",\n maxWidth: sheet ? \"100%\" : \"calc(100% - 32px)\",\n maxHeight: sheet ? \"100dvh\" : \"calc(100dvh - 32px)\",\n ...(sheet ? { height: \"100dvh\", borderLeft: `1px solid ${t.inputBorder}` } : {}),\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: t.bg,\n borderRadius: sheet ? 0 : \"12px\",\n boxShadow: sheet\n ? \"0 20px 60px rgba(0, 0, 0, 0.35)\"\n : \"0 20px 60px rgba(0, 0, 0, 0.2), 0 4px 16px rgba(0, 0, 0, 0.1)\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n overflow: \"hidden\",\n color: t.text,\n isolation: \"isolate\",\n }}\n >\n {/* Header */}\n <div\n style={{\n flexShrink: 0,\n padding: \"16px 16px 12px\",\n borderBottom: `1px solid ${t.border}`,\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n }}\n >\n {/* Back leads to the type grid — nowhere to go with one type. */}\n {step > 1 && availableTypes.length > 1 && (\n <button\n type=\"button\"\n onClick={() => setStep((s) => (s - 1) as 1 | 2)}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"2px\",\n display: \"flex\",\n alignItems: \"center\",\n }}\n aria-label=\"Back\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n >\n <path\n d=\"M10 3L5 8L10 13\"\n stroke={t.textMuted}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n )}\n <span\n style={{\n fontSize: \"15px\",\n fontWeight: 600,\n color: t.text,\n }}\n >\n {step === 1 ? \"What's on your mind?\" : \"Tell us more\"}\n </span>\n </div>\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n }}\n >\n {step === 1 && (\n <span\n title=\"Press this anywhere to open Glitchgrab\"\n style={{\n fontSize: \"10px\",\n fontWeight: 600,\n lineHeight: 1,\n padding: \"3px 6px\",\n borderRadius: \"4px\",\n border: `1px solid ${t.inputBorder}`,\n background: t.inputBg,\n color: t.textMuted,\n whiteSpace: \"nowrap\",\n }}\n >\n {getShortcutLabel()}\n </span>\n )}\n <button\n type=\"button\"\n onClick={handleClose}\n style={{\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n padding: \"4px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n aria-label=\"Close\"\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{ display: \"block\" }}\n >\n <path\n d=\"M4 4L12 12M12 4L4 12\"\n stroke={t.textMuted}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n {/* Two steps only exist when there is a type to pick. */}\n {availableTypes.length > 1 && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: \"0\",\n marginTop: \"12px\",\n }}\n >\n {[1, 2].map((s, i) => (\n <div\n key={s}\n style={{ display: \"flex\", alignItems: \"center\" }}\n >\n <div\n style={{\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"50%\",\n backgroundColor: s <= step ? t.accent : t.inputBorder,\n transition: \"background-color 0.2s ease\",\n }}\n />\n {i < 1 && (\n <div\n style={{\n width: \"40px\",\n height: \"2px\",\n backgroundColor:\n s < step ? t.accent : t.inputBorder,\n transition: \"background-color 0.2s ease\",\n }}\n />\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Body */}\n <div\n style={{\n padding: \"18px\",\n overflowY: \"auto\",\n flex: \"1 1 auto\",\n minHeight: 0,\n }}\n >\n {submitted ? (\n <div\n style={{\n textAlign: \"center\",\n padding: \"20px 0\",\n color: t.accent,\n fontSize: \"14px\",\n fontWeight: 500,\n }}\n >\n {queuedMessage ? (\n <span\n style={{\n // amber-500 reads on the dark panel, amber-700 on the light one\n color: isDark ? \"#f59e0b\" : \"#b45309\",\n fontWeight: 400,\n lineHeight: 1.5,\n }}\n >\n {queuedMessage}\n </span>\n ) : addedToIssue\n ? `Added to #${addedToIssue}${addedAsRelated ? \" as a related request\" : \"\"}. Thank you!`\n : `${getTypeLabel(reportType)} sent. Thank you!`}\n </div>\n ) : (\n <>\n {/* Step 1: Category */}\n {/* Rating hero — a compliment is a different act from filing\n a bug, so it gets its own row instead of hiding as the\n 8th identical tile. Clicking a star both sets it and\n advances, turning a 3-click flow into 1. */}\n {step === 1 && headerSlot ? (\n <div style={{ marginBottom: \"14px\" }}>{headerSlot}</div>\n ) : null}\n\n {step === 1 && sendFeedback && (\n <div\n style={{\n border: \"1px solid rgba(245,158,11,0.35)\",\n background: \"rgba(245,158,11,0.07)\",\n borderRadius: \"10px\",\n padding: \"14px 16px\",\n marginBottom: \"16px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: \"12px\",\n flexWrap: \"wrap\",\n }}\n onMouseLeave={() => setHoveredStar(0)}\n >\n <span\n style={{ fontSize: \"13px\", fontWeight: 600, color: t.text }}\n >\n How are we doing?\n </span>\n <span style={{ display: \"flex\", gap: \"4px\" }}>\n {[1, 2, 3, 4, 5].map((star) => {\n // `rating` is normally 0 here; it only shows through\n // when someone rated, hit Back, and returned.\n const filled = star <= (hoveredStar || rating);\n return (\n <button\n key={star}\n type=\"button\"\n data-gg-star={star}\n aria-label={`${star} star${star > 1 ? \"s\" : \"\"}`}\n onMouseEnter={() => setHoveredStar(star)}\n onFocus={() => setHoveredStar(star)}\n onClick={() => {\n setRating(star);\n setReportType(\"RATING\");\n setTypeChosen(true);\n setStep(2);\n }}\n style={{\n border: \"none\",\n background: \"transparent\",\n padding: 0,\n cursor: \"pointer\",\n lineHeight: 0,\n }}\n >\n <svg width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.4 6.8 19.1l1-5.8L3.5 9.2l5.9-.9L12 3z\"\n fill={filled ? \"#f59e0b\" : \"transparent\"}\n stroke=\"#f59e0b\"\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n );\n })}\n </span>\n </div>\n )}\n\n {step === 1 && sendFeedback && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"10px\",\n marginBottom: \"16px\",\n }}\n >\n <span style={{ flex: 1, height: \"1px\", background: t.border }} />\n <span style={{ fontSize: \"11px\", color: t.textMuted }}>\n or report something\n </span>\n <span style={{ flex: 1, height: \"1px\", background: t.border }} />\n </div>\n )}\n\n {/* The dialog screenshots the screen the moment it opens.\n Saying so here — with a way out — is the honest place to\n do it; step 2 was one screen too late to be a choice. */}\n {step === 1 && screenshots.length > 0 && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"10px\",\n marginBottom: \"14px\",\n padding: \"8px 10px\",\n border: `1px solid ${t.inputBorder}`,\n borderRadius: \"8px\",\n background: t.inputBg,\n }}\n >\n <img\n src={screenshots[0]}\n alt=\"\"\n style={{\n width: \"34px\",\n height: \"24px\",\n objectFit: \"cover\",\n borderRadius: \"4px\",\n border: `1px solid ${t.border}`,\n flexShrink: 0,\n }}\n />\n <span style={{ fontSize: \"11px\", color: t.textMuted, flex: 1 }}>\n Screenshot attached\n </span>\n <button\n type=\"button\"\n onClick={() => setScreenshots([])}\n aria-label=\"Remove screenshot\"\n style={{\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n cursor: \"pointer\",\n fontSize: \"15px\",\n lineHeight: 1,\n padding: \"2px 4px\",\n }}\n >\n ×\n </button>\n </div>\n )}\n\n {step === 1 && (\n <div\n ref={tileGridRef}\n onKeyDown={handleTileGridKeyDown}\n style={{\n display: \"grid\",\n gridTemplateColumns: \"1fr 1fr 1fr\",\n gap: \"10px\",\n }}\n >\n {availableTypes.map((type) => (\n <button\n key={type}\n type=\"button\"\n data-gg-type={type}\n onClick={() => {\n setReportType(type);\n setTypeChosen(true);\n setStep(2);\n }}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"9px\",\n padding: \"18px 10px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n background: t.inputBg,\n cursor: \"pointer\",\n color: t.text,\n fontFamily: \"inherit\",\n }}\n onMouseEnter={(e) => {\n (\n e.currentTarget as HTMLElement\n ).style.borderColor = t.accent;\n }}\n onMouseLeave={(e) => {\n (\n e.currentTarget as HTMLElement\n ).style.borderColor = t.inputBorder;\n }}\n >\n {getTypeIcon(type, t.accent, 22)}\n <span\n style={{\n fontSize: \"12px\",\n fontWeight: 600,\n textAlign: \"center\",\n lineHeight: \"1.2\",\n }}\n >\n {getTypeLabel(type)}\n </span>\n </button>\n ))}\n </div>\n )}\n\n {/* Step 2: Details */}\n {step === 2 && (\n <>\n {/* What you picked, still on screen and still changeable.\n Previously step 2 said only \"Tell us more\", so the\n only way to check or switch type was the Back arrow. */}\n <button\n type=\"button\"\n // One type means nothing to change it to — the chip is a label then.\n disabled={availableTypes.length === 1}\n onClick={() => setStep(1)}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"6px\",\n marginBottom: \"10px\",\n padding: \"4px 10px 4px 8px\",\n borderRadius: \"999px\",\n border: `1px solid ${isRating ? \"rgba(245,158,11,0.4)\" : t.inputBorder}`,\n background: isRating ? \"rgba(245,158,11,0.1)\" : t.inputBg,\n color: t.text,\n fontSize: \"11px\",\n fontWeight: 600,\n fontFamily: \"inherit\",\n cursor: availableTypes.length === 1 ? \"default\" : \"pointer\",\n }}\n >\n {getTypeIcon(reportType, isRating ? \"#f59e0b\" : t.accent, 13)}\n {getTypeLabel(reportType)}\n {availableTypes.length > 1 && (\n <span style={{ color: t.textMuted, fontWeight: 400 }}>· change</span>\n )}\n </button>\n\n {/* Stars carry the payload for a rating; the words below\n them are optional, so this sits above the textarea. */}\n {isRating && (\n <div\n style={{\n display: \"flex\",\n gap: \"6px\",\n marginBottom: \"12px\",\n }}\n onMouseLeave={() => setHoveredStar(0)}\n >\n {[1, 2, 3, 4, 5].map((star) => {\n const filled = star <= (hoveredStar || rating);\n return (\n <button\n key={star}\n type=\"button\"\n aria-label={`${star} star${star > 1 ? \"s\" : \"\"}`}\n onClick={() => {\n setRating(star);\n if (validationError) setValidationError(null);\n }}\n onMouseEnter={() => setHoveredStar(star)}\n style={{\n border: \"none\",\n background: \"transparent\",\n padding: 0,\n cursor: \"pointer\",\n lineHeight: 0,\n }}\n >\n <svg width=\"30\" height=\"30\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.4 6.8 19.1l1-5.8L3.5 9.2l5.9-.9L12 3z\"\n fill={filled ? \"#f59e0b\" : \"transparent\"}\n stroke={filled ? \"#f59e0b\" : t.inputBorder}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n );\n })}\n </div>\n )}\n {/* Entry point to the AI sheet (#330). The sheet itself\n renders in its own portal at the bottom of this\n component, not inline: a conversation crammed into a\n 420px card read like a form field, not a chat.\n Hidden for RATING — a star needs no help. */}\n {assist && !isRating && !assistUsed && (\n <button\n type=\"button\"\n onClick={() => {\n setAssistNotice(null);\n setTypeChosen(true);\n setAssistOpen(true);\n }}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"6px\",\n marginBottom: \"10px\",\n // 8px vertical keeps the tap target at ~32px.\n padding: \"8px 10px\",\n borderRadius: \"6px\",\n border: `1px solid ${t.accent}`,\n background: \"transparent\",\n color: t.accent,\n fontSize: \"12px\",\n fontWeight: 600,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n title=\"Answer a question or two and the assistant writes the report for you\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3zM19 15l.75 2.25L22 18l-2.25.75L19 21l-.75-2.25L16 18l2.25-.75L19 15z\"\n stroke={t.accent}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n Describe it with AI\n </button>\n )}\n <div style={{ position: \"relative\" }}>\n <textarea\n ref={textareaRef}\n value={description}\n onChange={(e) => {\n notePushToTalkEdit();\n setDescription(e.target.value);\n if (validationError) setValidationError(null);\n if (isEnhanced) {\n setIsEnhanced(false);\n setOriginalDescription(null);\n }\n }}\n placeholder={\n isTranscribing\n ? \"Transcribing your speech…\"\n : isListening\n ? \"Listening… speak now\"\n // `hasVoice` false once voice has failed: the\n // rotating placeholder advertises \"Hold Space\n // to speak\" directly above a line saying the\n // microphone is blocked.\n : getPlaceholder(reportType, placeholderIdx, !!transcribeAudio && !voiceError)\n }\n style={{\n width: \"100%\",\n minHeight: \"100px\",\n padding: enhanceText\n ? \"28px 12px 36px\"\n : transcribeAudio\n ? \"10px 12px 36px\"\n : \"10px 12px\",\n borderRadius: \"8px\",\n border: `1px solid ${isTranscribing ? \"#f59e0b\" : isListening ? t.accent : t.inputBorder}`,\n fontSize: \"14px\",\n fontFamily: \"inherit\",\n resize: \"none\",\n outline: \"none\",\n boxSizing: \"border-box\",\n color: t.text,\n backgroundColor: t.inputBg,\n transition: \"border-color 0.2s ease\",\n }}\n onKeyDown={handleSpaceDown}\n onKeyUp={handleSpaceUp}\n onFocus={(e) => {\n (\n e.target as HTMLTextAreaElement\n ).style.borderColor = t.accent;\n }}\n onBlur={(e) => {\n if (!isListening && !isTranscribing)\n (\n e.target as HTMLTextAreaElement\n ).style.borderColor = t.inputBorder;\n }}\n autoFocus\n />\n {/* Bottom-left: REC / Transcribing badge (same row as mic button) */}\n {(isListening || isTranscribing) && (\n <span\n style={{\n position: \"absolute\",\n bottom: \"10px\",\n left: \"10px\",\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"4px\",\n fontSize: \"10px\",\n fontWeight: 700,\n letterSpacing: \"0.04em\",\n color: isTranscribing ? \"#f59e0b\" : \"#ef4444\",\n pointerEvents: \"none\",\n zIndex: 1,\n }}\n >\n <span\n style={{\n width: \"6px\",\n height: \"6px\",\n borderRadius: \"50%\",\n backgroundColor: \"currentColor\",\n animation:\n \"gg-pulse 1.2s ease-in-out infinite\",\n display: \"inline-block\",\n flexShrink: 0,\n }}\n />\n {isTranscribing ? \"Transcribing…\" : \"REC\"}\n {isListening && !isTranscribing && (\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"flex-end\",\n gap: \"2px\",\n height: \"14px\",\n marginLeft: \"3px\",\n }}\n >\n {[\n { anim: \"gg-b1\", dur: \"0.6s\", delay: \"0s\" },\n {\n anim: \"gg-b2\",\n dur: \"0.5s\",\n delay: \"0.1s\",\n },\n {\n anim: \"gg-b3\",\n dur: \"0.7s\",\n delay: \"0.05s\",\n },\n {\n anim: \"gg-b4\",\n dur: \"0.55s\",\n delay: \"0.15s\",\n },\n ].map((b, i) => (\n <span\n key={i}\n style={{\n width: \"2.5px\",\n height: \"4px\",\n borderRadius: \"1px\",\n backgroundColor: \"#ef4444\",\n animation: `${b.anim} ${b.dur} ease-in-out ${b.delay} infinite`,\n display: \"inline-block\",\n alignSelf: \"center\",\n }}\n />\n ))}\n </span>\n )}\n </span>\n )}\n {/* Top-right: AI enhance */}\n {enhanceText && (\n <button\n type=\"button\"\n onClick={async () => {\n if (!description.trim() || isEnhancing) return;\n setIsEnhancing(true);\n try {\n const polished = await enhanceText(\n description,\n screenshots[0] ?? null,\n );\n if (polished && polished !== description) {\n setOriginalDescription(description);\n setDescription(polished);\n setIsEnhanced(true);\n if (validationError)\n setValidationError(null);\n }\n } finally {\n setIsEnhancing(false);\n }\n }}\n disabled={\n !description.trim() || isEnhancing || isEnhanced\n }\n style={{\n position: \"absolute\",\n top: \"6px\",\n right: \"6px\",\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"4px\",\n background: t.inputBg,\n border: \"none\",\n padding: \"2px 6px\",\n borderRadius: \"4px\",\n fontFamily: \"inherit\",\n fontSize: \"11px\",\n color: t.textMuted,\n cursor:\n !description.trim() || isEnhancing\n ? \"default\"\n : \"pointer\",\n opacity: !description.trim() ? 0.5 : 1,\n zIndex: 1,\n }}\n title=\"Polish grammar — preserves your meaning\"\n >\n <svg\n width=\"11\"\n height=\"11\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3zM19 15l.75 2.25L22 18l-2.25.75L19 21l-.75-2.25L16 18l2.25-.75L19 15z\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n {isEnhancing ? \"Enhancing...\" : \"AI enhance\"}\n </button>\n )}\n {/* Bottom-right: mic icon only, outlined */}\n {transcribeAudio && (\n <button\n type=\"button\"\n onClick={() => {\n void toggleVoice();\n }}\n title={\n isListening\n ? \"Stop recording\"\n : \"Speak your report\"\n }\n style={{\n position: \"absolute\",\n bottom: \"14px\",\n right: \"7px\",\n width: \"26px\",\n height: \"26px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n background: \"transparent\",\n border: `1.5px solid ${isListening ? \"#ef4444\" : t.inputBorder}`,\n borderRadius: \"6px\",\n color: isListening ? \"#ef4444\" : t.textMuted,\n cursor: \"pointer\",\n zIndex: 1,\n padding: 0,\n transition:\n \"border-color 0.2s ease, color 0.2s ease\",\n }}\n >\n {isListening ? (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <rect\n x=\"6\"\n y=\"6\"\n width=\"12\"\n height=\"12\"\n rx=\"2\"\n />\n </svg>\n ) : (\n <svg\n width=\"13\"\n height=\"13\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <rect\n x=\"9\"\n y=\"2\"\n width=\"6\"\n height=\"12\"\n rx=\"3\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n />\n <path\n d=\"M5 10a7 7 0 0014 0M12 19v3M9 22h6\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n />\n </svg>\n )}\n </button>\n )}\n </div>\n {/* Hidden once voice has failed: telling someone to\n hold Space to speak, directly above a line saying\n the microphone is blocked, advertises a gesture\n that cannot work. The error carries the mic story\n on its own until they retry. */}\n {transcribeAudio && !isListening && !isTranscribing && !voiceError && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"5px\",\n marginTop: \"5px\",\n fontSize: \"11px\",\n color: t.text,\n opacity: 0.55,\n userSelect: \"none\",\n }}\n >\n <svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\"/>\n </svg>\n Hold Space to speak — we'll transcribe it\n </div>\n )}\n {isEnhanced && originalDescription !== null && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n marginTop: \"6px\",\n padding: \"6px 8px\",\n borderRadius: \"6px\",\n background: isDark\n ? \"rgba(34,211,238,0.06)\"\n : \"rgba(8,145,178,0.05)\",\n border: `1px solid ${t.accent}40`,\n }}\n >\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{ flexShrink: 0 }}\n >\n <path\n d=\"M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z\"\n stroke={t.accent}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span\n style={{\n fontSize: \"11px\",\n color: t.textMuted,\n flex: 1,\n }}\n >\n AI enhanced\n </span>\n <button\n type=\"button\"\n onClick={() => {\n setIsEnhanced(false);\n setOriginalDescription(null);\n }}\n style={{\n padding: \"2px 8px\",\n borderRadius: \"4px\",\n border: `1px solid ${t.accent}`,\n background: t.accent,\n color: t.accentText,\n fontSize: \"11px\",\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n Keep\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setDescription(originalDescription);\n setIsEnhanced(false);\n setOriginalDescription(null);\n }}\n style={{\n padding: \"2px 8px\",\n borderRadius: \"4px\",\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"11px\",\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n Restore\n </button>\n </div>\n )}\n {/* Recovery instructions, not a one-word verdict —\n `lineHeight` and `maxWidth` so two sentences stay\n readable instead of running edge to edge. */}\n {voiceError && (\n <p\n role=\"alert\"\n style={{\n color: \"#ef4444\",\n fontSize: \"11px\",\n lineHeight: 1.5,\n marginTop: \"4px\",\n marginBottom: 0,\n }}\n >\n {voiceError}\n </p>\n )}\n\n {/* Why the assistant went away — a draft it wrote, a\n cap it hit, or a model that was down. Sits directly\n under the box it is talking about: a notice about\n the description that renders below Severity reads as\n being about Severity. */}\n {assistNotice && (\n <p\n style={{\n color: t.textMuted,\n fontSize: \"12px\",\n marginTop: \"6px\",\n marginBottom: 0,\n lineHeight: 1.5,\n }}\n >\n {assistNotice}\n </p>\n )}\n\n {/* Screenshot section — hidden for a rating. The dialog\n auto-captures the screen on open, and a testimonial\n has no reason to ship one (it may even be published\n publicly later). handleSubmit's rating branch never\n reads `screenshots`, so nothing leaks either way. */}\n {!isRating && (\n <div style={{ marginTop: \"10px\" }}>\n <span\n style={{\n fontSize: \"12px\",\n color: t.textMuted,\n marginBottom: \"6px\",\n display: \"block\",\n fontWeight: 500,\n }}\n >\n Attachments\n {screenshots.length + attachments.length > 0\n ? ` (${screenshots.length + attachments.length})`\n : \"\"}\n </span>\n {(screenshots.length > 0 || shotPending) && (\n <div\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: \"8px\",\n marginBottom: \"8px\",\n }}\n >\n {shotPending && (\n <div\n role=\"status\"\n aria-label=\"Capturing screenshot\"\n title=\"Capturing a screenshot of the page…\"\n style={{\n width: \"56px\",\n height: \"56px\",\n borderRadius: \"6px\",\n border: `1px dashed ${t.border}`,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"4px\",\n boxSizing: \"border-box\",\n fontSize: \"9px\",\n lineHeight: 1.2,\n textAlign: \"center\",\n color: t.textMuted,\n animation: \"gg-pulse 1.4s ease-in-out infinite\",\n }}\n >\n Capturing…\n </div>\n )}\n {screenshots.map((src, i) => (\n <div\n key={i}\n style={{\n position: \"relative\",\n width: \"56px\",\n height: \"56px\",\n }}\n >\n <img\n src={src}\n alt={`Screenshot ${i + 1}`}\n onClick={() => openPreview(i)}\n style={{\n width: \"100%\",\n height: \"100%\",\n borderRadius: \"6px\",\n border: `1px solid ${t.border}`,\n objectFit: \"cover\",\n objectPosition: \"top\",\n cursor: \"zoom-in\",\n display: \"block\",\n }}\n />\n <button\n type=\"button\"\n onClick={() =>\n setScreenshots((prev) =>\n prev.filter((_, idx) => idx !== i),\n )\n }\n aria-label={`Remove screenshot ${i + 1}`}\n style={{\n position: \"absolute\",\n top: \"-6px\",\n right: \"-6px\",\n width: \"17px\",\n height: \"17px\",\n borderRadius: \"50%\",\n border: \"none\",\n background: \"#ef4444\",\n color: \"#fff\",\n fontSize: \"11px\",\n lineHeight: 1,\n padding: 0,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <svg\n width=\"8\"\n height=\"8\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n >\n <path\n d=\"M1 1L9 9M9 1L1 9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n onClick={() => setAnnotatingIndex(i)}\n aria-label={`Annotate screenshot ${i + 1}`}\n title=\"Annotate\"\n style={{\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n width: \"24px\",\n height: \"24px\",\n borderRadius: \"50%\",\n border: \"none\",\n background: t.accent,\n color: t.accentText,\n padding: 0,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"0 2px 8px rgba(0,0,0,0.45)\",\n }}\n >\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n >\n <path\n d=\"M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z\"\n stroke=\"currentColor\"\n strokeWidth=\"2.2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n ))}\n </div>\n )}\n {attachments.length > 0 && (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"6px\",\n marginBottom: \"8px\",\n }}\n >\n {attachments.map((a, i) => (\n <div\n key={i}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n padding: \"6px 8px\",\n borderRadius: \"6px\",\n border: `1px solid ${t.border}`,\n }}\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{ flexShrink: 0, opacity: 0.6 }}\n >\n <path\n d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M14 2v6h6\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span\n style={{\n fontSize: \"11px\",\n color: t.text,\n flex: 1,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {a.name}\n </span>\n <span\n style={{ fontSize: \"10px\", color: t.textMuted }}\n >\n {(a.size / 1024).toFixed(0)}KB\n </span>\n <button\n type=\"button\"\n onClick={() =>\n setAttachments((prev) =>\n prev.filter((_, idx) => idx !== i),\n )\n }\n aria-label={`Remove ${a.name}`}\n style={{\n width: \"16px\",\n height: \"16px\",\n borderRadius: \"50%\",\n border: \"none\",\n background: \"#ef4444\",\n color: \"#fff\",\n fontSize: \"10px\",\n lineHeight: 1,\n padding: 0,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flexShrink: 0,\n }}\n >\n <svg\n width=\"8\"\n height=\"8\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n >\n <path\n d=\"M1 1L9 9M9 1L1 9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n ))}\n </div>\n )}\n {/* Drop zone — always available to add more */}\n <div\n onClick={() => fileInputRef.current?.click()}\n onDrop={(e) => {\n e.preventDefault();\n setScreenshotDragOver(false);\n addFiles(Array.from(e.dataTransfer.files));\n }}\n onDragOver={(e) => {\n e.preventDefault();\n setScreenshotDragOver(true);\n }}\n onDragLeave={() => setScreenshotDragOver(false)}\n style={{\n border: `1.5px dashed ${screenshotDragOver ? t.accent : t.inputBorder}`,\n borderRadius: \"8px\",\n padding:\n screenshots.length + attachments.length > 0\n ? \"8px 12px\"\n : \"18px 12px\",\n textAlign: \"center\",\n cursor: \"pointer\",\n background: screenshotDragOver\n ? isDark\n ? \"rgba(34,211,238,0.06)\"\n : \"rgba(8,145,178,0.04)\"\n : \"transparent\",\n transition:\n \"border-color 0.15s ease, background 0.15s ease\",\n }}\n >\n {screenshots.length + attachments.length > 0 ? (\n <p\n style={{\n margin: 0,\n fontSize: \"11px\",\n fontWeight: 500,\n color: t.textMuted,\n }}\n >\n {screenshotDragOver\n ? \"Drop to attach\"\n : \"+ Add more · Drag & drop · Paste\"}\n </p>\n ) : (\n <>\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{\n margin: \"0 auto 6px\",\n display: \"block\",\n opacity: 0.45,\n }}\n >\n <rect\n x=\"3\"\n y=\"3\"\n width=\"18\"\n height=\"18\"\n rx=\"2\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n />\n <circle\n cx=\"8.5\"\n cy=\"8.5\"\n r=\"1.5\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M21 15l-5-5L5 21\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <p\n style={{\n margin: 0,\n fontSize: \"12px\",\n fontWeight: 600,\n color: t.text,\n }}\n >\n {screenshotDragOver\n ? \"Drop to attach\"\n : \"Add screenshots or files\"}\n </p>\n <p\n style={{\n margin: \"3px 0 0\",\n fontSize: \"11px\",\n color: t.textMuted,\n }}\n >\n Images, PDF, DOC, XLS · Drag & drop · Paste\n ⌘V / Ctrl+V · Click to browse\n </p>\n </>\n )}\n </div>\n </div>\n )}\n\n {showSeverity && reportType === \"BUG\" && (\n <div style={{ marginTop: \"10px\" }}>\n <span\n style={{\n fontSize: \"12px\",\n color: t.textMuted,\n marginBottom: \"6px\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n }}\n >\n How bad is it?\n <span\n style={{\n color: severity\n ? t.textMuted\n : needsSeverity\n ? \"#ef4444\"\n : t.textMuted,\n fontSize: \"11px\",\n }}\n >\n {severity ? \"\" : \"· required\"}\n </span>\n </span>\n <div\n role=\"radiogroup\"\n aria-label=\"Severity\"\n style={{ display: \"flex\", gap: \"6px\" }}\n >\n {SEVERITY_LEVELS.map((s) => {\n const on = severity === s;\n return (\n <button\n key={s}\n type=\"button\"\n role=\"radio\"\n aria-checked={on}\n onClick={() => {\n setSeverity(s);\n if (validationError)\n setValidationError(null);\n }}\n style={{\n flex: 1,\n minWidth: 0,\n // 9px + 12px line + borders clears a 36px\n // tap target; 6px left it at ~29px.\n padding: \"9px 2px\",\n borderRadius: \"6px\",\n border: `1px solid ${\n on\n ? t.accent\n : needsSeverity\n ? \"#ef4444\"\n : t.inputBorder\n }`,\n background: on\n ? t.accent\n : \"transparent\",\n color: on ? t.accentText : t.text,\n fontSize: \"12px\",\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n whiteSpace: \"nowrap\",\n // Four labels where there were three: clip\n // rather than spill if a host squeezes the\n // dialog below ~260px.\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n transition: \"all 0.15s ease\",\n }}\n >\n {SEVERITY_LABELS[s]}\n </button>\n );\n })}\n </div>\n </div>\n )}\n {validationError && (\n <p\n style={{\n color: \"#ef4444\",\n fontSize: \"12px\",\n marginTop: \"6px\",\n }}\n >\n {validationError}\n </p>\n )}\n {similarIssues ? (\n // Same visual language as the assistant's \"Our team is\n // already on this\" card, so both routes to a duplicate\n // read as one feature.\n <div\n data-gg-similar=\"\"\n style={{\n marginTop: \"12px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"10px\",\n padding: \"12px\",\n borderRadius: \"10px\",\n border: \"1px solid rgba(245,158,11,0.4)\",\n backgroundColor: \"rgba(245,158,11,0.08)\",\n }}\n >\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"2px\" }}>\n {/* Theme text, not amber: amber on the tint is ~2:1 in light mode. */}\n <span style={{ color: t.text, fontWeight: 600, fontSize: \"13px\" }}>\n Our team may already have this, or something close\n </span>\n <span style={{ color: t.textMuted, fontSize: \"12px\", lineHeight: 1.5 }}>\n {similarIssues.length > 1\n ? \"Pick the one that matches. Same problem, or a different request for the same feature — it's added to that issue, so the team has it in one place.\"\n : \"Same problem, or a different request for the same feature? Pick it — it's added to that issue, so the team has it in one place.\"}\n </span>\n </div>\n {/* Title only, no link: an SDK reporter is a stranger to a\n private repo and the link would 404 for them. */}\n <div\n role=\"radiogroup\"\n aria-label=\"Existing issues\"\n style={{ display: \"flex\", flexDirection: \"column\", gap: \"6px\" }}\n >\n {similarIssues.map((issue) => {\n const picked = pickedSimilar === issue.number;\n return (\n <button\n key={issue.number}\n type=\"button\"\n role=\"radio\"\n aria-checked={picked}\n disabled={isSubmitting}\n onClick={() => setPickedSimilar(issue.number)}\n style={{\n display: \"flex\",\n alignItems: \"flex-start\",\n gap: \"10px\",\n width: \"100%\",\n minHeight: \"44px\",\n padding: \"9px 10px\",\n borderRadius: \"8px\",\n border: `1px solid ${picked ? t.accent : t.border}`,\n boxShadow: picked ? `0 0 0 1px ${t.accent}` : \"none\",\n backgroundColor: t.bg,\n color: t.text,\n textAlign: \"left\",\n cursor: isSubmitting ? \"not-allowed\" : \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n flexShrink: 0,\n marginTop: \"2px\",\n width: \"14px\",\n height: \"14px\",\n boxSizing: \"border-box\",\n borderRadius: \"50%\",\n border: `2px solid ${picked ? t.accent : t.textMuted}`,\n backgroundColor: picked ? t.accent : \"transparent\",\n boxShadow: picked ? `inset 0 0 0 2px ${t.bg}` : \"none\",\n }}\n />\n <span\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"3px\",\n minWidth: 0,\n }}\n >\n <span\n title={issue.title}\n style={{\n fontSize: \"12.5px\",\n lineHeight: 1.45,\n wordBreak: \"break-word\",\n overflow: \"hidden\",\n display: \"-webkit-box\",\n WebkitLineClamp: 3,\n WebkitBoxOrient: \"vertical\",\n }}\n >\n <span style={{ color: t.textMuted, fontWeight: 600 }}>\n #{issue.number}\n </span>{\" \"}\n {issue.title}\n </span>\n {issue.status && (\n <span style={{ fontSize: \"11.5px\", color: t.textMuted }}>\n {issue.status}\n </span>\n )}\n </span>\n </button>\n );\n })}\n </div>\n <button\n type=\"button\"\n disabled={isSubmitting || !pickedSimilar}\n onClick={() => {\n if (!pickedSimilar) return;\n setAttachingTo(pickedSimilar);\n setDuplicateIssueNumber(pickedSimilar);\n setDuplicateKind(\"duplicate\");\n void handleSubmit({ duplicateOf: pickedSimilar, kind: \"duplicate\" });\n }}\n style={{\n width: \"100%\",\n minHeight: \"40px\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor:\n isSubmitting || !pickedSimilar ? t.bgSecondary : t.accent,\n color: isSubmitting || !pickedSimilar ? t.textMuted : t.accentText,\n fontSize: \"14px\",\n fontWeight: 600,\n cursor: isSubmitting || !pickedSimilar ? \"not-allowed\" : \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n {typeof attachingTo === \"number\" && duplicateKind !== \"related\" ? (\n <>\n <ButtonSpinner />\n Adding to #{attachingTo}…\n </>\n ) : (\n pickedSimilar ? `Add to #${pickedSimilar}` : \"Pick the matching issue\"\n )}\n </button>\n {/* Not the same problem, but the same feature (practise_stack\n #1868 beside #1867). Only once a row is picked, so it always\n names the issue it writes to. */}\n {pickedSimilar && (\n <button\n type=\"button\"\n disabled={isSubmitting}\n onClick={() => {\n setAttachingTo(pickedSimilar);\n setDuplicateIssueNumber(pickedSimilar);\n setDuplicateKind(\"related\");\n void handleSubmit({ duplicateOf: pickedSimilar, kind: \"related\" });\n }}\n style={{\n width: \"100%\",\n minHeight: \"40px\",\n marginTop: \"-4px\",\n padding: \"9px 10px\",\n borderRadius: \"8px\",\n border: \"1px solid rgba(245,158,11,0.4)\",\n backgroundColor: \"transparent\",\n color: isSubmitting ? t.textMuted : t.text,\n fontSize: \"13px\",\n fontWeight: 600,\n cursor: isSubmitting ? \"not-allowed\" : \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n {typeof attachingTo === \"number\" && duplicateKind === \"related\" ? (\n <>\n <ButtonSpinner />\n Adding to #{attachingTo}…\n </>\n ) : (\n `Related request — add to #${pickedSimilar}`\n )}\n </button>\n )}\n <button\n type=\"button\"\n disabled={isSubmitting}\n onClick={() => {\n setAttachingTo(\"new\");\n void handleSubmit({ skipSimilar: true });\n }}\n style={{\n width: \"100%\",\n minHeight: \"40px\",\n marginTop: \"-4px\",\n padding: \"8px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor: \"transparent\",\n color: isSubmitting ? t.textMuted : t.text,\n fontSize: \"13px\",\n fontWeight: 500,\n textDecoration: \"underline\",\n textUnderlineOffset: \"3px\",\n cursor: isSubmitting ? \"not-allowed\" : \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n {attachingTo === \"new\" ? (\n <>\n <ButtonSpinner />\n Sending as new…\n </>\n ) : (\n \"No, mine is different — send as new\"\n )}\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n onClick={() => void handleSubmit()}\n disabled={submitDisabled}\n style={{\n marginTop: \"12px\",\n width: \"100%\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor: submitDisabled\n ? t.bgSecondary\n : t.accent,\n color: submitDisabled ? t.textMuted : t.accentText,\n fontSize: \"14px\",\n fontWeight: 600,\n cursor: submitDisabled ? \"not-allowed\" : \"pointer\",\n fontFamily: \"inherit\",\n transition: \"background-color 0.15s ease\",\n }}\n >\n {checkingSimilar ? (\n <>\n <ButtonSpinner />\n Checking for existing reports…\n </>\n ) : isSubmitting\n ? shotPending && !isRating\n ? \"Attaching screenshot…\"\n : \"Sending...\"\n : isRating\n ? \"Send Rating\"\n : \"Send Report\"}\n </button>\n )}\n </>\n )}\n </>\n )}\n </div>\n\n {/* Footer — who's reporting, and the attribution */}\n <div\n style={{\n padding: \"8px 16px 10px\",\n borderTop: `1px solid ${t.border}`,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: \"12px\",\n }}\n >\n <ReporterChip reporter={reporter} t={t} />\n {reportGlitchgrabProblem ? (\n <button\n type=\"button\"\n data-gg-self-report=\"\"\n onClick={() => {\n setSelfReportPrefill(\"\");\n setSelfReportFrom(\"form\");\n }}\n title=\"Something wrong with this reporter itself? Tell the Glitchgrab team.\"\n style={{\n fontSize: \"11px\",\n color: t.textMuted,\n whiteSpace: \"nowrap\",\n flexShrink: 0,\n border: \"none\",\n background: \"transparent\",\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n textDecoration: \"underline\",\n textUnderlineOffset: \"2px\",\n // A ~30px tap target without growing the footer.\n padding: \"9px 0\",\n margin: \"-9px 0\",\n }}\n >\n Problem with Glitchgrab?\n </button>\n ) : (\n <span\n style={{\n fontSize: \"11px\",\n color: t.textMuted,\n whiteSpace: \"nowrap\",\n flexShrink: 0,\n }}\n >\n Powered by Glitchgrab\n </span>\n )}\n </div>\n </div>\n </div>,\n document.body,\n )}\n\n {/* Hidden file input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={ATTACHMENT_ACCEPT}\n multiple\n onChange={handleFileUpload}\n style={{ display: \"none\" }}\n />\n\n {/* Full-screen screenshot preview */}\n {isOpen &&\n previewIndex !== null &&\n screenshots[previewIndex] &&\n createPortal(\n <div\n data-glitchgrab-layer=\"\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n backgroundColor: \"rgba(0,0,0,0.85)\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n cursor: \"pointer\",\n }}\n onClick={(e) => {\n e.stopPropagation();\n closePreview();\n }}\n onMouseDown={(e) => e.stopPropagation()}\n >\n <div\n ref={previewImgRef}\n style={{\n position: \"relative\",\n display: \"flex\",\n maxWidth: \"100%\",\n maxHeight: \"calc(100vh - 80px)\",\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div\n ref={previewScrollRef}\n onPointerDown={handlePanStart}\n onPointerMove={handlePanMove}\n onPointerUp={handlePanEnd}\n onPointerCancel={handlePanEnd}\n onClick={togglePreviewZoom}\n style={\n previewZoomed\n ? {\n // Fill the overlay so there is room to pan around a\n // full-resolution screenshot.\n width: \"calc(100vw - 32px)\",\n height: \"calc(100vh - 80px)\",\n overflow: \"auto\",\n borderRadius: \"8px\",\n touchAction: \"none\",\n cursor: \"grab\",\n }\n : { maxWidth: \"100%\", lineHeight: 0 }\n }\n >\n <img\n ref={previewImgElRef}\n src={screenshots[previewIndex]}\n alt=\"Screenshot preview\"\n onLoad={(e) =>\n setPreviewNatural({\n w: e.currentTarget.naturalWidth,\n h: e.currentTarget.naturalHeight,\n })\n }\n style={\n previewZoomed\n ? {\n // Natural size — one image pixel per CSS pixel.\n maxWidth: \"none\",\n maxHeight: \"none\",\n display: \"block\",\n cursor: \"zoom-out\",\n }\n : {\n maxWidth: \"100%\",\n maxHeight: \"calc(100vh - 80px)\",\n borderRadius: \"8px\",\n objectFit: \"contain\",\n cursor: canZoomPreview ? \"zoom-in\" : \"default\",\n display: \"block\",\n }\n }\n />\n </div>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setAnnotatingIndex(previewIndex);\n }}\n style={{\n position: \"absolute\",\n top: \"12px\",\n right: \"12px\",\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"6px\",\n padding: \"8px 14px\",\n borderRadius: \"999px\",\n border: \"none\",\n background: t.accent,\n color: t.accentText,\n fontSize: \"13px\",\n fontWeight: 700,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n boxShadow: \"0 4px 14px rgba(0,0,0,0.35)\",\n animation: \"gg-pulse 2s ease-in-out infinite\",\n }}\n >\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n Annotate\n </button>\n </div>\n <div\n style={{\n marginTop: \"12px\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"12px\",\n }}\n >\n <span\n style={{\n color: t.textMuted,\n fontSize: \"12px\",\n }}\n >\n {[\n screenshots.length > 1\n ? `${previewIndex + 1} / ${screenshots.length}`\n : null,\n canZoomPreview\n ? previewZoomed\n ? \"Drag to pan · click image to fit\"\n : \"Click image to zoom to full size\"\n : null,\n previewZoomed ? \"Esc to fit\" : \"Click outside to close\",\n ]\n .filter(Boolean)\n .join(\" · \")}\n </span>\n </div>\n </div>,\n document.body,\n )}\n\n {/* Annotation overlay */}\n {isOpen &&\n annotatingIndex !== null &&\n screenshots[annotatingIndex] &&\n createPortal(\n <AnnotationCanvas\n imageSrc={screenshots[annotatingIndex]}\n onCancel={() => setAnnotatingIndex(null)}\n onSave={(dataUrl) => {\n // Marking up the page shot keeps it the page shot.\n if (screenshots[annotatingIndex] === pageShot) setPageShot(dataUrl);\n setScreenshots((prev) =>\n prev.map((s, i) => (i === annotatingIndex ? dataUrl : s)),\n );\n setAnnotatingIndex(null);\n }}\n />,\n document.body,\n )}\n\n {/* \"Problem with Glitchgrab?\" (#366) — above the dialog AND the sheet,\n with its own send. Mounted after the sheet's portal, so at the same\n z-index it paints on top. */}\n {isOpen && selfReportFrom && reportGlitchgrabProblem && (\n <GlitchgrabProblemPanel\n send={reportGlitchgrabProblem}\n theme={layerTheme}\n surface={selfReportFrom}\n conversationId={aiConversationId}\n reportType={reportType}\n screenshots={screenshots}\n initialText={selfReportPrefill}\n onClose={() => setSelfReportFrom(null)}\n />\n )}\n\n {/* The AI sheet (#330) — its own layer, above the dialog. It owns the\n whole flow (chat → draft → Send) but NOT submission: `description`,\n `severity` and `handleSubmit` are this component's own, so there is\n exactly one submit path and the sheet cannot drift from it. */}\n {isOpen && sheetUp && (\n <AssistSheet\n assist={assist}\n theme={layerTheme}\n // Every image, not just the first: the auto page shot arrived at [0],\n // so passing that one meant a pasted picture never reached the model\n // however visibly it was attached (#352). The sheet sends the newest\n // few and shows the rest.\n screenshots={screenshots}\n pageShot={pageShot}\n onAddFiles={addFiles}\n onRemoveImage={(index) =>\n setScreenshots((prev) => prev.filter((_, i) => i !== index))\n }\n // Non-image attachments too (#1851): the assistant reads the text\n // ones, so a mockup attached on the form is part of the conversation.\n files={attachments}\n onRemoveFile={(index) =>\n setAttachments((prev) => prev.filter((_, i) => i !== index))\n }\n attachmentCount={screenshots.length + attachments.length}\n context={{ ...(assistContext ?? {}), reportType }}\n reportTypeLabel={getTypeLabel(reportType)}\n typePicked={typeChosen}\n currentTile={reportType}\n tiles={sendFeedback ? [...availableTypes, \"RATING\"] : availableTypes}\n onPickType={(tile) => {\n setReportType(tile);\n setTypeChosen(true);\n // Keep the dialog underneath in step with the sheet, so \"Write it\n // myself\" lands on the form for the tile that was just picked\n // rather than back on the grid.\n setStep(2);\n }}\n onDuplicateChange={(issueNumber, kind) => {\n setDuplicateIssueNumber(issueNumber);\n setDuplicateKind(issueNumber && kind === \"related\" ? \"related\" : \"duplicate\");\n }}\n onConversationChange={setAiConversationId}\n // The brief answered it: close everything rather than dropping them\n // back onto an empty form, which reads as \"file it anyway\".\n onFinish={handleClose}\n rating={rating}\n onRatingChange={(value) => {\n setRating(value);\n if (validationError) setValidationError(null);\n }}\n projectSlot={headerSlot}\n reporterName={reporter?.name ?? null}\n description={description}\n onDescriptionChange={(value) => {\n setDescription(value);\n if (validationError) setValidationError(null);\n }}\n severity={severity}\n onSeverityChange={(value) => {\n setSeverity(value);\n if (validationError) setValidationError(null);\n }}\n showSeverity={showSeverity}\n validationError={validationError}\n severityRefused={needsSeverity}\n isSubmitting={isSubmitting}\n submitted={submitted}\n onSend={() => void handleSubmit({ skipSimilar: true })}\n onReportGlitchgrabProblem={\n reportGlitchgrabProblem\n ? (prefill) => {\n setSelfReportPrefill(prefill ?? \"\");\n setSelfReportFrom(\"assist\");\n }\n : undefined\n }\n onDegrade={(message, retryable) => {\n setAssistOpen(false);\n // An hourly limit clears in minutes: keep the button so they can try\n // again on this report. Retiring it read as \"the AI threw me out\"\n // to a QA team sharing one office IP.\n if (!retryable) setAssistUsed(true);\n setAssistNotice(message);\n }}\n onClose={() => {\n setAssistOpen(false);\n // Closing by hand is not \"used up\" — someone who peeked and backed\n // out should still find the button where they left it. Only a\n // degrade that will not clear by itself (cap, outage) retires the\n // assistant for this report.\n requestAnimationFrame(() => textareaRef.current?.focus());\n }}\n />\n )}\n </>\n );\n}\n\n/* ─── Helpers ─── */\n\nfunction getPlaceholder(type: DialogTile, idx = 0, hasVoice = false): string {\n if (type === \"RATING\") return \"What made it good — or what let you down? (optional)\";\n if (hasVoice && idx === 1) return \"Hold Space to speak — we'll transcribe it\";\n switch (type) {\n case \"BUG\":\n return \"What went wrong? Describe it or paste an error...\";\n case \"FEATURE_REQUEST\":\n return \"Describe the feature you'd like...\";\n case \"UI_IMPROVEMENT\":\n return \"What looks off? Describe the visual issue...\";\n case \"PERFORMANCE\":\n return \"What's slow? Describe when it happens...\";\n case \"SECURITY\":\n return \"Describe the security concern...\";\n case \"QUESTION\":\n return \"What would you like to know?\";\n case \"OTHER\":\n return \"Tell us what's on your mind...\";\n }\n}\n\nfunction getTypeIcon(type: DialogTile, color: string, size = 24): ReactNode {\n const props = {\n width: size,\n height: size,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n style: { flexShrink: 0 } as CSSProperties,\n };\n switch (type) {\n case \"RATING\":\n return (\n <svg {...props}>\n <path\n d=\"M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.4 6.8 19.1l1-5.8L3.5 9.2l5.9-.9L12 3z\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n case \"BUG\":\n return (\n <svg {...props}>\n <path\n d=\"M8 2L6.5 3.5M16 2L17.5 3.5M3 9H7M17 9H21M12 2a5 5 0 015 5v4a5 5 0 01-10 0V7a5 5 0 015-5zM7 16l-2 3M17 16l2 3\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n case \"FEATURE_REQUEST\":\n return (\n <svg {...props}>\n <path\n d=\"M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2z\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n case \"UI_IMPROVEMENT\":\n return (\n <svg {...props}>\n <rect\n x=\"3\"\n y=\"3\"\n width=\"18\"\n height=\"18\"\n rx=\"2\"\n stroke={color}\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M3 9h18M9 21V9\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n );\n case \"PERFORMANCE\":\n return (\n <svg {...props}>\n <path\n d=\"M12 21a9 9 0 100-18 9 9 0 000 18zM12 12l4-4M12 7v.01\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n case \"SECURITY\":\n return (\n <svg {...props}>\n <path\n d=\"M12 3l7 3v5c0 4.5-3 8.5-7 10-4-1.5-7-5.5-7-10V6l7-3z\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n case \"QUESTION\":\n return (\n <svg {...props}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke={color} strokeWidth=\"1.5\" />\n <path\n d=\"M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3M12 17h.01\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n case \"OTHER\":\n return (\n <svg {...props}>\n <path\n d=\"M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2v10z\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n }\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { encodeScreenshot } from \"./image-encode\";\n\ntype Point = { x: number; y: number };\n\ntype Stroke =\n | { type: \"freehand\"; color: string; width: number; points: Point[] }\n | { type: \"circle\"; color: string; width: number; cx: number; cy: number; r: number };\n\nconst PALETTE = [\"#ef4444\", \"#f59e0b\", \"#22c55e\", \"#3b82f6\", \"#a855f7\", \"#ffffff\"];\n\nfunction drawStroke(ctx: CanvasRenderingContext2D, s: Stroke) {\n ctx.strokeStyle = s.color;\n ctx.lineWidth = s.width;\n ctx.lineCap = \"round\";\n ctx.lineJoin = \"round\";\n if (s.type === \"freehand\") {\n if (s.points.length < 2) return;\n ctx.beginPath();\n ctx.moveTo(s.points[0].x, s.points[0].y);\n for (let i = 1; i < s.points.length; i++) ctx.lineTo(s.points[i].x, s.points[i].y);\n ctx.stroke();\n } else {\n ctx.beginPath();\n ctx.arc(s.cx, s.cy, s.r, 0, Math.PI * 2);\n ctx.stroke();\n }\n}\n\ninterface AnnotationCanvasProps {\n imageSrc: string;\n onSave: (dataUrl: string) => void;\n onCancel: () => void;\n}\n\n/** Freehand + circle annotation overlay for a screenshot preview — draws directly on a canvas sized to the image's natural resolution, composited on save. */\nexport function AnnotationCanvas({ imageSrc, onSave, onCancel }: AnnotationCanvasProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const imgRef = useRef<HTMLImageElement | null>(null);\n const [ready, setReady] = useState(false);\n const [tool, setTool] = useState<\"pen\" | \"circle\">(\"pen\");\n const [color, setColor] = useState(PALETTE[0]);\n const [strokeWidth, setStrokeWidth] = useState(4);\n const [strokes, setStrokes] = useState<Stroke[]>([]);\n const [currentStroke, setCurrentStroke] = useState<Stroke | null>(null);\n\n useEffect(() => {\n const img = new Image();\n img.onload = () => {\n imgRef.current = img;\n const canvas = canvasRef.current;\n if (canvas) {\n canvas.width = img.naturalWidth;\n canvas.height = img.naturalHeight;\n }\n setReady(true);\n };\n img.src = imageSrc;\n }, [imageSrc]);\n\n useEffect(() => {\n if (!ready) return;\n const canvas = canvasRef.current;\n const img = imgRef.current;\n if (!canvas || !img) return;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\n for (const s of strokes) drawStroke(ctx, s);\n if (currentStroke) drawStroke(ctx, currentStroke);\n }, [ready, strokes, currentStroke]);\n\n const getPos = (e: React.PointerEvent<HTMLCanvasElement>): Point => {\n const canvas = e.currentTarget;\n const rect = canvas.getBoundingClientRect();\n return {\n x: ((e.clientX - rect.left) * canvas.width) / rect.width,\n y: ((e.clientY - rect.top) * canvas.height) / rect.height,\n };\n };\n\n const handlePointerDown = (e: React.PointerEvent<HTMLCanvasElement>) => {\n e.currentTarget.setPointerCapture(e.pointerId);\n const { x, y } = getPos(e);\n setCurrentStroke(\n tool === \"pen\"\n ? { type: \"freehand\", color, width: strokeWidth, points: [{ x, y }] }\n : { type: \"circle\", color, width: strokeWidth, cx: x, cy: y, r: 0 },\n );\n };\n\n const handlePointerMove = (e: React.PointerEvent<HTMLCanvasElement>) => {\n if (!currentStroke) return;\n const { x, y } = getPos(e);\n setCurrentStroke((prev) => {\n if (!prev) return prev;\n if (prev.type === \"freehand\") return { ...prev, points: [...prev.points, { x, y }] };\n return { ...prev, r: Math.hypot(x - prev.cx, y - prev.cy) };\n });\n };\n\n const handlePointerUp = () => {\n setCurrentStroke((prev) => {\n if (prev) setStrokes((s) => [...s, prev]);\n return null;\n });\n };\n\n const handleSave = () => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n // Annotating re-encodes an already-JPEG image, so quality is chosen by the\n // shared budget ladder rather than a fixed low value — a second lossy pass\n // at 0.85 was visibly degrading text.\n onSave(encodeScreenshot(canvas));\n };\n\n const iconBtn = (active = false): React.CSSProperties => ({\n width: \"30px\",\n height: \"30px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"6px\",\n border: `1.5px solid ${active ? \"#22d3ee\" : \"rgba(255,255,255,0.15)\"}`,\n background: active ? \"rgba(34,211,238,0.15)\" : \"transparent\",\n color: \"#fff\",\n cursor: \"pointer\",\n padding: 0,\n });\n\n return (\n <div\n data-glitchgrab-layer=\"\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n backgroundColor: \"rgba(0,0,0,0.9)\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n }}\n onClick={(e) => {\n e.stopPropagation();\n if (e.target === e.currentTarget) onCancel();\n }}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <canvas\n ref={canvasRef}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n style={{\n maxWidth: \"100%\",\n maxHeight: \"calc(100vh - 140px)\",\n borderRadius: \"8px\",\n touchAction: \"none\",\n cursor: \"crosshair\",\n display: \"block\",\n }}\n />\n\n <div\n style={{\n marginTop: \"14px\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n flexWrap: \"wrap\",\n justifyContent: \"center\",\n maxWidth: \"100%\",\n }}\n >\n <button type=\"button\" onClick={() => setTool(\"pen\")} style={iconBtn(tool === \"pen\")} title=\"Freehand\" aria-label=\"Freehand tool\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path d=\"M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n <button type=\"button\" onClick={() => setTool(\"circle\")} style={iconBtn(tool === \"circle\")} title=\"Circle\" aria-label=\"Circle tool\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"12\" r=\"8\" stroke=\"currentColor\" strokeWidth=\"1.8\" />\n </svg>\n </button>\n\n <div style={{ width: \"1px\", height: \"20px\", background: \"rgba(255,255,255,0.15)\" }} />\n\n {PALETTE.map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => setColor(c)}\n aria-label={`Color ${c}`}\n style={{\n width: \"22px\",\n height: \"22px\",\n borderRadius: \"50%\",\n background: c,\n border: color === c ? \"2px solid #22d3ee\" : \"2px solid rgba(255,255,255,0.3)\",\n cursor: \"pointer\",\n padding: 0,\n }}\n />\n ))}\n <input\n type=\"color\"\n value={color}\n onChange={(e) => setColor(e.target.value)}\n title=\"Custom color\"\n aria-label=\"Custom color\"\n style={{\n width: \"22px\",\n height: \"22px\",\n padding: 0,\n border: \"none\",\n background: \"none\",\n cursor: \"pointer\",\n }}\n />\n\n <div style={{ width: \"1px\", height: \"20px\", background: \"rgba(255,255,255,0.15)\" }} />\n\n <input\n type=\"range\"\n min={2}\n max={12}\n value={strokeWidth}\n onChange={(e) => setStrokeWidth(Number(e.target.value))}\n title=\"Stroke width\"\n aria-label=\"Stroke width\"\n style={{ width: \"70px\" }}\n />\n\n <div style={{ width: \"1px\", height: \"20px\", background: \"rgba(255,255,255,0.15)\" }} />\n\n <button\n type=\"button\"\n onClick={() => setStrokes((s) => s.slice(0, -1))}\n disabled={strokes.length === 0}\n style={{ ...iconBtn(), opacity: strokes.length === 0 ? 0.35 : 1 }}\n title=\"Undo\"\n aria-label=\"Undo\"\n >\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path d=\"M9 14L4 9l5-5M4 9h10a6 6 0 010 12h-2\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n <button\n type=\"button\"\n onClick={() => setStrokes([])}\n disabled={strokes.length === 0}\n style={{ ...iconBtn(), opacity: strokes.length === 0 ? 0.35 : 1 }}\n title=\"Clear all\"\n aria-label=\"Clear all\"\n >\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path d=\"M3 6h18M8 6V4a1 1 0 011-1h6a1 1 0 011 1v2m2 0v14a1 1 0 01-1 1H7a1 1 0 01-1-1V6h12z\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div style={{ marginTop: \"12px\", display: \"flex\", gap: \"8px\" }}>\n <button\n type=\"button\"\n onClick={onCancel}\n style={{\n padding: \"8px 16px\",\n borderRadius: \"8px\",\n border: \"1.5px solid rgba(255,255,255,0.2)\",\n background: \"transparent\",\n color: \"#fff\",\n fontSize: \"13px\",\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleSave}\n style={{\n padding: \"8px 16px\",\n borderRadius: \"8px\",\n border: \"none\",\n background: \"#22d3ee\",\n color: \"#09090b\",\n fontSize: \"13px\",\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n }}\n >\n Save annotation\n </button>\n </div>\n </div>\n );\n}\n","/**\n * Screenshot encoding shared by the capture path and the annotation editor.\n *\n * Screenshots travel to `/api/v1/sdk/report` as base64 inside a JSON body, so\n * every extra pixel is billed against the serverless request-body limit\n * (~4.5 MB on Vercel). We want the sharpest image that still leaves room for a\n * second screenshot plus the rest of the payload, so encode at high quality\n * first and only step down when the result overshoots the budget.\n */\n\n/** Max length of a single screenshot data URL. Two of these still fit in one request. */\nexport const MAX_SCREENSHOT_DATA_URL_LENGTH = 1_800_000;\n\n/** Tried in order — the first one under budget wins. */\nconst QUALITY_LADDER = [0.92, 0.85, 0.75] as const;\n\n/** When even q0.75 overshoots: redraw at this factor, then re-run the ladder. */\nconst DOWNSCALE_FACTOR = 0.7;\n\n/**\n * Full resolution plus three downscales (0.7, 0.49, 0.34). One downscale used\n * to be the limit, and an image still over budget after it was returned over\n * budget — the cap was advisory for exactly the images it existed for.\n */\nconst MAX_ROUNDS = 4;\n\nfunction downscale(\n canvas: HTMLCanvasElement,\n factor: number,\n): HTMLCanvasElement | null {\n const next = document.createElement(\"canvas\");\n next.width = Math.max(1, Math.round(canvas.width * factor));\n next.height = Math.max(1, Math.round(canvas.height * factor));\n const ctx = next.getContext(\"2d\");\n if (!ctx) return null;\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = \"high\";\n ctx.drawImage(canvas, 0, 0, next.width, next.height);\n return next;\n}\n\n/**\n * JPEG-encode a canvas at the highest quality that fits the payload budget.\n * Resolution is preserved unless every quality step overshoots — losing pixels\n * is what made screenshots unreadable, so it is the last thing we give up.\n */\nexport function encodeScreenshot(\n canvas: HTMLCanvasElement,\n maxLength = MAX_SCREENSHOT_DATA_URL_LENGTH,\n): string {\n let current = canvas;\n let encoded = \"\";\n\n for (let round = 0; round < MAX_ROUNDS; round++) {\n for (const quality of QUALITY_LADDER) {\n encoded = current.toDataURL(\"image/jpeg\", quality);\n if (encoded.length <= maxLength) return encoded;\n }\n if (round === MAX_ROUNDS - 1) break;\n const smaller = downscale(current, DOWNSCALE_FACTOR);\n if (!smaller) break;\n current = smaller;\n }\n\n // Nothing fit. The smallest attempt beats no image; the sheet's total budget\n // decides whether it rides along.\n return encoded;\n}\n\nfunction readAsDataUrl(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n}\n\nasync function reencodeImageFile(file: File, maxLength: number): Promise<string | null> {\n if (typeof createImageBitmap !== \"function\") return null;\n const bitmap = await createImageBitmap(file);\n try {\n const canvas = document.createElement(\"canvas\");\n canvas.width = bitmap.width;\n canvas.height = bitmap.height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n // JPEG has no alpha channel — transparent pixels would come out black.\n ctx.fillStyle = \"#ffffff\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(bitmap, 0, 0);\n return encodeScreenshot(canvas, maxLength);\n } finally {\n bitmap.close?.();\n }\n}\n\n/**\n * An image the reporter attached or pasted, as a data URL held to the same\n * budget as a captured screenshot.\n *\n * These used to ride along exactly as read off disk. A retina PNG from the\n * clipboard is routinely 5–10 MB — over the request-body limit on its own — so\n * Vercel refused the assistant turn at the edge with a 413 before the route\n * ran: no log, no degrade message from the server, the sheet just closed.\n *\n * A file already under budget passes through untouched, so a small PNG crop\n * stays a sharp PNG. Anything that cannot be decoded here (no\n * `createImageBitmap`, a format the browser can't draw) comes back raw; the\n * sheet's total budget is the backstop for those.\n */\nexport async function encodeImageFile(\n file: File,\n maxLength = MAX_SCREENSHOT_DATA_URL_LENGTH,\n): Promise<string> {\n // A data URL is base64 (4 chars per 3 bytes) behind a short `data:…;base64,`\n // prefix, so the size is known before reading a byte.\n const rawLength = Math.ceil(file.size / 3) * 4 + 64;\n if (rawLength > maxLength) {\n try {\n const shrunk = await reencodeImageFile(file, maxLength);\n if (shrunk && shrunk.length < rawLength) return shrunk;\n } catch {\n // Fall through to the raw file — an unreadable image is still evidence.\n }\n }\n return readAsDataUrl(file);\n}\n","\"use client\";\n\nimport { useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type {\n AssistFile,\n AssistFn,\n AssistSheetEvent,\n AssistTurnResult,\n AttachKind,\n DialogTile,\n ReportSeverity,\n} from \"./types\";\nimport {\n MAX_ASSIST_FILE_CHARS,\n MAX_ASSIST_FILE_CHARS_EACH,\n MAX_ASSIST_FILES,\n MAX_ASSIST_IMAGE_CHARS,\n MAX_ASSIST_IMAGES,\n SEVERITY_LEVELS,\n SEVERITY_LABELS,\n} from \"./types\";\nimport {\n ASSIST_ATTACHMENT_ACCEPT,\n decodeTextDataUrl,\n isAssistReadableFile,\n} from \"./attachments\";\nimport { getTypeLabel } from \"./labels\";\nimport { ChatMarkdown } from \"./chat-markdown\";\n\n/**\n * The AI report assistant, as a sheet (#330).\n *\n * A right-hand drawer on a wide screen, a bottom sheet under 640px — the shape\n * every chat surface a reporter has ever used already has. It replaced an\n * in-dialog panel that technically worked and read like a form field: a\n * conversation crammed into 150px of a 420px card never felt like talking to\n * anyone.\n *\n * The sheet owns the whole flow — chat, then the draft, then Send. There is no\n * hand-back to the dialog, because a context switch at the exact moment someone\n * is finished is the worst possible time to move them.\n *\n * It does NOT own submission. `description`, `severity` and `onSend` are the\n * dialog's own state and handler passed straight through, so there is exactly\n * one submit path in this package and the sheet cannot drift from it.\n *\n * Every failure path ends the same way: `onDegrade` fires, the sheet closes,\n * and the plain form is there. Filing a bug never depends on a model.\n */\n\nexport interface AssistTheme {\n bg: string;\n bgSecondary: string;\n border: string;\n text: string;\n textMuted: string;\n inputBg: string;\n inputBorder: string;\n accent: string;\n accentText: string;\n}\n\ninterface ChatMessage {\n role: \"user\" | \"assistant\";\n content: string;\n /**\n * A draft the model wrote. Its `content` is the draft TEXT, not a \"here's\n * your report\" line — the model has to see what it wrote, or \"keep chatting\"\n * makes the reporter describe the whole thing again (#357).\n */\n kind?: \"report\";\n}\n\n/**\n * The images one turn can carry: newest first, at most `MAX_ASSIST_IMAGES`,\n * and never more than `MAX_ASSIST_IMAGE_CHARS` between them. An image that\n * would overflow is skipped rather than ending the pick, so a heavy paste costs\n * itself, not the small page shot behind it. Returned oldest-first, the order\n * the model reads them in.\n */\nfunction pickAssistImages(all: string[]): string[] {\n const picked: string[] = [];\n let total = 0;\n for (let i = all.length - 1; i >= 0 && picked.length < MAX_ASSIST_IMAGES; i--) {\n const shot = all[i];\n if (total + shot.length > MAX_ASSIST_IMAGE_CHARS) continue;\n picked.unshift(shot);\n total += shot.length;\n }\n return picked;\n}\n\n/** A non-image file attached to the report, as the dialog holds it. */\ninterface SheetFile {\n name: string;\n size: number;\n dataUrl: string;\n}\n\n/** Stable empty default, so the memo below does not re-decode every render. */\nconst NO_FILES: SheetFile[] = [];\n\n/**\n * The text files one turn can carry (#1851): readable types only, newest\n * first, at most `MAX_ASSIST_FILES` and `MAX_ASSIST_FILE_CHARS` between them,\n * each cut at `MAX_ASSIST_FILE_CHARS_EACH`. Returned oldest-first with each\n * file's index in `files`, so the strip marks exactly the ones sent.\n */\nfunction pickAssistFiles(files: SheetFile[]): { index: number; file: AssistFile }[] {\n const picked: { index: number; file: AssistFile }[] = [];\n let total = 0;\n for (let i = files.length - 1; i >= 0 && picked.length < MAX_ASSIST_FILES; i--) {\n const attached = files[i];\n if (!isAssistReadableFile(attached.name)) continue;\n const text = decodeTextDataUrl(attached.dataUrl);\n if (!text || !text.trim()) continue;\n const content = text.slice(0, MAX_ASSIST_FILE_CHARS_EACH);\n if (total + content.length > MAX_ASSIST_FILE_CHARS) continue;\n picked.unshift({ index: i, file: { name: attached.name, content } });\n total += content.length;\n }\n return picked;\n}\n\ninterface AssistSheetProps {\n assist: AssistFn;\n theme: AssistTheme;\n /**\n * Every image attached to the report, oldest first — the auto-captured page\n * shot, then anything pasted or picked in here. The newest that fit\n * `MAX_ASSIST_IMAGES` and `MAX_ASSIST_IMAGE_CHARS` go to the model\n * (`pickAssistImages`); the strip above the composer shows all of them, because a\n * paste that lands somewhere invisible reads as a paste that failed (#352).\n */\n screenshots: string[];\n /**\n * The shot the dialog captured itself when it opened, if it did. Every other\n * entry of `screenshots` was added by the reporter — and is usually the thing\n * they are complaining about, which may not be this page at all (#357).\n */\n pageShot?: string | null;\n /**\n * Add images or files from inside the sheet. The host owns both lists and\n * sorts them: images to `screenshots`, anything else to `files`.\n */\n onAddFiles?: (files: File[]) => void;\n /**\n * Every non-image file attached to the report, oldest first (#1851). The\n * text ones the assistant can read are sent with each turn; the rest (pdf,\n * docx) are shown so the reporter knows they are attached, and dimmed.\n */\n files?: SheetFile[];\n /** Take one file back off the report, by its index in `files`. */\n onRemoveFile?: (index: number) => void;\n /**\n * Take one image back off the report, by its index in `screenshots` (#360).\n * Without it a wrong paste could only be undone by leaving the sheet — and\n * the reporter had no idea the dialog behind it had a remove button.\n */\n onRemoveImage?: (index: number) => void;\n /** How many screenshots + files are attached, for the draft's summary line. */\n attachmentCount: number;\n /** Page URL / breadcrumbs / report type — whatever the host knows. */\n context: Record<string, unknown> | null;\n /** \"Bug Report\", \"Feature Request\", … — shown in the header. */\n reportTypeLabel: string;\n\n /**\n * The picker turn (#330 follow-up). ⌘⇧G now lands here instead of on the\n * dialog's tile grid, so the very first thing the sheet does is ask what\n * this is — as chips, not as a model turn. Deterministic, instant, and it\n * costs nothing from the project's monthly conversation cap.\n *\n * `typePicked` is true when the host already knows (a tile was clicked in\n * the dialog, or the host opened with a type), and the picker is skipped.\n */\n typePicked: boolean;\n /** What the dialog currently holds — decides whether a picked type is a\n * rating (stars, no model) or a report (chat). */\n currentTile: DialogTile;\n tiles: DialogTile[];\n onPickType: (tile: DialogTile) => void;\n\n /**\n * The rating step. A star needs no assistant, so this branch never calls the\n * model: stars + an optional line, straight down the host's FeedbackFn.\n * The submit path itself stays the dialog's — `onSend` is its `handleSubmit`,\n * which already routes a RATING through `FeedbackFn` instead of the report\n * API. The sheet never grows a second way to submit.\n */\n rating: number;\n onRatingChange: (value: number) => void;\n /** The host's \"Reporting to <project>\" line, reused verbatim. */\n projectSlot?: ReactNode;\n reporterName?: string | null;\n\n /** The dialog's description state. The draft box edits it in place. */\n description: string;\n onDescriptionChange: (value: string) => void;\n /** `null` until picked — the sheet never pre-selects one either (#353). */\n severity: ReportSeverity | null;\n onSeverityChange: (value: ReportSeverity) => void;\n showSeverity: boolean;\n /**\n * The dialog owns submission, so a refused send (no severity, low-quality\n * text) sets an error the reporter cannot see behind this sheet. Rendered\n * above Send.\n */\n validationError?: string | null;\n /**\n * True only when the refusal was ABOUT severity. Computed by the dialog,\n * which owns the error: painting the row red for a low-quality-text refusal\n * would point at the wrong field and teach people to ignore red.\n */\n severityRefused?: boolean;\n\n /**\n * Tells the dialog which issue to attach to, so its ONE submit path carries\n * the number into report metadata. Null clears it — the reporter kept typing\n * and it stopped looking like a duplicate. `kind` says whether it is the same\n * problem or a related request for that issue.\n */\n onDuplicateChange?: (issueNumber: number | null, kind?: AttachKind) => void;\n\n /**\n * Tells the dialog which chat this is, so its ONE submit path carries the id\n * into report metadata. That link is the only way to answer \"how many prompts\n * does a filed issue cost\" — a conversation with no report against it is one\n * that went nowhere, and that is a finding too.\n */\n onConversationChange?: (conversationId: string | null) => void;\n\n isSubmitting: boolean;\n submitted: boolean;\n onSend: () => void;\n\n /** `retryable`: the reason clears on its own, so the assistant is not retired. */\n onDegrade: (message: string, retryable?: boolean) => void;\n onClose: () => void;\n /**\n * Close the whole dialog, not just the sheet. Used when the brief answered\n * the question: dropping them back onto an empty report form after telling\n * them they are done would read as \"now file it anyway\".\n */\n onFinish?: () => void;\n /**\n * Opens the dialog's \"Problem with Glitchgrab?\" panel (#366). The sheet is\n * where the assistant goes wrong, so the way to say so lives here too — as a\n * link, and as a card when the assistant itself decides the chat is about\n * Glitchgrab. `prefill` is the reporter's own words, so they never retype.\n * Omitted when the host did not offer it.\n */\n onReportGlitchgrabProblem?: (prefill?: string) => void;\n}\n\n/**\n * Openers, not instructions. Someone who does not know what to type is the\n * whole reason this surface exists; a blank box helps them least.\n */\nconst STARTERS = [\n \"Something on this page is broken\",\n \"It did the wrong thing\",\n \"I wish it could…\",\n];\n\n/**\n * The check-back chip the prompt offers before the first report\n * (`apps/web/lib/ai-assist/prompt.ts`, pinned in `prompt.test.ts`). Tapping it\n * already confirmed the restatement, so the report it produces files itself\n * after a short countdown instead of asking for a second Send (#402). A plain\n * typed yes arms it too (`isAffirmativeReply`): reporters answer \"Is that right?\"\n * by typing \"yes\", and were then made to press Send on top of saying yes.\n */\nconst CONFIRM_OPTION = \"Yes, that's it\";\n\n/**\n * The assistant saying back what it understood (\"So you're saying… Is that\n * right?\"). The prompt pairs it with the \"Yes, that's it\" chip, but the model\n * does not always send the chip — and a yes to the question is the same answer\n * either way.\n */\nexport function isCheckBackQuestion(text: string): boolean {\n const t = text.trim();\n return (\n /^so,? you['’]?re saying\\b/i.test(t) ||\n /\\b(is that right|is that correct|did i get (that|it) right|have i got (that|it) right)\\s*\\??\\s*$/i.test(t)\n );\n}\n\n/**\n * A reply that is only a yes — \"yes\", \"yeah\", \"correct\", \"haan\", \"👍\". Anything\n * with more in it is a correction and must go back to the model, so the whole\n * message has to be the yes.\n */\nexport function isAffirmativeReply(text: string): boolean {\n return /^(y|ya|yah|yes|yess|yeah|yep|yup|ok|okay|sure|correct|right|exactly|confirm(ed)?|that['’]?s (it|right|correct)|yes,? that['’]?s (it|right)|haan|han|ha|ho|hmm yes|👍)[\\s.!👍]*$/i.test(\n text.trim(),\n );\n}\n\n/**\n * Seconds a confirmed draft stays on screen before it files itself (#402). The\n * reporter never read the draft before confirming — it is written after the\n * tap — so this is the window in which a wrong or injected draft gets stopped,\n * with the × beside the countdown (#406).\n */\nconst AUTO_FILE_SECONDS = 3;\n\nconst NARROW_QUERY = \"(max-width: 640px)\";\n\nfunction useIsNarrow(): boolean {\n const [narrow, setNarrow] = useState(false);\n useEffect(() => {\n try {\n const mq = window.matchMedia(NARROW_QUERY);\n setNarrow(mq.matches);\n const onChange = (e: MediaQueryListEvent) => setNarrow(e.matches);\n mq.addEventListener(\"change\", onChange);\n return () => mq.removeEventListener(\"change\", onChange);\n } catch {\n // Never crash a host page over a layout preference.\n }\n }, []);\n return narrow;\n}\n\nfunction Sparkle({ color, size = 14 }: { color: string; size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3zM19 15l.75 2.25L22 18l-2.25.75L19 21l-.75-2.25L16 18l2.25-.75L19 15z\"\n stroke={color}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n\n/** Small round avatar so a transcript reads as two people, not one log. */\nfunction Avatar({\n who,\n theme: t,\n initials,\n}: {\n who: \"user\" | \"assistant\";\n theme: AssistTheme;\n /** The reporter's own initials. A stray \"Y\" for \"You\" reads as a typo. */\n initials?: string;\n}) {\n const isAi = who === \"assistant\";\n return (\n <span\n aria-hidden=\"true\"\n style={{\n flexShrink: 0,\n width: \"24px\",\n height: \"24px\",\n borderRadius: \"50%\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n marginTop: \"2px\",\n backgroundColor: isAi ? `${t.accent}22` : t.bgSecondary,\n border: `1px solid ${isAi ? t.accent : t.inputBorder}`,\n color: isAi ? t.accent : t.textMuted,\n fontSize: \"10px\",\n fontWeight: 700,\n }}\n >\n {isAi ? (\n <Sparkle color={t.accent} size={12} />\n ) : initials ? (\n initials\n ) : (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"8\" r=\"3.4\" stroke=\"currentColor\" strokeWidth=\"1.8\" />\n <path\n d=\"M5 20c0-3.6 3.1-5.6 7-5.6s7 2 7 5.6\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n />\n </svg>\n )}\n </span>\n );\n}\n\nexport function AssistSheet({\n assist,\n theme: t,\n screenshots,\n pageShot = null,\n onAddFiles,\n files = NO_FILES,\n onRemoveFile,\n onRemoveImage,\n attachmentCount,\n context,\n reportTypeLabel,\n typePicked,\n currentTile,\n tiles,\n onPickType,\n rating,\n onRatingChange,\n projectSlot,\n reporterName,\n description,\n onDescriptionChange,\n severity,\n onSeverityChange,\n showSeverity,\n validationError,\n severityRefused = false,\n onDuplicateChange,\n onConversationChange,\n isSubmitting,\n submitted,\n onSend,\n onDegrade,\n onClose,\n onFinish,\n onReportGlitchgrabProblem,\n}: AssistSheetProps) {\n const narrow = useIsNarrow();\n /** A send the dialog refused because nothing is picked yet — turns the row red. */\n /**\n * The picker mirrors the dialog's gate exactly — `showSeverity` AND a bug.\n * A feature request has no severity to give, and showing \"required\" on a\n * field the dialog will not ask for makes Send unexplainable.\n */\n const severityAsked = showSeverity && currentTile === \"BUG\";\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [input, setInput] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [conversationId, setConversationId] = useState<string | null>(null);\n /** Star hover preview — local, because it is pure presentation. */\n const [hoveredStar, setHoveredStar] = useState(0);\n /**\n * Tappable answers offered with the last question. Cleared the moment\n * anything is sent — a stale chip row invites answering a question that has\n * already moved on.\n */\n const [options, setOptions] = useState<string[]>([]);\n /**\n * The already-open issue this turned out to be. Server-validated, so the\n * number is safe to hand back on submit: the report is added to that issue\n * as a comment rather than opening a second one.\n */\n const [duplicate, setDuplicate] = useState<\n (NonNullable<AssistTurnResult[\"duplicate\"]> & { kind: AttachKind }) | null\n >(null);\n /** The assistant said \"this is about Glitchgrab, not this app\" (#366) — show the offer card. */\n const [glitchgrabOffer, setGlitchgrabOffer] = useState(false);\n /**\n * The brief answered it. Nothing is filed and the dialog closes — the whole\n * point of giving the assistant the project's guides is that some people\n * should never have to write a report at all.\n */\n const [solved, setSolved] = useState<string | null>(null);\n /**\n * A bug is asked how bad it is right after its type, before the chat (#402).\n * Asked once: a severity already picked on the form is not asked again.\n */\n const needsSeverity = (tile: DialogTile) => showSeverity && tile === \"BUG\" && !severity;\n /**\n * \"type\" → the picker chips, \"severity\" → how bad a bug is, \"rating\" →\n * stars, \"chat\" → the conversation, \"draft\" → the model's report, ready to\n * send. A sheet opened from the dialog's own \"Describe it with AI\" button\n * already knows its type and starts at \"chat\" (or \"severity\" for a bug);\n * ⌘⇧G starts at \"type\".\n */\n const [phase, setPhase] = useState<\n \"type\" | \"severity\" | \"rating\" | \"chat\" | \"draft\" | \"solved\"\n >(() =>\n !typePicked\n ? \"type\"\n : currentTile === \"RATING\"\n ? \"rating\"\n : needsSeverity(currentTile)\n ? \"severity\"\n : \"chat\",\n );\n /**\n * Seconds until a confirmed draft files itself (#402), null when nothing is\n * counting. Driven by the effect below, so closing the sheet, a degrade or\n * the dialog starting its own submit all stop it without a stray timer.\n */\n const [autoFileLeft, setAutoFileLeft] = useState<number | null>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n const draftRef = useRef<HTMLTextAreaElement>(null);\n /** Guards the seed below against React 18's double-invoked effects. */\n const seededRef = useRef(false);\n /** The opening turn is waiting for the severity answer (#402). */\n const seedPendingRef = useRef(false);\n /**\n * Clicks the server has not seen yet (#357). They ride along with the next\n * turn, or go on their own when the sheet is left — the moment someone gives\n * up on the assistant is exactly the click worth keeping.\n */\n const eventsRef = useRef<AssistSheetEvent[]>([]);\n /** The model's own last draft, to tell \"sent as drafted\" from \"edited\". */\n const aiDraftRef = useRef<string | null>(null);\n\n function logEvent(type: AssistSheetEvent[\"type\"], detail?: string) {\n eventsRef.current.push({ type, at: Date.now(), ...(detail ? { detail } : {}) });\n }\n\n function takeEvents(): AssistSheetEvent[] | undefined {\n if (eventsRef.current.length === 0) return undefined;\n const events = eventsRef.current;\n eventsRef.current = [];\n return events;\n }\n\n /**\n * Send pending clicks without a model turn. Fire-and-forget: the server\n * answers an empty `messages` with no model call and nothing counted, and\n * nobody waits on it. Needs a conversation to attach to — clicks before the\n * first reply have nowhere to go and ride with that reply instead.\n */\n function flushEvents() {\n if (!conversationId) return;\n const events = takeEvents();\n if (!events) return;\n try {\n void Promise.resolve(\n assist({ messages: [], conversationId, events, screenshots: [], context: null }),\n ).catch(() => {});\n } catch {\n // A host's fn threw synchronously. Losing a click log is fine.\n }\n }\n\n // What the next turn will actually send — the strip marks exactly these, so\n // an image dropped for size reads as unread, not just one dropped for count.\n const readShots = new Set(pickAssistImages(screenshots));\n // Decoding a mockup is not free, and this body re-runs on every keystroke.\n const sentFiles = useMemo(() => pickAssistFiles(files), [files]);\n const readFiles = new Set(sentFiles.map((f) => f.index));\n\n /** Every way out of the sheet that is not Send. */\n function leave(type: \"write_myself\" | \"closed\", detail?: string) {\n logEvent(type, detail);\n flushEvents();\n onClose();\n }\n\n useEffect(() => {\n const el = scrollRef.current;\n if (el) el.scrollTop = el.scrollHeight;\n }, [messages, busy, phase]);\n\n useEffect(() => {\n if (phase === \"draft\") draftRef.current?.focus();\n }, [phase]);\n\n useEffect(() => {\n if (autoFileLeft === null) return;\n // The dialog took over (Send pressed by hand) or the draft went away.\n if (isSubmitting || submitted || phase !== \"draft\") {\n setAutoFileLeft(null);\n return;\n }\n if (autoFileLeft <= 0) {\n sendDraft(true);\n return;\n }\n const id = setTimeout(() => setAutoFileLeft((n) => (n === null ? null : n - 1)), 1000);\n return () => clearTimeout(id);\n // `sendDraft` is re-created every render; the tick that reaches 0 renders\n // first, so it is always the current one.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [autoFileLeft, isSubmitting, submitted, phase]);\n\n /** The reporter touched the draft, so it is theirs to send now (#402). */\n function stopAutoFile(reason: string) {\n if (autoFileLeft === null) return;\n setAutoFileLeft(null);\n logEvent(\"auto_file_stopped\", reason);\n }\n\n /**\n * A turn that failed carried clicks with it. Put them back and flush them on\n * their own — the clicks right before an outage are exactly the ones worth\n * reading, and a cap/rate-limit degrade still accepts an events-only flush.\n */\n function degradeKeepingEvents(\n events: AssistSheetEvent[] | undefined,\n message: string,\n retryable?: boolean,\n ) {\n if (events) eventsRef.current = [...events, ...eventsRef.current];\n flushEvents();\n onDegrade(message, retryable);\n }\n\n /**\n * `autoFile`: this turn answers the check-back chip, so a plain report it\n * returns starts the countdown instead of waiting for Send (#402).\n */\n async function runTurn(history: ChatMessage[], autoFile = false) {\n setBusy(true);\n setAutoFileLeft(null);\n let result: AssistTurnResult;\n const events = takeEvents();\n try {\n // Held to a total budget, and no singular `screenshot` beside it: a body\n // over the request limit is refused at the edge with a 413 before the\n // route runs, and repeating the newest image is what tipped real turns\n // over it.\n const sent = pickAssistImages(screenshots);\n result = await assist({\n // `kind` only on drafts, so an older server sees the exact shape it\n // always did — it just learns the draft text now instead of a\n // placeholder line.\n messages: history.map((m) =>\n m.kind ? { role: m.role, content: m.content, kind: m.kind } : m,\n ),\n conversationId,\n screenshots: sent,\n // Only when there is something: an older server then sees the body\n // it always did.\n ...(sentFiles.length > 0 ? { files: sentFiles.map((f) => f.file) } : {}),\n context: {\n ...(context ?? {}),\n imageSources: sent.map((shot) => (pageShot && shot === pageShot ? \"page\" : \"attached\")),\n // Whether this dialog can open the #366 panel at all. A hint — the\n // server decides whether the model may offer it.\n canReportGlitchgrab: !!onReportGlitchgrabProblem,\n },\n events,\n });\n } catch {\n // AssistFn is documented as never-throwing, but a host is a host.\n degradeKeepingEvents(\n events,\n \"The assistant is unavailable — write your report below and send it as normal.\",\n );\n return;\n } finally {\n setBusy(false);\n }\n\n if (result.degraded) {\n degradeKeepingEvents(events, result.degraded, result.retryable === true);\n return;\n }\n if (result.conversationId) {\n setConversationId(result.conversationId);\n onConversationChange?.(result.conversationId);\n }\n\n // One card, one submit path for both: the SAME problem, or a related request\n // the model asked about. The server never sends both.\n const attach = result.duplicate\n ? { ...result.duplicate, kind: \"duplicate\" as const }\n : result.related\n ? { ...result.related, kind: \"related\" as const }\n : null;\n setDuplicate(attach);\n onDuplicateChange?.(attach?.number ?? null, attach?.kind);\n setGlitchgrabOffer(!!result.aboutGlitchgrab && !!onReportGlitchgrabProblem && !!result.question);\n\n if (result.solved) {\n setSolved(result.solved);\n setOptions([]);\n setPhase(\"solved\");\n return;\n }\n\n if (result.report) {\n onDescriptionChange(result.report);\n aiDraftRef.current = result.report;\n logEvent(\"draft_shown\");\n setMessages([...history, { role: \"assistant\", content: result.report, kind: \"report\" }]);\n setOptions([]);\n setPhase(\"draft\");\n // Never onto somebody else's issue: attaching to the wrong thread stays a\n // deliberate click. And never without a severity the dialog would refuse.\n if (autoFile && !attach && !(severityAsked && !severity)) {\n setAutoFileLeft(AUTO_FILE_SECONDS);\n }\n return;\n }\n if (result.question) {\n setMessages([...history, { role: \"assistant\", content: result.question }]);\n setOptions(result.options ?? []);\n return;\n }\n onDegrade(\"The assistant had nothing to add — write your report below and send it as normal.\");\n }\n\n // Whatever was already typed IS the first message. Making someone retype it\n // to \"start the chat\" would be the most annoying thing this feature could do.\n useEffect(() => {\n if (seededRef.current) return;\n seededRef.current = true;\n // Nothing to seed until we know what this is — the picker runs first, and\n // anything typed before it would be a report about an unknown thing.\n // A rating never calls the model, so whatever is in the box is a comment,\n // not the opening line of a conversation.\n if (!typePicked || currentTile === \"RATING\") return;\n // A bug answers \"how bad is it?\" first (#402); the opening turn waits.\n if (phase === \"severity\") {\n seedPendingRef.current = true;\n return;\n }\n seedFromDescription();\n // Intentionally once, on mount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n function seedFromDescription() {\n const seed = description.trim();\n if (!seed) return;\n const history: ChatMessage[] = [{ role: \"user\", content: seed }];\n setMessages(history);\n void runTurn(history);\n }\n\n function answerSeverity(value: ReportSeverity) {\n onSeverityChange(value);\n setPhase(\"chat\");\n if (seedPendingRef.current) {\n seedPendingRef.current = false;\n seedFromDescription();\n }\n }\n\n /** Typed into the composer: a plain yes to \"Is that right?\" counts as the tap. */\n function sendTyped(text: string) {\n const lastAssistant = [...messages].reverse().find((m) => m.role === \"assistant\");\n const checkingBack =\n options.includes(CONFIRM_OPTION) ||\n (lastAssistant?.kind !== \"report\" && isCheckBackQuestion(lastAssistant?.content ?? \"\"));\n send(text, checkingBack && isAffirmativeReply(text));\n }\n\n function send(text: string, autoFile = false) {\n const value = text.trim();\n if (!value || busy) return;\n setOptions([]);\n // Replying at all answers the offer — the card goes, the chat carries on.\n setGlitchgrabOffer(false);\n // Typed under a draft, it is a correction to that draft (#360 — the chat box\n // stays there, so asking for a change is just replying). Logged as\n // `keep_chatting`, the first number read when tuning the prompt.\n const underDraft = phase === \"draft\";\n if (underDraft) {\n const edited =\n aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();\n logEvent(\"keep_chatting\", edited ? \"after editing\" : undefined);\n setPhase(\"chat\");\n }\n const base = underDraft ? withCurrentDraft(messages) : messages;\n const history: ChatMessage[] = [...base, { role: \"user\", content: value }];\n setMessages(history);\n setInput(\"\");\n void runTurn(history, autoFile);\n }\n\n /**\n * One tap answers \"what do you want to do?\". RATING branches away from the\n * model entirely; every other tile drops into the conversation the sheet\n * already had.\n */\n function pickType(tile: DialogTile) {\n onPickType(tile);\n setPhase(tile === \"RATING\" ? \"rating\" : needsSeverity(tile) ? \"severity\" : \"chat\");\n }\n\n /**\n * The draft stays in the conversation — as the reporter last left it, hand\n * edits included — so the next message is read as a correction to it, not as\n * the start of a new report (#357).\n */\n function withCurrentDraft(history: ChatMessage[]): ChatMessage[] {\n const current = description.trim();\n const next = [...history];\n for (let i = next.length - 1; i >= 0; i--) {\n if (next[i].kind === \"report\") {\n if (current) next[i] = { ...next[i], content: current };\n break;\n }\n }\n return next;\n }\n\n /** `auto`: the countdown ran out, so nobody pressed Send — kept apart in the log. */\n function sendDraft(auto = false) {\n setAutoFileLeft(null);\n const edited = aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();\n logEvent(\"draft_sent\", auto ? \"auto-filed\" : edited ? \"edited\" : \"as drafted\");\n flushEvents();\n onSend();\n }\n\n const empty = phase === \"chat\" && messages.length === 0 && !busy;\n\n /**\n * The already-open issue, and where its fix stands. Shown beside the \"is it\n * the same problem?\" question and again above the draft — \"we know, we're on\n * it\" is the answer the reporter came for, so it is said before Send, not\n * after. `status` is the server's, off GitHub's milestone; never the model's.\n *\n * `title: false` beside the question, which already names the issue — the\n * card then adds only what the model cannot say: where the fix stands.\n */\n function renderKnownIssue({ title, footer }: { title: boolean; footer?: string }) {\n if (!duplicate) return null;\n return (\n <div\n data-gg-known-issue=\"\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"3px\",\n padding: \"9px 10px\",\n borderRadius: \"8px\",\n border: \"1px solid rgba(245,158,11,0.4)\",\n backgroundColor: \"rgba(245,158,11,0.08)\",\n fontSize: \"12px\",\n lineHeight: 1.5,\n minWidth: 0,\n }}\n >\n {/* Theme text, not amber: amber on the tint is ~2:1 in light mode. */}\n <span style={{ color: t.text, fontWeight: 600 }}>\n {duplicate.kind === \"related\"\n ? title\n ? \"Your request goes onto this issue\"\n : `Connected to #${duplicate.number}`\n : title\n ? \"Our team is already on this\"\n : `Our team is already on #${duplicate.number}`}\n </span>\n {title && (\n <span style={{ color: t.textMuted, wordBreak: \"break-word\" }}>\n #{duplicate.number} {duplicate.title}\n </span>\n )}\n {/* Where THAT issue's fix stands says nothing about a new request added\n to it — \"Fix expected by 18 Sep\" would read as a promise for theirs. */}\n {duplicate.status && duplicate.kind !== \"related\" && (\n <span style={{ color: t.text, fontWeight: 600 }}>{duplicate.status}</span>\n )}\n {footer && (\n <span style={{ color: t.textMuted }}>\n {duplicate.kind === \"related\"\n ? \"Added as a separate request on it, not a repeat — the team sees both.\"\n : footer}\n </span>\n )}\n </div>\n );\n }\n\n /** \"Naresh Bhosale\" → \"NB\". Blank when we were given no name at all. */\n const initials = (reporterName ?? \"\")\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((w) => w[0]?.toUpperCase() ?? \"\")\n .join(\"\");\n\n const panelStyle: React.CSSProperties = narrow\n ? {\n width: \"100%\",\n maxHeight: \"88dvh\",\n borderTopLeftRadius: \"16px\",\n borderTopRightRadius: \"16px\",\n animation: \"gg-sheet-up .22s cubic-bezier(.2,.8,.2,1)\",\n }\n : {\n width: \"440px\",\n maxWidth: \"100%\",\n height: \"100dvh\",\n borderLeft: `1px solid ${t.border}`,\n animation: \"gg-sheet-in .22s cubic-bezier(.2,.8,.2,1)\",\n };\n\n return createPortal(\n <>\n <style>{`\n @keyframes gg-sheet-in{from{transform:translateX(24px);opacity:0}to{transform:translateX(0);opacity:1}}\n @keyframes gg-sheet-up{from{transform:translateY(24px);opacity:0}to{transform:translateY(0);opacity:1}}\n @keyframes gg-sheet-fade{from{opacity:0}to{opacity:1}}\n @keyframes gg-autofile{from{transform:scaleX(0)}to{transform:scaleX(1)}}\n @keyframes gg-dot{0%,80%,100%{transform:translateY(0);opacity:.4}40%{transform:translateY(-3px);opacity:1}}\n [data-gg-sheet-send]:focus-visible,[data-gg-chip]:focus-visible,[data-gg-assist-remove]:focus-visible,[data-gg-stop-auto-file]:focus-visible{outline:2px solid currentColor;outline-offset:2px}\n `}</style>\n <div\n data-glitchgrab-layer=\"\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Describe your report with AI\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n display: \"flex\",\n alignItems: narrow ? \"flex-end\" : \"stretch\",\n justifyContent: narrow ? \"center\" : \"flex-end\",\n backgroundColor: \"rgba(0,0,0,0.5)\",\n animation: \"gg-sheet-fade .18s ease\",\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n }}\n onClick={() => leave(\"closed\")}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <div\n onClick={(e) => e.stopPropagation()}\n style={{\n ...panelStyle,\n display: \"flex\",\n flexDirection: \"column\",\n // A flex child defaults to min-width:auto, so a long chat bubble\n // grows the sheet past the viewport instead of wrapping inside it.\n // This is what keeps the bottom sheet on screen.\n minWidth: 0,\n maxWidth: \"100%\",\n boxSizing: \"border-box\",\n backgroundColor: t.bg,\n color: t.text,\n boxShadow: \"0 20px 60px rgba(0,0,0,.35)\",\n overflow: \"hidden\",\n isolation: \"isolate\",\n }}\n >\n {/* ── Header ─────────────────────────────────────────────── */}\n <div\n data-gg-sheet-header=\"\"\n style={{\n flexShrink: 0,\n padding: \"14px 16px\",\n borderBottom: `1px solid ${t.border}`,\n display: \"flex\",\n alignItems: \"flex-start\",\n justifyContent: \"space-between\",\n gap: \"12px\",\n minWidth: 0,\n }}\n >\n {/* No overflow:hidden here. The extension's project picker drops its\n search list out of this column, and clipping it left the list\n cut off under the search box with nothing to click (#380).\n minWidth:0 alone lets the column shrink; the picker ellipsizes\n its own label. */}\n <div style={{ minWidth: 0 }}>\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"7px\",\n fontSize: \"14px\",\n fontWeight: 600,\n }}\n >\n <Sparkle color={t.accent} />\n Describe it with AI\n <span\n style={{\n fontSize: \"10px\",\n fontWeight: 600,\n letterSpacing: \".04em\",\n textTransform: \"uppercase\",\n color: t.accent,\n border: `1px solid ${t.accent}55`,\n borderRadius: \"4px\",\n padding: \"1px 5px\",\n }}\n >\n Beta\n </span>\n </div>\n <div style={{ fontSize: \"11.5px\", color: t.textMuted, marginTop: \"3px\" }}>\n {/* The picker's own bubble asks the question — saying it again\n here reads as two prompts for one answer. */}\n {phase === \"type\" ? null : reportTypeLabel}\n {/* The severity step's chips are gone once answered — this is\n where the answer stays visible. */}\n {phase !== \"type\" && severityAsked && severity\n ? ` · ${SEVERITY_LABELS[severity]}`\n : null}\n {projectSlot ? <span style={{ marginLeft: \"6px\" }}>{projectSlot}</span> : null}\n </div>\n </div>\n {/* The way out of the assistant, on every width.\n This used to be a bare × on a phone, which reads as \"close the\n whole thing\" — so someone the assistant was not helping had no\n visible way to reach the form, only a way to give up. It is a\n switch, so it says what it switches to. */}\n <button\n type=\"button\"\n data-gg-write-myself=\"\"\n onClick={() => leave(\"write_myself\", `header, ${phase}`)}\n aria-label=\"Write it myself instead\"\n style={{\n flexShrink: 0,\n border: `1px solid ${t.inputBorder}`,\n borderRadius: \"999px\",\n background: \"transparent\",\n color: t.textMuted,\n cursor: \"pointer\",\n fontSize: \"11.5px\",\n lineHeight: 1,\n fontFamily: \"inherit\",\n whiteSpace: \"nowrap\",\n // ~32px tall either way — this is the escape hatch, not a hint.\n padding: \"9px 11px\",\n }}\n >\n Write it myself\n </button>\n </div>\n\n {/* ── Transcript ─────────────────────────────────────────── */}\n <div\n ref={scrollRef}\n style={{\n flex: 1,\n minHeight: narrow ? \"180px\" : 0,\n overflowY: \"auto\",\n padding: \"16px\",\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n {/* `marginTop: auto` is what pins a short transcript to the BOTTOM\n of a tall drawer, the way every chat surface behaves. Doing it\n with justify-content instead breaks scrolling once the\n conversation outgrows the panel. */}\n <div\n style={{\n marginTop: \"auto\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"12px\",\n minWidth: 0,\n }}\n >\n {phase === \"type\" && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"12px\" }}>\n <div style={{ display: \"flex\", gap: \"8px\" }}>\n <Avatar who=\"assistant\" theme={t} />\n <div\n style={{\n padding: \"9px 12px\",\n borderRadius: \"12px 12px 12px 4px\",\n backgroundColor: t.bgSecondary,\n fontSize: \"13px\",\n lineHeight: 1.55,\n maxWidth: \"88%\",\n }}\n >\n {reporterName ? `Hi ${reporterName.split(\" \")[0]} — w` : \"W\"}hat do you want to\n do? Pick one and I'll take it from there.\n </div>\n </div>\n <div\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: \"6px\",\n paddingLeft: \"32px\",\n }}\n >\n {tiles.map((tile) => {\n const rate = tile === \"RATING\";\n return (\n <button\n key={tile}\n type=\"button\"\n data-gg-chip=\"\"\n data-gg-tile={tile}\n onClick={() => pickType(tile)}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"5px\",\n // The rating is the only tile that isn't a report, so\n // it wears the star colour the dialog's hero row uses\n // rather than hiding among the report types.\n border: `1px solid ${rate ? \"rgba(245,158,11,0.5)\" : t.inputBorder}`,\n background: rate ? \"rgba(245,158,11,0.08)\" : \"transparent\",\n color: rate ? \"#f59e0b\" : t.textMuted,\n borderRadius: \"999px\",\n // 8px vertical keeps the tap target at ~32px.\n padding: \"8px 12px\",\n fontSize: \"12px\",\n fontWeight: rate ? 600 : 400,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n >\n {rate ? \"★ Rate us\" : getTypeLabel(tile)}\n </button>\n );\n })}\n </div>\n </div>\n )}\n\n {/* #402: one tap, right after \"Bug\", so a confirmed draft has\n everything the dialog needs to file it without a second stop. */}\n {phase === \"severity\" && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"12px\" }}>\n <div style={{ display: \"flex\", gap: \"8px\" }}>\n <Avatar who=\"assistant\" theme={t} />\n <div\n style={{\n padding: \"9px 12px\",\n borderRadius: \"12px 12px 12px 4px\",\n backgroundColor: t.bgSecondary,\n fontSize: \"13px\",\n lineHeight: 1.55,\n maxWidth: \"88%\",\n }}\n >\n How bad is it?\n </div>\n </div>\n <div\n role=\"radiogroup\"\n aria-label=\"Severity\"\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: \"6px\",\n paddingLeft: \"32px\",\n }}\n >\n {SEVERITY_LEVELS.map((s) => (\n <button\n key={s}\n type=\"button\"\n role=\"radio\"\n aria-checked={severity === s}\n data-gg-chip=\"\"\n data-gg-severity={s}\n onClick={() => answerSeverity(s)}\n style={{\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.textMuted,\n borderRadius: \"999px\",\n // Same as the picker and option chips — one chip size.\n padding: \"8px 12px\",\n fontSize: \"12px\",\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n >\n {SEVERITY_LABELS[s]}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {phase === \"rating\" && !submitted && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"12px\" }}>\n <div style={{ display: \"flex\", gap: \"8px\" }}>\n <Avatar who=\"assistant\" theme={t} />\n <div\n style={{\n padding: \"9px 12px\",\n borderRadius: \"12px 12px 12px 4px\",\n backgroundColor: t.bgSecondary,\n fontSize: \"13px\",\n lineHeight: 1.55,\n maxWidth: \"88%\",\n }}\n >\n How are we doing? Tap a star — the words are optional.\n </div>\n </div>\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"10px\",\n marginLeft: \"32px\",\n padding: \"12px\",\n borderRadius: \"12px\",\n border: \"1px solid rgba(245,158,11,0.4)\",\n backgroundColor: \"rgba(245,158,11,0.06)\",\n }}\n >\n <div style={{ display: \"flex\", gap: \"4px\" }} role=\"group\" aria-label=\"Rating\">\n {[1, 2, 3, 4, 5].map((star) => {\n const filled = star <= (hoveredStar || rating);\n return (\n <button\n key={star}\n type=\"button\"\n aria-label={`${star} star${star > 1 ? \"s\" : \"\"}`}\n aria-pressed={star <= rating}\n onClick={() => onRatingChange(star)}\n onMouseEnter={() => setHoveredStar(star)}\n onMouseLeave={() => setHoveredStar(0)}\n style={{\n border: \"none\",\n background: \"transparent\",\n padding: 0,\n cursor: \"pointer\",\n lineHeight: 0,\n }}\n >\n <svg width=\"30\" height=\"30\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.4 6.8 19.1l1-5.8L3.5 9.2l5.9-.9L12 3z\"\n fill={filled ? \"#f59e0b\" : \"transparent\"}\n stroke={filled ? \"#f59e0b\" : t.inputBorder}\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n );\n })}\n </div>\n <textarea\n value={description}\n onChange={(e) => onDescriptionChange(e.target.value)}\n rows={3}\n placeholder=\"What made it good — or what let you down? (optional)\"\n style={{\n width: \"100%\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n backgroundColor: t.inputBg,\n color: t.text,\n fontSize: \"13px\",\n lineHeight: 1.5,\n fontFamily: \"inherit\",\n resize: \"vertical\",\n outline: \"none\",\n boxSizing: \"border-box\",\n }}\n />\n <button\n type=\"button\"\n onClick={() => setPhase(\"type\")}\n style={{\n alignSelf: \"flex-start\",\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"12px\",\n fontFamily: \"inherit\",\n // A bare text link is ~14px tall — half a thumb.\n padding: \"9px 0\",\n cursor: \"pointer\",\n textDecoration: \"underline\",\n }}\n >\n Report something instead\n </button>\n </div>\n </div>\n )}\n\n {empty && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"12px\" }}>\n <div style={{ display: \"flex\", gap: \"8px\" }}>\n <Avatar who=\"assistant\" theme={t} />\n <div\n style={{\n padding: \"9px 12px\",\n borderRadius: \"12px 12px 12px 4px\",\n backgroundColor: t.bgSecondary,\n fontSize: \"13px\",\n lineHeight: 1.55,\n maxWidth: \"88%\",\n }}\n >\n {reporterName ? `Hi ${reporterName.split(\" \")[0]} — t` : \"T\"}ell me what went\n wrong in your own words. I can already see your screenshot and what you clicked,\n so skip the boring parts.\n </div>\n </div>\n <div\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: \"6px\",\n paddingLeft: \"32px\",\n }}\n >\n {STARTERS.map((s) => (\n <button\n key={s}\n type=\"button\"\n data-gg-chip=\"\"\n onClick={() => {\n logEvent(\"starter_tap\", s);\n send(s);\n }}\n style={{\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.textMuted,\n borderRadius: \"999px\",\n padding: \"6px 11px\",\n fontSize: \"12px\",\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n >\n {s}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {messages.map((m, i) => {\n const mine = m.role === \"user\";\n if (m.kind === \"report\") {\n // While the draft card is up it shows the text itself, so the\n // bubble only points at it. Once they go back to chatting, the\n // draft stays readable in the transcript: they are correcting\n // it, and a correction to something you cannot see is a guess.\n const live = phase === \"draft\" && i === messages.length - 1;\n return (\n <div key={i} style={{ display: \"flex\", gap: \"8px\", minWidth: 0 }}>\n <Avatar who=\"assistant\" theme={t} />\n <div\n data-gg-draft-bubble=\"\"\n style={{\n maxWidth: \"82%\",\n minWidth: 0,\n padding: \"9px 12px\",\n borderRadius: \"12px 12px 12px 4px\",\n fontSize: \"13px\",\n lineHeight: 1.55,\n backgroundColor: t.bgSecondary,\n color: t.text,\n border: live ? \"none\" : `1px solid ${t.accent}66`,\n }}\n >\n {live ? (\n // #402: \"have a read\" beside a countdown reads as a\n // contradiction. Say what is about to happen instead.\n autoFileLeft !== null ? (\n \"Here's your report — I'll file it unless you want to change something.\"\n ) : (\n \"Here's your report — have a read.\"\n )\n ) : (\n <>\n <span\n style={{\n display: \"block\",\n fontSize: \"10px\",\n fontWeight: 700,\n letterSpacing: \".06em\",\n textTransform: \"uppercase\",\n color: t.accent,\n marginBottom: \"4px\",\n }}\n >\n Draft so far\n </span>\n <span\n style={{\n display: \"block\",\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n maxHeight: \"160px\",\n overflowY: \"auto\",\n color: t.textMuted,\n }}\n >\n {m.content}\n </span>\n </>\n )}\n </div>\n </div>\n );\n }\n return (\n <div\n key={i}\n style={{\n display: \"flex\",\n gap: \"8px\",\n minWidth: 0,\n flexDirection: mine ? \"row-reverse\" : \"row\",\n }}\n >\n <Avatar who={m.role} theme={t} initials={initials} />\n <div\n style={{\n maxWidth: \"82%\",\n minWidth: 0,\n padding: \"9px 12px\",\n borderRadius: mine ? \"12px 12px 4px 12px\" : \"12px 12px 12px 4px\",\n fontSize: \"13px\",\n lineHeight: 1.55,\n // Markdown owns the assistant's line breaks and lists.\n whiteSpace: mine ? \"pre-wrap\" : \"normal\",\n wordBreak: \"break-word\",\n backgroundColor: mine ? t.accent : t.bgSecondary,\n color: mine ? t.accentText : t.text,\n }}\n >\n {/* The reporter's own words stay literal — someone typing\n `**` meant the asterisks. */}\n {mine ? m.content : <ChatMarkdown text={m.content} theme={t} />}\n </div>\n </div>\n );\n })}\n\n {/* Answers to the question above, as chips. The assistant sends these\n when the reporter has said something it cannot act on (\"it could\n be better\") — re-asking \"what specifically?\" is what made that\n conversation go in circles. */}\n {/* The model thinks this is an open issue and is asking. The card\n sits with the question so \"is it the same problem?\" is answered\n looking at the actual issue — and its status. */}\n {duplicate && !busy && phase === \"chat\" && (\n <div style={{ paddingLeft: \"32px\", minWidth: 0 }}>\n {renderKnownIssue({ title: false })}\n </div>\n )}\n\n {/* #366 — the assistant thinks this is about Glitchgrab itself, not\n this app. Offered, never automatic: a wrong guess must not yank\n someone out of a real report. One tap sends it on with their own\n words already in the box; one tap says no and the chat goes on. */}\n {glitchgrabOffer && onReportGlitchgrabProblem && !busy && phase === \"chat\" && (\n <div style={{ paddingLeft: \"32px\", minWidth: 0 }}>\n <div\n data-gg-glitchgrab-offer=\"\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"8px\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.accent}55`,\n backgroundColor: `${t.accent}14`,\n fontSize: \"12px\",\n lineHeight: 1.5,\n }}\n >\n <span style={{ color: t.text, fontWeight: 600 }}>\n This is about Glitchgrab, not this app\n </span>\n <span style={{ color: t.textMuted }}>\n It goes to the team that builds this reporter, with your chat attached.\n </span>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"6px\" }}>\n <button\n type=\"button\"\n data-gg-glitchgrab-offer-send=\"\"\n onClick={() => {\n logEvent(\"glitchgrab_offer_tap\");\n setGlitchgrabOffer(false);\n onReportGlitchgrabProblem(\n messages\n .filter((m) => m.role === \"user\")\n .map((m) => m.content.trim())\n .filter(Boolean)\n .join(\"\\n\\n\"),\n );\n }}\n style={{\n padding: \"8px 12px\",\n borderRadius: \"999px\",\n border: \"none\",\n backgroundColor: t.accent,\n color: t.accentText,\n fontSize: \"12px\",\n fontWeight: 700,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n // Both stretch, so on a phone each wrapped line reads as\n // a choice rather than one button left stranded.\n flex: \"1 1 auto\",\n }}\n >\n Send to the Glitchgrab team\n </button>\n <button\n type=\"button\"\n data-gg-glitchgrab-offer-no=\"\"\n onClick={() => {\n logEvent(\"glitchgrab_offer_declined\");\n send(\"No — it's about this app, not the reporting tool\");\n }}\n style={{\n padding: \"8px 12px\",\n borderRadius: \"999px\",\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"12px\",\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n flex: \"1 1 auto\",\n }}\n >\n No, it's about this app\n </button>\n </div>\n </div>\n </div>\n )}\n\n {options.length > 0 && !busy && phase === \"chat\" && !glitchgrabOffer && (\n <div\n style={{\n display: \"flex\",\n // Long labels wrapped into a ragged row that always stranded\n // the last chip on a line of its own. Past ~24 characters\n // these stop being chips and become a choice list, so they\n // stack full width and read like one.\n flexDirection: options.some((o) => o.length > 24) ? \"column\" : \"row\",\n alignItems: options.some((o) => o.length > 24) ? \"stretch\" : \"flex-start\",\n flexWrap: \"wrap\",\n gap: \"6px\",\n paddingLeft: \"32px\",\n }}\n >\n {options.map((option) => (\n <button\n key={option}\n type=\"button\"\n data-gg-chip=\"\"\n data-gg-option=\"\"\n onClick={() => {\n logEvent(\"option_tap\", option);\n send(option, option === CONFIRM_OPTION);\n }}\n style={{\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.textMuted,\n borderRadius: \"999px\",\n // Same 8px as the picker chips — one tap target size in\n // this sheet, not two.\n padding: \"8px 12px\",\n fontSize: \"12px\",\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n textAlign: \"left\",\n }}\n >\n {option}\n </button>\n ))}\n </div>\n )}\n\n {busy && (\n <div style={{ display: \"flex\", gap: \"8px\" }} role=\"status\" aria-label=\"Thinking\">\n <Avatar who=\"assistant\" theme={t} />\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"4px\",\n padding: \"12px\",\n borderRadius: \"12px 12px 12px 4px\",\n backgroundColor: t.bgSecondary,\n }}\n >\n {[0, 1, 2].map((i) => (\n <span\n key={i}\n style={{\n width: \"5px\",\n height: \"5px\",\n borderRadius: \"50%\",\n backgroundColor: t.textMuted,\n animation: `gg-dot 1.1s ease-in-out ${i * 0.15}s infinite`,\n }}\n />\n ))}\n </span>\n </div>\n )}\n\n {/* ── The draft ────────────────────────────────────────── */}\n {phase === \"draft\" && !submitted && (\n <div\n style={{\n border: `1px solid ${t.accent}`,\n borderRadius: \"12px\",\n backgroundColor: t.bgSecondary,\n padding: \"12px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"10px\",\n minWidth: 0,\n boxSizing: \"border-box\",\n }}\n >\n <span\n style={{\n fontSize: \"10px\",\n fontWeight: 700,\n letterSpacing: \".06em\",\n textTransform: \"uppercase\",\n color: t.accent,\n }}\n >\n {duplicate\n ? `What we'll add to #${duplicate.number}${duplicate.kind === \"related\" ? \" as a related request\" : \"\"} · edit anything`\n : \"Your report · edit anything\"}\n </span>\n\n {renderKnownIssue({\n title: true,\n footer: \"Your details will be added to it instead of opening a new issue.\",\n })}\n <textarea\n ref={draftRef}\n value={description}\n onChange={(e) => {\n stopAutoFile(\"edited the draft\");\n onDescriptionChange(e.target.value);\n }}\n rows={6}\n style={{\n width: \"100%\",\n minHeight: \"120px\",\n padding: \"10px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n backgroundColor: t.inputBg,\n color: t.text,\n fontSize: \"13px\",\n lineHeight: 1.55,\n fontFamily: \"inherit\",\n resize: \"vertical\",\n outline: \"none\",\n boxSizing: \"border-box\",\n }}\n />\n\n {/* Answered a step ago; while the countdown runs a second\n picker is only something to mis-tap. Stopping it brings the\n picker back so the answer can still be changed. */}\n {severityAsked && autoFileLeft === null && (\n <div>\n <span\n style={{\n fontSize: \"11.5px\",\n color: t.textMuted,\n display: \"block\",\n marginBottom: \"6px\",\n }}\n >\n How bad is it?\n {!severity && (\n <span\n style={{\n marginLeft: \"6px\",\n fontSize: \"11px\",\n color: severityRefused ? \"#ef4444\" : t.textMuted,\n }}\n >\n · required\n </span>\n )}\n </span>\n <div\n role=\"radiogroup\"\n aria-label=\"Severity\"\n style={{ display: \"flex\", gap: \"6px\" }}\n >\n {SEVERITY_LEVELS.map((s) => {\n const on = severity === s;\n return (\n <button\n key={s}\n type=\"button\"\n onClick={() => onSeverityChange(s)}\n role=\"radio\"\n aria-checked={on}\n style={{\n flex: 1,\n minWidth: 0,\n padding: \"8px 2px\",\n borderRadius: \"8px\",\n border: `1px solid ${\n on\n ? t.accent\n : severityRefused\n ? \"#ef4444\"\n : t.inputBorder\n }`,\n backgroundColor: on ? t.accent : \"transparent\",\n color: on ? t.accentText : t.textMuted,\n fontSize: \"12px\",\n fontWeight: 600,\n fontFamily: \"inherit\",\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n cursor: \"pointer\",\n }}\n >\n {SEVERITY_LABELS[s]}\n </button>\n );\n })}\n </div>\n </div>\n )}\n\n {attachmentCount > 0 && (\n <span style={{ fontSize: \"11.5px\", color: t.textMuted }}>\n {attachmentCount} {attachmentCount === 1 ? \"attachment\" : \"attachments\"} will be\n sent with this.\n </span>\n )}\n </div>\n )}\n\n {phase === \"solved\" && solved && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"12px\" }}>\n <div style={{ display: \"flex\", gap: \"8px\" }}>\n <Avatar who=\"assistant\" theme={t} />\n <div\n style={{\n padding: \"9px 12px\",\n borderRadius: \"12px 12px 12px 4px\",\n backgroundColor: t.bgSecondary,\n fontSize: \"13px\",\n lineHeight: 1.55,\n maxWidth: \"88%\",\n whiteSpace: \"pre-wrap\",\n }}\n >\n {solved}\n </div>\n </div>\n <span\n style={{ fontSize: \"11.5px\", color: t.textMuted, paddingLeft: \"32px\" }}\n >\n Nothing was filed — you are all set.\n </span>\n </div>\n )}\n\n {submitted && (\n <div\n style={{\n textAlign: \"center\",\n padding: \"24px 0\",\n color: t.accent,\n fontSize: \"14px\",\n fontWeight: 600,\n }}\n >\n {reportTypeLabel} sent. Thank you!\n </div>\n )}\n </div>\n </div>\n\n {/* ── Composer / Send ────────────────────────────────────── */}\n {/* The picker has nothing to compose — a chip IS the answer, and an\n input under it invites someone to type a type name we then have\n to parse. */}\n {!submitted && phase !== \"type\" && phase !== \"severity\" && (\n <div\n style={{\n flexShrink: 0,\n borderTop: `1px solid ${t.border}`,\n padding: \"12px 16px\",\n paddingBottom: narrow ? \"max(12px, env(safe-area-inset-bottom))\" : \"12px\",\n backgroundColor: t.bg,\n }}\n >\n {phase === \"solved\" ? (\n <button\n type=\"button\"\n data-gg-sheet-send=\"\"\n onClick={() => (onFinish ?? onClose)()}\n style={{\n width: \"100%\",\n padding: \"12px\",\n borderRadius: \"10px\",\n border: \"none\",\n backgroundColor: t.accent,\n color: t.accentText,\n fontSize: \"14px\",\n fontWeight: 700,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n >\n Done\n </button>\n ) : phase === \"rating\" ? (\n <button\n type=\"button\"\n data-gg-sheet-send=\"\"\n onClick={onSend}\n disabled={isSubmitting || rating < 1}\n style={{\n width: \"100%\",\n padding: \"12px\",\n borderRadius: \"10px\",\n border: \"none\",\n backgroundColor: isSubmitting || rating < 1 ? t.bgSecondary : \"#f59e0b\",\n color: isSubmitting || rating < 1 ? t.textMuted : \"#1a1a1a\",\n fontSize: \"14px\",\n fontWeight: 700,\n fontFamily: \"inherit\",\n cursor: isSubmitting || rating < 1 ? \"default\" : \"pointer\",\n }}\n >\n {isSubmitting ? \"Sending…\" : rating < 1 ? \"Pick a star first\" : \"Send Rating\"}\n </button>\n ) : (\n // Chat AND draft share this branch, so the chat box is the same\n // element on both sides of a draft landing — it stays put\n // instead of remounting, and a draft is something you can\n // still reply to (#360), not a form that replaced the chat.\n <>\n {/* Proof that a pasted image landed. ⌘V is handled by the\n dialog underneath, which used to swallow the picture into a\n strip hidden behind this sheet — indistinguishable from\n paste being unsupported (#352). */}\n {(screenshots.length > 0 || files.length > 0 || onAddFiles) && (\n <div\n style={{\n display: \"flex\",\n gap: \"8px\",\n alignItems: \"center\",\n flexWrap: \"wrap\",\n marginBottom: \"8px\",\n }}\n >\n {screenshots.map((shot, i) => {\n // Only some are actually sent (count and size caps), so\n // the rest are dimmed rather than hidden: \"it is attached\n // but the assistant is not looking at it\" is the true\n // statement.\n const read = readShots.has(shot);\n return (\n <div\n key={`${i}-${shot.slice(-16)}`}\n style={{\n position: \"relative\",\n width: \"40px\",\n height: \"40px\",\n flexShrink: 0,\n }}\n >\n <img\n src={shot}\n alt={read ? \"Attached image the assistant reads\" : \"Attached image\"}\n data-gg-assist-thumb=\"\"\n style={{\n display: \"block\",\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n borderRadius: \"8px\",\n border: `1px solid ${read ? t.accent : t.inputBorder}`,\n opacity: read ? 1 : 0.45,\n boxSizing: \"border-box\",\n }}\n />\n {/* #360: a wrong paste could not be taken back from\n in here, so reporters described \"the third\n screenshot\" in words instead. Same red × as the\n dialog's own strip. */}\n {onRemoveImage && (\n <button\n type=\"button\"\n data-gg-assist-remove=\"\"\n aria-label={`Remove image ${i + 1}`}\n title=\"Remove this image\"\n onClick={() => {\n stopAutoFile(\"changed attachments\");\n logEvent(\n \"image_removed\",\n pageShot && shot === pageShot ? \"page capture\" : \"attached\",\n );\n onRemoveImage(i);\n }}\n // 32px to tap, 20px to see: the dot stays small on a\n // 40px thumbnail, the target does not.\n style={{\n position: \"absolute\",\n top: \"-13px\",\n right: \"-13px\",\n width: \"32px\",\n height: \"32px\",\n border: \"none\",\n background: \"transparent\",\n padding: 0,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"50%\",\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: \"20px\",\n height: \"20px\",\n boxSizing: \"border-box\",\n borderRadius: \"50%\",\n border: `2px solid ${t.bg}`,\n background: \"#ef4444\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path\n d=\"M1 1L9 9M9 1L1 9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n </button>\n )}\n </div>\n );\n })}\n {/* #1851: a mockup attached on the form was invisible here,\n and the assistant asked about a page it never saw. A\n file it reads is outlined like a read image; one it\n cannot read is dimmed, and says why on hover. */}\n {files.map((file, i) => {\n const read = readFiles.has(i);\n const why = read\n ? \"the assistant reads this file\"\n : isAssistReadableFile(file.name)\n ? \"attached, but more than one message can carry, so the assistant is not reading it\"\n : \"attached to the report — the assistant can't read this kind of file\";\n return (\n <div\n key={`file-${i}-${file.name}`}\n data-gg-assist-file=\"\"\n data-gg-assist-file-read={read ? \"\" : undefined}\n title={`${file.name} — ${why}`}\n style={{\n position: \"relative\",\n height: \"40px\",\n maxWidth: \"170px\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n padding: \"0 10px\",\n borderRadius: \"8px\",\n border: `1px solid ${read ? t.accent : t.inputBorder}`,\n opacity: read ? 1 : 0.55,\n boxSizing: \"border-box\",\n flexShrink: 0,\n }}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\" style={{ flexShrink: 0 }}>\n <path\n d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z M14 2v6h6\"\n stroke={t.textMuted}\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span\n style={{\n fontSize: \"11.5px\",\n color: t.text,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {file.name}\n </span>\n {onRemoveFile && (\n <button\n type=\"button\"\n data-gg-assist-remove-file=\"\"\n aria-label={`Remove file ${file.name}`}\n title=\"Remove this file\"\n onClick={() => {\n stopAutoFile(\"changed attachments\");\n logEvent(\"file_removed\", read ? \"read\" : \"not read\");\n onRemoveFile(i);\n }}\n style={{\n position: \"absolute\",\n top: \"-13px\",\n right: \"-13px\",\n width: \"32px\",\n height: \"32px\",\n border: \"none\",\n background: \"transparent\",\n padding: 0,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"50%\",\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: \"20px\",\n height: \"20px\",\n boxSizing: \"border-box\",\n borderRadius: \"50%\",\n border: `2px solid ${t.bg}`,\n background: \"#ef4444\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path\n d=\"M1 1L9 9M9 1L1 9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n </button>\n )}\n </div>\n );\n })}\n {onAddFiles && (\n <label\n data-gg-assist-attach=\"\"\n title=\"Attach an image or a file (html, json, log…) — or paste one\"\n style={{\n width: \"40px\",\n height: \"40px\",\n borderRadius: \"8px\",\n border: `1px dashed ${t.inputBorder}`,\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n color: t.textMuted,\n fontSize: \"18px\",\n cursor: \"pointer\",\n flexShrink: 0,\n }}\n >\n +\n <input\n type=\"file\"\n accept={ASSIST_ATTACHMENT_ACCEPT}\n multiple\n onChange={(e) => {\n const picked = Array.from(e.target.files ?? []);\n if (picked.length) {\n stopAutoFile(\"changed attachments\");\n const images = picked.filter((f) => f.type.startsWith(\"image/\")).length;\n if (images) logEvent(\"image_added\", String(images));\n if (picked.length > images) {\n logEvent(\"file_added\", String(picked.length - images));\n }\n onAddFiles(picked);\n }\n // Same file twice in a row fires no change event\n // unless the input is cleared.\n e.target.value = \"\";\n }}\n style={{ display: \"none\" }}\n />\n </label>\n )}\n {readShots.size < screenshots.length && (\n <span style={{ color: t.textMuted, fontSize: \"11px\" }}>\n {readShots.size} of {screenshots.length} read\n </span>\n )}\n </div>\n )}\n <div style={{ display: \"flex\", gap: \"8px\", alignItems: \"flex-end\" }}>\n <textarea\n value={input}\n onChange={(e) => {\n // Typing a change under the draft — it must not file mid-sentence.\n stopAutoFile(\"typing a change\");\n setInput(e.target.value);\n }}\n onKeyDown={(e) => {\n // Enter sends, Shift+Enter breaks the line — the rule\n // every chat surface uses, so nobody has to learn it.\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n sendTyped(input);\n }\n }}\n placeholder={\n phase === \"draft\" ? \"Anything to change? Tell me here…\" : \"Type your answer…\"\n }\n rows={1}\n disabled={busy}\n autoFocus\n style={{\n flex: 1,\n minHeight: \"42px\",\n maxHeight: \"120px\",\n padding: \"11px 12px\",\n borderRadius: \"10px\",\n border: `1px solid ${t.inputBorder}`,\n backgroundColor: t.inputBg,\n color: t.text,\n fontSize: \"13px\",\n lineHeight: 1.4,\n fontFamily: \"inherit\",\n resize: \"none\",\n outline: \"none\",\n boxSizing: \"border-box\",\n }}\n />\n <button\n type=\"button\"\n data-gg-sheet-send=\"\"\n onClick={() => sendTyped(input)}\n disabled={busy || !input.trim()}\n aria-label=\"Send message\"\n data-gg-send-message=\"\"\n style={{\n flexShrink: 0,\n width: \"42px\",\n height: \"42px\",\n borderRadius: \"10px\",\n border: \"none\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: busy || !input.trim() ? t.bgSecondary : t.accent,\n color: busy || !input.trim() ? t.textMuted : t.accentText,\n cursor: busy || !input.trim() ? \"default\" : \"pointer\",\n }}\n >\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n {/* Paper plane, nose to the RIGHT. Direction is the\n entire meaning of this icon — get it backwards and it\n reads as \"back\", which is the opposite action. */}\n <path\n d=\"M3 20.5L21.5 12 3 3.5V10l12 2-12 2v6.5z\"\n fill=\"currentColor\"\n />\n </svg>\n </button>\n </div>\n {phase === \"draft\" && (\n <>\n {validationError && (\n <p\n style={{\n margin: \"8px 0 0\",\n color: \"#ef4444\",\n fontSize: \"12px\",\n }}\n >\n {validationError}\n </p>\n )}\n {autoFileLeft !== null ? (\n // #402: \"Yes, that's it\" was the confirmation. The draft\n // files itself unless they stop it — the bar shows how\n // long is left, the button sends now, the × on its right\n // stops it (#406). Stopping keeps the draft: Send Report\n // comes back, and closing the sheet drops it.\n <div style={{ display: \"flex\", gap: \"8px\", marginTop: \"8px\" }}>\n <button\n type=\"button\"\n data-gg-sheet-send=\"\"\n data-gg-auto-file=\"\"\n onClick={() => sendDraft()}\n style={{\n flex: 1,\n minWidth: 0,\n position: \"relative\",\n overflow: \"hidden\",\n padding: \"12px\",\n borderRadius: \"10px\",\n border: \"none\",\n backgroundColor: t.accent,\n color: t.accentText,\n fontSize: \"14px\",\n fontWeight: 700,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n position: \"absolute\",\n inset: 0,\n backgroundColor: \"rgba(255,255,255,0.22)\",\n transformOrigin: \"left\",\n animation: `gg-autofile ${AUTO_FILE_SECONDS}s linear forwards`,\n }}\n />\n <span style={{ position: \"relative\" }}>Filing in {autoFileLeft}s…</span>\n </button>\n <button\n type=\"button\"\n data-gg-stop-auto-file=\"\"\n onClick={() => stopAutoFile(\"pressed stop\")}\n aria-label=\"Stop — don't send\"\n title=\"Stop — don't send\"\n style={{\n flexShrink: 0,\n width: \"44px\",\n borderRadius: \"10px\",\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.text,\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: \"pointer\",\n }}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n strokeWidth=\"2.25\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n data-gg-sheet-send=\"\"\n onClick={() => sendDraft()}\n disabled={isSubmitting || !description.trim()}\n style={{\n width: \"100%\",\n marginTop: \"8px\",\n padding: \"12px\",\n borderRadius: \"10px\",\n border: \"none\",\n backgroundColor:\n isSubmitting || !description.trim() ? t.bgSecondary : t.accent,\n color: isSubmitting || !description.trim() ? t.textMuted : t.accentText,\n fontSize: \"14px\",\n fontWeight: 700,\n fontFamily: \"inherit\",\n cursor: isSubmitting || !description.trim() ? \"default\" : \"pointer\",\n }}\n >\n {isSubmitting\n ? \"Sending…\"\n : duplicate\n ? `Add to #${duplicate.number}`\n : \"Send Report\"}\n </button>\n )}\n </>\n )}\n </>\n )}\n\n {/* The moment people actually give up is two replies into a\n conversation that is not landing — not while looking at the\n header. Offer the form there, in as many words. */}\n {phase === \"chat\" && messages.length > 0 && (\n <button\n type=\"button\"\n data-gg-write-myself=\"\"\n onClick={() => leave(\"write_myself\", \"footer\")}\n style={{\n display: \"block\",\n margin: \"8px auto 0\",\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"11.5px\",\n fontFamily: \"inherit\",\n padding: \"6px 8px\",\n cursor: \"pointer\",\n }}\n >\n Not getting it? Fill the form yourself →\n </button>\n )}\n\n {/* #366 — the assistant itself is what went wrong. That report\n belongs to Glitchgrab, not to the project behind this sheet. */}\n {/* Hidden while the offer card is up — it says the same thing, bigger. */}\n {onReportGlitchgrabProblem && phase !== \"solved\" && !glitchgrabOffer && (\n <button\n type=\"button\"\n data-gg-self-report=\"\"\n onClick={() => onReportGlitchgrabProblem()}\n style={{\n display: \"block\",\n // ~32px tap target; the negative margins keep the composer\n // from growing to make room for it.\n margin: \"-2px auto -8px\",\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"11.5px\",\n fontFamily: \"inherit\",\n padding: \"10px 8px\",\n cursor: \"pointer\",\n textDecoration: \"underline\",\n textUnderlineOffset: \"2px\",\n }}\n >\n Assistant misbehaving? Tell Glitchgrab\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n </>,\n document.body,\n );\n}\n","// Minimal type surface ReportDialog needs — kept separate from the SDK's\n// full types.ts (which also covers auto-capture/breadcrumbs, irrelevant here).\n\nexport type ReportType =\n | \"BUG\"\n | \"FEATURE_REQUEST\"\n | \"UI_IMPROVEMENT\"\n | \"PERFORMANCE\"\n | \"SECURITY\"\n | \"QUESTION\"\n | \"OTHER\";\n\n/**\n * What the user can pick on step 1. A superset of `ReportType`: `RATING` is a\n * tile, not a report type — it never reaches the report API or GitHub, it saves\n * a star rating through `FeedbackFn` instead. Kept out of `ReportType` so the\n * report endpoint's validated enum stays exactly what it was.\n */\nexport type DialogTile = ReportType | \"RATING\";\n\nexport type ReportSeverity = \"low\" | \"medium\" | \"high\" | \"critical\";\n\n/**\n * The picker's order, left to right. Kept next to the union so a new level\n * can't be added to the type and forgotten in the two pickers that render it\n * (the dialog's own row and the assist sheet's).\n *\n * Mirrored server-side by `SEVERITY_VALUES` in `apps/web/lib/severity.ts`,\n * which rejects anything outside it — add a level in both, or the button files\n * a 400.\n */\nexport const SEVERITY_LEVELS: readonly ReportSeverity[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"critical\",\n];\n\n/**\n * Display text. The buttons used to render the raw union value through\n * `text-transform: capitalize`, which meant the label and the GitHub label\n * (`severity:<value>`) could never diverge — fine until a level needs wording\n * the label can't carry.\n */\nexport const SEVERITY_LABELS: Record<ReportSeverity, string> = {\n low: \"Low\",\n medium: \"Medium\",\n high: \"High\",\n critical: \"Critical\",\n};\n\nexport interface ReportResult {\n success: boolean;\n reportId?: string;\n issueUrl?: string;\n issueNumber?: number;\n title?: string;\n intent?: string;\n message?: string;\n /** \"QUEUED\" when saved but not filed yet — the repo lost GitHub access. */\n status?: string;\n}\n\n/**\n * Who the dialog says is filing the report. Hosts resolve this differently —\n * the SDK from its `session` prop, the extension and GlitchRecord from the\n * server-side `ExtensionSession` identity — so the dialog takes it as data and\n * never guesses.\n *\n * `null`/omitted renders the anonymous state rather than nothing: a reporter\n * who believes they're signed in and isn't would otherwise file a report with\n * no way to be followed up, and never know.\n */\nexport interface ReportReporter {\n name?: string | null;\n email?: string | null;\n avatarUrl?: string | null;\n /** Optional role suffix, e.g. \"tester\" — shown next to the name */\n role?: string | null;\n}\n\n/** The function a host (SDK or extension) supplies to actually submit a report. */\nexport type ReportFn = (\n type: ReportType,\n description: string,\n metadata?: Record<string, string>\n) => Promise<ReportResult | null>;\n\n/**\n * Saves a 1–5 star rating. Supplying this is what makes the `RATING` tile\n * appear — a host with no feedback wiring (GlitchRecord desktop today) simply\n * doesn't show it rather than showing a tile that fails on submit.\n */\nexport type FeedbackFn = (\n rating: number,\n message?: string\n) => Promise<{ success: boolean } | null>;\n\n/** Optional: polish description text. Never throws — returns original text on failure. */\nexport type EnhanceTextFn = (text: string, screenshot?: string | null) => Promise<string>;\n\n/**\n * One turn of the AI report assistant (#330).\n *\n * `question` and `report` are mutually exclusive: the assistant is either still\n * asking, or it has written the description. `degraded` is set when the\n * assistant cannot help right now — over the project's monthly cap, rate\n * limited, model down, or simply switched off. That is not an error state: the\n * panel closes, the message is shown once, and the plain form the dialog has\n * always had takes over. Filing a report must never depend on a model.\n */\nexport interface AssistTurnResult {\n conversationId: string | null;\n question: string | null;\n /**\n * Tappable answers to `question`. Sent when the reporter has said something\n * too vague to act on — \"it could be better\" — and the assistant read\n * candidates off the screenshot instead of asking them to phrase it again.\n * Empty when it asked an open question.\n */\n options?: string[];\n report: string | null;\n /**\n * An issue that is already open for this exact problem. Server-validated\n * against the repo's real open issues, so the number is safe to send back:\n * the report is added to that issue as a comment instead of opening another.\n *\n * `status` is where the fix stands, worded by the server off GitHub's own\n * milestone and assignees — \"Fix expected by 18 Sep (v1.8).\" Never from the\n * model. Absent from servers older than it.\n */\n duplicate?: { number: number; title: string; url: string; status?: string } | null;\n /**\n * An open issue this is a DIFFERENT requirement for, in the same feature. The\n * assistant asks whether to add it there; yes → a comment marked as a related\n * request. Server-validated like `duplicate`, never set together with it.\n * Top-level on purpose: a host that predates it ignores it and files a new\n * issue, instead of posting new work as \"another report of this\".\n */\n related?: { number: number; title: string; url: string; status?: string } | null;\n /**\n * The project's own brief answered it and the reporter confirmed. Nothing is\n * filed — the sheet shows this line and the dialog closes. Someone whose\n * problem already had an answer leaves with the answer, not a ticket number.\n */\n solved?: string | null;\n /**\n * The assistant thinks this is a problem with Glitchgrab itself, not the\n * project (#366). The sheet offers to send it to the Glitchgrab team —\n * only when the host passed `reportGlitchgrabProblem`.\n */\n aboutGlitchgrab?: boolean;\n degraded?: string | null;\n /**\n * With `degraded`: the reason clears on its own (an hourly rate limit), so the\n * dialog keeps the assistant button for this report instead of retiring it.\n * A monthly cap or an outage leaves this unset. Absent from older hosts, which\n * then retire the assistant exactly as before.\n */\n retryable?: boolean;\n}\n\n/**\n * How many images ride along with one assistant turn.\n *\n * Capped rather than unbounded: every image is vision tokens against the\n * repo's monthly conversation cap, and a reporter who drags in eight shots\n * would spend the project's month on one bug. The newest win — the picture\n * someone just pasted is the one they are talking about.\n */\nexport const MAX_ASSIST_IMAGES = 3;\n\n/**\n * Total characters of image data one assistant turn may carry.\n *\n * Vercel refuses a request body over ~4.5 MB at the edge with a 413, before the\n * route runs — so the server never gets to answer `degrade`, nothing is logged,\n * and the sheet simply closes. Images are nearly the whole body; this leaves\n * about a megabyte for the conversation, context and events.\n */\nexport const MAX_ASSIST_IMAGE_CHARS = 3_500_000;\n\n/**\n * A text file the reporter attached, decoded for the assistant (#1851) — an\n * HTML mockup, a JSON export, a log. Images go in `screenshots`; binaries (pdf,\n * docx) are not read.\n */\nexport interface AssistFile {\n name: string;\n content: string;\n}\n\n/** Files one assistant turn may carry. The newest win, like images. */\nexport const MAX_ASSIST_FILES = 3;\n\n/**\n * Characters of file text one turn may carry in total, and per file. Sized to\n * fit the megabyte `MAX_ASSIST_IMAGE_CHARS` leaves under the request limit. The\n * server caps again and shows the model an outline plus an excerpt, so this\n * bounds the request body, not how much the model reads.\n */\nexport const MAX_ASSIST_FILE_CHARS = 300_000;\nexport const MAX_ASSIST_FILE_CHARS_EACH = 200_000;\n\n/**\n * Something the reporter did in the sheet, as opposed to something they typed\n * (#357). Kept so the team can see where a conversation stopped working —\n * \"keep chatting\" after a draft, \"write it myself\", a chip tapped.\n */\nexport interface AssistSheetEvent {\n type:\n | \"draft_shown\"\n | \"keep_chatting\"\n | \"write_myself\"\n | \"option_tap\"\n | \"starter_tap\"\n | \"image_added\"\n | \"image_removed\"\n | \"file_added\"\n | \"file_removed\"\n | \"draft_sent\"\n | \"auto_file_stopped\"\n | \"closed\"\n | \"glitchgrab_offer_tap\"\n | \"glitchgrab_offer_declined\";\n detail?: string;\n /** Epoch ms on the reporter's clock. */\n at: number;\n}\n\nexport interface AssistTurnParams {\n /**\n * The conversation so far. An assistant message with `kind: \"report\"` is a\n * draft the reporter was shown, its `content` the draft as they last left it\n * — so \"keep chatting\" revises the draft instead of starting over (#357).\n * Empty on an events-only flush.\n */\n messages: { role: \"user\" | \"assistant\"; content: string; kind?: \"report\" }[];\n conversationId: string | null;\n /**\n * Sheet clicks since the last call. Hosts forward params verbatim, so this\n * needs no host code; the server stores it against the conversation.\n */\n events?: AssistSheetEvent[];\n /**\n * Images the model reads — the auto-captured page shot plus anything the\n * reporter pasted or attached, newest last, at most `MAX_ASSIST_IMAGES` and\n * `MAX_ASSIST_IMAGE_CHARS` between them.\n */\n screenshots?: string[];\n /**\n * @deprecated Superseded by `screenshots`, and no longer sent by the sheet:\n * repeating the newest image doubled the heaviest part of the body and pushed\n * turns past the request-size limit. The server still reads it from SDK\n * builds that predate `screenshots`.\n */\n screenshot?: string | null;\n /**\n * Text files attached to the report (html, json, log…), decoded, newest last,\n * at most `MAX_ASSIST_FILES` (#1851). Omitted when there are none, so a host\n * or server that predates it sees the exact body it always did.\n */\n files?: AssistFile[];\n /**\n * Page URL, visited pages, breadcrumbs, report type. Host-supplied. The sheet\n * adds `imageSources` — \"page\" | \"attached\" per entry of `screenshots` — so\n * the model can tell the screen they were on from what they pasted (#357).\n */\n context?: Record<string, unknown> | null;\n}\n\n/**\n * Runs one assistant turn. Supplied by the host (SDK / extension /\n * GlitchRecord), because only the host knows how to authenticate. Must never\n * throw — a failure comes back as `degraded`.\n */\nexport type AssistFn = (params: AssistTurnParams) => Promise<AssistTurnResult>;\n\n/**\n * Why a report is added to an open issue instead of opening one: the SAME\n * problem (`duplicate`), or a different requirement for the same feature the\n * reporter chose to keep on that issue (`related`).\n */\nexport type AttachKind = \"duplicate\" | \"related\";\n\n/** An already-open issue the plain form's duplicate check matched. */\nexport interface SimilarIssue {\n number: number;\n title: string;\n url: string;\n /**\n * Where the fix stands, worded by the server off GitHub's milestone and\n * assignees — the same line the assistant's duplicate card shows. Absent from\n * hosts or servers that predate it.\n */\n status?: string;\n}\n\n/**\n * \"Is this already filed?\" — asked when the plain form's Send is pressed.\n *\n * Deterministic on the server (word overlap on the repo's open issues, no\n * model), so it can sit in front of Send without making filing depend on a\n * model. Hosts return `[]` when the project has it off and `null` on any\n * failure; the dialog treats both as \"send now\". Must never throw.\n */\nexport type FindSimilarIssuesFn = (description: string) => Promise<SimilarIssue[] | null>;\n\n/** What the dialog hands the host when someone reports a problem with Glitchgrab itself (#366). */\nexport interface GlitchgrabProblemParams {\n description: string;\n /** Where they were when it went wrong — the plain form, or the AI sheet. */\n surface: \"form\" | \"assist\";\n /**\n * The assistant chat, if there was one. The server checks it belongs to the\n * host's project, then puts the full transcript in the issue.\n */\n conversationId: string | null;\n /** The tile they were filing — \"BUG\", \"FEATURE_REQUEST\", … */\n reportType: string;\n /** Every image attached to the report, page shot first, as data URLs. */\n screenshots: string[];\n}\n\n/**\n * Sends a report about the report dialog itself to the Glitchgrab team, never\n * to the host project. Supplying it adds \"Problem with Glitchgrab?\" to the\n * dialog footer and the AI sheet; omitting it leaves both exactly as they were.\n * The SDK passes it only when the project's owner switched it on.\n */\nexport type GlitchgrabProblemFn = (\n params: GlitchgrabProblemParams\n) => Promise<ReportResult | null>;\n","/**\n * File types the report dialog offers in its picker. Mirrors the server-side\n * allowlist in `apps/web/lib/attachments-constants.ts` — the server is the\n * authority, this list only shapes the native file dialog.\n *\n * Text-like files (html, json, log…) are previewed in the GitHub issue body and\n * stored whole on the CDN as plain text; binaries (pdf, docx…) are committed to\n * the repo attachments branch.\n */\nconst TEXT_ATTACHMENT_EXTENSIONS = [\n \".html\",\n \".htm\",\n \".txt\",\n \".md\",\n \".json\",\n \".xml\",\n \".log\",\n \".yml\",\n \".yaml\",\n \".csv\",\n \".har\",\n \".js\",\n \".mjs\",\n \".cjs\",\n \".ts\",\n \".tsx\",\n \".jsx\",\n \".css\",\n \".scss\",\n \".py\",\n \".sh\",\n] as const;\n\nconst BINARY_ATTACHMENT_EXTENSIONS = [\".pdf\", \".doc\", \".docx\", \".xls\", \".xlsx\", \".zip\"] as const;\n\nexport const ATTACHMENT_ACCEPT = [\n \"image/*\",\n ...TEXT_ATTACHMENT_EXTENSIONS,\n ...BINARY_ATTACHMENT_EXTENSIONS,\n].join(\",\");\n\n/**\n * The AI sheet's picker (#1851): images, and the text files the assistant can\n * read. Binaries stay on the dialog's own picker — offering a PDF in a chat\n * that cannot read it would promise something the assistant does not do.\n */\nexport const ASSIST_ATTACHMENT_ACCEPT = [\"image/*\", ...TEXT_ATTACHMENT_EXTENSIONS].join(\",\");\n\n/** True for a file the assistant reads as text. Judged by name, like the server. */\nexport function isAssistReadableFile(name: string): boolean {\n const lower = name.toLowerCase();\n return TEXT_ATTACHMENT_EXTENSIONS.some((ext) => lower.endsWith(ext));\n}\n\n/**\n * The dialog holds attachments as `readAsDataURL` output. Back to text, UTF-8,\n * so an HTML mockup with \"—\" or Marathi in it reaches the model intact. Null on\n * anything that is not a data URL — never throws.\n */\nexport function decodeTextDataUrl(dataUrl: string): string | null {\n try {\n if (!dataUrl.startsWith(\"data:\")) return null;\n const comma = dataUrl.indexOf(\",\");\n if (comma < 0) return null;\n const meta = dataUrl.slice(5, comma);\n const payload = dataUrl.slice(comma + 1);\n if (!meta.endsWith(\";base64\")) return decodeURIComponent(payload);\n const binary = atob(payload);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder(\"utf-8\").decode(bytes);\n } catch {\n return null;\n }\n}\n","import type { DialogTile } from \"./types\";\n\n/**\n * The human name of a tile.\n *\n * Lives here rather than inside `report-dialog` because the AI sheet now shows\n * the same tiles as its first turn (#330 follow-up). Two copies of this list\n * would drift the moment a type is added, and the reporter would see one name\n * in the dialog and a different one in the chat.\n */\nexport function getTypeLabel(type: DialogTile): string {\n switch (type) {\n case \"RATING\":\n return \"Rating\";\n case \"BUG\":\n return \"Bug Report\";\n case \"FEATURE_REQUEST\":\n return \"Feature Request\";\n case \"UI_IMPROVEMENT\":\n return \"UI Improvement\";\n case \"PERFORMANCE\":\n return \"Performance\";\n case \"SECURITY\":\n return \"Security\";\n case \"QUESTION\":\n return \"Question\";\n case \"OTHER\":\n return \"Other\";\n }\n}\n","\"use client\";\n\nimport type { CSSProperties, ReactNode } from \"react\";\n\n/**\n * The markdown the assistant writes in a chat bubble, rendered as formatting\n * instead of literal `**` and `#`.\n *\n * Blocks: paragraphs, headings, bullet / numbered / task lists (nested),\n * > quotes, fenced code, tables, rules. Inline: bold, italic, ~~strike~~,\n * `code`, links, bare URLs, backslash escapes.\n *\n * Hand-rolled on purpose. This ships inside the SDK, whose only dependency\n * beyond React is html2canvas-pro, and a markdown library would be the largest\n * thing in the bundle to format a chat reply.\n *\n * Output is React elements, never HTML. The reply is model output built from\n * page content, attached files and project notes — all untrusted — so a string\n * reaching `innerHTML` is an injection path. Links are `http(s)` only, and an\n * image is shown as a link, never loaded: an `<img>` pointed anywhere by\n * injected text is a tracking pixel inside the host's page.\n *\n * Every block gets explicit inline styles, and headings are `div`s: the SDK\n * renders inside someone else's page, and their global `h2` / `ul` / `table`\n * CSS would otherwise restyle our bubble.\n *\n * No lookbehind in any pattern: Safari before 16.4 throws on it at parse time,\n * and a module that fails to load takes the host app with it.\n */\n\n/** The slice of `AssistTheme` this paints with — declared here, not imported, so\n * this module and assist-sheet do not import each other. */\ntype MdTheme = { accent: string; bg: string; border: string; textMuted: string };\n\n// ─── Inline ────────────────────────────────────────────────────────────────\n\nconst CODE = /`([^`\\n]+)`/y;\nconst MD_LINK = /\\[([^\\]\\n]*)\\]\\((https?:\\/\\/[^\\s)]+)\\)/y;\nconst BOLD_STAR = /\\*\\*(\\S(?:[^\\n]*?\\S)?)\\*\\*/y;\nconst BOLD_UNDER = /__(\\S(?:[^\\n]*?\\S)?)__/y;\nconst ITALIC_STAR = /\\*(\\S(?:[^*\\n]*?\\S)?)\\*/y;\nconst ITALIC_UNDER = /_(\\S(?:[^_\\n]*?\\S)?)_/y;\nconst STRIKE = /~~(\\S(?:[^\\n]*?\\S)?)~~/y;\nconst FULL_URL = /https?:\\/\\/[^\\s<>]+/y;\n// A bare domain only counts with a path — \"glitchgrab.dev/guides\" is a link,\n// \"sms.ts\" is a file name. Lowercase only, so \"Next.js/React\" stays prose.\nconst BARE_URL = /(?:[a-z0-9-]+\\.)+[a-z]{2,24}\\/[^\\s<>]*/y;\n\nconst WORD = /[A-Za-z0-9]/;\nconst URL_EDGE = /[A-Za-z0-9@./-]/;\nconst TRAILING_PUNCT = /[.,;:!?'\")\\]*_~]+$/;\nconst ESCAPABLE = \"\\\\`*_{}[]()#+-.!|~>\";\n\nconst MONO = \"ui-monospace, SFMono-Regular, Menlo, Consolas, monospace\";\n\nfunction at(re: RegExp, text: string, i: number): RegExpExecArray | null {\n re.lastIndex = i;\n return re.exec(text);\n}\n\nfunction isSafeHref(href: string): boolean {\n try {\n const { protocol } = new URL(href);\n return protocol === \"http:\" || protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\nfunction renderInline(text: string, theme: MdTheme, key: string): ReactNode[] {\n const out: ReactNode[] = [];\n let plain = \"\";\n let i = 0;\n\n const flush = () => {\n if (plain) out.push(plain);\n plain = \"\";\n };\n const link = (href: string, label: ReactNode, k: string) => (\n <a\n key={k}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer nofollow\"\n title={href}\n style={{\n color: \"inherit\",\n textDecoration: \"underline\",\n textDecorationColor: theme.accent,\n textUnderlineOffset: \"2px\",\n wordBreak: \"break-word\",\n }}\n >\n {label}\n </a>\n );\n\n while (i < text.length) {\n const ch = text[i];\n const prev = i > 0 ? text[i - 1] : \"\";\n const k = `${key}.${i}`;\n let m: RegExpExecArray | null;\n\n if (ch === \"\\\\\" && i + 1 < text.length && ESCAPABLE.includes(text[i + 1])) {\n plain += text[i + 1];\n i += 2;\n continue;\n }\n\n if (ch === \"`\" && (m = at(CODE, text, i))) {\n flush();\n out.push(\n <code\n key={k}\n style={{\n fontFamily: MONO,\n fontSize: \"0.92em\",\n padding: \"1px 4px\",\n borderRadius: \"4px\",\n backgroundColor: theme.bg,\n border: `1px solid ${theme.border}`,\n wordBreak: \"break-word\",\n }}\n >\n {m[1]}\n </code>\n );\n i += m[0].length;\n continue;\n }\n\n //  — shown as a link to the image, never loaded.\n const image = ch === \"!\" && text[i + 1] === \"[\";\n if ((ch === \"[\" || image) && (m = at(MD_LINK, text, image ? i + 1 : i)) && isSafeHref(m[2])) {\n flush();\n const label = m[1] ? renderInline(m[1], theme, k) : m[2];\n out.push(link(m[2], label, k));\n i += m[0].length + (image ? 1 : 0);\n continue;\n }\n\n if (ch === \"~\" && text[i + 1] === \"~\" && (m = at(STRIKE, text, i))) {\n flush();\n out.push(<del key={k}>{renderInline(m[1], theme, k)}</del>);\n i += m[0].length;\n continue;\n }\n\n if ((ch === \"*\" || ch === \"_\") && !WORD.test(prev)) {\n const double = text[i + 1] === ch;\n const bold = double ? at(ch === \"*\" ? BOLD_STAR : BOLD_UNDER, text, i) : null;\n const italic = bold ? null : at(ch === \"*\" ? ITALIC_STAR : ITALIC_UNDER, text, i);\n m = bold ?? italic;\n // `snake_case_name` and `2*3*4` are not emphasis: the closing mark must\n // not run straight into a word either.\n if (m && !WORD.test(text[i + m[0].length] ?? \"\")) {\n flush();\n const inner = renderInline(m[1], theme, k);\n out.push(\n bold ? (\n <strong key={k} style={{ fontWeight: 700 }}>\n {inner}\n </strong>\n ) : (\n <em key={k} style={{ fontStyle: \"italic\" }}>\n {inner}\n </em>\n )\n );\n i += m[0].length;\n continue;\n }\n }\n\n if (!URL_EDGE.test(prev)) {\n m = ch === \"h\" ? at(FULL_URL, text, i) : null;\n const bare = m ? null : /[a-z0-9]/.test(ch) ? at(BARE_URL, text, i) : null;\n const raw = m?.[0] ?? bare?.[0];\n if (raw) {\n const shown = raw.replace(TRAILING_PUNCT, \"\");\n const href = m ? shown : `https://${shown}`;\n if (shown.includes(\"/\") && isSafeHref(href)) {\n flush();\n out.push(link(href, shown, k));\n i += shown.length;\n continue;\n }\n }\n }\n\n plain += ch;\n i += 1;\n }\n\n flush();\n return out;\n}\n\n// ─── Blocks ────────────────────────────────────────────────────────────────\n\nconst FENCE = /^\\s{0,3}(`{3,}|~{3,})/;\nconst HEADING = /^\\s{0,3}(#{1,6})\\s+(.+?)(?:\\s+#+)?\\s*$/;\nconst RULE = /^\\s{0,3}([-*_])(?:\\s*\\1){2,}\\s*$/;\nconst QUOTE = /^\\s{0,3}>\\s?(.*)$/;\nconst LIST_ITEM = /^(\\s*)([-*+]|\\d{1,9}[.)])\\s+(.*)$/;\nconst TABLE_SEP = /^\\s*\\|?\\s*:?-+:?\\s*(?:\\|\\s*:?-+:?\\s*)*\\|?\\s*$/;\nconst TASK = /^\\[([ xX])\\]\\s+(.*)$/;\n\nconst STACK: CSSProperties = {\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"6px\",\n minWidth: 0,\n};\n\n/** Splits a table row on unescaped pipes, dropping the outer ones. */\nfunction splitRow(line: string): string[] {\n let s = line.trim();\n if (s.startsWith(\"|\")) s = s.slice(1);\n if (s.endsWith(\"|\") && !s.endsWith(\"\\\\|\")) s = s.slice(0, -1);\n const cells: string[] = [];\n let cell = \"\";\n for (let i = 0; i < s.length; i++) {\n if (s[i] === \"\\\\\" && s[i + 1] === \"|\") {\n cell += \"|\";\n i++;\n } else if (s[i] === \"|\") {\n cells.push(cell.trim());\n cell = \"\";\n } else {\n cell += s[i];\n }\n }\n cells.push(cell.trim());\n return cells;\n}\n\nfunction tableAt(lines: string[], i: number): string[] | null {\n const head = lines[i];\n const sep = lines[i + 1];\n if (!head?.includes(\"|\") || !sep?.includes(\"|\") || !TABLE_SEP.test(sep)) return null;\n const aligns = splitRow(sep);\n return aligns.length === splitRow(head).length ? aligns : null;\n}\n\nfunction startsBlock(lines: string[], i: number): boolean {\n const line = lines[i];\n return (\n FENCE.test(line) ||\n HEADING.test(line) ||\n RULE.test(line) ||\n QUOTE.test(line) ||\n LIST_ITEM.test(line) ||\n tableAt(lines, i) !== null\n );\n}\n\nfunction renderBlocks(lines: string[], theme: MdTheme, key: string): ReactNode[] {\n const out: ReactNode[] = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n const k = `${key}-${i}`;\n let m: RegExpExecArray | null;\n\n if (!line.trim()) {\n i++;\n continue;\n }\n\n if ((m = FENCE.exec(line))) {\n const fence = m[1];\n const body: string[] = [];\n i++;\n while (i < lines.length) {\n const t = lines[i].trim();\n if (t.length >= fence.length && [...t].every((c) => c === fence[0])) break;\n body.push(lines[i]);\n i++;\n }\n i++; // the closing fence, or past the end when the model never closed it\n out.push(\n <pre\n key={k}\n style={{\n margin: 0,\n padding: \"8px 10px\",\n borderRadius: \"6px\",\n backgroundColor: theme.bg,\n border: `1px solid ${theme.border}`,\n overflowX: \"auto\",\n maxWidth: \"100%\",\n fontFamily: MONO,\n fontSize: \"12px\",\n lineHeight: 1.5,\n whiteSpace: \"pre\",\n }}\n >\n <code style={{ fontFamily: \"inherit\" }}>{body.join(\"\\n\")}</code>\n </pre>\n );\n continue;\n }\n\n if ((m = HEADING.exec(line))) {\n const level = m[1].length;\n out.push(\n <div\n key={k}\n role=\"heading\"\n aria-level={level}\n style={{\n fontWeight: 700,\n fontSize: level === 1 ? \"1.15em\" : level === 2 ? \"1.08em\" : \"1em\",\n lineHeight: 1.35,\n }}\n >\n {renderInline(m[2], theme, k)}\n </div>\n );\n i++;\n continue;\n }\n\n if (RULE.test(line)) {\n out.push(<div key={k} role=\"separator\" style={{ borderTop: `1px solid ${theme.border}` }} />);\n i++;\n continue;\n }\n\n if (QUOTE.test(line)) {\n const inner: string[] = [];\n while (i < lines.length && (m = QUOTE.exec(lines[i]))) {\n inner.push(m[1]);\n i++;\n }\n out.push(\n <blockquote\n key={k}\n style={{\n ...STACK,\n margin: 0,\n paddingLeft: \"10px\",\n // `border` is near the bubble's own colour; the bar vanished.\n borderLeft: `3px solid ${theme.accent}66`,\n color: theme.textMuted,\n }}\n >\n {renderBlocks(inner, theme, k)}\n </blockquote>\n );\n continue;\n }\n\n const aligns = tableAt(lines, i);\n if (aligns) {\n const head = splitRow(line);\n const rows: string[][] = [];\n i += 2;\n while (i < lines.length && lines[i].trim() && lines[i].includes(\"|\")) {\n rows.push(splitRow(lines[i]));\n i++;\n }\n const align = (c: number): CSSProperties[\"textAlign\"] => {\n const a = aligns[c] ?? \"\";\n if (a.startsWith(\":\") && a.endsWith(\":\")) return \"center\";\n return a.endsWith(\":\") ? \"right\" : \"left\";\n };\n const cell = (c: number): CSSProperties => ({\n border: `1px solid ${theme.border}`,\n padding: \"4px 8px\",\n textAlign: align(c),\n verticalAlign: \"top\",\n });\n out.push(\n <div key={k} style={{ overflowX: \"auto\", maxWidth: \"100%\" }}>\n <table style={{ borderCollapse: \"collapse\", fontSize: \"12px\", margin: 0 }}>\n <thead>\n <tr>\n {head.map((h, c) => (\n <th key={c} style={{ ...cell(c), fontWeight: 600, backgroundColor: theme.bg }}>\n {renderInline(h, theme, `${k}h${c}`)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.map((row, r) => (\n <tr key={r}>\n {head.map((_, c) => (\n <td key={c} style={cell(c)}>\n {renderInline(row[c] ?? \"\", theme, `${k}r${r}c${c}`)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n continue;\n }\n\n if ((m = LIST_ITEM.exec(line))) {\n const baseIndent = m[1].length;\n const ordered = /\\d/.test(m[2]);\n const start = ordered ? parseInt(m[2], 10) : 1;\n const items: string[][] = [];\n\n while (i < lines.length) {\n const l = lines[i];\n const lm = LIST_ITEM.exec(l);\n const indent = l.length - l.trimStart().length;\n if (lm && indent <= baseIndent + 1) {\n if (/\\d/.test(lm[2]) !== ordered) break;\n items.push([lm[3]]);\n i++;\n continue;\n }\n const current = items[items.length - 1];\n if (!l.trim()) {\n // A blank line ends the list unless more of it follows.\n const next = lines[i + 1];\n const nextIndent = next ? next.length - next.trimStart().length : 0;\n if (next?.trim() && (nextIndent > baseIndent + 1 || LIST_ITEM.test(next))) {\n current.push(\"\");\n i++;\n continue;\n }\n break;\n }\n if (indent > baseIndent + 1) {\n // Content indent: strip what belongs to this list's own marker, so a\n // nested list comes out at the left edge of the item.\n current.push(l.slice(Math.min(indent, baseIndent + 2)));\n i++;\n continue;\n }\n break;\n }\n\n const ListTag = ordered ? \"ol\" : \"ul\";\n out.push(\n <ListTag\n key={k}\n start={ordered && start !== 1 ? start : undefined}\n style={{\n margin: 0,\n paddingLeft: \"20px\",\n listStyleType: ordered ? \"decimal\" : \"disc\",\n listStylePosition: \"outside\",\n }}\n >\n {items.map((itemLines, n) => {\n const ik = `${k}i${n}`;\n const task = TASK.exec(itemLines[0]);\n const body = task ? [task[2], ...itemLines.slice(1)] : itemLines;\n const box = task ? (\n <span aria-hidden=\"true\" style={{ marginRight: \"6px\" }}>\n {task[1] === \" \" ? \"☐\" : \"☑\"}\n </span>\n ) : null;\n const simple = body.filter((x) => x.trim()).length === 1;\n return (\n <li\n key={ik}\n style={{\n display: \"list-item\",\n marginTop: n ? \"3px\" : 0,\n paddingLeft: \"2px\",\n listStyleType: task ? \"none\" : undefined,\n }}\n >\n {simple ? (\n <>\n {box}\n {renderInline(body[0], theme, ik)}\n </>\n ) : (\n <div style={STACK}>\n {box ? (\n <div>\n {box}\n {renderInline(body[0], theme, ik)}\n </div>\n ) : null}\n {renderBlocks(box ? body.slice(1) : body, theme, ik)}\n </div>\n )}\n </li>\n );\n })}\n </ListTag>\n );\n continue;\n }\n\n // Paragraph: runs until a blank line or the start of another block. A\n // single line break stays a line break — this is chat, not a document.\n const para: string[] = [];\n while (i < lines.length && lines[i].trim() && !(para.length && startsBlock(lines, i))) {\n para.push(lines[i].trim());\n i++;\n }\n out.push(\n <div key={k}>\n {para.flatMap((p, n) => {\n const inline = renderInline(p, theme, `${k}p${n}`);\n return n ? [<br key={`${k}br${n}`} />, ...inline] : inline;\n })}\n </div>\n );\n }\n\n return out;\n}\n\nexport function ChatMarkdown({ text, theme }: { text: string; theme: MdTheme }) {\n return <div style={STACK}>{renderBlocks(text.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\"), theme, \"md\")}</div>;\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { AssistTheme } from \"./assist-sheet\";\nimport { encodeImageFile } from \"./image-encode\";\nimport type { GlitchgrabProblemFn } from \"./types\";\n\n/**\n * \"Problem with Glitchgrab?\" (#366).\n *\n * Someone reporting a bug in a customer's app hits a problem with the reporter\n * itself — the assistant loops, a button does nothing. That report belongs to\n * Glitchgrab, not to the project behind the dialog, so it gets its own small\n * layer on top of everything with its own send, instead of hijacking the\n * dialog's one submit path. The report underneath is never touched: closing\n * this panel lands them exactly where they were.\n */\n\nconst FONT = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif';\nconst FAILED = \"Couldn't send it. Try again in a moment.\";\n\n/** The server keeps the first 5 (`lib/glitchgrab-self-report.ts`); past that the button hides. */\nexport const MAX_SELF_REPORT_IMAGES = 5;\n\ninterface GlitchgrabProblemPanelProps {\n send: GlitchgrabProblemFn;\n theme: AssistTheme;\n surface: \"form\" | \"assist\";\n conversationId: string | null;\n reportType: string;\n /**\n * The report's images — what the panel starts with. Adding or removing one in\n * the panel changes only what goes to Glitchgrab, never the report underneath.\n */\n screenshots: string[];\n /** Opening text — the reporter's own chat words when the assistant offered this. */\n initialText?: string;\n onClose: () => void;\n}\n\n/**\n * \"your AI chat, what you did on this page and 2 screenshots\".\n *\n * Said before Send because none of it is the reporter's to give away silently:\n * it is their session on someone else's product, leaving that product.\n */\nexport function describeSentAlong(hasChat: boolean, screenshotCount: number): string {\n const parts = [\n ...(hasChat ? [\"your AI chat\"] : []),\n \"what you did on this page\",\n ...(screenshotCount > 0\n ? [`${screenshotCount} screenshot${screenshotCount === 1 ? \"\" : \"s\"}`]\n : []),\n ];\n if (parts.length === 1) return parts[0];\n return `${parts.slice(0, -1).join(\", \")} and ${parts[parts.length - 1]}`;\n}\n\nexport function GlitchgrabProblemPanel({\n send,\n theme: t,\n surface,\n conversationId,\n reportType,\n screenshots,\n initialText = \"\",\n onClose,\n}: GlitchgrabProblemPanelProps) {\n const [text, setText] = useState(initialText);\n const [busy, setBusy] = useState(false);\n const [sent, setSent] = useState(false);\n const [error, setError] = useState<string | null>(null);\n // The panel's own copy. #375: a reporter showing us the problem had no way to\n // add the screenshot of it — the report's images went along unseen.\n const [images, setImages] = useState<string[]>(() =>\n screenshots.slice(0, MAX_SELF_REPORT_IMAGES),\n );\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const fileRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n inputRef.current?.focus();\n }, []);\n\n // Same budget as the dialog's own attachments: a retina paste alone can be\n // over the request-body limit.\n const addImages = useCallback((files: File[]) => {\n const picked = files.filter((file) => file.type.startsWith(\"image/\"));\n if (!picked.length) return;\n void Promise.all(picked.map((file) => encodeImageFile(file).catch(() => null))).then(\n (encoded) => {\n const added = encoded.filter((url): url is string => !!url);\n if (added.length) {\n setImages((prev) => [...prev, ...added].slice(0, MAX_SELF_REPORT_IMAGES));\n }\n },\n );\n }, []);\n\n // A pasted image belongs to this panel. Window + capture runs before the\n // dialog's own paste handler on window; without stopping it there the image\n // lands on the report underneath, where the reporter never sees it arrive.\n // Immediate, not plain stopPropagation: an event targeted at window itself\n // still runs every other window listener after a plain stop.\n useEffect(() => {\n const onPaste = (e: ClipboardEvent) => {\n try {\n const items = e.clipboardData?.items;\n if (!items) return;\n const files: File[] = [];\n for (let i = 0; i < items.length; i++) {\n if (items[i].kind !== \"file\") continue;\n const file = items[i].getAsFile();\n if (file) files.push(file);\n }\n if (!files.length) return;\n e.preventDefault();\n e.stopImmediatePropagation();\n addImages(files);\n } catch {\n // An unreadable clipboard is just a paste that did nothing.\n }\n };\n window.addEventListener(\"paste\", onPaste, true);\n return () => window.removeEventListener(\"paste\", onPaste, true);\n }, [addImages]);\n\n // Escape closes this layer and nothing else. Window + capture runs before the\n // dialog's own Escape handler on document; stopping it here keeps the report\n // underneath open — closing that would throw away the very draft this panel\n // promises to leave alone.\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n e.stopPropagation();\n onClose();\n };\n window.addEventListener(\"keydown\", onKey, true);\n return () => window.removeEventListener(\"keydown\", onKey, true);\n }, [onClose]);\n\n const submit = async () => {\n const description = text.trim();\n if (!description || busy) return;\n setBusy(true);\n setError(null);\n try {\n const result = await send({\n description,\n surface,\n conversationId,\n reportType,\n screenshots: images,\n });\n if (result?.success) setSent(true);\n else setError(result?.message || FAILED);\n } catch {\n setError(FAILED);\n } finally {\n setBusy(false);\n }\n };\n\n const canSend = !!text.trim() && !busy;\n\n const secondaryButton = {\n padding: \"10px 14px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n background: \"transparent\",\n color: t.text,\n fontSize: \"13px\",\n fontWeight: 600,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n } as const;\n\n const primaryButton = (enabled: boolean) =>\n ({\n padding: \"10px 14px\",\n borderRadius: \"8px\",\n border: \"none\",\n backgroundColor: enabled ? t.accent : t.bgSecondary,\n color: enabled ? t.accentText : t.textMuted,\n fontSize: \"13px\",\n fontWeight: 700,\n fontFamily: \"inherit\",\n cursor: enabled ? \"pointer\" : \"default\",\n }) as const;\n\n return createPortal(\n // No close on backdrop click: a stray click would throw away what they typed.\n // `data-glitchgrab-layer` exempts this from the dialog's anti-focus-trap\n // sweep, which sets `inert` on every other role=\"dialog\" on the page —\n // without it the panel renders but cannot be typed into.\n <div\n data-glitchgrab-layer=\"\"\n data-gg-self-report-panel=\"\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"gg-self-report-title\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n backgroundColor: \"rgba(0,0,0,0.55)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n boxSizing: \"border-box\",\n fontFamily: FONT,\n }}\n >\n <div\n style={{\n width: \"100%\",\n maxWidth: \"420px\",\n boxSizing: \"border-box\",\n backgroundColor: t.bg,\n color: t.text,\n border: `1px solid ${t.border}`,\n borderRadius: \"12px\",\n boxShadow: \"0 20px 50px rgba(0,0,0,0.5)\",\n padding: \"18px\",\n }}\n >\n {sent ? (\n <>\n <div id=\"gg-self-report-title\" style={{ fontSize: \"15px\", fontWeight: 600 }}>\n Sent to the Glitchgrab team\n </div>\n <p style={{ margin: \"6px 0 16px\", fontSize: \"13px\", lineHeight: 1.5, color: t.textMuted }}>\n Thanks — we'll look into it. Your report is still open behind this, exactly as\n you left it.\n </p>\n <button\n type=\"button\"\n data-gg-self-report-done=\"\"\n onClick={onClose}\n style={{ ...primaryButton(true), width: \"100%\" }}\n >\n Back to your report\n </button>\n </>\n ) : (\n <>\n <div\n style={{\n display: \"flex\",\n alignItems: \"flex-start\",\n justifyContent: \"space-between\",\n gap: \"12px\",\n }}\n >\n <div id=\"gg-self-report-title\" style={{ fontSize: \"15px\", fontWeight: 600 }}>\n Problem with Glitchgrab?\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n style={{\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"18px\",\n lineHeight: 1,\n cursor: \"pointer\",\n padding: \"4px 6px\",\n margin: \"-4px -6px 0 0\",\n }}\n >\n ×\n </button>\n </div>\n <p style={{ margin: \"6px 0 12px\", fontSize: \"13px\", lineHeight: 1.5, color: t.textMuted }}>\n This goes to the people who build this reporter — not to this project's team.\n Tell us what went wrong: the AI chat, a button, anything.\n </p>\n\n <textarea\n ref={inputRef}\n data-gg-self-report-input=\"\"\n value={text}\n onChange={(e) => {\n setText(e.target.value);\n if (error) setError(null);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n void submit();\n }\n }}\n rows={4}\n placeholder=\"e.g. The assistant kept asking the same question and never wrote a draft\"\n style={{\n width: \"100%\",\n boxSizing: \"border-box\",\n resize: \"vertical\",\n padding: \"10px 12px\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n backgroundColor: t.inputBg,\n color: t.text,\n fontSize: \"14px\",\n lineHeight: 1.45,\n fontFamily: \"inherit\",\n outline: \"none\",\n }}\n />\n\n <div\n data-gg-self-report-images=\"\"\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n alignItems: \"center\",\n gap: \"8px\",\n marginTop: \"10px\",\n }}\n >\n {images.map((src, i) => (\n <div key={i} style={{ position: \"relative\", width: \"48px\", height: \"48px\" }}>\n <img\n src={src}\n alt={`Screenshot ${i + 1}`}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n display: \"block\",\n boxSizing: \"border-box\",\n borderRadius: \"8px\",\n border: `1px solid ${t.inputBorder}`,\n }}\n />\n <button\n type=\"button\"\n data-gg-self-report-remove-image=\"\"\n aria-label={`Remove screenshot ${i + 1}`}\n title=\"Don't send this one\"\n onClick={() => setImages((prev) => prev.filter((_, j) => j !== i))}\n style={{\n position: \"absolute\",\n top: \"-13px\",\n right: \"-13px\",\n width: \"32px\",\n height: \"32px\",\n border: \"none\",\n background: \"transparent\",\n padding: 0,\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: \"50%\",\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: \"20px\",\n height: \"20px\",\n boxSizing: \"border-box\",\n borderRadius: \"50%\",\n border: `2px solid ${t.bg}`,\n background: \"#ef4444\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path\n d=\"M1 1L9 9M9 1L1 9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n />\n </svg>\n </span>\n </button>\n </div>\n ))}\n {images.length < MAX_SELF_REPORT_IMAGES && (\n <button\n type=\"button\"\n data-gg-self-report-attach=\"\"\n aria-label=\"Add screenshot\"\n title=\"Add a screenshot — or paste one\"\n onClick={() => fileRef.current?.click()}\n style={{\n height: \"48px\",\n padding: \"0 12px\",\n boxSizing: \"border-box\",\n borderRadius: \"8px\",\n border: `1px dashed ${t.inputBorder}`,\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"12.5px\",\n fontWeight: 600,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n }}\n >\n {/* Short once thumbnails fill the row, or on a phone it wraps\n onto a line of its own. */}\n {images.length >= 3 ? \"+ Add\" : \"+ Add screenshot\"}\n </button>\n )}\n <input\n ref={fileRef}\n type=\"file\"\n accept=\"image/*\"\n multiple\n data-gg-self-report-file=\"\"\n onChange={(e) => {\n addImages(Array.from(e.target.files ?? []));\n // The same file twice in a row fires no change unless cleared.\n e.target.value = \"\";\n }}\n style={{ display: \"none\" }}\n />\n </div>\n\n <p\n data-gg-self-report-includes=\"\"\n style={{ margin: \"8px 0 0\", fontSize: \"11.5px\", lineHeight: 1.45, color: t.textMuted }}\n >\n Also sent, so we can see what happened:{\" \"}\n {describeSentAlong(conversationId !== null, images.length)}.\n </p>\n {error && (\n <p role=\"alert\" style={{ margin: \"8px 0 0\", fontSize: \"12px\", color: \"#ef4444\" }}>\n {error}\n </p>\n )}\n\n <div style={{ display: \"flex\", justifyContent: \"flex-end\", gap: \"8px\", marginTop: \"14px\" }}>\n <button type=\"button\" onClick={onClose} style={secondaryButton}>\n Cancel\n </button>\n <button\n type=\"button\"\n data-gg-self-report-send=\"\"\n onClick={() => void submit()}\n disabled={!canSend}\n style={primaryButton(canSend)}\n >\n {busy ? \"Sending…\" : \"Send to Glitchgrab\"}\n </button>\n </div>\n </>\n )}\n </div>\n </div>,\n document.body,\n );\n}\n","/**\n * The global keyboard shortcut that opens the Glitchgrab report dialog.\n * Single source of truth — the provider's keydown handler and every label\n * rendered anywhere (SDK dialog, host app UI) derive from this.\n */\n\n/** Server-safe label. Used during SSR and as the non-Mac label. */\nexport const GLITCHGRAB_SHORTCUT = \"Ctrl+Shift+G\";\n\n/** Mac label, using the platform's modifier glyphs. */\nexport const GLITCHGRAB_SHORTCUT_MAC = \"⌘⇧G\";\n\n/** True when running on a Mac-like platform. Always false on the server. */\nfunction isMac(): boolean {\n try {\n if (typeof navigator === \"undefined\") return false;\n return /Mac|iPhone|iPad|iPod/i.test(navigator.platform || navigator.userAgent);\n } catch {\n return false;\n }\n}\n\n/**\n * OS-aware label for the report-dialog shortcut — `⌘⇧G` on Mac,\n * `Ctrl+Shift+G` elsewhere. Returns the non-Mac label on the server, so\n * render it client-side (or after mount) to avoid a hydration mismatch.\n */\nexport function getShortcutLabel(): string {\n return isMac() ? GLITCHGRAB_SHORTCUT_MAC : GLITCHGRAB_SHORTCUT;\n}\n\n/** True when the keyboard event matches the report-dialog shortcut. */\nexport function matchesShortcut(e: KeyboardEvent): boolean {\n return (\n (e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === \"g\"\n );\n}\n","/**\n * Default screenshot capture for hosts that embed the dialog in the page being\n * reported (the SDK). Standalone hosts inject their own — see\n * `ReportDialogProps.captureScreenshot`.\n *\n * html2canvas does not photograph the page, it re-draws it from computed CSS,\n * and that re-draw drifts from what the reporter actually sees: in one\n * production report every border fell back to Tailwind's preflight\n * `border: 0 solid` (solid, currentColor), so a dark dashboard came out ringed\n * in white and a dashed box came out solid. A screenshot that disagrees with\n * the screen is worse than none — the developer ends up debugging the capture.\n *\n * So where the browser can hand over the tab's real pixels, take those, and\n * keep html2canvas as the fallback for everywhere it can't.\n */\n\nimport { encodeScreenshot } from \"./image-encode\";\n\n/** Capture at the display's own density, capped — beyond 2× the payload grows faster than the legibility. */\nconst MAX_SCALE = 2;\n\n/** A frame that never arrives must not hold the dialog closed. */\nconst FRAME_TIMEOUT_MS = 3000;\n\n/**\n * Ceiling on everything after the reporter clicked Allow. `waitForFrame` has\n * its own timeout but `video.play()` does not, and an await that never settles\n * never reaches the `finally` that stops the stream — the \"Sharing this tab\"\n * bar would then outlive the report (#364, not reproduced: a static page stops\n * in ~140ms in real Chromium). Bounded here so no await in the path can do it.\n */\nconst GRAB_TIMEOUT_MS = FRAME_TIMEOUT_MS + 2000;\n\n/**\n * Chromium-only members of the `getDisplayMedia` options. Not in lib.dom yet;\n * other engines ignore unknown keys, so passing them is harmless.\n */\ntype TabCaptureOptions = DisplayMediaStreamOptions & {\n preferCurrentTab?: boolean;\n selfBrowserSurface?: \"include\" | \"exclude\";\n surfaceSwitching?: \"include\" | \"exclude\";\n monitorTypeSurfaces?: \"include\" | \"exclude\";\n};\n\ntype FrameCallbackVideo = HTMLVideoElement & {\n requestVideoFrameCallback?: (callback: () => void) => number;\n};\n\n/**\n * Only Chromium offers \"this tab\" as a one-click Allow. Safari and Firefox\n * would open a full screen/window picker instead — a worse experience than the\n * re-draw, and one that invites sharing the whole desktop — so they go straight\n * to html2canvas. `CaptureController` ships only in Chromium, which makes it a\n * stand-in for \"honours preferCurrentTab\" without sniffing the user agent.\n */\nexport function canCaptureTabPixels(): boolean {\n try {\n return (\n typeof navigator !== \"undefined\" &&\n typeof navigator.mediaDevices?.getDisplayMedia === \"function\" &&\n typeof (globalThis as { CaptureController?: unknown }).CaptureController !== \"undefined\"\n );\n } catch {\n return false;\n }\n}\n\n/** `HTMLMediaElement.HAVE_CURRENT_DATA` — a frame is decoded and drawable. */\nconst HAVE_CURRENT_DATA = 2;\n\n/** Resolves true once a frame is decoded, false if none arrived in time. */\nfunction waitForFrame(video: FrameCallbackVideo): Promise<boolean> {\n // play() usually resolves with the first frame already decoded — use it.\n // Waiting for the *next* one stalls: tab capture only emits a frame when the\n // page repaints, so on a page that isn't moving it may never come (measured:\n // a static page sat out the full timeout at 1× and fell back every time).\n if (video.readyState >= HAVE_CURRENT_DATA && video.videoWidth > 0) {\n return Promise.resolve(true);\n }\n return new Promise((resolve) => {\n const timer = setTimeout(() => resolve(false), FRAME_TIMEOUT_MS);\n const done = () => {\n clearTimeout(timer);\n resolve(true);\n };\n if (typeof video.requestVideoFrameCallback === \"function\") {\n video.requestVideoFrameCallback(done);\n } else if (video.readyState >= 2) {\n done();\n } else {\n video.addEventListener(\"loadeddata\", done, { once: true });\n }\n });\n}\n\nasync function grabFrame(stream: MediaStream): Promise<HTMLCanvasElement | null> {\n const video = document.createElement(\"video\") as FrameCallbackVideo;\n video.muted = true;\n video.playsInline = true;\n video.srcObject = stream;\n try {\n await video.play();\n if (!(await waitForFrame(video))) return null;\n if (!video.videoWidth || !video.videoHeight) return null;\n\n const maxWidth = Math.max(1, window.innerWidth) * MAX_SCALE;\n const factor = Math.min(1, maxWidth / video.videoWidth);\n const canvas = document.createElement(\"canvas\");\n canvas.width = Math.round(video.videoWidth * factor);\n canvas.height = Math.round(video.videoHeight * factor);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n ctx.drawImage(video, 0, 0, canvas.width, canvas.height);\n return canvas;\n } finally {\n video.srcObject = null;\n }\n}\n\n/**\n * The tab's real pixels via `getDisplayMedia({ preferCurrentTab })`.\n *\n * Chrome asks \"Allow this site to see this tab?\" on every call — that prompt is\n * the price of an exact image. Must be called inside the click (or keypress)\n * that opened the dialog: the browser refuses without a user gesture, which is\n * why the dialog captures before its first await.\n *\n * Returns null — never throws — on a refusal, an unsupported browser, a\n * missing `display-capture` permission policy, or anything other than a tab.\n */\nexport async function captureViaTabPixels(): Promise<string | null> {\n if (!canCaptureTabPixels()) return null;\n\n let stream: MediaStream | null = null;\n try {\n const options: TabCaptureOptions = {\n video: { displaySurface: \"browser\" } as MediaTrackConstraints,\n audio: false,\n preferCurrentTab: true,\n selfBrowserSurface: \"include\",\n surfaceSwitching: \"exclude\",\n monitorTypeSurfaces: \"exclude\",\n };\n stream = await navigator.mediaDevices.getDisplayMedia(options);\n\n // The picker can still offer a window or a whole screen. This image goes to\n // the host app's issue tracker, so anything beyond the host's own tab —\n // another app, a password manager, a chat — must never be encoded.\n const surface = (\n stream.getVideoTracks()[0]?.getSettings() as { displaySurface?: string } | undefined\n )?.displaySurface;\n if (surface && surface !== \"browser\") return null;\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timedOut = new Promise<null>((resolve) => {\n timer = setTimeout(() => resolve(null), GRAB_TIMEOUT_MS);\n });\n const canvas = await Promise.race([grabFrame(stream), timedOut]).finally(() =>\n clearTimeout(timer)\n );\n return canvas ? encodeScreenshot(canvas) : null;\n } catch {\n return null;\n } finally {\n // Stop at once — the \"sharing this tab\" indicator should last as long as\n // one frame takes, not as long as the dialog stays open.\n stream?.getTracks().forEach((track) => track.stop());\n }\n}\n\n/**\n * Longest one image may hold up the re-draw. html2canvas waits 15s per image by\n * default, and `useCORS` re-fetches every cross-origin one — a list of avatars\n * on a slow line kept the capture running for most of a minute (#363). An image\n * that misses this is left out of the screenshot; the page around it is not.\n */\nconst IMAGE_TIMEOUT_MS = 3000;\n\n/**\n * Our own dialog, sheet and overlays. The SDK opens the dialog before the\n * re-draw finishes (#363), so without this the page shot would show the dialog\n * sitting on top of the page it is meant to be a picture of.\n */\nfunction isGlitchgrabLayer(el: Element): boolean {\n return el.hasAttribute(\"data-glitchgrab-layer\");\n}\n\n/** Re-draw the viewport from the DOM. Needs no permission; not always faithful. */\nexport async function captureViaHtml2Canvas(): Promise<string | null> {\n try {\n const { default: html2canvas } = await import(\"html2canvas-pro\");\n const scale = Math.min(Math.max(window.devicePixelRatio || 1, 1), MAX_SCALE);\n const canvas = await html2canvas(document.body, {\n scale,\n logging: false,\n useCORS: true,\n allowTaint: true,\n imageTimeout: IMAGE_TIMEOUT_MS,\n ignoreElements: isGlitchgrabLayer,\n x: window.scrollX,\n y: window.scrollY,\n width: window.innerWidth,\n height: window.innerHeight,\n windowWidth: window.innerWidth,\n windowHeight: window.innerHeight,\n });\n return encodeScreenshot(canvas);\n } catch {\n return null;\n }\n}\n\n/**\n * The capture already running, if any. One ⌘⇧G on an SDK page with the\n * extension installed opened the dialog twice — both keydown listeners fired —\n * and each open asked Chrome for the tab: two share prompts for one report\n * (#364). An open that arrives mid-capture gets the same image instead.\n */\nlet inFlight: Promise<string | null> | null = null;\n\nexport interface CaptureOptions {\n /**\n * Called the moment the capture falls back to the DOM re-draw — the point at\n * which the dialog can open (#363). Real pixels are taken before the dialog\n * is on screen, or the frame would show it; the re-draw leaves our own layers\n * out, so it doesn't have to wait. On a slow CPU and a long page the re-draw\n * took seconds, and the dialog used to stay closed for all of them.\n */\n onRedraw?: () => void;\n}\n\n/**\n * Resolves once the browser has painted, so a dialog opened in `onRedraw` is on\n * screen before html2canvas takes the main thread. Capped, because a hidden tab\n * never paints.\n */\nfunction nextPaint(): Promise<void> {\n return new Promise((resolve) => {\n const cap = setTimeout(resolve, 100);\n if (typeof requestAnimationFrame !== \"function\") return;\n requestAnimationFrame(() =>\n setTimeout(() => {\n clearTimeout(cap);\n resolve();\n }, 0)\n );\n });\n}\n\n/**\n * Real pixels first, the re-draw when those aren't available. A refused prompt\n * still yields a screenshot — the reporter said no to screen sharing, not to\n * filing the report.\n *\n * `getDisplayMedia` is still reached synchronously on a fresh call: the async\n * body runs up to its first await before this returns.\n */\nexport function captureDefaultScreenshot(options?: CaptureOptions): Promise<string | null> {\n if (inFlight) return inFlight;\n inFlight = (async () => {\n const pixels = await captureViaTabPixels();\n if (pixels) return pixels;\n if (options?.onRedraw) {\n try {\n options.onRedraw();\n } catch {\n // The caller's problem — the screenshot still gets taken.\n }\n await nextPaint();\n }\n return captureViaHtml2Canvas();\n })().finally(() => {\n inFlight = null;\n });\n return inFlight;\n}\n","/**\n * The host page's own look, read at the moment a Glitchgrab surface opens.\n *\n * Every dialog Glitchgrab draws lives inside someone else's product, so it\n * takes that product's light/dark and brand colour rather than imposing ours.\n * Shared by the report dialog and the SDK's demo booking dialog so a project\n * gets one consistent look from both.\n */\n\n/**\n * Detect if the host page uses a dark or light theme. Reads computed styles,\n * which forces a style recalculation on the host page — see the call site.\n */\nexport function detectDark(): boolean {\n if (typeof window === \"undefined\") return true;\n try {\n // Check body then html — most sites set background on html, not body\n for (const el of [document.body, document.documentElement]) {\n const bg = getComputedStyle(el).backgroundColor;\n const match = bg.match(\n /rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)(?:\\s*,\\s*([\\d.]+))?\\s*\\)/,\n );\n if (match) {\n const alpha = match[4] !== undefined ? parseFloat(match[4]) : 1;\n if (alpha < 0.05) continue; // transparent — skip to next element\n const [r, g, b] = [\n Number(match[1]),\n Number(match[2]),\n Number(match[3]),\n ];\n return (r * 299 + g * 587 + b * 114) / 1000 < 128;\n }\n }\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n } catch {\n return true;\n }\n}\n\n/** Convert HSL values to a hex color string */\nfunction hslToHex(h: number, s: number, l: number): string {\n s /= 100;\n l /= 100;\n const a = s * Math.min(l, 1 - l);\n const f = (n: number) => {\n const k = (n + h / 30) % 12;\n const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);\n return Math.round(255 * color)\n .toString(16)\n .padStart(2, \"0\");\n };\n return `#${f(0)}${f(8)}${f(4)}`;\n}\n\n/** Parse a CSS color value into [r, g, b] or null */\nfunction parseColorToRgb(value: string): [number, number, number] | null {\n try {\n const trimmed = value.trim();\n\n // hex (#fff, #ffffff)\n const hexMatch = trimmed.match(/^#([0-9a-f]{3,8})$/i);\n if (hexMatch) {\n let hex = hexMatch[1];\n if (hex.length === 3)\n hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n return [\n parseInt(hex.slice(0, 2), 16),\n parseInt(hex.slice(2, 4), 16),\n parseInt(hex.slice(4, 6), 16),\n ];\n }\n\n // rgb(r, g, b) or rgba(r, g, b, a)\n const rgbMatch = trimmed.match(/rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/);\n if (rgbMatch)\n return [Number(rgbMatch[1]), Number(rgbMatch[2]), Number(rgbMatch[3])];\n\n // hsl(h, s%, l%) or hsla(h, s%, l%, a)\n const hslMatch = trimmed.match(\n /hsla?\\(\\s*([\\d.]+)\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%/,\n );\n if (hslMatch) {\n const hex = hslToHex(\n Number(hslMatch[1]),\n Number(hslMatch[2]),\n Number(hslMatch[3]),\n );\n return parseColorToRgb(hex);\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n/** Compute relative luminance and return ideal contrast text color */\nfunction getContrastText(r: number, g: number, b: number): string {\n const luminance = (r * 299 + g * 587 + b * 114) / 1000;\n return luminance > 150 ? \"#09090b\" : \"#ffffff\";\n}\n\n/**\n * Auto-detect the host app's primary/accent color from CSS custom properties.\n * Checks common variable names used by shadcn/ui, Radix, Tailwind, MUI, etc.\n * Returns { accent, accentText } or null if no theme detected.\n */\nexport function detectHostAccent(): { accent: string; accentText: string } | null {\n if (typeof window === \"undefined\") return null;\n try {\n const root = getComputedStyle(document.documentElement);\n\n // Common CSS variable names for primary/accent color\n const varNames = [\n \"--primary\",\n \"--accent\",\n \"--brand\",\n \"--color-primary\",\n \"--theme-primary\",\n \"--chakra-colors-primary-500\",\n \"--mui-palette-primary-main\",\n ];\n\n for (const name of varNames) {\n const raw = root.getPropertyValue(name).trim();\n if (!raw) continue;\n\n // shadcn/ui style: space-separated HSL values like \"243 75% 59%\"\n const hslSpaceMatch = raw.match(/^([\\d.]+)\\s+([\\d.]+)%\\s+([\\d.]+)%$/);\n if (hslSpaceMatch) {\n const hex = hslToHex(\n Number(hslSpaceMatch[1]),\n Number(hslSpaceMatch[2]),\n Number(hslSpaceMatch[3]),\n );\n const rgb = parseColorToRgb(hex);\n return {\n accent: hex,\n accentText: rgb ? getContrastText(...rgb) : \"#ffffff\",\n };\n }\n\n // Standard color values (hex, rgb, hsl)\n const rgb = parseColorToRgb(raw);\n if (rgb) {\n const hex = `#${rgb.map((c) => c.toString(16).padStart(2, \"0\")).join(\"\")}`;\n return { accent: hex, accentText: getContrastText(...rgb) };\n }\n }\n\n return null;\n } catch {\n return null;\n }\n}\n","import type { AssistTurnResult } from \"./types\";\n\n/**\n * Turning the `/api/v1/ai/report-chat` response into what the sheet renders —\n * one copy for every host.\n *\n * The SDK, the Chrome extension and GlitchRecord each mapped it by hand, and\n * GlitchRecord's copy kept only question/report: its sheet never got the\n * \"Yes, that's it\" chip, \"our team is already on #N\", or an answer from the\n * project's guides. A field added here reaches all three.\n *\n * React-free on purpose: GlitchRecord's Electron main process imports it.\n */\n\n/** Shown when the assistant cannot be reached — the plain form takes over. */\nexport const ASSIST_OFFLINE_MESSAGE =\n \"The assistant is unavailable — write your report below and send it as normal.\";\n\nexport function assistOffline(): AssistTurnResult {\n return { conversationId: null, question: null, report: null, degraded: ASSIST_OFFLINE_MESSAGE };\n}\n\ntype IssueRef = { number: number; title: string; url: string; status?: string };\n\ninterface ReportChatEnvelope {\n success?: boolean;\n error?: string;\n retryable?: boolean;\n data?: {\n conversationId?: string | null;\n question?: string | null;\n options?: unknown;\n report?: string | null;\n duplicate?: IssueRef | null;\n related?: IssueRef | null;\n solved?: string | null;\n aboutGlitchgrab?: boolean;\n };\n}\n\n/**\n * @param ok `response.ok`\n * @param body the parsed JSON body, or `null` when it was not JSON\n */\nexport function toAssistTurnResult(ok: boolean, body: unknown): AssistTurnResult {\n const envelope = (body ?? null) as ReportChatEnvelope | null;\n if (!ok || !envelope?.success) {\n return {\n ...assistOffline(),\n // The server words why (cap, rate limit, switched off). An hourly limit\n // keeps the assistant button for this report.\n degraded: envelope?.error ?? ASSIST_OFFLINE_MESSAGE,\n retryable: envelope?.retryable === true,\n };\n }\n const d = envelope.data ?? {};\n return {\n conversationId: d.conversationId ?? null,\n question: d.question ?? null,\n options: Array.isArray(d.options)\n ? d.options.filter((o): o is string => typeof o === \"string\")\n : [],\n report: d.report ?? null,\n duplicate: d.duplicate ?? null,\n related: d.related ?? null,\n solved: d.solved ?? null,\n aboutGlitchgrab: d.aboutGlitchgrab === true,\n degraded: null,\n };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { detectDark, detectHostAccent } from \"@glitchgrab/report-ui\";\n\n/**\n * Demo booking, rendered inside the host app.\n *\n * The customer embeds Glitchgrab, and their visitors book a demo without ever\n * leaving the page — no redirect to a scheduling site, no separate brand in the\n * middle of a sales moment. The SDK token identifies the project, so the server\n * knows whose calendar to read and where to file the recording afterwards.\n *\n * Laid out like the scheduling pages visitors already know (#438): who and what\n * on the left, a month calendar with the bookable days picked out, and that\n * day's times down the right. Narrow screens stack the three.\n *\n * Colours come from the host page, the same way the report dialog's do: its\n * background decides light or dark, and its `--primary`/`--brand` variable\n * paints the selected day and the buttons, so the dialog reads as part of the\n * product it opened from.\n *\n * Styled inline for the same reason the report dialog is: this renders inside\n * someone else's stylesheet and must not inherit from it or fight it. The one\n * `<style>` tag carries only what inline styles cannot express — hover and\n * focus rings — under a prefix no host is going to use.\n */\n\ninterface Slot {\n startsAt: string;\n endsAt?: string;\n}\n\ntype Step = \"slots\" | \"details\" | \"code\" | \"done\";\n\ninterface Theme {\n bg: string;\n pane: string;\n border: string;\n text: string;\n muted: string;\n faint: string;\n /** A day with free times. */\n open: string;\n /** Selected day and the primary button — the host's brand colour when it has one. */\n ink: string;\n onInk: string;\n input: string;\n danger: string;\n}\n\nconst LIGHT: Theme = {\n bg: \"#ffffff\",\n pane: \"#ffffff\",\n border: \"#e5e7eb\",\n text: \"#111827\",\n muted: \"#6b7280\",\n faint: \"#9ca3af\",\n open: \"#e8e8eb\",\n ink: \"#111111\",\n onInk: \"#ffffff\",\n input: \"#ffffff\",\n danger: \"#dc2626\",\n};\n\nconst DARK: Theme = {\n bg: \"#141414\",\n pane: \"#141414\",\n border: \"#2a2a2a\",\n text: \"#f3f4f6\",\n muted: \"#9ca3af\",\n faint: \"#6b7280\",\n open: \"#262626\",\n ink: \"#f3f4f6\",\n onInk: \"#111111\",\n input: \"#1c1c1c\",\n danger: \"#f87171\",\n};\n\nconst WEEKDAYS = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"];\nconst DAY_MS = 86_400_000;\n/** Widest gap between any zone and UTC, so a month's range covers every zone. */\nconst ZONE_PAD_MS = 14 * 3_600_000;\n/** Below this the three panes stack. */\nconst WIDE_QUERY = \"(min-width: 900px)\";\n\n/** The visitor's own zone — a demo confirmed in the wrong one is the worst bug this can have. */\nfunction localZone(): string {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone;\n } catch {\n return \"UTC\";\n }\n}\n\nfunction zoneList(current: string): string[] {\n try {\n const all = (Intl as unknown as { supportedValuesOf?: (k: string) => string[] }).supportedValuesOf?.(\"timeZone\");\n if (all?.length) return all.includes(current) ? all : [current, ...all];\n } catch {\n // Older engines: the visitor's own zone is still a correct, if short, list.\n }\n return [current];\n}\n\n/** Whether the visitor's locale reads times on a 12-hour clock. */\nfunction prefers12h(): boolean {\n try {\n return new Intl.DateTimeFormat(undefined, { hour: \"numeric\" }).resolvedOptions().hour12 === true;\n } catch {\n return false;\n }\n}\n\nfunction useMediaQuery(query: string, fallback: boolean): boolean {\n const [matches, setMatches] = useState(() =>\n typeof window !== \"undefined\" && window.matchMedia ? window.matchMedia(query).matches : fallback\n );\n useEffect(() => {\n if (typeof window === \"undefined\" || !window.matchMedia) return;\n const mql = window.matchMedia(query);\n const onChange = () => setMatches(mql.matches);\n onChange();\n mql.addEventListener?.(\"change\", onChange);\n return () => mql.removeEventListener?.(\"change\", onChange);\n }, [query]);\n return matches;\n}\n\n/** `YYYY-MM-DD` of an instant on the wall calendar of `timeZone`. */\nfunction dayKeyIn(iso: string | number, timeZone: string): string {\n try {\n return new Intl.DateTimeFormat(\"en-CA\", { timeZone, year: \"numeric\", month: \"2-digit\", day: \"2-digit\" }).format(\n new Date(iso)\n );\n } catch {\n return new Date(iso).toISOString().slice(0, 10);\n }\n}\n\n/** Calendar arithmetic on `YYYY-MM-DD` keys, done in UTC so no zone can shift a day. */\nfunction keyToUtc(key: string): number {\n const [y, m, d] = key.split(\"-\").map(Number);\n return Date.UTC(y, m - 1, d);\n}\n\nfunction utcToKey(ms: number): string {\n return new Date(ms).toISOString().slice(0, 10);\n}\n\n/** 42 day keys, Monday first, covering `month` (`YYYY-MM`). */\nfunction monthGrid(month: string): string[] {\n const first = keyToUtc(`${month}-01`);\n const lead = (new Date(first).getUTCDay() + 6) % 7;\n const start = first - lead * DAY_MS;\n return Array.from({ length: 42 }, (_, i) => utcToKey(start + i * DAY_MS));\n}\n\nfunction shiftMonth(month: string, by: number): string {\n const [y, m] = month.split(\"-\").map(Number);\n return new Date(Date.UTC(y, m - 1 + by, 1)).toISOString().slice(0, 7);\n}\n\nfunction formatTime(iso: string, timeZone: string, twelve: boolean): string {\n try {\n if (twelve) {\n return new Date(iso)\n .toLocaleTimeString(\"en-US\", { hour: \"numeric\", minute: \"2-digit\", hour12: true, timeZone })\n .replace(\" \", \"\")\n .toLowerCase();\n }\n return new Date(iso).toLocaleTimeString(\"en-GB\", { hour: \"2-digit\", minute: \"2-digit\", hour12: false, timeZone });\n } catch {\n return new Date(iso).toLocaleTimeString();\n }\n}\n\nfunction ordinal(n: number): string {\n const tens = n % 100;\n if (tens >= 11 && tens <= 13) return `${n}th`;\n return `${n}${[\"th\", \"st\", \"nd\", \"rd\"][n % 10] ?? \"th\"}`;\n}\n\nfunction formatDuration(minutes: number): string {\n if (minutes < 60) return `${minutes}m`;\n const rest = minutes % 60;\n return rest ? `${Math.floor(minutes / 60)}h ${rest}m` : `${minutes / 60}h`;\n}\n\nfunction initials(name: string): string {\n return name\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((w) => w[0]?.toUpperCase())\n .join(\"\");\n}\n\nexport function BookingDialog({\n token,\n baseUrl,\n open,\n onClose,\n}: {\n token: string;\n baseUrl: string;\n open: boolean;\n onClose: () => void;\n}) {\n const wide = useMediaQuery(WIDE_QUERY, true);\n // Once per open: computed-style reads force a style recalc on the host page.\n const t = useMemo<Theme>(() => {\n if (!open) return LIGHT;\n const base = detectDark() ? DARK : LIGHT;\n const accent = detectHostAccent();\n return accent ? { ...base, ink: accent.accent, onInk: accent.accentText } : base;\n }, [open]);\n\n const [step, setStep] = useState<Step>(\"slots\");\n const [zone, setZone] = useState(localZone);\n const [twelve, setTwelve] = useState(prefers12h);\n const [month, setMonth] = useState(() => dayKeyIn(Date.now(), localZone()).slice(0, 7));\n /** Free slots per `YYYY-MM` already fetched this open; a key being present means it has loaded. */\n const [slotsByMonth, setSlotsByMonth] = useState<Record<string, Slot[]>>({});\n const [pickedDay, setPickedDay] = useState<string | null>(null);\n const [page, setPage] = useState<{\n title: string;\n description: string | null;\n hostName: string | null;\n hostAvatarUrl: string | null;\n slotMinutes: number;\n }>({ title: \"Book a demo\", description: null, hostName: null, hostAvatarUrl: null, slotMinutes: 30 });\n /** Set when the project has a WhatsApp code — the second way in. */\n const [whatsappUrl, setWhatsappUrl] = useState<string | null>(null);\n const [avatarFailed, setAvatarFailed] = useState(false);\n const [selected, setSelected] = useState<Slot | null>(null);\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [note, setNote] = useState(\"\");\n const [code, setCode] = useState(\"\");\n const [bookingId, setBookingId] = useState<string | null>(null);\n const [meetUrl, setMeetUrl] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const headers = useMemo(\n () => ({ Authorization: `Bearer ${token}`, \"Content-Type\": \"application/json\" }),\n [token]\n );\n\n const loadMonth = useCallback(\n async (target: string) => {\n const grid = monthGrid(target);\n // Padded by a day's worth of zone offsets either side: slots are placed on\n // the grid in the visitor's zone, and this way no zone loses an edge day.\n const from = Math.max(Date.now(), keyToUtc(grid[0]) - ZONE_PAD_MS);\n const to = keyToUtc(grid[41]) + DAY_MS + ZONE_PAD_MS;\n if (to <= from) {\n setSlotsByMonth((prev) => ({ ...prev, [target]: [] }));\n return;\n }\n try {\n const res = await fetch(\n `${baseUrl}/api/v1/sdk/booking/availability?from=${encodeURIComponent(new Date(from).toISOString())}&to=${encodeURIComponent(new Date(to).toISOString())}`,\n { headers }\n );\n const json = await res.json();\n if (!json.success) {\n setError(json.error ?? \"Couldn't load available times\");\n setSlotsByMonth((prev) => ({ ...prev, [target]: [] }));\n return;\n }\n const data = json.data ?? {};\n setSlotsByMonth((prev) => ({ ...prev, [target]: Array.isArray(data.slots) ? data.slots : [] }));\n setPage({\n title: typeof data.title === \"string\" && data.title ? data.title : \"Book a demo\",\n description: typeof data.description === \"string\" ? data.description : null,\n hostName: typeof data.hostName === \"string\" ? data.hostName : null,\n hostAvatarUrl: typeof data.hostAvatarUrl === \"string\" ? data.hostAvatarUrl : null,\n slotMinutes: typeof data.slotMinutes === \"number\" ? data.slotMinutes : 30,\n });\n setWhatsappUrl(data.whatsappUrl ?? null);\n } catch {\n setError(\"Couldn't reach the booking service\");\n setSlotsByMonth((prev) => ({ ...prev, [target]: [] }));\n }\n },\n [baseUrl, headers]\n );\n\n useEffect(() => {\n if (!open) return;\n // Reset every open: a dialog that reopens showing last week's chosen slot\n // and a half-filled form is worse than one that starts clean — and so is\n // availability cached from an hour ago.\n const now = localZone();\n setStep(\"slots\");\n setZone(now);\n setMonth(dayKeyIn(Date.now(), now).slice(0, 7));\n setSlotsByMonth({});\n setPickedDay(null);\n setSelected(null);\n setCode(\"\");\n setBookingId(null);\n setError(null);\n setAvatarFailed(false);\n }, [open]);\n\n const monthLoaded = month in slotsByMonth;\n\n useEffect(() => {\n if (!open || monthLoaded) return;\n setError(null);\n void loadMonth(month);\n }, [open, month, monthLoaded, loadMonth]);\n\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", onKey, true);\n return () => document.removeEventListener(\"keydown\", onKey, true);\n }, [open, onClose]);\n\n const zones = useMemo(() => (open ? zoneList(zone) : [zone]), [open, zone]);\n\n if (!open) return null;\n\n const today = dayKeyIn(Date.now(), zone);\n const grid = monthGrid(month);\n const byDay = new Map<string, Slot[]>();\n for (const slot of slotsByMonth[month] ?? []) {\n const key = dayKeyIn(slot.startsAt, zone);\n byDay.set(key, [...(byDay.get(key) ?? []), slot]);\n }\n // The visitor's pick when it still has times, else the first day that does —\n // so the right pane is never an empty column waiting for a click.\n const day =\n pickedDay && byDay.has(pickedDay) ? pickedDay : grid.find((k) => k >= today && byDay.has(k)) ?? null;\n const daySlots = day ? byDay.get(day) ?? [] : [];\n const atFirstMonth = month <= today.slice(0, 7);\n // Bookable days run continuously up to the project's horizon, so a later\n // month with nothing open means every month after it is empty too.\n const pastHorizon = monthLoaded && !error && byDay.size === 0 && !atFirstMonth;\n\n async function startBooking() {\n if (!selected) return;\n setBusy(true);\n setError(null);\n try {\n const res = await fetch(`${baseUrl}/api/v1/sdk/booking`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n name,\n email,\n phone,\n note,\n startsAt: selected.startsAt,\n // The zone the times were shown in, which is the one the visitor chose.\n timezone: zone,\n }),\n });\n const json = await res.json();\n if (!json.success) {\n setError(json.error ?? \"Couldn't hold that slot\");\n return;\n }\n setBookingId(json.data.bookingId);\n setStep(\"code\");\n } catch {\n setError(\"Couldn't reach the booking service\");\n } finally {\n setBusy(false);\n }\n }\n\n async function confirmBooking() {\n if (!bookingId) return;\n setBusy(true);\n setError(null);\n try {\n const res = await fetch(`${baseUrl}/api/v1/sdk/booking/verify`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ bookingId, code }),\n });\n const json = await res.json();\n if (!json.success) {\n setError(json.error ?? \"Couldn't confirm that code\");\n return;\n }\n setMeetUrl(json.data.meetUrl);\n setStep(\"done\");\n } catch {\n setError(\"Couldn't reach the booking service\");\n } finally {\n setBusy(false);\n }\n }\n\n const canSubmitDetails = name.trim() && email.includes(\"@\") && phone.replace(/\\D/g, \"\").length >= 8;\n\n const selectedEnd = selected\n ? selected.endsAt ?? new Date(new Date(selected.startsAt).getTime() + page.slotMinutes * 60_000).toISOString()\n : null;\n\n const monthDate = new Date(keyToUtc(`${month}-01`));\n const muted = { color: t.muted } as const;\n\n // ── Left: who and what ────────────────────────────────────────────────────\n const summary = (\n <div\n style={{\n position: \"relative\",\n padding: wide ? \"28px 24px\" : \"20px 20px 16px\",\n borderRight: wide ? `1px solid ${t.border}` : undefined,\n borderBottom: wide ? undefined : `1px solid ${t.border}`,\n width: wide ? 260 : undefined,\n flex: wide ? \"0 0 260px\" : undefined,\n boxSizing: \"border-box\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: 10,\n }}\n >\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"gg-bk-ghost\"\n style={{\n position: \"absolute\",\n top: 12,\n right: 12,\n width: 30,\n height: 30,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n border: 0,\n borderRadius: 8,\n background: \"transparent\",\n color: t.muted,\n cursor: \"pointer\",\n padding: 0,\n }}\n >\n <Icon name=\"x\" />\n </button>\n\n {(page.hostName || page.hostAvatarUrl) && (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 8, paddingRight: 32 }}>\n {page.hostAvatarUrl && !avatarFailed ? (\n // eslint-disable-next-line @next/next/no-img-element -- rendered on the host's page, not ours\n <img\n src={page.hostAvatarUrl}\n alt=\"\"\n width={36}\n height={36}\n referrerPolicy=\"no-referrer\"\n onError={() => setAvatarFailed(true)}\n style={{ width: 36, height: 36, borderRadius: 999, objectFit: \"cover\", border: `1px solid ${t.border}` }}\n />\n ) : page.hostName ? (\n <div\n aria-hidden\n style={{\n width: 36,\n height: 36,\n borderRadius: 999,\n background: t.open,\n color: t.text,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: 13,\n fontWeight: 600,\n }}\n >\n {initials(page.hostName)}\n </div>\n ) : null}\n {page.hostName && <div style={{ fontSize: 14, fontWeight: 500, ...muted }}>{page.hostName}</div>}\n </div>\n )}\n\n <div style={{ fontSize: 20, fontWeight: 600, lineHeight: 1.25, paddingRight: 32, overflowWrap: \"anywhere\" }}>\n {page.title}\n </div>\n {page.description && (\n <div style={{ fontSize: 13, lineHeight: 1.5, overflowWrap: \"anywhere\", ...muted }}>{page.description}</div>\n )}\n\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 10, marginTop: 4, fontSize: 14 }}>\n {selected && step !== \"slots\" && (\n <Row icon=\"calendar\" t={t}>\n <span>\n {new Date(selected.startsAt).toLocaleDateString(\"en-US\", {\n weekday: \"long\",\n month: \"long\",\n day: \"numeric\",\n year: \"numeric\",\n timeZone: zone,\n })}\n <br />\n <span style={muted}>\n {formatTime(selected.startsAt, zone, twelve)} – {selectedEnd && formatTime(selectedEnd, zone, twelve)}\n </span>\n </span>\n </Row>\n )}\n <Row icon=\"clock\" t={t}>\n {formatDuration(page.slotMinutes)}\n </Row>\n <Row icon=\"video\" t={t}>\n Google Meet\n </Row>\n <Row icon=\"globe\" t={t}>\n {step === \"slots\" ? (\n // The visible label is plain text; the native select sits on top of\n // it, invisible. A styled select sizes itself to the longest zone\n // name in the list, which pushed the chevron to the pane's edge.\n <span style={{ position: \"relative\", display: \"inline-flex\", alignItems: \"center\", gap: 4 }}>\n {zone}\n <span style={{ color: t.muted }}>\n <Icon name=\"down\" />\n </span>\n <select\n value={zone}\n onChange={(e) => setZone(e.target.value)}\n aria-label=\"Time zone\"\n style={{ position: \"absolute\", inset: 0, width: \"100%\", opacity: 0, cursor: \"pointer\", font: \"inherit\" }}\n >\n {zones.map((z) => (\n <option key={z} value={z}>\n {z}\n </option>\n ))}\n </select>\n </span>\n ) : (\n zone\n )}\n </Row>\n </div>\n\n {whatsappUrl && step === \"slots\" && (\n <a\n href={whatsappUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"gg-bk-ghost\"\n style={{\n marginTop: wide ? \"auto\" : 6,\n display: \"flex\",\n alignItems: \"center\",\n gap: 10,\n padding: \"10px 12px\",\n borderRadius: 8,\n border: `1px solid ${t.border}`,\n background: \"transparent\",\n color: t.text,\n fontSize: 13,\n fontWeight: 500,\n textDecoration: \"none\",\n }}\n >\n <span style={{ color: \"#25D366\", flex: \"0 0 auto\" }}>\n <WhatsAppIcon />\n </span>\n <span>\n Book on WhatsApp\n <span style={{ display: \"block\", fontSize: 12, fontWeight: 400, color: t.muted, marginTop: 1 }}>\n We'll ask the same questions in chat.\n </span>\n </span>\n </a>\n )}\n </div>\n );\n\n // ── Middle: the month ─────────────────────────────────────────────────────\n const calendar = (\n <div\n style={{\n flex: \"1 1 auto\",\n minWidth: 0,\n padding: wide ? \"24px 24px 20px\" : \"16px 16px 8px\",\n boxSizing: \"border-box\",\n overflowY: wide ? \"auto\" : undefined,\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", marginBottom: 14 }}>\n <div style={{ fontSize: 16, fontWeight: 600 }}>\n {monthDate.toLocaleDateString(\"en-US\", { month: \"long\", timeZone: \"UTC\" })}{\" \"}\n <span style={{ fontWeight: 500, ...muted }}>{monthDate.getUTCFullYear()}</span>\n </div>\n <div style={{ display: \"flex\", gap: 4 }}>\n <NavButton\n t={t}\n label=\"Previous month\"\n icon=\"left\"\n disabled={atFirstMonth}\n onClick={() => setMonth(shiftMonth(month, -1))}\n />\n <NavButton\n t={t}\n label=\"Next month\"\n icon=\"right\"\n disabled={pastHorizon}\n onClick={() => setMonth(shiftMonth(month, 1))}\n />\n </div>\n </div>\n\n <div style={{ display: \"grid\", gridTemplateColumns: \"repeat(7, minmax(0, 1fr))\", gap: wide ? 6 : 4 }}>\n {WEEKDAYS.map((w) => (\n <div\n key={w}\n style={{\n textAlign: \"center\",\n fontSize: 11,\n fontWeight: 500,\n letterSpacing: \".08em\",\n textTransform: \"uppercase\",\n padding: \"6px 0 8px\",\n color: t.text,\n }}\n >\n {w}\n </div>\n ))}\n {grid.map((key) => {\n const inMonth = key.startsWith(month);\n const bookable = byDay.has(key);\n const isSelected = key === day;\n const dayNum = Number(key.slice(8));\n // Days of the neighbouring months are only worth showing when they\n // can be booked — otherwise they are noise around this month.\n if (!inMonth && !bookable) return <div key={key} aria-hidden />;\n return (\n <button\n key={key}\n type=\"button\"\n disabled={!bookable}\n onClick={() => setPickedDay(key)}\n aria-pressed={isSelected}\n aria-label={new Date(keyToUtc(key)).toLocaleDateString(\"en-US\", {\n weekday: \"long\",\n month: \"long\",\n day: \"numeric\",\n timeZone: \"UTC\",\n })}\n className={bookable && !isSelected ? \"gg-bk-day\" : undefined}\n style={{\n position: \"relative\",\n aspectRatio: \"1 / 1\",\n minHeight: 36,\n border: 0,\n borderRadius: 8,\n padding: 0,\n fontFamily: \"inherit\",\n fontSize: wide ? 15 : 14,\n fontWeight: bookable ? 600 : 400,\n cursor: bookable ? \"pointer\" : \"default\",\n background: isSelected ? t.ink : bookable ? t.open : \"transparent\",\n color: isSelected ? t.onInk : bookable ? t.text : t.faint,\n opacity: monthLoaded ? 1 : 0.5,\n }}\n >\n {!inMonth && dayNum === 1 && (\n <span\n style={{\n position: \"absolute\",\n top: 4,\n left: 0,\n right: 0,\n fontSize: 9,\n fontWeight: 500,\n letterSpacing: \".06em\",\n textTransform: \"uppercase\",\n }}\n >\n {new Date(keyToUtc(key)).toLocaleDateString(\"en-US\", { month: \"short\", timeZone: \"UTC\" })}\n </span>\n )}\n {dayNum}\n {key === today && (\n <span\n aria-hidden\n style={{\n position: \"absolute\",\n bottom: 6,\n left: \"50%\",\n width: 4,\n height: 4,\n marginLeft: -2,\n borderRadius: 999,\n background: isSelected ? t.onInk : t.text,\n }}\n />\n )}\n </button>\n );\n })}\n </div>\n </div>\n );\n\n // ── Right: that day's times ───────────────────────────────────────────────\n const times = (\n <div\n style={{\n width: wide ? 260 : undefined,\n flex: wide ? \"0 0 260px\" : undefined,\n borderLeft: wide ? `1px solid ${t.border}` : undefined,\n borderTop: wide ? undefined : `1px solid ${t.border}`,\n padding: wide ? \"24px 20px 0\" : \"16px 16px 0\",\n boxSizing: \"border-box\",\n display: \"flex\",\n flexDirection: \"column\",\n minHeight: 0,\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", gap: 8, marginBottom: 14 }}>\n <div style={{ fontSize: 16, fontWeight: 600, whiteSpace: \"nowrap\" }}>\n {day ? (\n <>\n {new Date(keyToUtc(day)).toLocaleDateString(\"en-US\", { weekday: \"short\", timeZone: \"UTC\" })}{\" \"}\n <span style={{ fontWeight: 500, ...muted }}>{ordinal(Number(day.slice(8)))}</span>\n </>\n ) : (\n <span style={{ fontWeight: 500, ...muted }}>Times</span>\n )}\n </div>\n <div\n role=\"group\"\n aria-label=\"Clock format\"\n style={{ display: \"flex\", padding: 3, borderRadius: 8, background: t.open, flex: \"0 0 auto\" }}\n >\n {([true, false] as const).map((h12) => (\n <button\n key={String(h12)}\n type=\"button\"\n aria-pressed={twelve === h12}\n onClick={() => setTwelve(h12)}\n style={{\n border: 0,\n borderRadius: 6,\n padding: \"4px 9px\",\n fontFamily: \"inherit\",\n fontSize: 13,\n fontWeight: 500,\n cursor: \"pointer\",\n background: twelve === h12 ? t.bg : \"transparent\",\n color: twelve === h12 ? t.text : t.muted,\n boxShadow: twelve === h12 ? \"0 1px 2px rgba(0,0,0,.12)\" : \"none\",\n }}\n >\n {h12 ? \"12h\" : \"24h\"}\n </button>\n ))}\n </div>\n </div>\n\n <div\n style={{\n overflowY: wide ? \"auto\" : undefined,\n flex: \"1 1 auto\",\n minHeight: 0,\n paddingBottom: 20,\n display: wide ? \"flex\" : \"grid\",\n flexDirection: \"column\",\n gridTemplateColumns: \"repeat(auto-fill, minmax(96px, 1fr))\",\n gap: 8,\n }}\n >\n {error && <div style={{ color: t.danger, fontSize: 13, lineHeight: 1.5, gridColumn: \"1 / -1\" }}>{error}</div>}\n {!monthLoaded && !error && <div style={{ fontSize: 13, gridColumn: \"1 / -1\", ...muted }}>Finding times…</div>}\n {monthLoaded && !error && !day && (\n <div style={{ fontSize: 13, lineHeight: 1.5, gridColumn: \"1 / -1\", ...muted }}>\n {pastHorizon ? \"Nothing can be booked this far ahead yet.\" : \"No times left this month. Try the next one.\"}\n </div>\n )}\n {monthLoaded &&\n daySlots.map((slot) => (\n <button\n key={slot.startsAt}\n type=\"button\"\n className=\"gg-bk-slot\"\n onClick={() => {\n setSelected(slot);\n setError(null);\n setStep(\"details\");\n }}\n style={{\n flex: \"0 0 auto\",\n padding: \"11px 12px\",\n borderRadius: 8,\n border: `1px solid ${t.border}`,\n background: t.pane,\n color: t.text,\n fontFamily: \"inherit\",\n fontSize: 14,\n fontWeight: 500,\n cursor: \"pointer\",\n textAlign: \"center\",\n }}\n >\n {formatTime(slot.startsAt, zone, twelve)}\n </button>\n ))}\n </div>\n </div>\n );\n\n // ── Details → code → done, in place of the calendar ───────────────────────\n const form = (\n <div\n style={{\n flex: \"1 1 auto\",\n minWidth: 0,\n padding: wide ? \"28px 32px\" : \"20px\",\n boxSizing: \"border-box\",\n overflowY: wide ? \"auto\" : undefined,\n }}\n >\n <div style={{ maxWidth: 440, display: \"flex\", flexDirection: \"column\", gap: 14 }}>\n {error && <div style={{ color: t.danger, fontSize: 13, lineHeight: 1.5 }}>{error}</div>}\n\n {step === \"details\" && (\n <>\n <Field t={t} label=\"Your name\" value={name} onChange={setName} autoComplete=\"name\" />\n <Field t={t} label=\"Email\" value={email} onChange={setEmail} type=\"email\" autoComplete=\"email\" />\n <Field\n t={t}\n label=\"Mobile number\"\n value={phone}\n onChange={setPhone}\n type=\"tel\"\n autoComplete=\"tel\"\n hint=\"We send a code here to confirm, then a reminder before the call.\"\n />\n <Field t={t} label=\"Anything we should know? (optional)\" value={note} onChange={setNote} multiline />\n <div style={{ display: \"flex\", justifyContent: \"flex-end\", gap: 8, marginTop: 4 }}>\n <button\n type=\"button\"\n className=\"gg-bk-ghost\"\n onClick={() => {\n setError(null);\n setStep(\"slots\");\n }}\n style={secondaryStyle(t)}\n >\n Back\n </button>\n <button\n type=\"button\"\n onClick={startBooking}\n disabled={!canSubmitDetails || busy}\n style={primaryStyle(t, !canSubmitDetails || busy)}\n >\n {busy ? \"Sending code…\" : \"Send verification code\"}\n </button>\n </div>\n </>\n )}\n\n {step === \"code\" && (\n <>\n <div style={{ fontSize: 14, lineHeight: 1.5, ...muted }}>\n We sent a code to your phone. Your slot is held for 10 minutes.\n </div>\n <Field t={t} label=\"Code\" value={code} onChange={setCode} autoComplete=\"one-time-code\" inputMode=\"numeric\" />\n <div style={{ display: \"flex\", justifyContent: \"flex-end\", marginTop: 4 }}>\n <button\n type=\"button\"\n onClick={confirmBooking}\n disabled={code.trim().length < 4 || busy}\n style={primaryStyle(t, code.trim().length < 4 || busy)}\n >\n {busy ? \"Confirming…\" : \"Confirm booking\"}\n </button>\n </div>\n </>\n )}\n\n {step === \"done\" && (\n <>\n <div style={{ fontSize: 20, fontWeight: 600 }}>You're booked.</div>\n <div style={{ fontSize: 14, lineHeight: 1.6, ...muted }}>\n A calendar invite is on its way to {email}, and we'll send a WhatsApp reminder before the call.\n </div>\n {meetUrl && (\n <a\n href={meetUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n style={{ ...primaryStyle(t, false), alignSelf: \"flex-start\", textDecoration: \"none\" }}\n >\n Open the meeting link\n </a>\n )}\n </>\n )}\n </div>\n </div>\n );\n\n return (\n <div\n onClick={(e) => {\n if (e.target === e.currentTarget) onClose();\n }}\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483000,\n background: \"rgba(0,0,0,.6)\",\n display: \"flex\",\n alignItems: wide ? \"center\" : \"flex-start\",\n justifyContent: \"center\",\n padding: wide ? 24 : 12,\n boxSizing: \"border-box\",\n overflowY: \"auto\",\n fontFamily: \"Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\",\n }}\n >\n <style>{`\n .gg-bk-day:hover { box-shadow: inset 0 0 0 1.5px ${t.ink}; }\n .gg-bk-slot:hover { border-color: ${t.ink} !important; }\n .gg-bk-ghost:hover { background: ${t.open} !important; }\n .gg-bk-root button:focus-visible, .gg-bk-root a:focus-visible,\n .gg-bk-root span:has(> select:focus-visible), .gg-bk-root input:focus-visible, .gg-bk-root textarea:focus-visible {\n outline: 2px solid ${t.ink}; outline-offset: 2px;\n }\n `}</style>\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={page.title}\n className=\"gg-bk-root\"\n style={{\n width: step === \"slots\" ? \"min(1060px, 100%)\" : \"min(820px, 100%)\",\n // A month grid should not jump in height between months; the form\n // steps are short and would sit in a mostly empty box.\n height: wide && step === \"slots\" ? \"min(640px, calc(100vh - 48px))\" : undefined,\n minHeight: wide && step !== \"slots\" ? 420 : undefined,\n margin: wide ? undefined : \"auto 0\",\n display: \"flex\",\n flexDirection: wide ? \"row\" : \"column\",\n background: t.bg,\n color: t.text,\n border: `1px solid ${t.border}`,\n borderRadius: 14,\n boxShadow: \"0 24px 64px rgba(0,0,0,.35)\",\n overflow: \"hidden\",\n boxSizing: \"border-box\",\n textAlign: \"left\",\n lineHeight: 1.4,\n }}\n >\n {summary}\n {step === \"slots\" ? (\n <>\n {calendar}\n {times}\n </>\n ) : (\n form\n )}\n </div>\n </div>\n );\n}\n\nfunction primaryStyle(t: Theme, disabled: boolean) {\n return {\n padding: \"10px 16px\",\n borderRadius: 8,\n border: 0,\n background: t.ink,\n color: t.onInk,\n opacity: disabled ? 0.4 : 1,\n fontFamily: \"inherit\",\n fontSize: 14,\n fontWeight: 600,\n cursor: disabled ? \"default\" : \"pointer\",\n } as const;\n}\n\nfunction secondaryStyle(t: Theme) {\n return {\n padding: \"10px 16px\",\n borderRadius: 8,\n border: 0,\n background: \"transparent\",\n color: t.text,\n fontFamily: \"inherit\",\n fontSize: 14,\n fontWeight: 500,\n cursor: \"pointer\",\n } as const;\n}\n\nfunction Row({ icon, t, children }: { icon: IconName; t: Theme; children: ReactNode }) {\n return (\n <div style={{ display: \"flex\", alignItems: \"flex-start\", gap: 10, color: t.text, minWidth: 0 }}>\n <span style={{ color: t.muted, flex: \"0 0 auto\", marginTop: 1 }}>\n <Icon name={icon} />\n </span>\n <span style={{ minWidth: 0, overflowWrap: \"anywhere\" }}>{children}</span>\n </div>\n );\n}\n\nfunction NavButton({\n t,\n label,\n icon,\n disabled,\n onClick,\n}: {\n t: Theme;\n label: string;\n icon: IconName;\n disabled?: boolean;\n onClick: () => void;\n}) {\n return (\n <button\n type=\"button\"\n aria-label={label}\n disabled={disabled}\n onClick={onClick}\n className={disabled ? undefined : \"gg-bk-ghost\"}\n style={{\n width: 32,\n height: 32,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n border: 0,\n borderRadius: 8,\n background: \"transparent\",\n color: disabled ? t.faint : t.text,\n opacity: disabled ? 0.5 : 1,\n cursor: disabled ? \"default\" : \"pointer\",\n padding: 0,\n }}\n >\n <Icon name={icon} />\n </button>\n );\n}\n\nfunction WhatsAppIcon() {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden style={{ display: \"block\" }}>\n <path d=\"M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 0 1-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 0 1-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 0 1 2.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0 0 12.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 0 0 5.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 0 0-3.48-8.413Z\" />\n </svg>\n );\n}\n\ntype IconName = \"x\" | \"left\" | \"right\" | \"down\" | \"clock\" | \"video\" | \"globe\" | \"calendar\";\n\nfunction Icon({ name }: { name: IconName }) {\n const paths: Record<IconName, ReactNode> = {\n x: <path d=\"M18 6 6 18M6 6l12 12\" />,\n left: <path d=\"m15 18-6-6 6-6\" />,\n right: <path d=\"m9 18 6-6-6-6\" />,\n down: <path d=\"m6 9 6 6 6-6\" />,\n clock: (\n <>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <path d=\"M12 7v5l3 2\" />\n </>\n ),\n video: (\n <>\n <rect x=\"3\" y=\"6\" width=\"13\" height=\"12\" rx=\"2\" />\n <path d=\"m16 10 5-3v10l-5-3\" />\n </>\n ),\n globe: (\n <>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <path d=\"M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18\" />\n </>\n ),\n calendar: (\n <>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"16\" rx=\"2\" />\n <path d=\"M3 10h18M8 3v4M16 3v4\" />\n </>\n ),\n };\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n style={{ display: \"block\" }}\n >\n {paths[name]}\n </svg>\n );\n}\n\nfunction Field({\n t,\n label,\n value,\n onChange,\n type = \"text\",\n hint,\n autoComplete,\n inputMode,\n multiline,\n}: {\n t: Theme;\n label: string;\n value: string;\n onChange: (v: string) => void;\n type?: string;\n hint?: string;\n autoComplete?: string;\n inputMode?: \"numeric\" | \"text\";\n multiline?: boolean;\n}) {\n const inputStyle = {\n display: \"block\",\n width: \"100%\",\n boxSizing: \"border-box\",\n marginTop: 6,\n padding: \"9px 12px\",\n background: t.input,\n color: t.text,\n border: `1px solid ${t.border}`,\n borderRadius: 8,\n fontFamily: \"inherit\",\n fontSize: 14,\n outline: \"none\",\n resize: \"vertical\",\n } as const;\n return (\n <label style={{ display: \"block\", fontSize: 13, fontWeight: 500, color: t.text }}>\n {label}\n {multiline ? (\n <textarea rows={3} value={value} onChange={(e) => onChange(e.target.value)} style={inputStyle} />\n ) : (\n <input\n type={type}\n value={value}\n autoComplete={autoComplete}\n inputMode={inputMode}\n onChange={(e) => onChange(e.target.value)}\n style={inputStyle}\n />\n )}\n {hint && <div style={{ marginTop: 6, fontSize: 12, fontWeight: 400, color: t.muted }}>{hint}</div>}\n </label>\n );\n}\n","/**\n * Unhandled rejection reasons are not always `Error` instances. A rejection with\n * a plain object reason used to stringify to `\"[object Object]\"` — a title and a\n * body with no message, no stack and nothing to triage.\n *\n * `describeRejection` extracts the most useful *stable* message it can, plus the\n * `.stack` when one exists (cross-realm errors from extensions and iframes fail\n * `instanceof Error` but still carry a usable stack), plus a serialized dump of\n * the whole reason for the report metadata.\n */\n\n/** Max length of the serialized reason stored in report metadata. */\nconst DETAILS_MAX_LENGTH = 1000;\n\n/** Max length of a message rung promoted into `errorMessage`. */\nconst MESSAGE_MAX_LENGTH = 200;\n\nexport interface RejectionDescription {\n /** Short, stable message — safe to hash for dedup and to slice into an issue title. */\n message: string;\n /** Stack trace when the reason carries one, regardless of `instanceof Error`. */\n stack?: string;\n /** Full serialized reason for `metadata.rejectionReason`. Empty when unavailable. */\n details?: string;\n}\n\n/** A rejection with neither a message nor a stack cannot be triaged by anyone. */\nexport function isUnactionableRejection(description: RejectionDescription): boolean {\n if (description.stack) return false;\n const message = description.message.trim();\n return message === \"\" || message === \"[object Object]\";\n}\n\nfunction readString(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n if (trimmed === \"\" || trimmed === \"[object Object]\") return undefined;\n return trimmed.slice(0, MESSAGE_MAX_LENGTH);\n}\n\n/** `.code`/`.status` are often numbers — accept those, but never objects. */\nfunction readScalar(value: unknown): string | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) return String(value);\n return readString(value);\n}\n\nfunction readStack(reason: unknown): string | undefined {\n try {\n const stack = (reason as { stack?: unknown } | null)?.stack;\n return typeof stack === \"string\" && stack.trim() !== \"\" ? stack : undefined;\n } catch {\n // Getters can throw — a missing stack is better than a crash.\n return undefined;\n }\n}\n\n/** `JSON.stringify` throws on circular refs and BigInt, and on throwing getters. */\nfunction serialize(reason: unknown): string | undefined {\n try {\n const seen = new WeakSet<object>();\n const json = JSON.stringify(reason, (_key, value) => {\n if (typeof value === \"bigint\") return `${value}n`;\n if (typeof value === \"object\" && value !== null) {\n if (seen.has(value)) return \"[Circular]\";\n seen.add(value);\n }\n return value;\n });\n if (!json || json === \"{}\" || json === \"null\") return undefined;\n return json.slice(0, DETAILS_MAX_LENGTH);\n } catch {\n return undefined;\n }\n}\n\n/** Max own keys listed when falling back to a shape description. */\nconst SHAPE_MAX_KEYS = 5;\n\n/**\n * Last resort when no stable field exists: name the reason's keys, not its values.\n * Stable across occurrences, so the dedup signature still collapses repeats.\n */\nfunction describeShape(reason: unknown): string {\n try {\n const keys = Object.keys(reason as object);\n if (keys.length === 0) return \"\";\n const listed = keys.slice(0, SHAPE_MAX_KEYS).join(\", \");\n const suffix = keys.length > SHAPE_MAX_KEYS ? \", …\" : \"\";\n return `Rejected object: ${listed}${suffix}`.slice(0, MESSAGE_MAX_LENGTH);\n } catch {\n return \"\";\n }\n}\n\n/** Max length of a resource URL appended to an event message. */\nconst EVENT_URL_MAX_LENGTH = 120;\n\n/**\n * Events cross realm boundaries (iframes, extensions) and fail `instanceof`,\n * and `Event` is undefined outside the DOM. Duck-type instead: every event\n * carries a string `type` and a boolean `isTrusted`.\n */\nfunction isEventLike(reason: unknown): boolean {\n try {\n if (typeof Event !== \"undefined\" && reason instanceof Event) return true;\n const source = reason as { type?: unknown; isTrusted?: unknown } | null;\n return typeof source?.type === \"string\" && typeof source?.isTrusted === \"boolean\";\n } catch {\n return false;\n }\n}\n\n/**\n * A promise rejected with a DOM Event — a script/img/media `onerror`, an\n * IndexedDB request, a third-party embed — carries no `.message` and no\n * `.stack`. Its only own key in Chrome is `isTrusted`, so the shape fallback\n * produced \"Rejected object: isTrusted\": a report naming nothing at all.\n *\n * The event's own `type` and `target` say which resource failed, so read those\n * instead. The URL is stripped of its query and hash — a cache-busting param\n * would otherwise give every occurrence a unique dedup signature.\n */\nfunction describeEvent(reason: unknown): string {\n const parts: string[] = [];\n\n try {\n const source = reason as { constructor?: { name?: string }; type?: unknown };\n const name = source.constructor?.name || \"Event\";\n parts.push(`${name} (\"${String(source.type ?? \"\")}\")`);\n } catch {\n parts.push(\"Event\");\n }\n\n try {\n const target = (reason as { target?: unknown }).target as\n | (Element & { src?: string; href?: string; currentSrc?: string })\n | null\n | undefined;\n const tag = target?.tagName?.toLowerCase();\n if (tag) parts.push(`from <${tag}>`);\n const url =\n readString(target?.currentSrc) ?? readString(target?.src) ?? readString(target?.href);\n if (url) parts.push(`— ${url.split(/[?#]/)[0].slice(0, EVENT_URL_MAX_LENGTH)}`);\n } catch {\n // Cross-origin or detached targets throw on access — the type alone still\n // beats a key list.\n }\n\n return parts.join(\" \").slice(0, MESSAGE_MAX_LENGTH);\n}\n\nexport function describeRejection(reason: unknown): RejectionDescription {\n try {\n if (reason instanceof Error) {\n return {\n message: reason.message || reason.name || \"\",\n stack: reason.stack,\n };\n }\n\n const stack = readStack(reason);\n\n if (typeof reason === \"string\") {\n return { message: readString(reason) ?? \"\", stack };\n }\n if (typeof reason === \"number\" || typeof reason === \"boolean\") {\n return { message: String(reason), stack };\n }\n if (reason === null || reason === undefined) {\n return { message: \"\" };\n }\n\n const source = reason as Record<string, unknown>;\n const nestedError = source.error;\n\n // Stable rungs first — these keep the dedup signature and the issue title\n // meaningful. A volatile JSON dump would defeat both.\n const message =\n readString(source.message) ??\n readString(nestedError) ??\n readString((nestedError as { message?: unknown } | null | undefined)?.message) ??\n readScalar(source.code) ??\n readString(source.name) ??\n readScalar(source.status) ??\n readString(source.statusText) ??\n \"\";\n\n const details = serialize(reason);\n\n // No stable rung — describe the reason by its key *shape*, never by its values.\n // `errorMessage` feeds computeSignature, so a message carrying volatile fields\n // (requestId, timestamps) would give every occurrence a unique signature and\n // defeat dedup entirely. The values still travel in `details`.\n //\n // An event is the one shapeless reason worth reporting: its type and target\n // name the failing resource, so it gets a real message and stays actionable.\n return {\n message:\n message || (isEventLike(reason) ? describeEvent(reason) : describeShape(reason)),\n stack,\n details,\n };\n } catch {\n // Never throw out of the SDK — an empty description is dropped upstream.\n return { message: \"\" };\n }\n}\n","/**\n * The global keyboard shortcut that opens the Glitchgrab report dialog.\n * Single source of truth — the provider's keydown handler and every label\n * rendered anywhere (SDK dialog, host app UI) derive from this.\n */\n\n/** Server-safe label. Used during SSR and as the non-Mac label. */\nexport const GLITCHGRAB_SHORTCUT = \"Ctrl+Shift+G\";\n\n/** Mac label, using the platform's modifier glyphs. */\nexport const GLITCHGRAB_SHORTCUT_MAC = \"⌘⇧G\";\n\n/** True when running on a Mac-like platform. Always false on the server. */\nfunction isMac(): boolean {\n try {\n if (typeof navigator === \"undefined\") return false;\n return /Mac|iPhone|iPad|iPod/i.test(navigator.platform || navigator.userAgent);\n } catch {\n return false;\n }\n}\n\n/**\n * OS-aware label for the report-dialog shortcut — `⌘⇧G` on Mac,\n * `Ctrl+Shift+G` elsewhere. Returns the non-Mac label on the server, so\n * render it client-side (or after mount) to avoid a hydration mismatch.\n */\nexport function getShortcutLabel(): string {\n return isMac() ? GLITCHGRAB_SHORTCUT_MAC : GLITCHGRAB_SHORTCUT;\n}\n\n/** True when the keyboard event matches the report-dialog shortcut. */\nexport function matchesShortcut(e: KeyboardEvent): boolean {\n return (\n (e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === \"g\"\n );\n}\n","\"use client\";\n\nimport { useState, type CSSProperties, type ReactNode } from \"react\";\nimport type { ReportButtonProps } from \"./types\";\nimport { useGlitchgrab } from \"./provider\";\n\n/** Safe version of useGlitchgrab that returns null when outside provider */\nfunction useGlitchgrabSafe() {\n try {\n return useGlitchgrab();\n } catch {\n return null;\n }\n}\n\n/**\n * Optional trigger button for opening the report dialog.\n *\n * The dialog itself lives inside `GlitchgrabProvider` — you don't need this component\n * unless you want a visible trigger button. You can also open the dialog programmatically\n * via `useGlitchgrab().openReportDialog()`.\n *\n * @example\n * ```tsx\n * // Use the default floating button\n * <ReportButton />\n *\n * // Use your own trigger\n * <ReportButton>\n * {({ onClick }) => <button onClick={onClick}>Report</button>}\n * </ReportButton>\n *\n * // Or skip ReportButton entirely and use the hook\n * const { openReportDialog } = useGlitchgrab();\n * <button onClick={() => openReportDialog()}>Report</button>\n * ```\n */\nexport function ReportButton({\n position = \"bottom-right\",\n label = \"Report Bug\",\n className,\n children,\n}: ReportButtonProps & {\n children?: (props: { onClick: () => void; capturing: boolean }) => ReactNode;\n}) {\n const [capturing, setCapturing] = useState(false);\n const glitchgrab = useGlitchgrabSafe();\n\n if (!glitchgrab) return null;\n\n const handleClick = async () => {\n setCapturing(true);\n glitchgrab.openReportDialog();\n setCapturing(false);\n };\n\n // Custom trigger via render prop\n if (children) {\n return <>{children({ onClick: handleClick, capturing })}</>;\n }\n\n // Default floating button\n const isTop = position?.startsWith(\"top\") ?? false;\n const isLeft = position?.endsWith(\"left\") ?? false;\n\n const positionStyles: CSSProperties = {\n ...(isLeft ? { left: \"16px\" } : { right: \"16px\" }),\n ...(isTop ? { top: \"16px\" } : { bottom: \"16px\" }),\n };\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={capturing}\n className={className}\n style={{\n position: \"fixed\",\n ...positionStyles,\n zIndex: 99999,\n padding: \"10px 18px\",\n borderRadius: \"24px\",\n border: \"none\",\n backgroundColor: \"#18181b\",\n color: \"#fafafa\",\n fontSize: \"14px\",\n fontWeight: 500,\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n cursor: capturing ? \"wait\" : \"pointer\",\n boxShadow:\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1)\",\n transition: \"transform 0.15s ease, box-shadow 0.15s ease\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n opacity: capturing ? 0.7 : 1,\n }}\n onMouseEnter={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1.05)\";\n }}\n onMouseLeave={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1)\";\n }}\n aria-label={label}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{ flexShrink: 0 }}\n >\n <path\n d=\"M8 1C4.134 1 1 4.134 1 8s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zm0 12.5a.75.75 0 110-1.5.75.75 0 010 1.5zm.75-3.5a.75.75 0 01-1.5 0V5a.75.75 0 011.5 0v5z\"\n fill=\"currentColor\"\n />\n </svg>\n {capturing ? \"Capturing...\" : label}\n </button>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useGlitchgrab } from \"./provider\";\n\n/**\n * Trigger for the demo booking dialog.\n *\n * The dialog itself lives in `GlitchgrabProvider`; this is only a convenience.\n * Most hosts will want their own button in their own design, which is what the\n * render prop is for — or skip this entirely and call\n * `useGlitchgrab().openBookingDialog()`.\n *\n * @example\n * ```tsx\n * <BookDemoButton />\n *\n * <BookDemoButton>\n * {({ onClick }) => <MyCta onClick={onClick}>Talk to us</MyCta>}\n * </BookDemoButton>\n * ```\n */\nexport function BookDemoButton({\n label = \"Book a demo\",\n className,\n children,\n}: {\n label?: string;\n className?: string;\n children?: (props: { onClick: () => void }) => ReactNode;\n}) {\n const { openBookingDialog } = useGlitchgrab();\n\n if (children) return <>{children({ onClick: openBookingDialog })}</>;\n\n return (\n <button\n type=\"button\"\n onClick={openBookingDialog}\n className={className}\n style={\n className\n ? undefined\n : {\n padding: \"10px 18px\",\n borderRadius: 999,\n border: 0,\n background: \"#3b82f6\",\n color: \"#fff\",\n fontSize: 14,\n fontWeight: 500,\n cursor: \"pointer\",\n }\n }\n >\n {label}\n </button>\n );\n}\n","\"use client\";\n\nimport type { CSSProperties, ReactNode } from \"react\";\nimport type { FeedbackButtonProps } from \"./types\";\nimport { useGlitchgrab } from \"./provider\";\n\n/** Safe version of useGlitchgrab that returns null when outside provider */\nfunction useGlitchgrabSafe() {\n try {\n return useGlitchgrab();\n } catch {\n return null;\n }\n}\n\n/**\n * Trigger for the built-in feedback dialog (stars + message).\n *\n * The dialog itself lives inside `GlitchgrabProvider` — this is only the visible\n * trigger. Open it programmatically with `useGlitchgrab().openFeedbackDialog()`,\n * or skip the dialog entirely and call `sendFeedback(rating, message)` from your\n * own UI.\n *\n * @example\n * ```tsx\n * // Default floating button\n * <FeedbackButton />\n *\n * // Your own trigger\n * <FeedbackButton>\n * {({ onClick }) => <button onClick={onClick}>Rate us</button>}\n * </FeedbackButton>\n * ```\n */\nexport function FeedbackButton({\n position = \"bottom-left\",\n label = \"Feedback\",\n className,\n children,\n}: FeedbackButtonProps & {\n children?: (props: { onClick: () => void }) => ReactNode;\n}) {\n const glitchgrab = useGlitchgrabSafe();\n\n if (!glitchgrab) return null;\n\n const handleClick = () => glitchgrab.openFeedbackDialog();\n\n if (children) {\n return <>{children({ onClick: handleClick })}</>;\n }\n\n const isTop = position?.startsWith(\"top\") ?? false;\n const isLeft = position?.endsWith(\"left\") ?? false;\n\n const positionStyles: CSSProperties = {\n ...(isLeft ? { left: \"16px\" } : { right: \"16px\" }),\n ...(isTop ? { top: \"16px\" } : { bottom: \"16px\" }),\n };\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n className={className}\n style={{\n position: \"fixed\",\n ...positionStyles,\n zIndex: 99999,\n padding: \"10px 18px\",\n borderRadius: \"24px\",\n border: \"none\",\n backgroundColor: \"#18181b\",\n color: \"#fafafa\",\n fontSize: \"14px\",\n fontWeight: 500,\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n cursor: \"pointer\",\n boxShadow:\n \"0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1)\",\n transition: \"transform 0.15s ease, box-shadow 0.15s ease\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"6px\",\n }}\n onMouseEnter={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1.05)\";\n }}\n onMouseLeave={(e) => {\n (e.target as HTMLElement).style.transform = \"scale(1)\";\n }}\n aria-label={label}\n >\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{ flexShrink: 0 }}\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 2.5l2.9 5.9 6.5.9-4.7 4.6 1.1 6.5L12 17.4l-5.8 3 1.1-6.5L2.6 9.3l6.5-.9L12 2.5z\"\n fill=\"currentColor\"\n />\n </svg>\n {label}\n </button>\n );\n}\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\n\nexport interface GlitchgrabReport {\n id: string;\n source: string;\n status: string;\n rawInput: string | null;\n reporterPrimaryKey: string;\n reporterName: string;\n reporterEmail: string | null;\n reporterPhone: string | null;\n pageUrl: string | null;\n createdAt: string;\n /** Number of comments on the linked GitHub issue (0 if no issue) */\n commentCount: number;\n issue: {\n githubNumber: number;\n githubUrl: string;\n title: string;\n labels: string[];\n severity: string | null;\n githubState: string | null;\n } | null;\n}\n\nconst BASE_URL = \"https://glitchgrab.dev\";\n\n/**\n * Hook to fetch bug reports for a specific user.\n *\n * ```tsx\n * const { reports, isLoading, error, refetch } = useGlitchgrabReports({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * userId: session.user.id,\n * });\n * ```\n */\nexport function useGlitchgrabReports({\n token,\n userId,\n limit = 100,\n}: {\n token: string;\n userId: string;\n /** Max results (default 100, max 100) */\n limit?: number;\n}): {\n reports: GlitchgrabReport[];\n isLoading: boolean;\n isFetching: boolean;\n error: string | null;\n refetch: () => Promise<void>;\n} {\n const [reports, setReports] = useState<GlitchgrabReport[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const fetchReports = useCallback(async () => {\n if (!token || !userId) {\n setIsLoading(false);\n return;\n }\n\n setIsFetching(true);\n setError(null);\n\n try {\n const res = await fetch(\n `${BASE_URL}/api/v1/sdk/reports?reporterPrimaryKey=${encodeURIComponent(userId)}&limit=${limit}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n const data = await res.json();\n\n if (data.success) {\n setReports(data.data ?? []);\n } else {\n setError(data.error ?? \"Failed to fetch reports\");\n }\n } catch {\n setError(\"Network error\");\n } finally {\n setIsLoading(false);\n setIsFetching(false);\n }\n }, [token, userId, limit]);\n\n useEffect(() => {\n fetchReports();\n }, [fetchReports]);\n\n return { reports, isLoading, isFetching, error, refetch: fetchReports };\n}\n\n/**\n * Standalone fetcher — use with TanStack Query or any data fetching library.\n *\n * ```tsx\n * const { data } = useQuery({\n * queryKey: [\"glitchgrab-reports\", userId],\n * queryFn: () => fetchGlitchgrabReports({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * userId: session.user.id,\n * }),\n * });\n * ```\n */\nexport async function fetchGlitchgrabReports({\n token,\n userId,\n limit = 100,\n}: {\n token: string;\n userId: string;\n limit?: number;\n}): Promise<GlitchgrabReport[]> {\n const res = await fetch(\n `${BASE_URL}/api/v1/sdk/reports?reporterPrimaryKey=${encodeURIComponent(userId)}&limit=${limit}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n const data = await res.json();\n if (!data.success) throw new Error(data.error ?? \"Failed to fetch reports\");\n return data.data ?? [];\n}\n\n// ─── Report Actions ─────────────────────────────────────\n\nasync function reportAction(\n token: string,\n reportId: string,\n body: Record<string, string>\n): Promise<void> {\n const res = await fetch(`${BASE_URL}/api/v1/reports/${reportId}/actions`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok || !data.success) throw new Error(data.error ?? \"Action failed\");\n}\n\n/**\n * Hook to manage report actions with loading/error states.\n *\n * ```tsx\n * const { approve, reject, close, isPending, error } = useGlitchgrabActions({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * onSuccess: () => refetch(),\n * onError: (err) => toast.error(err.message),\n * });\n *\n * <button onClick={() => approve(reportId)} disabled={isPending}>\n * {isPending ? \"...\" : \"Approve\"}\n * </button>\n * ```\n */\nexport function useGlitchgrabActions({\n token,\n onSuccess,\n onError,\n}: {\n token: string;\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n}) {\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const run = useCallback(\n async (reportId: string, body: Record<string, string>) => {\n setIsPending(true);\n setError(null);\n try {\n await reportAction(token, reportId, body);\n onSuccess?.();\n } catch (e) {\n const err = e instanceof Error ? e : new Error(\"Action failed\");\n setError(err.message);\n onError?.(err);\n } finally {\n setIsPending(false);\n }\n },\n [token, onSuccess, onError]\n );\n\n return {\n approve: (reportId: string) => run(reportId, { action: \"label\", label: \"approved\" }),\n reject: (reportId: string) => run(reportId, { action: \"label\", label: \"rejected\" }),\n close: (reportId: string) => run(reportId, { action: \"close\" }),\n reopen: (reportId: string) => run(reportId, { action: \"reopen\" }),\n label: (reportId: string, label: string) => run(reportId, { action: \"label\", label }),\n unlabel: (reportId: string, label: string) => run(reportId, { action: \"unlabel\", label }),\n isPending,\n error,\n };\n}\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { GlitchgrabFeedback } from \"./types\";\n\nconst DEFAULT_BASE_URL = \"https://glitchgrab.dev\";\n\nexport interface FeedbackQuery {\n token: string;\n /** Only entries the repo owner published — use this for a public testimonials wall */\n approvedOnly?: boolean;\n /** Only this end-user's feedback (their primary key in your DB) */\n userId?: string;\n /** Floor on the star rating, 1–5 */\n minRating?: number;\n /** Max results (default 50, max 100) */\n limit?: number;\n baseUrl?: string;\n}\n\nfunction buildUrl({\n approvedOnly,\n userId,\n minRating,\n limit = 50,\n baseUrl,\n}: Omit<FeedbackQuery, \"token\">): string {\n const params = new URLSearchParams({ limit: String(limit) });\n if (approvedOnly) params.set(\"approved\", \"true\");\n if (userId) params.set(\"reporterPrimaryKey\", userId);\n if (minRating) params.set(\"minRating\", String(minRating));\n return `${baseUrl ?? DEFAULT_BASE_URL}/api/v1/sdk/feedback?${params.toString()}`;\n}\n\n/**\n * Standalone fetcher — use with TanStack Query or any data fetching library.\n *\n * ```tsx\n * const { data } = useQuery({\n * queryKey: [\"testimonials\"],\n * queryFn: () => fetchGlitchgrabFeedback({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * approvedOnly: true,\n * minRating: 4,\n * }),\n * });\n * ```\n */\nexport async function fetchGlitchgrabFeedback(\n query: FeedbackQuery\n): Promise<GlitchgrabFeedback[]> {\n const res = await fetch(buildUrl(query), {\n headers: { Authorization: `Bearer ${query.token}` },\n });\n const data = await res.json();\n if (!data.success) throw new Error(data.error ?? \"Failed to fetch feedback\");\n return data.data ?? [];\n}\n\n/**\n * Hook to read back the feedback your end-users left — render it as a\n * testimonials wall, or show a user their own past ratings.\n *\n * ```tsx\n * const { feedback, isLoading, error, refetch } = useGlitchgrabFeedback({\n * token: process.env.NEXT_PUBLIC_GLITCHGRAB_TOKEN!,\n * approvedOnly: true,\n * });\n * ```\n */\nexport function useGlitchgrabFeedback(query: FeedbackQuery): {\n feedback: GlitchgrabFeedback[];\n isLoading: boolean;\n isFetching: boolean;\n error: string | null;\n refetch: () => Promise<void>;\n} {\n const { token, approvedOnly, userId, minRating, limit, baseUrl } = query;\n\n const [feedback, setFeedback] = useState<GlitchgrabFeedback[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [isFetching, setIsFetching] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const load = useCallback(async () => {\n if (!token) {\n setIsLoading(false);\n return;\n }\n\n setIsFetching(true);\n setError(null);\n\n try {\n const data = await fetchGlitchgrabFeedback({\n token,\n approvedOnly,\n userId,\n minRating,\n limit,\n baseUrl,\n });\n setFeedback(data);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Network error\");\n } finally {\n setIsLoading(false);\n setIsFetching(false);\n }\n }, [token, approvedOnly, userId, minRating, limit, baseUrl]);\n\n useEffect(() => {\n load();\n }, [load]);\n\n return { feedback, isLoading, isFetching, error, refetch: load };\n}\n"],"mappings":"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","names":["GLITCHGRAB_SHORTCUT","GLITCHGRAB_SHORTCUT_MAC","getShortcutLabel","import_react","e","appContext","import_react","import_react_dom","import_jsx_runtime","jsx","jsxs","useState","useEffect","initials","useRef","history","Fragment","e","createPortal","rgb","jsx","useState","useEffect","initials","jsxs","words","sendFeedback","enhanceText","findSimilarIssues","transcribeAudio","useRef","_a","useMemo","e","t","result","Fragment","createPortal","import_react","import_jsx_runtime","_a","_b","_c","grid","seen","GLITCHGRAB_SHORTCUT","GLITCHGRAB_SHORTCUT_MAC","isMac","getShortcutLabel","import_jsx_runtime","DEFAULT_BASE_URL","maxBreadcrumbs","release","appContext","responseBodyOrigins","captureError","setContext","setContexts","addBreadcrumb","GLITCHGRAB_SHORTCUT","getShortcutLabel","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","useGlitchgrabSafe","import_react","import_react","DEFAULT_BASE_URL"]}
|