glitchgrab 1.36.0 → 1.37.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/provider.tsx","../src/error-boundary.tsx","../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/labels.ts","../../report-ui/src/shortcut.ts","../../report-ui/src/attachments.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\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 } from \"@glitchgrab/report-ui\";\nimport { BookingDialog } from \"./booking-dialog\";\nimport { sanitizeUrl, captureContext, contextMetadata, sendReport, sendFeedback, captureDeviceInfo, enhanceText, assistTurn, 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,\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 // 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 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 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);\n } catch {\n return text;\n }\n },\n [token, baseUrl]\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 screenshot?: string | null;\n context?: Record<string, unknown> | null;\n }) => {\n const ctx = captureContext(visitedPagesRef.current);\n return assistTurn(\n {\n ...params,\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]\n );\n\n const transcribe = useCallback(\n async (blob: Blob): Promise<string> => {\n try {\n return await transcribeAudio(blob, token, baseUrl);\n } catch {\n return \"\";\n }\n },\n [token, baseUrl]\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 * 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 })\n .catch(() => {\n // The dialog simply omits the line — never block reporting on it.\n });\n return () => { cancelled = true; };\n }, [baseUrl, token]);\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 enhanceText={enhance}\n assist={aiAssist ? assist : undefined}\n transcribeAudio={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","/**\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\nfunction argsToString(args: unknown[]): string {\n try {\n return args\n .map((a) => {\n if (typeof a === \"string\") return a;\n if (a instanceof Error) return a.message;\n try {\n return JSON.stringify(a);\n } catch {\n return String(a);\n }\n })\n .join(\" \")\n .slice(0, 200);\n } catch {\n return \"[unknown]\";\n }\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\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.textContent?.trim().slice(0, 50) ?? \"\";\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\";\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\nconst 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 * 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): 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 }),\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 * 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 token: string,\n baseUrl?: string\n): Promise<{\n conversationId: string | null;\n question: string | null;\n options?: string[];\n report: string | null;\n duplicate?: { number: number; title: string; url: string } | null;\n solved?: string | null;\n degraded?: string | null;\n}> {\n const offline = {\n conversationId: null,\n question: null,\n report: null,\n degraded:\n \"The assistant is unavailable — write your report below and send it as normal.\",\n };\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 const envelope = (await response.json().catch(() => null)) as {\n success?: boolean;\n error?: string;\n degrade?: boolean;\n disabled?: boolean;\n data?: {\n conversationId?: string;\n question?: string | null;\n options?: string[];\n report?: string | null;\n duplicate?: { number: number; title: string; url: string } | null;\n solved?: string | null;\n };\n } | null;\n\n if (!response.ok || !envelope?.success) {\n // The server distinguishes \"cannot help\" (cap, rate limit, model down,\n // switched off) from a bug. Either way the dialog does the same thing —\n // but the reason is the server's to word, so pass it through.\n return {\n conversationId: null,\n question: null,\n report: null,\n degraded: envelope?.error ?? offline.degraded,\n };\n }\n\n return {\n conversationId: envelope.data?.conversationId ?? null,\n question: envelope.data?.question ?? null,\n options: envelope.data?.options ?? [],\n report: envelope.data?.report ?? null,\n duplicate: envelope.data?.duplicate ?? null,\n solved: envelope.data?.solved ?? null,\n degraded: null,\n };\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): 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 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 type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { AnnotationCanvas } from \"./annotation-canvas\";\nimport { AssistSheet } from \"./assist-sheet\";\nimport { getShortcutLabel } from \"./shortcut\";\nimport { getTypeLabel } from \"./labels\";\nimport { ATTACHMENT_ACCEPT } from \"./attachments\";\nimport { encodeScreenshot } from \"./image-encode\";\nimport type {\n ReportType,\n ReportSeverity,\n DialogTile,\n ReportFn,\n FeedbackFn,\n EnhanceTextFn,\n AssistFn,\n ReportReporter,\n} from \"./types\";\n\n/** Detect if the host page uses a dark or light theme */\nfunction useIsDark(): 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 * 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 * html2canvas-pro over `document.body` (correct for the SDK, embedded in\n * the host page). Standalone hosts must inject their own — `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 → Electron `desktopCapturer` (whole screen, so it\n * works for any browser or native app, not just Chrome)\n * Return `null` to open without a screenshot.\n */\n captureScreenshot?: () => 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\nasync function captureViaHtml2Canvas(): Promise<string | null> {\n try {\n const { default: html2canvas } = await import(\"html2canvas-pro\");\n // Capture at the display's own pixel density so UI text stays readable.\n // Capped at 2 — beyond that the payload grows faster than the legibility.\n const scale = Math.min(Math.max(window.devicePixelRatio || 1, 1), 2);\n const canvas = await html2canvas(document.body, {\n scale,\n logging: false,\n useCORS: true,\n allowTaint: true,\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 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 assistContext = null,\n transcribeAudio,\n types,\n showSeverity = true,\n captureScreenshot = captureViaHtml2Canvas,\n reporter,\n onClose,\n headerSlot,\n}: ReportDialogProps) {\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 /**\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 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 const [screenshots, setScreenshots] = useState<string[]>([]);\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\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 const [severity, setSeverity] = useState<ReportSeverity>(\"medium\");\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 // 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 const isDark = useIsDark();\n const t = getTheme(isDark);\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 files.forEach((file) => {\n const reader = new FileReader();\n if (file.type.startsWith(\"image/\")) {\n reader.onload = () => {\n setScreenshots((prev) => [...prev, reader.result as string]);\n };\n } else {\n reader.onload = () => {\n setAttachments((prev) => [\n ...prev,\n { name: file.name, size: file.size, dataUrl: reader.result as string },\n ]);\n };\n }\n reader.readAsDataURL(file);\n });\n };\n\n const handleOpen = async () => {\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 shot = await captureScreenshot();\n if (shot) setScreenshots([shot]);\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\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 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 // 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 setSeverity(\"medium\");\n setValidationError(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 // 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 let stream: MediaStream | null = null;\n try {\n stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n } catch (err) {\n const isDenied = err instanceof DOMException && (err.name === \"NotAllowedError\" || err.name === \"PermissionDeniedError\");\n if (!SpeechRec || isDenied) { setVoiceError(\"Microphone access denied\"); return; }\n }\n\n if (stream && transcribeAudio) {\n streamRef.current = stream;\n sarvamChunksRef.current = [];\n textBeforeVoiceRef.current = description;\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 sep = textBeforeVoiceRef.current.trim() ? \" \" : \"\";\n // Replace live Web Speech preview with accurate Sarvam result\n setDescription(textBeforeVoiceRef.current + sep + text.trim());\n setValidationError(null);\n setIsEnhanced(false);\n setOriginalDescription(null);\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 voiceBaseRef.current = description;\n textBeforeVoiceRef.current = description;\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 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 setDescription(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 const isDenied = event.error === \"not-allowed\" || event.error === \"audio-capture\";\n setVoiceError(isDenied ? \"Microphone access denied\" : \"Speech recognition not available — try Chrome\");\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 const handleSpaceDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.code !== \"Space\") return;\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\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 const pos = e.currentTarget.selectionStart ?? description.length;\n spaceTimerRef.current = setTimeout(() => {\n spaceTimerRef.current = null;\n isPushToTalkRef.current = true;\n setDescription((prev) =>\n prev[pos] === \" \" ? prev.slice(0, pos) + prev.slice(pos + 1) : prev,\n );\n requestAnimationFrame(() => {\n if (textareaRef.current) {\n textareaRef.current.selectionStart = pos;\n textareaRef.current.selectionEnd = pos;\n }\n });\n void toggleVoice();\n }, 400);\n };\n\n const handleSpaceUp = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.code !== \"Space\") return;\n if (spaceTimerRef.current) {\n // Quick tap — space was already typed natively, nothing to do.\n clearTimeout(spaceTimerRef.current);\n spaceTimerRef.current = null;\n }\n if (isPushToTalkRef.current) {\n isPushToTalkRef.current = false;\n stopListeningAndTranscribe();\n }\n };\n\n const handleSubmit = async () => {\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 setIsSubmitting(true);\n const metadata: Record<string, string> = {};\n if (screenshots.length > 0) metadata.screenshots = JSON.stringify(screenshots);\n if (attachments.length > 0) metadata.attachments = JSON.stringify(attachments);\n if (showSeverity && reportType === \"BUG\") {\n metadata.severity = severity;\n }\n if (duplicateIssueNumber) {\n metadata.duplicateIssueNumber = String(duplicateIssueNumber);\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 setSubmitted(true);\n setDescription(\"\");\n setScreenshots([]);\n setAttachments([]);\n\n setTimeout(() => {\n setSubmitted(false);\n handleClose();\n }, 2000);\n }\n setIsSubmitting(false);\n } catch {\n setIsSubmitting(false);\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-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: \"center\",\n justifyContent: \"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 onClick={(e) => e.stopPropagation()}\n style={{\n position: \"relative\",\n zIndex: 2147483647,\n width: \"420px\",\n maxWidth: \"calc(100% - 32px)\",\n maxHeight: \"calc(100dvh - 32px)\",\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: t.bg,\n borderRadius: \"12px\",\n boxShadow:\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 {step > 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 <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 </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 {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 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: \"pointer\",\n }}\n >\n {getTypeIcon(reportType, isRating ? \"#f59e0b\" : t.accent, 13)}\n {getTypeLabel(reportType)}\n <span style={{ color: t.textMuted, fontWeight: 400 }}>· change</span>\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 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 : getPlaceholder(reportType, placeholderIdx, !!transcribeAudio)\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 {transcribeAudio && !isListening && !isTranscribing && (\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&apos;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 {voiceError && (\n <p\n style={{\n color: \"#ef4444\",\n fontSize: \"11px\",\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 && (\n <div\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: \"8px\",\n marginBottom: \"8px\",\n }}\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: \"block\",\n }}\n >\n Severity\n </span>\n <div style={{ display: \"flex\", gap: \"6px\" }}>\n {(\n [\"low\", \"medium\", \"high\"] as ReportSeverity[]\n ).map((s) => (\n <button\n key={s}\n type=\"button\"\n onClick={() => setSeverity(s)}\n style={{\n flex: 1,\n padding: \"6px 0\",\n borderRadius: \"6px\",\n border: `1px solid ${severity === s ? t.accent : t.inputBorder}`,\n background:\n severity === s ? t.accent : \"transparent\",\n color:\n severity === s ? t.accentText : t.text,\n fontSize: \"12px\",\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n textTransform: \"capitalize\",\n transition: \"all 0.15s ease\",\n }}\n >\n {s}\n </button>\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 <button\n type=\"button\"\n onClick={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 {isSubmitting\n ? \"Sending...\"\n : isRating\n ? \"Send Rating\"\n : \"Send Report\"}\n </button>\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 <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 </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 setScreenshots((prev) =>\n prev.map((s, i) => (i === annotatingIndex ? dataUrl : s)),\n );\n setAnnotatingIndex(null);\n }}\n />,\n document.body,\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={{\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 screenshot={screenshots[0] ?? null}\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={setDuplicateIssueNumber}\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={setSeverity}\n showSeverity={showSeverity}\n isSubmitting={isSubmitting}\n submitted={submitted}\n onSend={() => void handleSubmit()}\n onDegrade={(message) => {\n setAssistOpen(false);\n 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 (cap, outage) retires the 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/** Last resort when even q0.75 overshoots: redraw at this factor, then re-run the ladder. */\nconst DOWNSCALE_FACTOR = 0.7;\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\n // Two rounds: full resolution, then one downscale if nothing fit.\n for (let round = 0; round < 2; round++) {\n let encoded = \"\";\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 === 1) return encoded;\n const smaller = downscale(current, DOWNSCALE_FACTOR);\n if (!smaller) return encoded;\n current = smaller;\n }\n\n return current.toDataURL(\"image/jpeg\", QUALITY_LADDER[0]);\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { AssistFn, AssistTurnResult, DialogTile, ReportSeverity } from \"./types\";\nimport { getTypeLabel } from \"./labels\";\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\ninterface AssistSheetProps {\n assist: AssistFn;\n theme: AssistTheme;\n /** Screenshot already attached to the report — the model reads it. */\n screenshot: string | null;\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 severity: ReportSeverity;\n onSeverityChange: (value: ReportSeverity) => void;\n showSeverity: 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.\n */\n onDuplicateChange?: (issueNumber: number | null) => void;\n\n isSubmitting: boolean;\n submitted: boolean;\n onSend: () => void;\n\n onDegrade: (message: string) => 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\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\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 screenshot,\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 onDuplicateChange,\n isSubmitting,\n submitted,\n onSend,\n onDegrade,\n onClose,\n onFinish,\n}: AssistSheetProps) {\n const narrow = useIsNarrow();\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 { number: number; title: string; url: string } | null\n >(null);\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 * \"type\" → the picker chips, \"rating\" → stars, \"chat\" → the conversation,\n * \"draft\" → the model's report, ready to send. A sheet opened from the\n * dialog's own \"Describe it with AI\" button already knows its type and\n * starts at \"chat\"; ⌘⇧G starts at \"type\".\n */\n const [phase, setPhase] = useState<\"type\" | \"rating\" | \"chat\" | \"draft\" | \"solved\">(\n !typePicked ? \"type\" : currentTile === \"RATING\" ? \"rating\" : \"chat\",\n );\n const scrollRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLTextAreaElement>(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\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 async function runTurn(history: ChatMessage[]) {\n setBusy(true);\n let result: AssistTurnResult;\n try {\n result = await assist({ messages: history, conversationId, screenshot, context });\n } catch {\n // AssistFn is documented as never-throwing, but a host is a host.\n onDegrade(\"The assistant is unavailable — write your report below and send it as normal.\");\n return;\n } finally {\n setBusy(false);\n }\n\n if (result.degraded) {\n onDegrade(result.degraded);\n return;\n }\n if (result.conversationId) setConversationId(result.conversationId);\n\n setDuplicate(result.duplicate ?? null);\n onDuplicateChange?.(result.duplicate?.number ?? null);\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 setMessages([...history, { role: \"assistant\", content: \"Here's your report — have a read.\" }]);\n setOptions([]);\n setPhase(\"draft\");\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 const seed = description.trim();\n if (!seed) return;\n const history: ChatMessage[] = [{ role: \"user\", content: seed }];\n setMessages(history);\n void runTurn(history);\n // Intentionally once, on mount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n function send(text: string) {\n const value = text.trim();\n if (!value || busy) return;\n setOptions([]);\n const history: ChatMessage[] = [...messages, { role: \"user\", content: value }];\n setMessages(history);\n setInput(\"\");\n void runTurn(history);\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\" : \"chat\");\n }\n\n const empty = phase === \"chat\" && messages.length === 0 && !busy;\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-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{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={onClose}\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 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 <div style={{ minWidth: 0, overflow: \"hidden\" }}>\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 {projectSlot ? <span style={{ marginLeft: \"6px\" }}>{projectSlot}</span> : null}\n </div>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close and write it myself\"\n style={{\n flexShrink: 0,\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n cursor: \"pointer\",\n fontSize: narrow ? \"18px\" : \"12px\",\n lineHeight: 1,\n fontFamily: \"inherit\",\n padding: narrow ? \"4px 6px\" : \"6px 4px\",\n }}\n >\n {/* A phone header has no room for a sentence. */}\n {narrow ? \"×\" : \"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 {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={() => send(s)}\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 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 padding: \"9px 12px\",\n borderRadius: mine ? \"12px 12px 4px 12px\" : \"12px 12px 12px 4px\",\n fontSize: \"13px\",\n lineHeight: 1.55,\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n backgroundColor: mine ? t.accent : t.bgSecondary,\n color: mine ? t.accentText : t.text,\n }}\n >\n {m.content}\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 {options.length > 0 && !busy && phase === \"chat\" && (\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={() => send(option)}\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 Your report · edit anything\n </span>\n\n {/* Someone already reported this. Said before Send, not after,\n because \"we know, we're on it\" is the answer they came for —\n and it is why this goes onto that issue instead of becoming\n the fifth copy of it. */}\n {duplicate && (\n <div\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 }}\n >\n <span style={{ color: \"#f59e0b\", fontWeight: 600 }}>\n Our team is already on this\n </span>\n <span style={{ color: t.textMuted, wordBreak: \"break-word\" }}>\n #{duplicate.number} {duplicate.title}\n </span>\n <span style={{ color: t.textMuted }}>\n Your details will be added to it instead of opening a new issue.\n </span>\n </div>\n )}\n <textarea\n ref={draftRef}\n value={description}\n onChange={(e) => onDescriptionChange(e.target.value)}\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 {showSeverity && (\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 </span>\n <div style={{ display: \"flex\", gap: \"6px\" }}>\n {([\"low\", \"medium\", \"high\"] as ReportSeverity[]).map((s) => {\n const on = severity === s;\n return (\n <button\n key={s}\n type=\"button\"\n onClick={() => onSeverityChange(s)}\n aria-pressed={on}\n style={{\n flex: 1,\n minWidth: 0,\n padding: \"8px 0\",\n borderRadius: \"8px\",\n border: `1px solid ${on ? t.accent : t.inputBorder}`,\n backgroundColor: on ? t.accent : \"transparent\",\n color: on ? t.accentText : t.textMuted,\n fontSize: \"12px\",\n fontWeight: 600,\n fontFamily: \"inherit\",\n textTransform: \"capitalize\",\n cursor: \"pointer\",\n }}\n >\n {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\n <button\n type=\"button\"\n onClick={() => setPhase(\"chat\")}\n style={{\n alignSelf: \"flex-start\",\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"12px\",\n fontFamily: \"inherit\",\n padding: \"9px 0\",\n cursor: \"pointer\",\n textDecoration: \"underline\",\n }}\n >\n Not quite — keep chatting\n </button>\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\" && (\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 ) : phase === \"draft\" ? (\n <button\n type=\"button\"\n data-gg-sheet-send=\"\"\n onClick={onSend}\n disabled={isSubmitting || !description.trim()}\n style={{\n width: \"100%\",\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 <div style={{ display: \"flex\", gap: \"8px\", alignItems: \"flex-end\" }}>\n <textarea\n ref={inputRef}\n value={input}\n onChange={(e) => setInput(e.target.value)}\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 send(input);\n }\n }}\n placeholder=\"Type your answer…\"\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={() => send(input)}\n disabled={busy || !input.trim()}\n aria-label=\"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 )}\n </div>\n )}\n </div>\n </div>\n </>,\n document.body,\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","/**\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 * 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 embedded in the GitHub issue body as\n * fenced code; binaries (pdf, docx…) are committed to the repo attachments branch.\n */\nexport const ATTACHMENT_ACCEPT = [\n \"image/*\",\n // text — inlined into the issue body\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 // binary documents\n \".pdf\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".zip\",\n].join(\",\");\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&apos;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&apos;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&apos;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":["useRef","useEffect","useCallback","useMemo","useState","e","appContext","t","useState","useRef","useEffect","createPortal","jsx","jsxs","Fragment","t","history","rgb","t","useState","useEffect","jsxs","jsx","words","sendFeedback","enhanceText","transcribeAudio","useRef","_a","_b","e","result","Fragment","createPortal","useEffect","useState","Fragment","jsx","jsxs","_a","seen","GLITCHGRAB_SHORTCUT","GLITCHGRAB_SHORTCUT_MAC","isMac","getShortcutLabel","Fragment","jsx","jsxs","DEFAULT_BASE_URL","maxBreadcrumbs","release","appContext","responseBodyOrigins","useRef","useEffect","useCallback","captureError","setContext","setContexts","addBreadcrumb","useState","useMemo","GLITCHGRAB_SHORTCUT","getShortcutLabel","useState","Fragment","jsx","jsxs","useState","Fragment","jsx","Fragment","jsx","jsxs","useGlitchgrabSafe","useState","useEffect","useCallback","useState","useEffect","useCallback","DEFAULT_BASE_URL"]}
1
+ {"version":3,"sources":["../src/provider.tsx","../src/error-boundary.tsx","../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/labels.ts","../../report-ui/src/shortcut.ts","../../report-ui/src/attachments.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\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 } from \"@glitchgrab/report-ui\";\nimport { BookingDialog } from \"./booking-dialog\";\nimport { sanitizeUrl, captureContext, contextMetadata, sendReport, sendFeedback, captureDeviceInfo, enhanceText, assistTurn, 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,\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 // 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 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 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);\n } catch {\n return text;\n }\n },\n [token, baseUrl]\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 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 }\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 const transcribe = useCallback(\n async (blob: Blob): Promise<string> => {\n try {\n return await transcribeAudio(blob, token, baseUrl);\n } catch {\n return \"\";\n }\n },\n [token, baseUrl]\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 * 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 })\n .catch(() => {\n // The dialog simply omits the line — never block reporting on it.\n });\n return () => { cancelled = true; };\n }, [baseUrl, token]);\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 enhanceText={enhance}\n assist={aiAssist ? assist : undefined}\n transcribeAudio={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","/**\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\nfunction argsToString(args: unknown[]): string {\n try {\n return args\n .map((a) => {\n if (typeof a === \"string\") return a;\n if (a instanceof Error) return a.message;\n try {\n return JSON.stringify(a);\n } catch {\n return String(a);\n }\n })\n .join(\" \")\n .slice(0, 200);\n } catch {\n return \"[unknown]\";\n }\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\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.textContent?.trim().slice(0, 50) ?? \"\";\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\";\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\nconst 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 * 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): 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 }),\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 * 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?: { key?: string | null; name?: string | null; email?: string | null };\n },\n token: string,\n baseUrl?: string\n): Promise<{\n conversationId: string | null;\n question: string | null;\n options?: string[];\n report: string | null;\n duplicate?: { number: number; title: string; url: string } | null;\n solved?: string | null;\n degraded?: string | null;\n}> {\n const offline = {\n conversationId: null,\n question: null,\n report: null,\n degraded:\n \"The assistant is unavailable — write your report below and send it as normal.\",\n };\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 const envelope = (await response.json().catch(() => null)) as {\n success?: boolean;\n error?: string;\n degrade?: boolean;\n disabled?: boolean;\n data?: {\n conversationId?: string;\n question?: string | null;\n options?: string[];\n report?: string | null;\n duplicate?: { number: number; title: string; url: string } | null;\n solved?: string | null;\n };\n } | null;\n\n if (!response.ok || !envelope?.success) {\n // The server distinguishes \"cannot help\" (cap, rate limit, model down,\n // switched off) from a bug. Either way the dialog does the same thing —\n // but the reason is the server's to word, so pass it through.\n return {\n conversationId: null,\n question: null,\n report: null,\n degraded: envelope?.error ?? offline.degraded,\n };\n }\n\n return {\n conversationId: envelope.data?.conversationId ?? null,\n question: envelope.data?.question ?? null,\n options: envelope.data?.options ?? [],\n report: envelope.data?.report ?? null,\n duplicate: envelope.data?.duplicate ?? null,\n solved: envelope.data?.solved ?? null,\n degraded: null,\n };\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): 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 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 type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { AnnotationCanvas } from \"./annotation-canvas\";\nimport { AssistSheet } from \"./assist-sheet\";\nimport { getShortcutLabel } from \"./shortcut\";\nimport { getTypeLabel } from \"./labels\";\nimport { ATTACHMENT_ACCEPT } from \"./attachments\";\nimport { encodeScreenshot } from \"./image-encode\";\nimport type {\n ReportType,\n ReportSeverity,\n DialogTile,\n ReportFn,\n FeedbackFn,\n EnhanceTextFn,\n AssistFn,\n ReportReporter,\n} from \"./types\";\n\n/** Detect if the host page uses a dark or light theme */\nfunction useIsDark(): 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 * 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 * html2canvas-pro over `document.body` (correct for the SDK, embedded in\n * the host page). Standalone hosts must inject their own — `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 → Electron `desktopCapturer` (whole screen, so it\n * works for any browser or native app, not just Chrome)\n * Return `null` to open without a screenshot.\n */\n captureScreenshot?: () => 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\nasync function captureViaHtml2Canvas(): Promise<string | null> {\n try {\n const { default: html2canvas } = await import(\"html2canvas-pro\");\n // Capture at the display's own pixel density so UI text stays readable.\n // Capped at 2 — beyond that the payload grows faster than the legibility.\n const scale = Math.min(Math.max(window.devicePixelRatio || 1, 1), 2);\n const canvas = await html2canvas(document.body, {\n scale,\n logging: false,\n useCORS: true,\n allowTaint: true,\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 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 assistContext = null,\n transcribeAudio,\n types,\n showSeverity = true,\n captureScreenshot = captureViaHtml2Canvas,\n reporter,\n onClose,\n headerSlot,\n}: ReportDialogProps) {\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 /**\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 * 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 const [screenshots, setScreenshots] = useState<string[]>([]);\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 const [severity, setSeverity] = useState<ReportSeverity>(\"medium\");\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 // 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 const isDark = useIsDark();\n const t = getTheme(isDark);\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 files.forEach((file) => {\n const reader = new FileReader();\n if (file.type.startsWith(\"image/\")) {\n reader.onload = () => {\n setScreenshots((prev) => [...prev, reader.result as string]);\n };\n } else {\n reader.onload = () => {\n setAttachments((prev) => [\n ...prev,\n { name: file.name, size: file.size, dataUrl: reader.result as string },\n ]);\n };\n }\n reader.readAsDataURL(file);\n });\n };\n\n const handleOpen = async () => {\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 shot = await captureScreenshot();\n if (shot) setScreenshots([shot]);\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\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 // 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 setSeverity(\"medium\");\n setValidationError(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 let stream: MediaStream | null = null;\n try {\n stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n } catch (err) {\n const isDenied = err instanceof DOMException && (err.name === \"NotAllowedError\" || err.name === \"PermissionDeniedError\");\n if (!SpeechRec || isDenied) { setVoiceError(\"Microphone access denied\"); 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 const isDenied = event.error === \"not-allowed\" || event.error === \"audio-capture\";\n setVoiceError(isDenied ? \"Microphone access denied\" : \"Speech recognition not available — try Chrome\");\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 () => {\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 setIsSubmitting(true);\n const metadata: Record<string, string> = {};\n if (screenshots.length > 0) metadata.screenshots = JSON.stringify(screenshots);\n if (attachments.length > 0) metadata.attachments = JSON.stringify(attachments);\n if (showSeverity && reportType === \"BUG\") {\n metadata.severity = severity;\n }\n if (duplicateIssueNumber) {\n metadata.duplicateIssueNumber = String(duplicateIssueNumber);\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 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\n setTimeout(() => {\n setSubmitted(false);\n handleClose();\n }, 2000);\n }\n setIsSubmitting(false);\n } catch {\n setIsSubmitting(false);\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-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: \"center\",\n justifyContent: \"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 onClick={(e) => e.stopPropagation()}\n style={{\n position: \"relative\",\n zIndex: 2147483647,\n width: \"420px\",\n maxWidth: \"calc(100% - 32px)\",\n maxHeight: \"calc(100dvh - 32px)\",\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: t.bg,\n borderRadius: \"12px\",\n boxShadow:\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 {step > 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 <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 </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 {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 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: \"pointer\",\n }}\n >\n {getTypeIcon(reportType, isRating ? \"#f59e0b\" : t.accent, 13)}\n {getTypeLabel(reportType)}\n <span style={{ color: t.textMuted, fontWeight: 400 }}>· change</span>\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 : getPlaceholder(reportType, placeholderIdx, !!transcribeAudio)\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 {transcribeAudio && !isListening && !isTranscribing && (\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&apos;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 {voiceError && (\n <p\n style={{\n color: \"#ef4444\",\n fontSize: \"11px\",\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 && (\n <div\n style={{\n display: \"flex\",\n flexWrap: \"wrap\",\n gap: \"8px\",\n marginBottom: \"8px\",\n }}\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: \"block\",\n }}\n >\n Severity\n </span>\n <div style={{ display: \"flex\", gap: \"6px\" }}>\n {(\n [\"low\", \"medium\", \"high\"] as ReportSeverity[]\n ).map((s) => (\n <button\n key={s}\n type=\"button\"\n onClick={() => setSeverity(s)}\n style={{\n flex: 1,\n padding: \"6px 0\",\n borderRadius: \"6px\",\n border: `1px solid ${severity === s ? t.accent : t.inputBorder}`,\n background:\n severity === s ? t.accent : \"transparent\",\n color:\n severity === s ? t.accentText : t.text,\n fontSize: \"12px\",\n fontWeight: 600,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n textTransform: \"capitalize\",\n transition: \"all 0.15s ease\",\n }}\n >\n {s}\n </button>\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 <button\n type=\"button\"\n onClick={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 {isSubmitting\n ? \"Sending...\"\n : isRating\n ? \"Send Rating\"\n : \"Send Report\"}\n </button>\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 <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 </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 setScreenshots((prev) =>\n prev.map((s, i) => (i === annotatingIndex ? dataUrl : s)),\n );\n setAnnotatingIndex(null);\n }}\n />,\n document.body,\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={{\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 screenshot={screenshots[0] ?? null}\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={setDuplicateIssueNumber}\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={setSeverity}\n showSeverity={showSeverity}\n isSubmitting={isSubmitting}\n submitted={submitted}\n onSend={() => void handleSubmit()}\n onDegrade={(message) => {\n setAssistOpen(false);\n 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 (cap, outage) retires the 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/** Last resort when even q0.75 overshoots: redraw at this factor, then re-run the ladder. */\nconst DOWNSCALE_FACTOR = 0.7;\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\n // Two rounds: full resolution, then one downscale if nothing fit.\n for (let round = 0; round < 2; round++) {\n let encoded = \"\";\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 === 1) return encoded;\n const smaller = downscale(current, DOWNSCALE_FACTOR);\n if (!smaller) return encoded;\n current = smaller;\n }\n\n return current.toDataURL(\"image/jpeg\", QUALITY_LADDER[0]);\n}\n","\"use client\";\n\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { AssistFn, AssistTurnResult, DialogTile, ReportSeverity } from \"./types\";\nimport { getTypeLabel } from \"./labels\";\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\ninterface AssistSheetProps {\n assist: AssistFn;\n theme: AssistTheme;\n /** Screenshot already attached to the report — the model reads it. */\n screenshot: string | null;\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 severity: ReportSeverity;\n onSeverityChange: (value: ReportSeverity) => void;\n showSeverity: 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.\n */\n onDuplicateChange?: (issueNumber: number | null) => 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 onDegrade: (message: string) => 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\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\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 screenshot,\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 onDuplicateChange,\n onConversationChange,\n isSubmitting,\n submitted,\n onSend,\n onDegrade,\n onClose,\n onFinish,\n}: AssistSheetProps) {\n const narrow = useIsNarrow();\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 { number: number; title: string; url: string } | null\n >(null);\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 * \"type\" → the picker chips, \"rating\" → stars, \"chat\" → the conversation,\n * \"draft\" → the model's report, ready to send. A sheet opened from the\n * dialog's own \"Describe it with AI\" button already knows its type and\n * starts at \"chat\"; ⌘⇧G starts at \"type\".\n */\n const [phase, setPhase] = useState<\"type\" | \"rating\" | \"chat\" | \"draft\" | \"solved\">(\n !typePicked ? \"type\" : currentTile === \"RATING\" ? \"rating\" : \"chat\",\n );\n const scrollRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLTextAreaElement>(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\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 async function runTurn(history: ChatMessage[]) {\n setBusy(true);\n let result: AssistTurnResult;\n try {\n result = await assist({ messages: history, conversationId, screenshot, context });\n } catch {\n // AssistFn is documented as never-throwing, but a host is a host.\n onDegrade(\"The assistant is unavailable — write your report below and send it as normal.\");\n return;\n } finally {\n setBusy(false);\n }\n\n if (result.degraded) {\n onDegrade(result.degraded);\n return;\n }\n if (result.conversationId) {\n setConversationId(result.conversationId);\n onConversationChange?.(result.conversationId);\n }\n\n setDuplicate(result.duplicate ?? null);\n onDuplicateChange?.(result.duplicate?.number ?? null);\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 setMessages([...history, { role: \"assistant\", content: \"Here's your report — have a read.\" }]);\n setOptions([]);\n setPhase(\"draft\");\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 const seed = description.trim();\n if (!seed) return;\n const history: ChatMessage[] = [{ role: \"user\", content: seed }];\n setMessages(history);\n void runTurn(history);\n // Intentionally once, on mount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n function send(text: string) {\n const value = text.trim();\n if (!value || busy) return;\n setOptions([]);\n const history: ChatMessage[] = [...messages, { role: \"user\", content: value }];\n setMessages(history);\n setInput(\"\");\n void runTurn(history);\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\" : \"chat\");\n }\n\n const empty = phase === \"chat\" && messages.length === 0 && !busy;\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-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{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={onClose}\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 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 <div style={{ minWidth: 0, overflow: \"hidden\" }}>\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 {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={onClose}\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 {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={() => send(s)}\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 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 padding: \"9px 12px\",\n borderRadius: mine ? \"12px 12px 4px 12px\" : \"12px 12px 12px 4px\",\n fontSize: \"13px\",\n lineHeight: 1.55,\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n backgroundColor: mine ? t.accent : t.bgSecondary,\n color: mine ? t.accentText : t.text,\n }}\n >\n {m.content}\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 {options.length > 0 && !busy && phase === \"chat\" && (\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={() => send(option)}\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 Your report · edit anything\n </span>\n\n {/* Someone already reported this. Said before Send, not after,\n because \"we know, we're on it\" is the answer they came for —\n and it is why this goes onto that issue instead of becoming\n the fifth copy of it. */}\n {duplicate && (\n <div\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 }}\n >\n <span style={{ color: \"#f59e0b\", fontWeight: 600 }}>\n Our team is already on this\n </span>\n <span style={{ color: t.textMuted, wordBreak: \"break-word\" }}>\n #{duplicate.number} {duplicate.title}\n </span>\n <span style={{ color: t.textMuted }}>\n Your details will be added to it instead of opening a new issue.\n </span>\n </div>\n )}\n <textarea\n ref={draftRef}\n value={description}\n onChange={(e) => onDescriptionChange(e.target.value)}\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 {showSeverity && (\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 </span>\n <div style={{ display: \"flex\", gap: \"6px\" }}>\n {([\"low\", \"medium\", \"high\"] as ReportSeverity[]).map((s) => {\n const on = severity === s;\n return (\n <button\n key={s}\n type=\"button\"\n onClick={() => onSeverityChange(s)}\n aria-pressed={on}\n style={{\n flex: 1,\n minWidth: 0,\n padding: \"8px 0\",\n borderRadius: \"8px\",\n border: `1px solid ${on ? t.accent : t.inputBorder}`,\n backgroundColor: on ? t.accent : \"transparent\",\n color: on ? t.accentText : t.textMuted,\n fontSize: \"12px\",\n fontWeight: 600,\n fontFamily: \"inherit\",\n textTransform: \"capitalize\",\n cursor: \"pointer\",\n }}\n >\n {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\n <button\n type=\"button\"\n onClick={() => setPhase(\"chat\")}\n style={{\n alignSelf: \"flex-start\",\n border: \"none\",\n background: \"transparent\",\n color: t.textMuted,\n fontSize: \"12px\",\n fontFamily: \"inherit\",\n padding: \"9px 0\",\n cursor: \"pointer\",\n textDecoration: \"underline\",\n }}\n >\n Not quite — keep chatting\n </button>\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\" && (\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 ) : phase === \"draft\" ? (\n <button\n type=\"button\"\n data-gg-sheet-send=\"\"\n onClick={onSend}\n disabled={isSubmitting || !description.trim()}\n style={{\n width: \"100%\",\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 <div style={{ display: \"flex\", gap: \"8px\", alignItems: \"flex-end\" }}>\n <textarea\n ref={inputRef}\n value={input}\n onChange={(e) => setInput(e.target.value)}\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 send(input);\n }\n }}\n placeholder=\"Type your answer…\"\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={() => send(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 )}\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={onClose}\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 </div>\n )}\n </div>\n </div>\n </>,\n document.body,\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","/**\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 * 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 embedded in the GitHub issue body as\n * fenced code; binaries (pdf, docx…) are committed to the repo attachments branch.\n */\nexport const ATTACHMENT_ACCEPT = [\n \"image/*\",\n // text — inlined into the issue body\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 // binary documents\n \".pdf\",\n \".doc\",\n \".docx\",\n \".xls\",\n \".xlsx\",\n \".zip\",\n].join(\",\");\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&apos;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&apos;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&apos;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":["useRef","useEffect","useCallback","useMemo","useState","e","appContext","t","useState","useRef","useEffect","createPortal","jsx","jsxs","Fragment","t","history","rgb","t","useState","useEffect","jsxs","jsx","words","sendFeedback","enhanceText","transcribeAudio","useRef","_a","_b","e","result","Fragment","createPortal","useEffect","useState","Fragment","jsx","jsxs","_a","seen","GLITCHGRAB_SHORTCUT","GLITCHGRAB_SHORTCUT_MAC","isMac","getShortcutLabel","Fragment","jsx","jsxs","DEFAULT_BASE_URL","maxBreadcrumbs","release","appContext","responseBodyOrigins","useRef","useEffect","useCallback","captureError","setContext","setContexts","addBreadcrumb","useState","useMemo","GLITCHGRAB_SHORTCUT","getShortcutLabel","useState","Fragment","jsx","jsxs","useState","Fragment","jsx","Fragment","jsx","jsxs","useGlitchgrabSafe","useState","useEffect","useCallback","useState","useEffect","useCallback","DEFAULT_BASE_URL"]}