glitchgrab 1.41.0 → 1.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -4,11 +4,11 @@
4
4
  import {
5
5
  createContext,
6
6
  useContext,
7
- useRef as useRef4,
8
- useEffect as useEffect5,
7
+ useRef as useRef5,
8
+ useEffect as useEffect6,
9
9
  useCallback as useCallback2,
10
- useMemo as useMemo2,
11
- useState as useState5
10
+ useMemo as useMemo3,
11
+ useState as useState6
12
12
  } from "react";
13
13
 
14
14
  // src/error-boundary.tsx
@@ -127,21 +127,84 @@ function interceptConsole() {
127
127
  origError.apply(console, args);
128
128
  };
129
129
  }
130
+ var CONSOLE_TEXT_MAX = 200;
130
131
  function argsToString(args) {
131
132
  try {
132
133
  return args.map((a) => {
133
- if (typeof a === "string") return a;
134
+ if (typeof a === "string") return a.slice(0, CONSOLE_TEXT_MAX);
134
135
  if (a instanceof Error) return a.message;
135
136
  try {
136
- return JSON.stringify(a);
137
+ return previewJson(a, CONSOLE_TEXT_MAX);
137
138
  } catch (e) {
138
139
  return String(a);
139
140
  }
140
- }).join(" ").slice(0, 200);
141
+ }).join(" ").slice(0, CONSOLE_TEXT_MAX);
141
142
  } catch (e) {
142
143
  return "[unknown]";
143
144
  }
144
145
  }
146
+ function previewJson(value, max) {
147
+ let out = "";
148
+ const path = /* @__PURE__ */ new WeakSet();
149
+ const write = (input, inArray) => {
150
+ if (out.length > max) return;
151
+ let v = input;
152
+ if (v !== null && typeof v === "object" && typeof v.toJSON === "function") {
153
+ v = v.toJSON();
154
+ }
155
+ if (v === null) {
156
+ out += "null";
157
+ return;
158
+ }
159
+ switch (typeof v) {
160
+ case "string":
161
+ out += JSON.stringify(v.length > max ? v.slice(0, max) : v);
162
+ return;
163
+ case "number":
164
+ out += Number.isFinite(v) ? String(v) : "null";
165
+ return;
166
+ case "boolean":
167
+ case "bigint":
168
+ out += String(v);
169
+ return;
170
+ case "object":
171
+ break;
172
+ default:
173
+ if (inArray) out += "null";
174
+ return;
175
+ }
176
+ const obj = v;
177
+ if (path.has(obj)) {
178
+ out += '"[Circular]"';
179
+ return;
180
+ }
181
+ path.add(obj);
182
+ if (Array.isArray(obj)) {
183
+ out += "[";
184
+ for (let i = 0; i < obj.length && out.length <= max; i++) {
185
+ if (i > 0) out += ",";
186
+ write(obj[i], true);
187
+ }
188
+ out += "]";
189
+ } else {
190
+ out += "{";
191
+ let first = true;
192
+ for (const key in obj) {
193
+ if (out.length > max) break;
194
+ if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
195
+ const child = obj[key];
196
+ if (child === void 0 || typeof child === "function" || typeof child === "symbol") continue;
197
+ out += `${first ? "" : ","}${JSON.stringify(key)}:`;
198
+ first = false;
199
+ write(child, false);
200
+ }
201
+ out += "}";
202
+ }
203
+ path.delete(obj);
204
+ };
205
+ write(value, false);
206
+ return out;
207
+ }
145
208
  async function readErrorBody(response, url) {
146
209
  try {
147
210
  if (response.ok) return "";
@@ -258,15 +321,27 @@ function interceptNavigation() {
258
321
  addBreadcrumb("navigation", `Back/Forward to ${window.location.pathname}`);
259
322
  });
260
323
  }
324
+ var CLICK_TEXT_MAX = 50;
325
+ var CLICK_TEXT_NODE_LIMIT = 500;
326
+ function leadingText(el, max) {
327
+ var _a;
328
+ let text = "";
329
+ let visited = 0;
330
+ const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
331
+ while (text.trimStart().length < max && visited++ < CLICK_TEXT_NODE_LIMIT && walker.nextNode()) {
332
+ text += (_a = walker.currentNode.nodeValue) != null ? _a : "";
333
+ }
334
+ return text.trim().slice(0, max);
335
+ }
261
336
  function interceptClicks() {
262
337
  document.addEventListener(
263
338
  "click",
264
339
  (e) => {
265
- var _a, _b, _c;
340
+ var _a;
266
341
  try {
267
342
  const target = e.target;
268
343
  const tag = (_a = target.tagName) == null ? void 0 : _a.toLowerCase();
269
- const text = (_c = (_b = target.textContent) == null ? void 0 : _b.trim().slice(0, 50)) != null ? _c : "";
344
+ const text = target instanceof Node ? leadingText(target, CLICK_TEXT_MAX) : "";
270
345
  const id = target.id ? `#${target.id}` : "";
271
346
  const cls = target.className && typeof target.className === "string" ? `.${target.className.split(" ")[0]}` : "";
272
347
  addBreadcrumb("click", `Click ${tag}${id}${cls} "${text}"`);
@@ -588,7 +663,7 @@ async function enhanceText(text, token, baseUrl, screenshot, context) {
588
663
  }
589
664
  }
590
665
  async function assistTurn(params, token, baseUrl) {
591
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
666
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
592
667
  const offline = {
593
668
  conversationId: null,
594
669
  question: null,
@@ -621,6 +696,7 @@ async function assistTurn(params, token, baseUrl) {
621
696
  report: (_i = (_h = envelope.data) == null ? void 0 : _h.report) != null ? _i : null,
622
697
  duplicate: (_k = (_j = envelope.data) == null ? void 0 : _j.duplicate) != null ? _k : null,
623
698
  solved: (_m = (_l = envelope.data) == null ? void 0 : _l.solved) != null ? _m : null,
699
+ aboutGlitchgrab: ((_n = envelope.data) == null ? void 0 : _n.aboutGlitchgrab) === true,
624
700
  degraded: null
625
701
  };
626
702
  } catch (e) {
@@ -835,20 +911,25 @@ var GlitchgrabErrorBoundary = class extends React.Component {
835
911
 
836
912
  // ../report-ui/dist/index.mjs
837
913
  import {
838
- useState as useState3,
839
- useRef as useRef3,
840
- useEffect as useEffect3
914
+ useState as useState4,
915
+ useRef as useRef4,
916
+ useEffect as useEffect4,
917
+ useMemo
841
918
  } from "react";
842
- import { createPortal as createPortal2 } from "react-dom";
919
+ import { createPortal as createPortal3 } from "react-dom";
843
920
  import { useEffect, useRef, useState } from "react";
844
921
  import { jsx, jsxs } from "react/jsx-runtime";
845
922
  import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
846
923
  import { createPortal } from "react-dom";
847
924
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
925
+ import { useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
926
+ import { createPortal as createPortal2 } from "react-dom";
848
927
  import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
928
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
849
929
  var MAX_SCREENSHOT_DATA_URL_LENGTH = 18e5;
850
930
  var QUALITY_LADDER = [0.92, 0.85, 0.75];
851
931
  var DOWNSCALE_FACTOR = 0.7;
932
+ var MAX_ROUNDS = 4;
852
933
  function downscale(canvas, factor) {
853
934
  const next = document.createElement("canvas");
854
935
  next.width = Math.max(1, Math.round(canvas.width * factor));
@@ -862,18 +943,55 @@ function downscale(canvas, factor) {
862
943
  }
863
944
  function encodeScreenshot(canvas, maxLength = MAX_SCREENSHOT_DATA_URL_LENGTH) {
864
945
  let current = canvas;
865
- for (let round = 0; round < 2; round++) {
866
- let encoded = "";
946
+ let encoded = "";
947
+ for (let round = 0; round < MAX_ROUNDS; round++) {
867
948
  for (const quality of QUALITY_LADDER) {
868
949
  encoded = current.toDataURL("image/jpeg", quality);
869
950
  if (encoded.length <= maxLength) return encoded;
870
951
  }
871
- if (round === 1) return encoded;
952
+ if (round === MAX_ROUNDS - 1) break;
872
953
  const smaller = downscale(current, DOWNSCALE_FACTOR);
873
- if (!smaller) return encoded;
954
+ if (!smaller) break;
874
955
  current = smaller;
875
956
  }
876
- return current.toDataURL("image/jpeg", QUALITY_LADDER[0]);
957
+ return encoded;
958
+ }
959
+ function readAsDataUrl(file) {
960
+ return new Promise((resolve, reject) => {
961
+ const reader = new FileReader();
962
+ reader.onload = () => resolve(reader.result);
963
+ reader.onerror = () => reject(reader.error);
964
+ reader.readAsDataURL(file);
965
+ });
966
+ }
967
+ async function reencodeImageFile(file, maxLength) {
968
+ var _a;
969
+ if (typeof createImageBitmap !== "function") return null;
970
+ const bitmap = await createImageBitmap(file);
971
+ try {
972
+ const canvas = document.createElement("canvas");
973
+ canvas.width = bitmap.width;
974
+ canvas.height = bitmap.height;
975
+ const ctx = canvas.getContext("2d");
976
+ if (!ctx) return null;
977
+ ctx.fillStyle = "#ffffff";
978
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
979
+ ctx.drawImage(bitmap, 0, 0);
980
+ return encodeScreenshot(canvas, maxLength);
981
+ } finally {
982
+ (_a = bitmap.close) == null ? void 0 : _a.call(bitmap);
983
+ }
984
+ }
985
+ async function encodeImageFile(file, maxLength = MAX_SCREENSHOT_DATA_URL_LENGTH) {
986
+ const rawLength = Math.ceil(file.size / 3) * 4 + 64;
987
+ if (rawLength > maxLength) {
988
+ try {
989
+ const shrunk = await reencodeImageFile(file, maxLength);
990
+ if (shrunk && shrunk.length < rawLength) return shrunk;
991
+ } catch (e) {
992
+ }
993
+ }
994
+ return readAsDataUrl(file);
877
995
  }
878
996
  var PALETTE = ["#ef4444", "#f59e0b", "#22c55e", "#3b82f6", "#a855f7", "#ffffff"];
879
997
  function drawStroke(ctx, s) {
@@ -1164,6 +1282,7 @@ var SEVERITY_LABELS = {
1164
1282
  critical: "Critical"
1165
1283
  };
1166
1284
  var MAX_ASSIST_IMAGES = 3;
1285
+ var MAX_ASSIST_IMAGE_CHARS = 35e5;
1167
1286
  function getTypeLabel(type) {
1168
1287
  switch (type) {
1169
1288
  case "RATING":
@@ -1184,6 +1303,17 @@ function getTypeLabel(type) {
1184
1303
  return "Other";
1185
1304
  }
1186
1305
  }
1306
+ function pickAssistImages(all) {
1307
+ const picked = [];
1308
+ let total = 0;
1309
+ for (let i = all.length - 1; i >= 0 && picked.length < MAX_ASSIST_IMAGES; i--) {
1310
+ const shot = all[i];
1311
+ if (total + shot.length > MAX_ASSIST_IMAGE_CHARS) continue;
1312
+ picked.unshift(shot);
1313
+ total += shot.length;
1314
+ }
1315
+ return picked;
1316
+ }
1187
1317
  var STARTERS = [
1188
1318
  "Something on this page is broken",
1189
1319
  "It did the wrong thing",
@@ -1261,6 +1391,7 @@ function AssistSheet({
1261
1391
  screenshots,
1262
1392
  pageShot = null,
1263
1393
  onAddImages,
1394
+ onRemoveImage,
1264
1395
  attachmentCount,
1265
1396
  context,
1266
1397
  reportTypeLabel,
@@ -1286,7 +1417,8 @@ function AssistSheet({
1286
1417
  onSend,
1287
1418
  onDegrade,
1288
1419
  onClose,
1289
- onFinish
1420
+ onFinish,
1421
+ onReportGlitchgrabProblem
1290
1422
  }) {
1291
1423
  const narrow = useIsNarrow();
1292
1424
  const severityAsked = showSeverity && currentTile === "BUG";
@@ -1297,12 +1429,12 @@ function AssistSheet({
1297
1429
  const [hoveredStar, setHoveredStar] = useState2(0);
1298
1430
  const [options, setOptions] = useState2([]);
1299
1431
  const [duplicate, setDuplicate] = useState2(null);
1432
+ const [glitchgrabOffer, setGlitchgrabOffer] = useState2(false);
1300
1433
  const [solved, setSolved] = useState2(null);
1301
1434
  const [phase, setPhase] = useState2(
1302
1435
  !typePicked ? "type" : currentTile === "RATING" ? "rating" : "chat"
1303
1436
  );
1304
1437
  const scrollRef = useRef2(null);
1305
- const inputRef = useRef2(null);
1306
1438
  const draftRef = useRef2(null);
1307
1439
  const seededRef = useRef2(false);
1308
1440
  const eventsRef = useRef2([]);
@@ -1328,6 +1460,7 @@ function AssistSheet({
1328
1460
  } catch (e) {
1329
1461
  }
1330
1462
  }
1463
+ const readShots = new Set(pickAssistImages(screenshots));
1331
1464
  function leave(type, detail) {
1332
1465
  logEvent(type, detail);
1333
1466
  flushEvents();
@@ -1347,12 +1480,12 @@ function AssistSheet({
1347
1480
  onDegrade(message);
1348
1481
  }
1349
1482
  async function runTurn(history2) {
1350
- var _a, _b, _c, _d, _e;
1483
+ var _a, _b, _c, _d;
1351
1484
  setBusy(true);
1352
1485
  let result;
1353
1486
  const events = takeEvents();
1354
1487
  try {
1355
- const sent = screenshots.slice(-MAX_ASSIST_IMAGES);
1488
+ const sent = pickAssistImages(screenshots);
1356
1489
  result = await assist({
1357
1490
  // `kind` only on drafts, so an older server sees the exact shape it
1358
1491
  // always did — it just learns the draft text now instead of a
@@ -1362,10 +1495,12 @@ function AssistSheet({
1362
1495
  ),
1363
1496
  conversationId,
1364
1497
  screenshots: sent,
1365
- screenshot: (_a = sent[sent.length - 1]) != null ? _a : null,
1366
1498
  context: {
1367
1499
  ...context != null ? context : {},
1368
- imageSources: sent.map((shot) => pageShot && shot === pageShot ? "page" : "attached")
1500
+ imageSources: sent.map((shot) => pageShot && shot === pageShot ? "page" : "attached"),
1501
+ // Whether this dialog can open the #366 panel at all. A hint — the
1502
+ // server decides whether the model may offer it.
1503
+ canReportGlitchgrab: !!onReportGlitchgrabProblem
1369
1504
  },
1370
1505
  events
1371
1506
  });
@@ -1386,8 +1521,9 @@ function AssistSheet({
1386
1521
  setConversationId(result.conversationId);
1387
1522
  onConversationChange == null ? void 0 : onConversationChange(result.conversationId);
1388
1523
  }
1389
- setDuplicate((_b = result.duplicate) != null ? _b : null);
1390
- onDuplicateChange == null ? void 0 : onDuplicateChange((_d = (_c = result.duplicate) == null ? void 0 : _c.number) != null ? _d : null);
1524
+ setDuplicate((_a = result.duplicate) != null ? _a : null);
1525
+ onDuplicateChange == null ? void 0 : onDuplicateChange((_c = (_b = result.duplicate) == null ? void 0 : _b.number) != null ? _c : null);
1526
+ setGlitchgrabOffer(!!result.aboutGlitchgrab && !!onReportGlitchgrabProblem && !!result.question);
1391
1527
  if (result.solved) {
1392
1528
  setSolved(result.solved);
1393
1529
  setOptions([]);
@@ -1405,7 +1541,7 @@ function AssistSheet({
1405
1541
  }
1406
1542
  if (result.question) {
1407
1543
  setMessages([...history2, { role: "assistant", content: result.question }]);
1408
- setOptions((_e = result.options) != null ? _e : []);
1544
+ setOptions((_d = result.options) != null ? _d : []);
1409
1545
  return;
1410
1546
  }
1411
1547
  onDegrade("The assistant had nothing to add \u2014 write your report below and send it as normal.");
@@ -1424,7 +1560,15 @@ function AssistSheet({
1424
1560
  const value = text.trim();
1425
1561
  if (!value || busy) return;
1426
1562
  setOptions([]);
1427
- const history2 = [...messages, { role: "user", content: value }];
1563
+ setGlitchgrabOffer(false);
1564
+ const underDraft = phase === "draft";
1565
+ if (underDraft) {
1566
+ const edited = aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();
1567
+ logEvent("keep_chatting", edited ? "after editing" : void 0);
1568
+ setPhase("chat");
1569
+ }
1570
+ const base = underDraft ? withCurrentDraft(messages) : messages;
1571
+ const history2 = [...base, { role: "user", content: value }];
1428
1572
  setMessages(history2);
1429
1573
  setInput("");
1430
1574
  void runTurn(history2);
@@ -1433,27 +1577,16 @@ function AssistSheet({
1433
1577
  onPickType(tile);
1434
1578
  setPhase(tile === "RATING" ? "rating" : "chat");
1435
1579
  }
1436
- function keepChatting() {
1580
+ function withCurrentDraft(history2) {
1437
1581
  const current = description.trim();
1438
- logEvent(
1439
- "keep_chatting",
1440
- aiDraftRef.current && current !== aiDraftRef.current.trim() ? "after editing" : void 0
1441
- );
1442
- setMessages((prev) => {
1443
- const next = [...prev];
1444
- for (let i = next.length - 1; i >= 0; i--) {
1445
- if (next[i].kind === "report") {
1446
- if (current) next[i] = { ...next[i], content: current };
1447
- break;
1448
- }
1582
+ const next = [...history2];
1583
+ for (let i = next.length - 1; i >= 0; i--) {
1584
+ if (next[i].kind === "report") {
1585
+ if (current) next[i] = { ...next[i], content: current };
1586
+ break;
1449
1587
  }
1450
- return next;
1451
- });
1452
- setPhase("chat");
1453
- requestAnimationFrame(() => {
1454
- var _a;
1455
- return (_a = inputRef.current) == null ? void 0 : _a.focus();
1456
- });
1588
+ }
1589
+ return next;
1457
1590
  }
1458
1591
  function sendDraft() {
1459
1592
  const edited = aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();
@@ -1461,9 +1594,39 @@ function AssistSheet({
1461
1594
  flushEvents();
1462
1595
  onSend();
1463
1596
  }
1464
- const lastMessage = messages[messages.length - 1];
1465
- const correcting = phase === "chat" && (lastMessage == null ? void 0 : lastMessage.kind) === "report";
1466
1597
  const empty = phase === "chat" && messages.length === 0 && !busy;
1598
+ function renderKnownIssue({ title, footer }) {
1599
+ if (!duplicate) return null;
1600
+ return /* @__PURE__ */ jsxs2(
1601
+ "div",
1602
+ {
1603
+ "data-gg-known-issue": "",
1604
+ style: {
1605
+ display: "flex",
1606
+ flexDirection: "column",
1607
+ gap: "3px",
1608
+ padding: "9px 10px",
1609
+ borderRadius: "8px",
1610
+ border: "1px solid rgba(245,158,11,0.4)",
1611
+ backgroundColor: "rgba(245,158,11,0.08)",
1612
+ fontSize: "12px",
1613
+ lineHeight: 1.5,
1614
+ minWidth: 0
1615
+ },
1616
+ children: [
1617
+ /* @__PURE__ */ jsx2("span", { style: { color: "#f59e0b", fontWeight: 600 }, children: title ? "Our team is already on this" : `Our team is already on #${duplicate.number}` }),
1618
+ title && /* @__PURE__ */ jsxs2("span", { style: { color: t2.textMuted, wordBreak: "break-word" }, children: [
1619
+ "#",
1620
+ duplicate.number,
1621
+ " ",
1622
+ duplicate.title
1623
+ ] }),
1624
+ duplicate.status && /* @__PURE__ */ jsx2("span", { style: { color: t2.text, fontWeight: 600 }, children: duplicate.status }),
1625
+ footer && /* @__PURE__ */ jsx2("span", { style: { color: t2.textMuted }, children: footer })
1626
+ ]
1627
+ }
1628
+ );
1629
+ }
1467
1630
  const initials = (reporterName != null ? reporterName : "").split(/\s+/).filter(Boolean).slice(0, 2).map((w) => {
1468
1631
  var _a, _b;
1469
1632
  return (_b = (_a = w[0]) == null ? void 0 : _a.toUpperCase()) != null ? _b : "";
@@ -1488,7 +1651,7 @@ function AssistSheet({
1488
1651
  @keyframes gg-sheet-up{from{transform:translateY(24px);opacity:0}to{transform:translateY(0);opacity:1}}
1489
1652
  @keyframes gg-sheet-fade{from{opacity:0}to{opacity:1}}
1490
1653
  @keyframes gg-dot{0%,80%,100%{transform:translateY(0);opacity:.4}40%{transform:translateY(-3px);opacity:1}}
1491
- [data-gg-sheet-send]:focus-visible,[data-gg-chip]:focus-visible{outline:2px solid currentColor;outline-offset:2px}
1654
+ [data-gg-sheet-send]:focus-visible,[data-gg-chip]:focus-visible,[data-gg-assist-remove]:focus-visible{outline:2px solid currentColor;outline-offset:2px}
1492
1655
  ` }),
1493
1656
  /* @__PURE__ */ jsx2(
1494
1657
  "div",
@@ -1954,7 +2117,83 @@ function AssistSheet({
1954
2117
  i
1955
2118
  );
1956
2119
  }),
1957
- options.length > 0 && !busy && phase === "chat" && /* @__PURE__ */ jsx2(
2120
+ duplicate && !busy && phase === "chat" && /* @__PURE__ */ jsx2("div", { style: { paddingLeft: "32px", minWidth: 0 }, children: renderKnownIssue({ title: false }) }),
2121
+ glitchgrabOffer && onReportGlitchgrabProblem && !busy && phase === "chat" && /* @__PURE__ */ jsx2("div", { style: { paddingLeft: "32px", minWidth: 0 }, children: /* @__PURE__ */ jsxs2(
2122
+ "div",
2123
+ {
2124
+ "data-gg-glitchgrab-offer": "",
2125
+ style: {
2126
+ display: "flex",
2127
+ flexDirection: "column",
2128
+ gap: "8px",
2129
+ padding: "10px",
2130
+ borderRadius: "8px",
2131
+ border: `1px solid ${t2.accent}55`,
2132
+ backgroundColor: `${t2.accent}14`,
2133
+ fontSize: "12px",
2134
+ lineHeight: 1.5
2135
+ },
2136
+ children: [
2137
+ /* @__PURE__ */ jsx2("span", { style: { color: t2.text, fontWeight: 600 }, children: "This is about Glitchgrab, not this app" }),
2138
+ /* @__PURE__ */ jsx2("span", { style: { color: t2.textMuted }, children: "It goes to the team that builds this reporter, with your chat attached." }),
2139
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px" }, children: [
2140
+ /* @__PURE__ */ jsx2(
2141
+ "button",
2142
+ {
2143
+ type: "button",
2144
+ "data-gg-glitchgrab-offer-send": "",
2145
+ onClick: () => {
2146
+ logEvent("glitchgrab_offer_tap");
2147
+ setGlitchgrabOffer(false);
2148
+ onReportGlitchgrabProblem(
2149
+ messages.filter((m) => m.role === "user").map((m) => m.content.trim()).filter(Boolean).join("\n\n")
2150
+ );
2151
+ },
2152
+ style: {
2153
+ padding: "8px 12px",
2154
+ borderRadius: "999px",
2155
+ border: "none",
2156
+ backgroundColor: t2.accent,
2157
+ color: t2.accentText,
2158
+ fontSize: "12px",
2159
+ fontWeight: 700,
2160
+ fontFamily: "inherit",
2161
+ cursor: "pointer",
2162
+ // Both stretch, so on a phone each wrapped line reads as
2163
+ // a choice rather than one button left stranded.
2164
+ flex: "1 1 auto"
2165
+ },
2166
+ children: "Send to the Glitchgrab team"
2167
+ }
2168
+ ),
2169
+ /* @__PURE__ */ jsx2(
2170
+ "button",
2171
+ {
2172
+ type: "button",
2173
+ "data-gg-glitchgrab-offer-no": "",
2174
+ onClick: () => {
2175
+ logEvent("glitchgrab_offer_declined");
2176
+ send("No \u2014 it's about this app, not the reporting tool");
2177
+ },
2178
+ style: {
2179
+ padding: "8px 12px",
2180
+ borderRadius: "999px",
2181
+ border: `1px solid ${t2.inputBorder}`,
2182
+ background: "transparent",
2183
+ color: t2.textMuted,
2184
+ fontSize: "12px",
2185
+ fontFamily: "inherit",
2186
+ cursor: "pointer",
2187
+ flex: "1 1 auto"
2188
+ },
2189
+ children: "No, it's about this app"
2190
+ }
2191
+ )
2192
+ ] })
2193
+ ]
2194
+ }
2195
+ ) }),
2196
+ options.length > 0 && !busy && phase === "chat" && !glitchgrabOffer && /* @__PURE__ */ jsx2(
1958
2197
  "div",
1959
2198
  {
1960
2199
  style: {
@@ -2052,35 +2291,13 @@ function AssistSheet({
2052
2291
  textTransform: "uppercase",
2053
2292
  color: t2.accent
2054
2293
  },
2055
- children: "Your report \xB7 edit anything"
2056
- }
2057
- ),
2058
- duplicate && /* @__PURE__ */ jsxs2(
2059
- "div",
2060
- {
2061
- style: {
2062
- display: "flex",
2063
- flexDirection: "column",
2064
- gap: "3px",
2065
- padding: "9px 10px",
2066
- borderRadius: "8px",
2067
- border: "1px solid rgba(245,158,11,0.4)",
2068
- backgroundColor: "rgba(245,158,11,0.08)",
2069
- fontSize: "12px",
2070
- lineHeight: 1.5
2071
- },
2072
- children: [
2073
- /* @__PURE__ */ jsx2("span", { style: { color: "#f59e0b", fontWeight: 600 }, children: "Our team is already on this" }),
2074
- /* @__PURE__ */ jsxs2("span", { style: { color: t2.textMuted, wordBreak: "break-word" }, children: [
2075
- "#",
2076
- duplicate.number,
2077
- " ",
2078
- duplicate.title
2079
- ] }),
2080
- /* @__PURE__ */ jsx2("span", { style: { color: t2.textMuted }, children: "Your details will be added to it instead of opening a new issue." })
2081
- ]
2294
+ children: duplicate ? `What we'll add to #${duplicate.number} \xB7 edit anything` : "Your report \xB7 edit anything"
2082
2295
  }
2083
2296
  ),
2297
+ renderKnownIssue({
2298
+ title: true,
2299
+ footer: "Your details will be added to it instead of opening a new issue."
2300
+ }),
2084
2301
  /* @__PURE__ */ jsx2(
2085
2302
  "textarea",
2086
2303
  {
@@ -2175,26 +2392,7 @@ function AssistSheet({
2175
2392
  " ",
2176
2393
  attachmentCount === 1 ? "attachment" : "attachments",
2177
2394
  " will be sent with this."
2178
- ] }),
2179
- /* @__PURE__ */ jsx2(
2180
- "button",
2181
- {
2182
- type: "button",
2183
- onClick: keepChatting,
2184
- style: {
2185
- alignSelf: "flex-start",
2186
- border: "none",
2187
- background: "transparent",
2188
- color: t2.textMuted,
2189
- fontSize: "12px",
2190
- fontFamily: "inherit",
2191
- padding: "9px 0",
2192
- cursor: "pointer",
2193
- textDecoration: "underline"
2194
- },
2195
- children: "Not quite \u2014 keep chatting"
2196
- }
2197
- )
2395
+ ] })
2198
2396
  ]
2199
2397
  }
2200
2398
  ),
@@ -2298,189 +2496,270 @@ function AssistSheet({
2298
2496
  },
2299
2497
  children: isSubmitting ? "Sending\u2026" : rating < 1 ? "Pick a star first" : "Send Rating"
2300
2498
  }
2301
- ) : phase === "draft" ? /* @__PURE__ */ jsxs2(Fragment, { children: [
2302
- validationError && /* @__PURE__ */ jsx2(
2303
- "p",
2304
- {
2305
- style: {
2306
- margin: "0 0 8px",
2307
- color: "#ef4444",
2308
- fontSize: "12px"
2309
- },
2310
- children: validationError
2311
- }
2312
- ),
2313
- /* @__PURE__ */ jsx2(
2314
- "button",
2315
- {
2316
- type: "button",
2317
- "data-gg-sheet-send": "",
2318
- onClick: sendDraft,
2319
- disabled: isSubmitting || !description.trim(),
2320
- style: {
2321
- width: "100%",
2322
- padding: "12px",
2323
- borderRadius: "10px",
2324
- border: "none",
2325
- backgroundColor: isSubmitting || !description.trim() ? t2.bgSecondary : t2.accent,
2326
- color: isSubmitting || !description.trim() ? t2.textMuted : t2.accentText,
2327
- fontSize: "14px",
2328
- fontWeight: 700,
2329
- fontFamily: "inherit",
2330
- cursor: isSubmitting || !description.trim() ? "default" : "pointer"
2331
- },
2332
- children: isSubmitting ? "Sending\u2026" : duplicate ? `Add to #${duplicate.number}` : "Send Report"
2333
- }
2334
- )
2335
- ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
2336
- (screenshots.length > 0 || onAddImages) && /* @__PURE__ */ jsxs2(
2337
- "div",
2338
- {
2339
- style: {
2340
- display: "flex",
2341
- gap: "8px",
2342
- alignItems: "center",
2343
- flexWrap: "wrap",
2344
- marginBottom: "8px"
2345
- },
2346
- children: [
2347
- screenshots.map((shot, i) => {
2348
- const read = i >= screenshots.length - MAX_ASSIST_IMAGES;
2349
- return /* @__PURE__ */ jsx2(
2350
- "img",
2499
+ ) : (
2500
+ // Chat AND draft share this branch, so the chat box is the same
2501
+ // element on both sides of a draft landing — it stays put
2502
+ // instead of remounting, and a draft is something you can
2503
+ // still reply to (#360), not a form that replaced the chat.
2504
+ /* @__PURE__ */ jsxs2(Fragment, { children: [
2505
+ (screenshots.length > 0 || onAddImages) && /* @__PURE__ */ jsxs2(
2506
+ "div",
2507
+ {
2508
+ style: {
2509
+ display: "flex",
2510
+ gap: "8px",
2511
+ alignItems: "center",
2512
+ flexWrap: "wrap",
2513
+ marginBottom: "8px"
2514
+ },
2515
+ children: [
2516
+ screenshots.map((shot, i) => {
2517
+ const read = readShots.has(shot);
2518
+ return /* @__PURE__ */ jsxs2(
2519
+ "div",
2520
+ {
2521
+ style: {
2522
+ position: "relative",
2523
+ width: "40px",
2524
+ height: "40px",
2525
+ flexShrink: 0
2526
+ },
2527
+ children: [
2528
+ /* @__PURE__ */ jsx2(
2529
+ "img",
2530
+ {
2531
+ src: shot,
2532
+ alt: read ? "Attached image the assistant reads" : "Attached image",
2533
+ "data-gg-assist-thumb": "",
2534
+ style: {
2535
+ display: "block",
2536
+ width: "100%",
2537
+ height: "100%",
2538
+ objectFit: "cover",
2539
+ borderRadius: "8px",
2540
+ border: `1px solid ${read ? t2.accent : t2.inputBorder}`,
2541
+ opacity: read ? 1 : 0.45,
2542
+ boxSizing: "border-box"
2543
+ }
2544
+ }
2545
+ ),
2546
+ onRemoveImage && /* @__PURE__ */ jsx2(
2547
+ "button",
2548
+ {
2549
+ type: "button",
2550
+ "data-gg-assist-remove": "",
2551
+ "aria-label": `Remove image ${i + 1}`,
2552
+ title: "Remove this image",
2553
+ onClick: () => {
2554
+ logEvent(
2555
+ "image_removed",
2556
+ pageShot && shot === pageShot ? "page capture" : "attached"
2557
+ );
2558
+ onRemoveImage(i);
2559
+ },
2560
+ style: {
2561
+ position: "absolute",
2562
+ top: "-13px",
2563
+ right: "-13px",
2564
+ width: "32px",
2565
+ height: "32px",
2566
+ border: "none",
2567
+ background: "transparent",
2568
+ padding: 0,
2569
+ cursor: "pointer",
2570
+ display: "flex",
2571
+ alignItems: "center",
2572
+ justifyContent: "center",
2573
+ borderRadius: "50%"
2574
+ },
2575
+ children: /* @__PURE__ */ jsx2(
2576
+ "span",
2577
+ {
2578
+ "aria-hidden": "true",
2579
+ style: {
2580
+ width: "20px",
2581
+ height: "20px",
2582
+ boxSizing: "border-box",
2583
+ borderRadius: "50%",
2584
+ border: `2px solid ${t2.bg}`,
2585
+ background: "#ef4444",
2586
+ color: "#fff",
2587
+ display: "flex",
2588
+ alignItems: "center",
2589
+ justifyContent: "center"
2590
+ },
2591
+ children: /* @__PURE__ */ jsx2("svg", { width: "8", height: "8", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx2(
2592
+ "path",
2593
+ {
2594
+ d: "M1 1L9 9M9 1L1 9",
2595
+ stroke: "currentColor",
2596
+ strokeWidth: "1.6",
2597
+ strokeLinecap: "round"
2598
+ }
2599
+ ) })
2600
+ }
2601
+ )
2602
+ }
2603
+ )
2604
+ ]
2605
+ },
2606
+ `${i}-${shot.slice(-16)}`
2607
+ );
2608
+ }),
2609
+ onAddImages && /* @__PURE__ */ jsxs2(
2610
+ "label",
2351
2611
  {
2352
- src: shot,
2353
- alt: read ? "Attached image the assistant reads" : "Attached image",
2354
- "data-gg-assist-thumb": "",
2612
+ "data-gg-assist-attach": "",
2613
+ title: "Attach an image \u2014 or just paste one",
2355
2614
  style: {
2356
2615
  width: "40px",
2357
2616
  height: "40px",
2358
- objectFit: "cover",
2359
2617
  borderRadius: "8px",
2360
- border: `1px solid ${read ? t2.accent : t2.inputBorder}`,
2361
- opacity: read ? 1 : 0.45
2362
- }
2363
- },
2364
- `${i}-${shot.slice(-16)}`
2365
- );
2366
- }),
2367
- onAddImages && /* @__PURE__ */ jsxs2(
2368
- "label",
2369
- {
2370
- "data-gg-assist-attach": "",
2371
- title: "Attach an image \u2014 or just paste one",
2372
- style: {
2373
- width: "40px",
2374
- height: "40px",
2375
- borderRadius: "8px",
2376
- border: `1px dashed ${t2.inputBorder}`,
2377
- display: "inline-flex",
2378
- alignItems: "center",
2379
- justifyContent: "center",
2380
- color: t2.textMuted,
2381
- fontSize: "18px",
2382
- cursor: "pointer",
2383
- flexShrink: 0
2384
- },
2385
- children: [
2386
- "+",
2387
- /* @__PURE__ */ jsx2(
2388
- "input",
2389
- {
2390
- type: "file",
2391
- accept: "image/*",
2392
- multiple: true,
2393
- onChange: (e) => {
2394
- var _a;
2395
- const files = Array.from((_a = e.target.files) != null ? _a : []);
2396
- if (files.length) {
2397
- logEvent("image_added", String(files.length));
2398
- onAddImages(files);
2399
- }
2400
- e.target.value = "";
2401
- },
2402
- style: { display: "none" }
2403
- }
2404
- )
2405
- ]
2406
- }
2407
- ),
2408
- screenshots.length > MAX_ASSIST_IMAGES && /* @__PURE__ */ jsxs2("span", { style: { color: t2.textMuted, fontSize: "11px" }, children: [
2409
- "newest ",
2410
- MAX_ASSIST_IMAGES,
2411
- " read"
2412
- ] })
2413
- ]
2414
- }
2415
- ),
2416
- /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
2417
- /* @__PURE__ */ jsx2(
2418
- "textarea",
2419
- {
2420
- ref: inputRef,
2421
- value: input,
2422
- onChange: (e) => setInput(e.target.value),
2423
- onKeyDown: (e) => {
2424
- if (e.key === "Enter" && !e.shiftKey) {
2425
- e.preventDefault();
2426
- send(input);
2427
- }
2428
- },
2429
- placeholder: correcting ? "What should change in the draft?" : "Type your answer\u2026",
2430
- rows: 1,
2431
- disabled: busy,
2432
- autoFocus: true,
2433
- style: {
2434
- flex: 1,
2435
- minHeight: "42px",
2436
- maxHeight: "120px",
2437
- padding: "11px 12px",
2438
- borderRadius: "10px",
2439
- border: `1px solid ${t2.inputBorder}`,
2440
- backgroundColor: t2.inputBg,
2441
- color: t2.text,
2442
- fontSize: "13px",
2443
- lineHeight: 1.4,
2444
- fontFamily: "inherit",
2445
- resize: "none",
2446
- outline: "none",
2447
- boxSizing: "border-box"
2448
- }
2618
+ border: `1px dashed ${t2.inputBorder}`,
2619
+ display: "inline-flex",
2620
+ alignItems: "center",
2621
+ justifyContent: "center",
2622
+ color: t2.textMuted,
2623
+ fontSize: "18px",
2624
+ cursor: "pointer",
2625
+ flexShrink: 0
2626
+ },
2627
+ children: [
2628
+ "+",
2629
+ /* @__PURE__ */ jsx2(
2630
+ "input",
2631
+ {
2632
+ type: "file",
2633
+ accept: "image/*",
2634
+ multiple: true,
2635
+ onChange: (e) => {
2636
+ var _a;
2637
+ const files = Array.from((_a = e.target.files) != null ? _a : []);
2638
+ if (files.length) {
2639
+ logEvent("image_added", String(files.length));
2640
+ onAddImages(files);
2641
+ }
2642
+ e.target.value = "";
2643
+ },
2644
+ style: { display: "none" }
2645
+ }
2646
+ )
2647
+ ]
2648
+ }
2649
+ ),
2650
+ readShots.size < screenshots.length && /* @__PURE__ */ jsxs2("span", { style: { color: t2.textMuted, fontSize: "11px" }, children: [
2651
+ readShots.size,
2652
+ " of ",
2653
+ screenshots.length,
2654
+ " read"
2655
+ ] })
2656
+ ]
2449
2657
  }
2450
2658
  ),
2451
- /* @__PURE__ */ jsx2(
2452
- "button",
2453
- {
2454
- type: "button",
2455
- "data-gg-sheet-send": "",
2456
- onClick: () => send(input),
2457
- disabled: busy || !input.trim(),
2458
- "aria-label": "Send message",
2459
- "data-gg-send-message": "",
2460
- style: {
2461
- flexShrink: 0,
2462
- width: "42px",
2463
- height: "42px",
2464
- borderRadius: "10px",
2465
- border: "none",
2466
- display: "inline-flex",
2467
- alignItems: "center",
2468
- justifyContent: "center",
2469
- backgroundColor: busy || !input.trim() ? t2.bgSecondary : t2.accent,
2470
- color: busy || !input.trim() ? t2.textMuted : t2.accentText,
2471
- cursor: busy || !input.trim() ? "default" : "pointer"
2472
- },
2473
- children: /* @__PURE__ */ jsx2("svg", { width: "17", height: "17", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(
2474
- "path",
2475
- {
2476
- d: "M3 20.5L21.5 12 3 3.5V10l12 2-12 2v6.5z",
2477
- fill: "currentColor"
2659
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
2660
+ /* @__PURE__ */ jsx2(
2661
+ "textarea",
2662
+ {
2663
+ value: input,
2664
+ onChange: (e) => setInput(e.target.value),
2665
+ onKeyDown: (e) => {
2666
+ if (e.key === "Enter" && !e.shiftKey) {
2667
+ e.preventDefault();
2668
+ send(input);
2669
+ }
2670
+ },
2671
+ placeholder: phase === "draft" ? "Anything to change? Tell me here\u2026" : "Type your answer\u2026",
2672
+ rows: 1,
2673
+ disabled: busy,
2674
+ autoFocus: true,
2675
+ style: {
2676
+ flex: 1,
2677
+ minHeight: "42px",
2678
+ maxHeight: "120px",
2679
+ padding: "11px 12px",
2680
+ borderRadius: "10px",
2681
+ border: `1px solid ${t2.inputBorder}`,
2682
+ backgroundColor: t2.inputBg,
2683
+ color: t2.text,
2684
+ fontSize: "13px",
2685
+ lineHeight: 1.4,
2686
+ fontFamily: "inherit",
2687
+ resize: "none",
2688
+ outline: "none",
2689
+ boxSizing: "border-box"
2478
2690
  }
2479
- ) })
2480
- }
2481
- )
2691
+ }
2692
+ ),
2693
+ /* @__PURE__ */ jsx2(
2694
+ "button",
2695
+ {
2696
+ type: "button",
2697
+ "data-gg-sheet-send": "",
2698
+ onClick: () => send(input),
2699
+ disabled: busy || !input.trim(),
2700
+ "aria-label": "Send message",
2701
+ "data-gg-send-message": "",
2702
+ style: {
2703
+ flexShrink: 0,
2704
+ width: "42px",
2705
+ height: "42px",
2706
+ borderRadius: "10px",
2707
+ border: "none",
2708
+ display: "inline-flex",
2709
+ alignItems: "center",
2710
+ justifyContent: "center",
2711
+ backgroundColor: busy || !input.trim() ? t2.bgSecondary : t2.accent,
2712
+ color: busy || !input.trim() ? t2.textMuted : t2.accentText,
2713
+ cursor: busy || !input.trim() ? "default" : "pointer"
2714
+ },
2715
+ children: /* @__PURE__ */ jsx2("svg", { width: "17", height: "17", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(
2716
+ "path",
2717
+ {
2718
+ d: "M3 20.5L21.5 12 3 3.5V10l12 2-12 2v6.5z",
2719
+ fill: "currentColor"
2720
+ }
2721
+ ) })
2722
+ }
2723
+ )
2724
+ ] }),
2725
+ phase === "draft" && /* @__PURE__ */ jsxs2(Fragment, { children: [
2726
+ validationError && /* @__PURE__ */ jsx2(
2727
+ "p",
2728
+ {
2729
+ style: {
2730
+ margin: "8px 0 0",
2731
+ color: "#ef4444",
2732
+ fontSize: "12px"
2733
+ },
2734
+ children: validationError
2735
+ }
2736
+ ),
2737
+ /* @__PURE__ */ jsx2(
2738
+ "button",
2739
+ {
2740
+ type: "button",
2741
+ "data-gg-sheet-send": "",
2742
+ onClick: sendDraft,
2743
+ disabled: isSubmitting || !description.trim(),
2744
+ style: {
2745
+ width: "100%",
2746
+ marginTop: "8px",
2747
+ padding: "12px",
2748
+ borderRadius: "10px",
2749
+ border: "none",
2750
+ backgroundColor: isSubmitting || !description.trim() ? t2.bgSecondary : t2.accent,
2751
+ color: isSubmitting || !description.trim() ? t2.textMuted : t2.accentText,
2752
+ fontSize: "14px",
2753
+ fontWeight: 700,
2754
+ fontFamily: "inherit",
2755
+ cursor: isSubmitting || !description.trim() ? "default" : "pointer"
2756
+ },
2757
+ children: isSubmitting ? "Sending\u2026" : duplicate ? `Add to #${duplicate.number}` : "Send Report"
2758
+ }
2759
+ )
2760
+ ] })
2482
2761
  ] })
2483
- ] }),
2762
+ ),
2484
2763
  phase === "chat" && messages.length > 0 && /* @__PURE__ */ jsx2(
2485
2764
  "button",
2486
2765
  {
@@ -2500,6 +2779,30 @@ function AssistSheet({
2500
2779
  },
2501
2780
  children: "Not getting it? Fill the form yourself \u2192"
2502
2781
  }
2782
+ ),
2783
+ onReportGlitchgrabProblem && phase !== "solved" && !glitchgrabOffer && /* @__PURE__ */ jsx2(
2784
+ "button",
2785
+ {
2786
+ type: "button",
2787
+ "data-gg-self-report": "",
2788
+ onClick: () => onReportGlitchgrabProblem(),
2789
+ style: {
2790
+ display: "block",
2791
+ // ~32px tap target; the negative margins keep the composer
2792
+ // from growing to make room for it.
2793
+ margin: "-2px auto -8px",
2794
+ border: "none",
2795
+ background: "transparent",
2796
+ color: t2.textMuted,
2797
+ fontSize: "11.5px",
2798
+ fontFamily: "inherit",
2799
+ padding: "10px 8px",
2800
+ cursor: "pointer",
2801
+ textDecoration: "underline",
2802
+ textUnderlineOffset: "2px"
2803
+ },
2804
+ children: "Assistant misbehaving? Tell Glitchgrab"
2805
+ }
2503
2806
  )
2504
2807
  ]
2505
2808
  }
@@ -2513,6 +2816,240 @@ function AssistSheet({
2513
2816
  document.body
2514
2817
  );
2515
2818
  }
2819
+ var FONT = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2820
+ var FAILED = "Couldn't send it. Try again in a moment.";
2821
+ function describeSentAlong(hasChat, screenshotCount) {
2822
+ const parts = [
2823
+ ...hasChat ? ["your AI chat"] : [],
2824
+ "what you did on this page",
2825
+ ...screenshotCount > 0 ? [`${screenshotCount} screenshot${screenshotCount === 1 ? "" : "s"}`] : []
2826
+ ];
2827
+ if (parts.length === 1) return parts[0];
2828
+ return `${parts.slice(0, -1).join(", ")} and ${parts[parts.length - 1]}`;
2829
+ }
2830
+ function GlitchgrabProblemPanel({
2831
+ send,
2832
+ theme: t2,
2833
+ surface,
2834
+ conversationId,
2835
+ reportType,
2836
+ screenshots,
2837
+ initialText = "",
2838
+ onClose
2839
+ }) {
2840
+ const [text, setText] = useState3(initialText);
2841
+ const [busy, setBusy] = useState3(false);
2842
+ const [sent, setSent] = useState3(false);
2843
+ const [error, setError] = useState3(null);
2844
+ const inputRef = useRef3(null);
2845
+ useEffect3(() => {
2846
+ var _a;
2847
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
2848
+ }, []);
2849
+ useEffect3(() => {
2850
+ const onKey = (e) => {
2851
+ if (e.key !== "Escape") return;
2852
+ e.stopPropagation();
2853
+ onClose();
2854
+ };
2855
+ window.addEventListener("keydown", onKey, true);
2856
+ return () => window.removeEventListener("keydown", onKey, true);
2857
+ }, [onClose]);
2858
+ const submit = async () => {
2859
+ const description = text.trim();
2860
+ if (!description || busy) return;
2861
+ setBusy(true);
2862
+ setError(null);
2863
+ try {
2864
+ const result = await send({ description, surface, conversationId, reportType, screenshots });
2865
+ if (result == null ? void 0 : result.success) setSent(true);
2866
+ else setError((result == null ? void 0 : result.message) || FAILED);
2867
+ } catch (e) {
2868
+ setError(FAILED);
2869
+ } finally {
2870
+ setBusy(false);
2871
+ }
2872
+ };
2873
+ const canSend = !!text.trim() && !busy;
2874
+ const secondaryButton = {
2875
+ padding: "10px 14px",
2876
+ borderRadius: "8px",
2877
+ border: `1px solid ${t2.inputBorder}`,
2878
+ background: "transparent",
2879
+ color: t2.text,
2880
+ fontSize: "13px",
2881
+ fontWeight: 600,
2882
+ fontFamily: "inherit",
2883
+ cursor: "pointer"
2884
+ };
2885
+ const primaryButton = (enabled) => ({
2886
+ padding: "10px 14px",
2887
+ borderRadius: "8px",
2888
+ border: "none",
2889
+ backgroundColor: enabled ? t2.accent : t2.bgSecondary,
2890
+ color: enabled ? t2.accentText : t2.textMuted,
2891
+ fontSize: "13px",
2892
+ fontWeight: 700,
2893
+ fontFamily: "inherit",
2894
+ cursor: enabled ? "pointer" : "default"
2895
+ });
2896
+ return createPortal2(
2897
+ // No close on backdrop click: a stray click would throw away what they typed.
2898
+ // `data-glitchgrab-layer` exempts this from the dialog's anti-focus-trap
2899
+ // sweep, which sets `inert` on every other role="dialog" on the page —
2900
+ // without it the panel renders but cannot be typed into.
2901
+ /* @__PURE__ */ jsx3(
2902
+ "div",
2903
+ {
2904
+ "data-glitchgrab-layer": "",
2905
+ "data-gg-self-report-panel": "",
2906
+ role: "dialog",
2907
+ "aria-modal": "true",
2908
+ "aria-labelledby": "gg-self-report-title",
2909
+ style: {
2910
+ position: "fixed",
2911
+ inset: 0,
2912
+ zIndex: 2147483647,
2913
+ backgroundColor: "rgba(0,0,0,0.55)",
2914
+ display: "flex",
2915
+ alignItems: "center",
2916
+ justifyContent: "center",
2917
+ padding: "16px",
2918
+ boxSizing: "border-box",
2919
+ fontFamily: FONT
2920
+ },
2921
+ children: /* @__PURE__ */ jsx3(
2922
+ "div",
2923
+ {
2924
+ style: {
2925
+ width: "100%",
2926
+ maxWidth: "420px",
2927
+ boxSizing: "border-box",
2928
+ backgroundColor: t2.bg,
2929
+ color: t2.text,
2930
+ border: `1px solid ${t2.border}`,
2931
+ borderRadius: "12px",
2932
+ boxShadow: "0 20px 50px rgba(0,0,0,0.5)",
2933
+ padding: "18px"
2934
+ },
2935
+ children: sent ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
2936
+ /* @__PURE__ */ jsx3("div", { id: "gg-self-report-title", style: { fontSize: "15px", fontWeight: 600 }, children: "Sent to the Glitchgrab team" }),
2937
+ /* @__PURE__ */ jsx3("p", { style: { margin: "6px 0 16px", fontSize: "13px", lineHeight: 1.5, color: t2.textMuted }, children: "Thanks \u2014 we'll look into it. Your report is still open behind this, exactly as you left it." }),
2938
+ /* @__PURE__ */ jsx3(
2939
+ "button",
2940
+ {
2941
+ type: "button",
2942
+ "data-gg-self-report-done": "",
2943
+ onClick: onClose,
2944
+ style: { ...primaryButton(true), width: "100%" },
2945
+ children: "Back to your report"
2946
+ }
2947
+ )
2948
+ ] }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
2949
+ /* @__PURE__ */ jsxs3(
2950
+ "div",
2951
+ {
2952
+ style: {
2953
+ display: "flex",
2954
+ alignItems: "flex-start",
2955
+ justifyContent: "space-between",
2956
+ gap: "12px"
2957
+ },
2958
+ children: [
2959
+ /* @__PURE__ */ jsx3("div", { id: "gg-self-report-title", style: { fontSize: "15px", fontWeight: 600 }, children: "Problem with Glitchgrab?" }),
2960
+ /* @__PURE__ */ jsx3(
2961
+ "button",
2962
+ {
2963
+ type: "button",
2964
+ onClick: onClose,
2965
+ "aria-label": "Close",
2966
+ style: {
2967
+ border: "none",
2968
+ background: "transparent",
2969
+ color: t2.textMuted,
2970
+ fontSize: "18px",
2971
+ lineHeight: 1,
2972
+ cursor: "pointer",
2973
+ padding: "4px 6px",
2974
+ margin: "-4px -6px 0 0"
2975
+ },
2976
+ children: "\xD7"
2977
+ }
2978
+ )
2979
+ ]
2980
+ }
2981
+ ),
2982
+ /* @__PURE__ */ jsx3("p", { style: { margin: "6px 0 12px", fontSize: "13px", lineHeight: 1.5, color: t2.textMuted }, children: "This goes to the people who build this reporter \u2014 not to this project's team. Tell us what went wrong: the AI chat, a button, anything." }),
2983
+ /* @__PURE__ */ jsx3(
2984
+ "textarea",
2985
+ {
2986
+ ref: inputRef,
2987
+ "data-gg-self-report-input": "",
2988
+ value: text,
2989
+ onChange: (e) => {
2990
+ setText(e.target.value);
2991
+ if (error) setError(null);
2992
+ },
2993
+ onKeyDown: (e) => {
2994
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
2995
+ e.preventDefault();
2996
+ void submit();
2997
+ }
2998
+ },
2999
+ rows: 4,
3000
+ placeholder: "e.g. The assistant kept asking the same question and never wrote a draft",
3001
+ style: {
3002
+ width: "100%",
3003
+ boxSizing: "border-box",
3004
+ resize: "vertical",
3005
+ padding: "10px 12px",
3006
+ borderRadius: "8px",
3007
+ border: `1px solid ${t2.inputBorder}`,
3008
+ backgroundColor: t2.inputBg,
3009
+ color: t2.text,
3010
+ fontSize: "14px",
3011
+ lineHeight: 1.45,
3012
+ fontFamily: "inherit",
3013
+ outline: "none"
3014
+ }
3015
+ }
3016
+ ),
3017
+ /* @__PURE__ */ jsxs3(
3018
+ "p",
3019
+ {
3020
+ "data-gg-self-report-includes": "",
3021
+ style: { margin: "8px 0 0", fontSize: "11.5px", lineHeight: 1.45, color: t2.textMuted },
3022
+ children: [
3023
+ "Also sent, so we can see what happened:",
3024
+ " ",
3025
+ describeSentAlong(conversationId !== null, screenshots.length),
3026
+ "."
3027
+ ]
3028
+ }
3029
+ ),
3030
+ error && /* @__PURE__ */ jsx3("p", { role: "alert", style: { margin: "8px 0 0", fontSize: "12px", color: "#ef4444" }, children: error }),
3031
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", justifyContent: "flex-end", gap: "8px", marginTop: "14px" }, children: [
3032
+ /* @__PURE__ */ jsx3("button", { type: "button", onClick: onClose, style: secondaryButton, children: "Cancel" }),
3033
+ /* @__PURE__ */ jsx3(
3034
+ "button",
3035
+ {
3036
+ type: "button",
3037
+ "data-gg-self-report-send": "",
3038
+ onClick: () => void submit(),
3039
+ disabled: !canSend,
3040
+ style: primaryButton(canSend),
3041
+ children: busy ? "Sending\u2026" : "Send to Glitchgrab"
3042
+ }
3043
+ )
3044
+ ] })
3045
+ ] })
3046
+ }
3047
+ )
3048
+ }
3049
+ ),
3050
+ document.body
3051
+ );
3052
+ }
2516
3053
  var GLITCHGRAB_SHORTCUT = "Ctrl+Shift+G";
2517
3054
  var GLITCHGRAB_SHORTCUT_MAC = "\u2318\u21E7G";
2518
3055
  function isMac() {
@@ -2560,6 +3097,7 @@ var ATTACHMENT_ACCEPT = [
2560
3097
  ].join(",");
2561
3098
  var MAX_SCALE = 2;
2562
3099
  var FRAME_TIMEOUT_MS = 3e3;
3100
+ var GRAB_TIMEOUT_MS = FRAME_TIMEOUT_MS + 2e3;
2563
3101
  function canCaptureTabPixels() {
2564
3102
  var _a;
2565
3103
  try {
@@ -2626,7 +3164,13 @@ async function captureViaTabPixels() {
2626
3164
  stream = await navigator.mediaDevices.getDisplayMedia(options);
2627
3165
  const surface = (_b = (_a = stream.getVideoTracks()[0]) == null ? void 0 : _a.getSettings()) == null ? void 0 : _b.displaySurface;
2628
3166
  if (surface && surface !== "browser") return null;
2629
- const canvas = await grabFrame(stream);
3167
+ let timer;
3168
+ const timedOut = new Promise((resolve) => {
3169
+ timer = setTimeout(() => resolve(null), GRAB_TIMEOUT_MS);
3170
+ });
3171
+ const canvas = await Promise.race([grabFrame(stream), timedOut]).finally(
3172
+ () => clearTimeout(timer)
3173
+ );
2630
3174
  return canvas ? encodeScreenshot(canvas) : null;
2631
3175
  } catch (e) {
2632
3176
  return null;
@@ -2634,6 +3178,10 @@ async function captureViaTabPixels() {
2634
3178
  stream == null ? void 0 : stream.getTracks().forEach((track) => track.stop());
2635
3179
  }
2636
3180
  }
3181
+ var IMAGE_TIMEOUT_MS = 3e3;
3182
+ function isGlitchgrabLayer(el) {
3183
+ return el.hasAttribute("data-glitchgrab-layer");
3184
+ }
2637
3185
  async function captureViaHtml2Canvas() {
2638
3186
  try {
2639
3187
  const { default: html2canvas } = await import("html2canvas-pro");
@@ -2643,6 +3191,8 @@ async function captureViaHtml2Canvas() {
2643
3191
  logging: false,
2644
3192
  useCORS: true,
2645
3193
  allowTaint: true,
3194
+ imageTimeout: IMAGE_TIMEOUT_MS,
3195
+ ignoreElements: isGlitchgrabLayer,
2646
3196
  x: window.scrollX,
2647
3197
  y: window.scrollY,
2648
3198
  width: window.innerWidth,
@@ -2655,12 +3205,40 @@ async function captureViaHtml2Canvas() {
2655
3205
  return null;
2656
3206
  }
2657
3207
  }
2658
- async function captureDefaultScreenshot() {
2659
- var _a;
2660
- return (_a = await captureViaTabPixels()) != null ? _a : await captureViaHtml2Canvas();
3208
+ var inFlight = null;
3209
+ function nextPaint() {
3210
+ return new Promise((resolve) => {
3211
+ const cap = setTimeout(resolve, 100);
3212
+ if (typeof requestAnimationFrame !== "function") return;
3213
+ requestAnimationFrame(
3214
+ () => setTimeout(() => {
3215
+ clearTimeout(cap);
3216
+ resolve();
3217
+ }, 0)
3218
+ );
3219
+ });
3220
+ }
3221
+ function captureDefaultScreenshot(options) {
3222
+ if (inFlight) return inFlight;
3223
+ inFlight = (async () => {
3224
+ const pixels = await captureViaTabPixels();
3225
+ if (pixels) return pixels;
3226
+ if (options == null ? void 0 : options.onRedraw) {
3227
+ try {
3228
+ options.onRedraw();
3229
+ } catch (e) {
3230
+ }
3231
+ await nextPaint();
3232
+ }
3233
+ return captureViaHtml2Canvas();
3234
+ })().finally(() => {
3235
+ inFlight = null;
3236
+ });
3237
+ return inFlight;
2661
3238
  }
2662
3239
  var SEVERITY_REQUIRED = "Pick how bad it is before sending.";
2663
- function useIsDark() {
3240
+ var SHOT_WAIT_MS = 3e3;
3241
+ function detectDark() {
2664
3242
  if (typeof window === "undefined") return true;
2665
3243
  try {
2666
3244
  for (const el of [document.body, document.documentElement]) {
@@ -2783,9 +3361,9 @@ function ReporterChip({
2783
3361
  t: t2
2784
3362
  }) {
2785
3363
  var _a;
2786
- const [avatarFailed, setAvatarFailed] = useState3(false);
3364
+ const [avatarFailed, setAvatarFailed] = useState4(false);
2787
3365
  const avatarUrl = (reporter == null ? void 0 : reporter.avatarUrl) || "";
2788
- useEffect3(() => {
3366
+ useEffect4(() => {
2789
3367
  setAvatarFailed(false);
2790
3368
  }, [avatarUrl]);
2791
3369
  const name = ((_a = reporter == null ? void 0 : reporter.name) == null ? void 0 : _a.trim()) || "";
@@ -2794,13 +3372,13 @@ function ReporterChip({
2794
3372
  const label = isAnonymous ? "Anonymous" : name;
2795
3373
  const title = isAnonymous ? "No reporter identity was passed to Glitchgrab \u2014 this report won't be attributed to anyone" : [name, reporter == null ? void 0 : reporter.email, reporter == null ? void 0 : reporter.role].filter(Boolean).join(" \xB7 ");
2796
3374
  const showAvatarImage = !!avatarUrl && !avatarFailed;
2797
- return /* @__PURE__ */ jsxs3(
3375
+ return /* @__PURE__ */ jsxs4(
2798
3376
  "span",
2799
3377
  {
2800
3378
  title,
2801
3379
  style: { display: "flex", alignItems: "center", gap: "6px", minWidth: 0 },
2802
3380
  children: [
2803
- /* @__PURE__ */ jsx3(
3381
+ /* @__PURE__ */ jsx4(
2804
3382
  "span",
2805
3383
  {
2806
3384
  "aria-hidden": "true",
@@ -2820,7 +3398,7 @@ function ReporterChip({
2820
3398
  color: isAnonymous ? t2.textMuted : t2.accentText,
2821
3399
  border: `1px solid ${isAnonymous ? t2.inputBorder : "transparent"}`
2822
3400
  },
2823
- children: showAvatarImage ? /* @__PURE__ */ jsx3(
3401
+ children: showAvatarImage ? /* @__PURE__ */ jsx4(
2824
3402
  "img",
2825
3403
  {
2826
3404
  src: avatarUrl,
@@ -2830,9 +3408,9 @@ function ReporterChip({
2830
3408
  onError: () => setAvatarFailed(true),
2831
3409
  style: { width: "100%", height: "100%", objectFit: "cover" }
2832
3410
  }
2833
- ) : initials ? initials : /* @__PURE__ */ jsxs3("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "none", children: [
2834
- /* @__PURE__ */ jsx3("circle", { cx: "8", cy: "5.5", r: "2.75", stroke: "currentColor", strokeWidth: "1.4" }),
2835
- /* @__PURE__ */ jsx3(
3411
+ ) : initials ? initials : /* @__PURE__ */ jsxs4("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "none", children: [
3412
+ /* @__PURE__ */ jsx4("circle", { cx: "8", cy: "5.5", r: "2.75", stroke: "currentColor", strokeWidth: "1.4" }),
3413
+ /* @__PURE__ */ jsx4(
2836
3414
  "path",
2837
3415
  {
2838
3416
  d: "M2.75 13.5c0-2.35 2.35-3.75 5.25-3.75s5.25 1.4 5.25 3.75",
@@ -2844,7 +3422,7 @@ function ReporterChip({
2844
3422
  ] })
2845
3423
  }
2846
3424
  ),
2847
- /* @__PURE__ */ jsxs3(
3425
+ /* @__PURE__ */ jsxs4(
2848
3426
  "span",
2849
3427
  {
2850
3428
  style: {
@@ -2973,43 +3551,49 @@ function ReportDialog({
2973
3551
  captureScreenshot = captureDefaultScreenshot,
2974
3552
  reporter,
2975
3553
  onClose,
2976
- headerSlot
3554
+ headerSlot,
3555
+ reportGlitchgrabProblem
2977
3556
  }) {
2978
3557
  var _a;
2979
- const [isEnhancing, setIsEnhancing] = useState3(false);
2980
- const [assistOpen, setAssistOpen] = useState3(false);
2981
- const [assistNotice, setAssistNotice] = useState3(null);
2982
- const [assistUsed, setAssistUsed] = useState3(false);
2983
- const [typeChosen, setTypeChosen] = useState3(false);
2984
- const [duplicateIssueNumber, setDuplicateIssueNumber] = useState3(null);
2985
- const [aiConversationId, setAiConversationId] = useState3(null);
2986
- const [isEnhanced, setIsEnhanced] = useState3(false);
2987
- const [originalDescription, setOriginalDescription] = useState3(
3558
+ const [isEnhancing, setIsEnhancing] = useState4(false);
3559
+ const [assistOpen, setAssistOpen] = useState4(false);
3560
+ const [assistNotice, setAssistNotice] = useState4(null);
3561
+ const [assistUsed, setAssistUsed] = useState4(false);
3562
+ const [selfReportFrom, setSelfReportFrom] = useState4(null);
3563
+ const [selfReportPrefill, setSelfReportPrefill] = useState4("");
3564
+ const [typeChosen, setTypeChosen] = useState4(false);
3565
+ const [duplicateIssueNumber, setDuplicateIssueNumber] = useState4(null);
3566
+ const [aiConversationId, setAiConversationId] = useState4(null);
3567
+ const [isEnhanced, setIsEnhanced] = useState4(false);
3568
+ const [originalDescription, setOriginalDescription] = useState4(
2988
3569
  null
2989
3570
  );
2990
- const [isListening, setIsListening] = useState3(false);
2991
- const [isTranscribing, setIsTranscribing] = useState3(false);
2992
- const [voiceError, setVoiceError] = useState3(null);
2993
- const [screenshotDragOver, setScreenshotDragOver] = useState3(false);
2994
- const [mounted, setMounted] = useState3(false);
2995
- useEffect3(() => {
3571
+ const [isListening, setIsListening] = useState4(false);
3572
+ const [isTranscribing, setIsTranscribing] = useState4(false);
3573
+ const [voiceError, setVoiceError] = useState4(null);
3574
+ const [screenshotDragOver, setScreenshotDragOver] = useState4(false);
3575
+ const [mounted, setMounted] = useState4(false);
3576
+ useEffect4(() => {
2996
3577
  setMounted(true);
2997
3578
  }, []);
2998
- const [isOpen, setIsOpen] = useState3(false);
2999
- const [description, setDescription] = useState3("");
3000
- const [isSubmitting, setIsSubmitting] = useState3(false);
3001
- const [submitted, setSubmitted] = useState3(false);
3002
- const [screenshots, setScreenshots] = useState3([]);
3003
- const [pageShot, setPageShot] = useState3(null);
3004
- const [attachments, setAttachments] = useState3([]);
3005
- const [previewIndex, setPreviewIndex] = useState3(null);
3006
- const [annotatingIndex, setAnnotatingIndex] = useState3(null);
3007
- const [previewZoomed, setPreviewZoomed] = useState3(false);
3008
- const [previewNatural, setPreviewNatural] = useState3(null);
3009
- const previewScrollRef = useRef3(null);
3010
- const previewImgElRef = useRef3(null);
3011
- const panRef = useRef3(null);
3012
- const zoomAnchorRef = useRef3(null);
3579
+ const [isOpen, setIsOpen] = useState4(false);
3580
+ const [description, setDescription] = useState4("");
3581
+ const [isSubmitting, setIsSubmitting] = useState4(false);
3582
+ const [submitted, setSubmitted] = useState4(false);
3583
+ const [screenshots, setScreenshots] = useState4([]);
3584
+ const [pageShot, setPageShot] = useState4(null);
3585
+ const [shotPending, setShotPending] = useState4(false);
3586
+ const pendingShotRef = useRef4(null);
3587
+ const openGenRef = useRef4(0);
3588
+ const [attachments, setAttachments] = useState4([]);
3589
+ const [previewIndex, setPreviewIndex] = useState4(null);
3590
+ const [annotatingIndex, setAnnotatingIndex] = useState4(null);
3591
+ const [previewZoomed, setPreviewZoomed] = useState4(false);
3592
+ const [previewNatural, setPreviewNatural] = useState4(null);
3593
+ const previewScrollRef = useRef4(null);
3594
+ const previewImgElRef = useRef4(null);
3595
+ const panRef = useRef4(null);
3596
+ const zoomAnchorRef = useRef4(null);
3013
3597
  const resetPreviewZoom = () => {
3014
3598
  setPreviewZoomed(false);
3015
3599
  setPreviewNatural(null);
@@ -3023,24 +3607,24 @@ function ReportDialog({
3023
3607
  resetPreviewZoom();
3024
3608
  setPreviewIndex(null);
3025
3609
  };
3026
- const fileInputRef = useRef3(null);
3027
- const modalRef = useRef3(null);
3028
- const previewImgRef = useRef3(null);
3029
- const textareaRef = useRef3(null);
3030
- const recognitionRef = useRef3(null);
3031
- const voiceBaseRef = useRef3("");
3032
- const usingWebSpeechRef = useRef3(false);
3033
- const textBeforeVoiceRef = useRef3("");
3034
- const mediaRecorderRef = useRef3(null);
3035
- const streamRef = useRef3(null);
3036
- const sarvamChunksRef = useRef3([]);
3037
- const spaceTimerRef = useRef3(null);
3038
- const isPushToTalkRef = useRef3(false);
3039
- const spaceEditsRef = useRef3(0);
3040
- const descriptionRef = useRef3("");
3041
- const lastVoiceTextRef = useRef3(null);
3042
- const hadWebSpeechRef = useRef3(false);
3043
- useEffect3(() => {
3610
+ const fileInputRef = useRef4(null);
3611
+ const modalRef = useRef4(null);
3612
+ const previewImgRef = useRef4(null);
3613
+ const textareaRef = useRef4(null);
3614
+ const recognitionRef = useRef4(null);
3615
+ const voiceBaseRef = useRef4("");
3616
+ const usingWebSpeechRef = useRef4(false);
3617
+ const textBeforeVoiceRef = useRef4("");
3618
+ const mediaRecorderRef = useRef4(null);
3619
+ const streamRef = useRef4(null);
3620
+ const sarvamChunksRef = useRef4([]);
3621
+ const spaceTimerRef = useRef4(null);
3622
+ const isPushToTalkRef = useRef4(false);
3623
+ const spaceEditsRef = useRef4(0);
3624
+ const descriptionRef = useRef4("");
3625
+ const lastVoiceTextRef = useRef4(null);
3626
+ const hadWebSpeechRef = useRef4(false);
3627
+ useEffect4(() => {
3044
3628
  if (!isOpen) return;
3045
3629
  const HOST_LAYERS = '[role="dialog"],[role="alertdialog"],[role="menu"],[role="listbox"]';
3046
3630
  const inerted = /* @__PURE__ */ new Set();
@@ -3066,13 +3650,13 @@ function ReportDialog({
3066
3650
  inerted.forEach((el) => el.removeAttribute("inert"));
3067
3651
  };
3068
3652
  }, [isOpen]);
3069
- const [step, setStep] = useState3(1);
3070
- const [reportType, setReportType] = useState3("BUG");
3071
- const [severity, setSeverity] = useState3(null);
3072
- const [validationError, setValidationError] = useState3(null);
3073
- const [placeholderIdx, setPlaceholderIdx] = useState3(0);
3074
- const [rating, setRating] = useState3(0);
3075
- const [hoveredStar, setHoveredStar] = useState3(0);
3653
+ const [step, setStep] = useState4(1);
3654
+ const [reportType, setReportType] = useState4("BUG");
3655
+ const [severity, setSeverity] = useState4(null);
3656
+ const [validationError, setValidationError] = useState4(null);
3657
+ const [placeholderIdx, setPlaceholderIdx] = useState4(0);
3658
+ const [rating, setRating] = useState4(0);
3659
+ const [hoveredStar, setHoveredStar] = useState4(0);
3076
3660
  const isRating = reportType === "RATING";
3077
3661
  const submitDisabled = isSubmitting || (isRating ? rating < 1 : !description.trim());
3078
3662
  const needsSeverity = validationError === SEVERITY_REQUIRED && showSeverity && reportType === "BUG" && !severity;
@@ -3084,8 +3668,8 @@ function ReportDialog({
3084
3668
  "SECURITY",
3085
3669
  "QUESTION"
3086
3670
  ];
3087
- const tileGridRef = useRef3(null);
3088
- useEffect3(() => {
3671
+ const tileGridRef = useRef4(null);
3672
+ useEffect4(() => {
3089
3673
  if (!isOpen || step !== 1) return;
3090
3674
  const onKey = (e) => {
3091
3675
  const el = e.target;
@@ -3129,8 +3713,19 @@ function ReportDialog({
3129
3713
  const next = current === -1 ? 0 : Math.min(Math.max(current + delta, 0), tiles.length - 1);
3130
3714
  (_c = tiles[next]) == null ? void 0 : _c.focus();
3131
3715
  };
3132
- const isDark = useIsDark();
3716
+ const isDark = useMemo(() => isOpen ? detectDark() : true, [isOpen]);
3133
3717
  const t2 = getTheme(isDark);
3718
+ const layerTheme = {
3719
+ bg: t2.bg,
3720
+ bgSecondary: t2.bgSecondary,
3721
+ border: t2.border,
3722
+ text: t2.text,
3723
+ textMuted: t2.textMuted,
3724
+ inputBg: t2.inputBg,
3725
+ inputBorder: t2.inputBorder,
3726
+ accent: t2.accent,
3727
+ accentText: t2.accentText
3728
+ };
3134
3729
  const canZoomPreview = previewNatural !== null && typeof window !== "undefined" && (previewNatural.w > window.innerWidth - 32 || previewNatural.h > window.innerHeight - 80);
3135
3730
  const handleFileUpload = (e) => {
3136
3731
  const files = e.target.files;
@@ -3139,24 +3734,28 @@ function ReportDialog({
3139
3734
  e.target.value = "";
3140
3735
  };
3141
3736
  const addFiles = (files) => {
3142
- files.forEach((file) => {
3737
+ const images = files.filter((file) => file.type.startsWith("image/"));
3738
+ if (images.length > 0) {
3739
+ void Promise.all(images.map((file) => encodeImageFile(file).catch(() => null))).then(
3740
+ (encoded) => {
3741
+ const added = encoded.filter((url) => !!url);
3742
+ if (added.length > 0) setScreenshots((prev) => [...prev, ...added]);
3743
+ }
3744
+ );
3745
+ }
3746
+ files.filter((file) => !file.type.startsWith("image/")).forEach((file) => {
3143
3747
  const reader = new FileReader();
3144
- if (file.type.startsWith("image/")) {
3145
- reader.onload = () => {
3146
- setScreenshots((prev) => [...prev, reader.result]);
3147
- };
3148
- } else {
3149
- reader.onload = () => {
3150
- setAttachments((prev) => [
3151
- ...prev,
3152
- { name: file.name, size: file.size, dataUrl: reader.result }
3153
- ]);
3154
- };
3155
- }
3748
+ reader.onload = () => {
3749
+ setAttachments((prev) => [
3750
+ ...prev,
3751
+ { name: file.name, size: file.size, dataUrl: reader.result }
3752
+ ]);
3753
+ };
3156
3754
  reader.readAsDataURL(file);
3157
3755
  });
3158
3756
  };
3159
3757
  const handleOpen = async () => {
3758
+ const gen = openGenRef.current;
3160
3759
  setSubmitted(false);
3161
3760
  closePreview();
3162
3761
  setAnnotatingIndex(null);
@@ -3165,13 +3764,34 @@ function ReportDialog({
3165
3764
  setTypeChosen(true);
3166
3765
  setStep(2);
3167
3766
  }
3168
- const shot = await captureScreenshot();
3767
+ const show = () => {
3768
+ if (gen !== openGenRef.current) return;
3769
+ if (assist && !assistUsed) setAssistOpen(true);
3770
+ setIsOpen(true);
3771
+ };
3772
+ const capture = captureScreenshot({
3773
+ onRedraw: () => {
3774
+ if (gen !== openGenRef.current) return;
3775
+ setShotPending(true);
3776
+ show();
3777
+ }
3778
+ });
3779
+ pendingShotRef.current = capture;
3780
+ const previousPageShot = pageShot;
3781
+ const shot = await capture.catch(() => null);
3782
+ if (gen !== openGenRef.current) return;
3783
+ pendingShotRef.current = null;
3784
+ setShotPending(false);
3169
3785
  setPageShot(shot != null ? shot : null);
3170
- if (shot) setScreenshots([shot]);
3171
- if (assist && !assistUsed) setAssistOpen(true);
3172
- setIsOpen(true);
3786
+ if (shot) {
3787
+ setScreenshots((prev) => [
3788
+ shot,
3789
+ ...prev.filter((s) => s !== shot && s !== previousPageShot)
3790
+ ]);
3791
+ }
3792
+ show();
3173
3793
  };
3174
- useEffect3(() => {
3794
+ useEffect4(() => {
3175
3795
  const handler = (e) => {
3176
3796
  if (isOpen) return;
3177
3797
  const detail = e.detail;
@@ -3186,7 +3806,7 @@ function ReportDialog({
3186
3806
  window.addEventListener("glitchgrab:open-report", handler);
3187
3807
  return () => window.removeEventListener("glitchgrab:open-report", handler);
3188
3808
  }, [isOpen, handleOpen]);
3189
- useEffect3(() => {
3809
+ useEffect4(() => {
3190
3810
  if (!isOpen) return;
3191
3811
  const handleEsc = (e) => {
3192
3812
  if (e.key === "Escape") {
@@ -3199,7 +3819,7 @@ function ReportDialog({
3199
3819
  document.addEventListener("keydown", handleEsc);
3200
3820
  return () => document.removeEventListener("keydown", handleEsc);
3201
3821
  }, [isOpen, previewIndex, previewZoomed, annotatingIndex]);
3202
- useEffect3(() => {
3822
+ useEffect4(() => {
3203
3823
  if (previewIndex === null || annotatingIndex !== null) return;
3204
3824
  const handlePointerDown = (e) => {
3205
3825
  var _a2;
@@ -3210,7 +3830,7 @@ function ReportDialog({
3210
3830
  document.addEventListener("pointerdown", handlePointerDown, true);
3211
3831
  return () => document.removeEventListener("pointerdown", handlePointerDown, true);
3212
3832
  }, [previewIndex, annotatingIndex]);
3213
- useEffect3(() => {
3833
+ useEffect4(() => {
3214
3834
  var _a2;
3215
3835
  const el = previewScrollRef.current;
3216
3836
  if (!previewZoomed || !el) return;
@@ -3272,7 +3892,7 @@ function ReportDialog({
3272
3892
  panRef.current = null;
3273
3893
  }
3274
3894
  };
3275
- useEffect3(() => {
3895
+ useEffect4(() => {
3276
3896
  if (!isOpen) return;
3277
3897
  const handlePaste = (e) => {
3278
3898
  var _a2;
@@ -3295,14 +3915,14 @@ function ReportDialog({
3295
3915
  window.addEventListener("paste", handlePaste);
3296
3916
  return () => window.removeEventListener("paste", handlePaste);
3297
3917
  }, [isOpen]);
3298
- useEffect3(() => {
3918
+ useEffect4(() => {
3299
3919
  if (!isOpen || !transcribeAudio2) return;
3300
3920
  const id = setInterval(() => {
3301
3921
  setPlaceholderIdx((i) => (i + 1) % 2);
3302
3922
  }, 3e3);
3303
3923
  return () => clearInterval(id);
3304
3924
  }, [isOpen, transcribeAudio2]);
3305
- useEffect3(() => {
3925
+ useEffect4(() => {
3306
3926
  descriptionRef.current = description;
3307
3927
  }, [description]);
3308
3928
  const rebaseVoiceOnUserEdits = () => {
@@ -3347,7 +3967,7 @@ function ReportDialog({
3347
3967
  }
3348
3968
  };
3349
3969
  const sheetUp = !!assist && assistOpen;
3350
- useEffect3(() => {
3970
+ useEffect4(() => {
3351
3971
  const el = modalRef.current;
3352
3972
  if (!el) return;
3353
3973
  if (sheetUp) {
@@ -3362,6 +3982,9 @@ function ReportDialog({
3362
3982
  stopVoice();
3363
3983
  setIsOpen(false);
3364
3984
  onClose == null ? void 0 : onClose();
3985
+ openGenRef.current += 1;
3986
+ pendingShotRef.current = null;
3987
+ setShotPending(false);
3365
3988
  closePreview();
3366
3989
  setAnnotatingIndex(null);
3367
3990
  setStep(1);
@@ -3372,6 +3995,7 @@ function ReportDialog({
3372
3995
  setDuplicateIssueNumber(null);
3373
3996
  setSeverity(null);
3374
3997
  setValidationError(null);
3998
+ setSelfReportFrom(null);
3375
3999
  setVoiceError(null);
3376
4000
  setIsEnhanced(false);
3377
4001
  setOriginalDescription(null);
@@ -3594,8 +4218,19 @@ function ReportDialog({
3594
4218
  return;
3595
4219
  }
3596
4220
  setIsSubmitting(true);
4221
+ let shots = screenshots;
4222
+ const pending = pendingShotRef.current;
4223
+ if (pending) {
4224
+ const shot = await Promise.race([
4225
+ pending.catch(() => null),
4226
+ new Promise((resolve) => setTimeout(() => resolve(null), SHOT_WAIT_MS))
4227
+ ]);
4228
+ if (shot && !shots.includes(shot)) {
4229
+ shots = [shot, ...shots.filter((s) => s !== pageShot)];
4230
+ }
4231
+ }
3597
4232
  const metadata = {};
3598
- if (screenshots.length > 0) metadata.screenshots = JSON.stringify(screenshots);
4233
+ if (shots.length > 0) metadata.screenshots = JSON.stringify(shots);
3599
4234
  if (attachments.length > 0) metadata.attachments = JSON.stringify(attachments);
3600
4235
  if (showSeverity && reportType === "BUG" && severity) {
3601
4236
  metadata.severity = severity;
@@ -3631,9 +4266,9 @@ function ReportDialog({
3631
4266
  }
3632
4267
  };
3633
4268
  if (!mounted) return null;
3634
- return /* @__PURE__ */ jsxs3(Fragment2, { children: [
3635
- isOpen && createPortal2(
3636
- /* @__PURE__ */ jsx3("style", { children: `
4269
+ return /* @__PURE__ */ jsxs4(Fragment3, { children: [
4270
+ isOpen && createPortal3(
4271
+ /* @__PURE__ */ jsx4("style", { children: `
3637
4272
  @keyframes gg-pulse{0%,100%{opacity:1}50%{opacity:0.35}}
3638
4273
  @keyframes gg-b1{0%,100%{height:3px}40%{height:13px}}
3639
4274
  @keyframes gg-b2{0%,100%{height:8px}50%{height:3px}}
@@ -3669,8 +4304,8 @@ function ReportDialog({
3669
4304
  ` }),
3670
4305
  document.body
3671
4306
  ),
3672
- isOpen && createPortal2(
3673
- /* @__PURE__ */ jsx3(
4307
+ isOpen && createPortal3(
4308
+ /* @__PURE__ */ jsx4(
3674
4309
  "div",
3675
4310
  {
3676
4311
  "data-glitchgrab-layer": "",
@@ -3693,10 +4328,13 @@ function ReportDialog({
3693
4328
  },
3694
4329
  onPointerDown: (e) => e.stopPropagation(),
3695
4330
  onFocus: (e) => e.stopPropagation(),
3696
- children: /* @__PURE__ */ jsxs3(
4331
+ children: /* @__PURE__ */ jsxs4(
3697
4332
  "div",
3698
4333
  {
3699
4334
  ref: modalRef,
4335
+ role: "dialog",
4336
+ "aria-modal": "true",
4337
+ "aria-label": "Report an issue",
3700
4338
  onClick: (e) => e.stopPropagation(),
3701
4339
  style: {
3702
4340
  position: "relative",
@@ -3715,7 +4353,7 @@ function ReportDialog({
3715
4353
  isolation: "isolate"
3716
4354
  },
3717
4355
  children: [
3718
- /* @__PURE__ */ jsxs3(
4356
+ /* @__PURE__ */ jsxs4(
3719
4357
  "div",
3720
4358
  {
3721
4359
  style: {
@@ -3724,7 +4362,7 @@ function ReportDialog({
3724
4362
  borderBottom: `1px solid ${t2.border}`
3725
4363
  },
3726
4364
  children: [
3727
- /* @__PURE__ */ jsxs3(
4365
+ /* @__PURE__ */ jsxs4(
3728
4366
  "div",
3729
4367
  {
3730
4368
  style: {
@@ -3733,7 +4371,7 @@ function ReportDialog({
3733
4371
  alignItems: "center"
3734
4372
  },
3735
4373
  children: [
3736
- /* @__PURE__ */ jsxs3(
4374
+ /* @__PURE__ */ jsxs4(
3737
4375
  "div",
3738
4376
  {
3739
4377
  style: {
@@ -3742,7 +4380,7 @@ function ReportDialog({
3742
4380
  gap: "8px"
3743
4381
  },
3744
4382
  children: [
3745
- step > 1 && /* @__PURE__ */ jsx3(
4383
+ step > 1 && /* @__PURE__ */ jsx4(
3746
4384
  "button",
3747
4385
  {
3748
4386
  type: "button",
@@ -3756,14 +4394,14 @@ function ReportDialog({
3756
4394
  alignItems: "center"
3757
4395
  },
3758
4396
  "aria-label": "Back",
3759
- children: /* @__PURE__ */ jsx3(
4397
+ children: /* @__PURE__ */ jsx4(
3760
4398
  "svg",
3761
4399
  {
3762
4400
  width: "16",
3763
4401
  height: "16",
3764
4402
  viewBox: "0 0 16 16",
3765
4403
  fill: "none",
3766
- children: /* @__PURE__ */ jsx3(
4404
+ children: /* @__PURE__ */ jsx4(
3767
4405
  "path",
3768
4406
  {
3769
4407
  d: "M10 3L5 8L10 13",
@@ -3777,7 +4415,7 @@ function ReportDialog({
3777
4415
  )
3778
4416
  }
3779
4417
  ),
3780
- /* @__PURE__ */ jsx3(
4418
+ /* @__PURE__ */ jsx4(
3781
4419
  "span",
3782
4420
  {
3783
4421
  style: {
@@ -3791,7 +4429,7 @@ function ReportDialog({
3791
4429
  ]
3792
4430
  }
3793
4431
  ),
3794
- /* @__PURE__ */ jsxs3(
4432
+ /* @__PURE__ */ jsxs4(
3795
4433
  "div",
3796
4434
  {
3797
4435
  style: {
@@ -3800,7 +4438,7 @@ function ReportDialog({
3800
4438
  gap: "8px"
3801
4439
  },
3802
4440
  children: [
3803
- step === 1 && /* @__PURE__ */ jsx3(
4441
+ step === 1 && /* @__PURE__ */ jsx4(
3804
4442
  "span",
3805
4443
  {
3806
4444
  title: "Press this anywhere to open Glitchgrab",
@@ -3818,7 +4456,7 @@ function ReportDialog({
3818
4456
  children: getShortcutLabel()
3819
4457
  }
3820
4458
  ),
3821
- /* @__PURE__ */ jsx3(
4459
+ /* @__PURE__ */ jsx4(
3822
4460
  "button",
3823
4461
  {
3824
4462
  type: "button",
@@ -3833,7 +4471,7 @@ function ReportDialog({
3833
4471
  justifyContent: "center"
3834
4472
  },
3835
4473
  "aria-label": "Close",
3836
- children: /* @__PURE__ */ jsx3(
4474
+ children: /* @__PURE__ */ jsx4(
3837
4475
  "svg",
3838
4476
  {
3839
4477
  width: "16",
@@ -3841,7 +4479,7 @@ function ReportDialog({
3841
4479
  viewBox: "0 0 16 16",
3842
4480
  fill: "none",
3843
4481
  style: { display: "block" },
3844
- children: /* @__PURE__ */ jsx3(
4482
+ children: /* @__PURE__ */ jsx4(
3845
4483
  "path",
3846
4484
  {
3847
4485
  d: "M4 4L12 12M12 4L4 12",
@@ -3860,7 +4498,7 @@ function ReportDialog({
3860
4498
  ]
3861
4499
  }
3862
4500
  ),
3863
- /* @__PURE__ */ jsx3(
4501
+ /* @__PURE__ */ jsx4(
3864
4502
  "div",
3865
4503
  {
3866
4504
  style: {
@@ -3870,12 +4508,12 @@ function ReportDialog({
3870
4508
  gap: "0",
3871
4509
  marginTop: "12px"
3872
4510
  },
3873
- children: [1, 2].map((s, i) => /* @__PURE__ */ jsxs3(
4511
+ children: [1, 2].map((s, i) => /* @__PURE__ */ jsxs4(
3874
4512
  "div",
3875
4513
  {
3876
4514
  style: { display: "flex", alignItems: "center" },
3877
4515
  children: [
3878
- /* @__PURE__ */ jsx3(
4516
+ /* @__PURE__ */ jsx4(
3879
4517
  "div",
3880
4518
  {
3881
4519
  style: {
@@ -3887,7 +4525,7 @@ function ReportDialog({
3887
4525
  }
3888
4526
  }
3889
4527
  ),
3890
- i < 1 && /* @__PURE__ */ jsx3(
4528
+ i < 1 && /* @__PURE__ */ jsx4(
3891
4529
  "div",
3892
4530
  {
3893
4531
  style: {
@@ -3907,7 +4545,7 @@ function ReportDialog({
3907
4545
  ]
3908
4546
  }
3909
4547
  ),
3910
- /* @__PURE__ */ jsx3(
4548
+ /* @__PURE__ */ jsx4(
3911
4549
  "div",
3912
4550
  {
3913
4551
  style: {
@@ -3916,7 +4554,7 @@ function ReportDialog({
3916
4554
  flex: "1 1 auto",
3917
4555
  minHeight: 0
3918
4556
  },
3919
- children: submitted ? /* @__PURE__ */ jsxs3(
4557
+ children: submitted ? /* @__PURE__ */ jsxs4(
3920
4558
  "div",
3921
4559
  {
3922
4560
  style: {
@@ -3931,9 +4569,9 @@ function ReportDialog({
3931
4569
  " sent. Thank you!"
3932
4570
  ]
3933
4571
  }
3934
- ) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
3935
- step === 1 && headerSlot ? /* @__PURE__ */ jsx3("div", { style: { marginBottom: "14px" }, children: headerSlot }) : null,
3936
- step === 1 && sendFeedback2 && /* @__PURE__ */ jsxs3(
4572
+ ) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
4573
+ step === 1 && headerSlot ? /* @__PURE__ */ jsx4("div", { style: { marginBottom: "14px" }, children: headerSlot }) : null,
4574
+ step === 1 && sendFeedback2 && /* @__PURE__ */ jsxs4(
3937
4575
  "div",
3938
4576
  {
3939
4577
  style: {
@@ -3950,16 +4588,16 @@ function ReportDialog({
3950
4588
  },
3951
4589
  onMouseLeave: () => setHoveredStar(0),
3952
4590
  children: [
3953
- /* @__PURE__ */ jsx3(
4591
+ /* @__PURE__ */ jsx4(
3954
4592
  "span",
3955
4593
  {
3956
4594
  style: { fontSize: "13px", fontWeight: 600, color: t2.text },
3957
4595
  children: "How are we doing?"
3958
4596
  }
3959
4597
  ),
3960
- /* @__PURE__ */ jsx3("span", { style: { display: "flex", gap: "4px" }, children: [1, 2, 3, 4, 5].map((star) => {
4598
+ /* @__PURE__ */ jsx4("span", { style: { display: "flex", gap: "4px" }, children: [1, 2, 3, 4, 5].map((star) => {
3961
4599
  const filled = star <= (hoveredStar || rating);
3962
- return /* @__PURE__ */ jsx3(
4600
+ return /* @__PURE__ */ jsx4(
3963
4601
  "button",
3964
4602
  {
3965
4603
  type: "button",
@@ -3980,7 +4618,7 @@ function ReportDialog({
3980
4618
  cursor: "pointer",
3981
4619
  lineHeight: 0
3982
4620
  },
3983
- children: /* @__PURE__ */ jsx3("svg", { width: "26", height: "26", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(
4621
+ children: /* @__PURE__ */ jsx4("svg", { width: "26", height: "26", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(
3984
4622
  "path",
3985
4623
  {
3986
4624
  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",
@@ -3997,7 +4635,7 @@ function ReportDialog({
3997
4635
  ]
3998
4636
  }
3999
4637
  ),
4000
- step === 1 && sendFeedback2 && /* @__PURE__ */ jsxs3(
4638
+ step === 1 && sendFeedback2 && /* @__PURE__ */ jsxs4(
4001
4639
  "div",
4002
4640
  {
4003
4641
  style: {
@@ -4007,13 +4645,13 @@ function ReportDialog({
4007
4645
  marginBottom: "16px"
4008
4646
  },
4009
4647
  children: [
4010
- /* @__PURE__ */ jsx3("span", { style: { flex: 1, height: "1px", background: t2.border } }),
4011
- /* @__PURE__ */ jsx3("span", { style: { fontSize: "11px", color: t2.textMuted }, children: "or report something" }),
4012
- /* @__PURE__ */ jsx3("span", { style: { flex: 1, height: "1px", background: t2.border } })
4648
+ /* @__PURE__ */ jsx4("span", { style: { flex: 1, height: "1px", background: t2.border } }),
4649
+ /* @__PURE__ */ jsx4("span", { style: { fontSize: "11px", color: t2.textMuted }, children: "or report something" }),
4650
+ /* @__PURE__ */ jsx4("span", { style: { flex: 1, height: "1px", background: t2.border } })
4013
4651
  ]
4014
4652
  }
4015
4653
  ),
4016
- step === 1 && screenshots.length > 0 && /* @__PURE__ */ jsxs3(
4654
+ step === 1 && screenshots.length > 0 && /* @__PURE__ */ jsxs4(
4017
4655
  "div",
4018
4656
  {
4019
4657
  style: {
@@ -4027,7 +4665,7 @@ function ReportDialog({
4027
4665
  background: t2.inputBg
4028
4666
  },
4029
4667
  children: [
4030
- /* @__PURE__ */ jsx3(
4668
+ /* @__PURE__ */ jsx4(
4031
4669
  "img",
4032
4670
  {
4033
4671
  src: screenshots[0],
@@ -4042,8 +4680,8 @@ function ReportDialog({
4042
4680
  }
4043
4681
  }
4044
4682
  ),
4045
- /* @__PURE__ */ jsx3("span", { style: { fontSize: "11px", color: t2.textMuted, flex: 1 }, children: "Screenshot attached" }),
4046
- /* @__PURE__ */ jsx3(
4683
+ /* @__PURE__ */ jsx4("span", { style: { fontSize: "11px", color: t2.textMuted, flex: 1 }, children: "Screenshot attached" }),
4684
+ /* @__PURE__ */ jsx4(
4047
4685
  "button",
4048
4686
  {
4049
4687
  type: "button",
@@ -4064,7 +4702,7 @@ function ReportDialog({
4064
4702
  ]
4065
4703
  }
4066
4704
  ),
4067
- step === 1 && /* @__PURE__ */ jsx3(
4705
+ step === 1 && /* @__PURE__ */ jsx4(
4068
4706
  "div",
4069
4707
  {
4070
4708
  ref: tileGridRef,
@@ -4074,7 +4712,7 @@ function ReportDialog({
4074
4712
  gridTemplateColumns: "1fr 1fr 1fr",
4075
4713
  gap: "10px"
4076
4714
  },
4077
- children: availableTypes.map((type) => /* @__PURE__ */ jsxs3(
4715
+ children: availableTypes.map((type) => /* @__PURE__ */ jsxs4(
4078
4716
  "button",
4079
4717
  {
4080
4718
  type: "button",
@@ -4105,7 +4743,7 @@ function ReportDialog({
4105
4743
  },
4106
4744
  children: [
4107
4745
  getTypeIcon(type, t2.accent, 22),
4108
- /* @__PURE__ */ jsx3(
4746
+ /* @__PURE__ */ jsx4(
4109
4747
  "span",
4110
4748
  {
4111
4749
  style: {
@@ -4123,8 +4761,8 @@ function ReportDialog({
4123
4761
  ))
4124
4762
  }
4125
4763
  ),
4126
- step === 2 && /* @__PURE__ */ jsxs3(Fragment2, { children: [
4127
- /* @__PURE__ */ jsxs3(
4764
+ step === 2 && /* @__PURE__ */ jsxs4(Fragment3, { children: [
4765
+ /* @__PURE__ */ jsxs4(
4128
4766
  "button",
4129
4767
  {
4130
4768
  type: "button",
@@ -4147,11 +4785,11 @@ function ReportDialog({
4147
4785
  children: [
4148
4786
  getTypeIcon(reportType, isRating ? "#f59e0b" : t2.accent, 13),
4149
4787
  getTypeLabel(reportType),
4150
- /* @__PURE__ */ jsx3("span", { style: { color: t2.textMuted, fontWeight: 400 }, children: "\xB7 change" })
4788
+ /* @__PURE__ */ jsx4("span", { style: { color: t2.textMuted, fontWeight: 400 }, children: "\xB7 change" })
4151
4789
  ]
4152
4790
  }
4153
4791
  ),
4154
- isRating && /* @__PURE__ */ jsx3(
4792
+ isRating && /* @__PURE__ */ jsx4(
4155
4793
  "div",
4156
4794
  {
4157
4795
  style: {
@@ -4162,7 +4800,7 @@ function ReportDialog({
4162
4800
  onMouseLeave: () => setHoveredStar(0),
4163
4801
  children: [1, 2, 3, 4, 5].map((star) => {
4164
4802
  const filled = star <= (hoveredStar || rating);
4165
- return /* @__PURE__ */ jsx3(
4803
+ return /* @__PURE__ */ jsx4(
4166
4804
  "button",
4167
4805
  {
4168
4806
  type: "button",
@@ -4179,7 +4817,7 @@ function ReportDialog({
4179
4817
  cursor: "pointer",
4180
4818
  lineHeight: 0
4181
4819
  },
4182
- children: /* @__PURE__ */ jsx3("svg", { width: "30", height: "30", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(
4820
+ children: /* @__PURE__ */ jsx4("svg", { width: "30", height: "30", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(
4183
4821
  "path",
4184
4822
  {
4185
4823
  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",
@@ -4195,7 +4833,7 @@ function ReportDialog({
4195
4833
  })
4196
4834
  }
4197
4835
  ),
4198
- assist && !isRating && !assistUsed && /* @__PURE__ */ jsxs3(
4836
+ assist && !isRating && !assistUsed && /* @__PURE__ */ jsxs4(
4199
4837
  "button",
4200
4838
  {
4201
4839
  type: "button",
@@ -4222,7 +4860,7 @@ function ReportDialog({
4222
4860
  },
4223
4861
  title: "Answer a question or two and the assistant writes the report for you",
4224
4862
  children: [
4225
- /* @__PURE__ */ jsx3("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(
4863
+ /* @__PURE__ */ jsx4("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(
4226
4864
  "path",
4227
4865
  {
4228
4866
  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",
@@ -4235,8 +4873,8 @@ function ReportDialog({
4235
4873
  ]
4236
4874
  }
4237
4875
  ),
4238
- /* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
4239
- /* @__PURE__ */ jsx3(
4876
+ /* @__PURE__ */ jsxs4("div", { style: { position: "relative" }, children: [
4877
+ /* @__PURE__ */ jsx4(
4240
4878
  "textarea",
4241
4879
  {
4242
4880
  ref: textareaRef,
@@ -4278,7 +4916,7 @@ function ReportDialog({
4278
4916
  autoFocus: true
4279
4917
  }
4280
4918
  ),
4281
- (isListening || isTranscribing) && /* @__PURE__ */ jsxs3(
4919
+ (isListening || isTranscribing) && /* @__PURE__ */ jsxs4(
4282
4920
  "span",
4283
4921
  {
4284
4922
  style: {
@@ -4296,7 +4934,7 @@ function ReportDialog({
4296
4934
  zIndex: 1
4297
4935
  },
4298
4936
  children: [
4299
- /* @__PURE__ */ jsx3(
4937
+ /* @__PURE__ */ jsx4(
4300
4938
  "span",
4301
4939
  {
4302
4940
  style: {
@@ -4311,7 +4949,7 @@ function ReportDialog({
4311
4949
  }
4312
4950
  ),
4313
4951
  isTranscribing ? "Transcribing\u2026" : "REC",
4314
- isListening && !isTranscribing && /* @__PURE__ */ jsx3(
4952
+ isListening && !isTranscribing && /* @__PURE__ */ jsx4(
4315
4953
  "span",
4316
4954
  {
4317
4955
  style: {
@@ -4338,7 +4976,7 @@ function ReportDialog({
4338
4976
  dur: "0.55s",
4339
4977
  delay: "0.15s"
4340
4978
  }
4341
- ].map((b, i) => /* @__PURE__ */ jsx3(
4979
+ ].map((b, i) => /* @__PURE__ */ jsx4(
4342
4980
  "span",
4343
4981
  {
4344
4982
  style: {
@@ -4358,7 +4996,7 @@ function ReportDialog({
4358
4996
  ]
4359
4997
  }
4360
4998
  ),
4361
- enhanceText2 && /* @__PURE__ */ jsxs3(
4999
+ enhanceText2 && /* @__PURE__ */ jsxs4(
4362
5000
  "button",
4363
5001
  {
4364
5002
  type: "button",
@@ -4403,7 +5041,7 @@ function ReportDialog({
4403
5041
  },
4404
5042
  title: "Polish grammar \u2014 preserves your meaning",
4405
5043
  children: [
4406
- /* @__PURE__ */ jsx3(
5044
+ /* @__PURE__ */ jsx4(
4407
5045
  "svg",
4408
5046
  {
4409
5047
  width: "11",
@@ -4411,7 +5049,7 @@ function ReportDialog({
4411
5049
  viewBox: "0 0 24 24",
4412
5050
  fill: "none",
4413
5051
  "aria-hidden": "true",
4414
- children: /* @__PURE__ */ jsx3(
5052
+ children: /* @__PURE__ */ jsx4(
4415
5053
  "path",
4416
5054
  {
4417
5055
  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",
@@ -4426,7 +5064,7 @@ function ReportDialog({
4426
5064
  ]
4427
5065
  }
4428
5066
  ),
4429
- transcribeAudio2 && /* @__PURE__ */ jsx3(
5067
+ transcribeAudio2 && /* @__PURE__ */ jsx4(
4430
5068
  "button",
4431
5069
  {
4432
5070
  type: "button",
@@ -4452,7 +5090,7 @@ function ReportDialog({
4452
5090
  padding: 0,
4453
5091
  transition: "border-color 0.2s ease, color 0.2s ease"
4454
5092
  },
4455
- children: isListening ? /* @__PURE__ */ jsx3(
5093
+ children: isListening ? /* @__PURE__ */ jsx4(
4456
5094
  "svg",
4457
5095
  {
4458
5096
  width: "12",
@@ -4460,7 +5098,7 @@ function ReportDialog({
4460
5098
  viewBox: "0 0 24 24",
4461
5099
  fill: "currentColor",
4462
5100
  "aria-hidden": "true",
4463
- children: /* @__PURE__ */ jsx3(
5101
+ children: /* @__PURE__ */ jsx4(
4464
5102
  "rect",
4465
5103
  {
4466
5104
  x: "6",
@@ -4471,7 +5109,7 @@ function ReportDialog({
4471
5109
  }
4472
5110
  )
4473
5111
  }
4474
- ) : /* @__PURE__ */ jsxs3(
5112
+ ) : /* @__PURE__ */ jsxs4(
4475
5113
  "svg",
4476
5114
  {
4477
5115
  width: "13",
@@ -4480,7 +5118,7 @@ function ReportDialog({
4480
5118
  fill: "none",
4481
5119
  "aria-hidden": "true",
4482
5120
  children: [
4483
- /* @__PURE__ */ jsx3(
5121
+ /* @__PURE__ */ jsx4(
4484
5122
  "rect",
4485
5123
  {
4486
5124
  x: "9",
@@ -4492,7 +5130,7 @@ function ReportDialog({
4492
5130
  strokeWidth: "1.8"
4493
5131
  }
4494
5132
  ),
4495
- /* @__PURE__ */ jsx3(
5133
+ /* @__PURE__ */ jsx4(
4496
5134
  "path",
4497
5135
  {
4498
5136
  d: "M5 10a7 7 0 0014 0M12 19v3M9 22h6",
@@ -4507,7 +5145,7 @@ function ReportDialog({
4507
5145
  }
4508
5146
  )
4509
5147
  ] }),
4510
- transcribeAudio2 && !isListening && !isTranscribing && !voiceError && /* @__PURE__ */ jsxs3(
5148
+ transcribeAudio2 && !isListening && !isTranscribing && !voiceError && /* @__PURE__ */ jsxs4(
4511
5149
  "div",
4512
5150
  {
4513
5151
  style: {
@@ -4521,16 +5159,16 @@ function ReportDialog({
4521
5159
  userSelect: "none"
4522
5160
  },
4523
5161
  children: [
4524
- /* @__PURE__ */ jsxs3("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4525
- /* @__PURE__ */ jsx3("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" }),
4526
- /* @__PURE__ */ jsx3("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
4527
- /* @__PURE__ */ jsx3("line", { x1: "12", x2: "12", y1: "19", y2: "22" })
5162
+ /* @__PURE__ */ jsxs4("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
5163
+ /* @__PURE__ */ jsx4("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" }),
5164
+ /* @__PURE__ */ jsx4("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
5165
+ /* @__PURE__ */ jsx4("line", { x1: "12", x2: "12", y1: "19", y2: "22" })
4528
5166
  ] }),
4529
5167
  "Hold Space to speak \u2014 we'll transcribe it"
4530
5168
  ]
4531
5169
  }
4532
5170
  ),
4533
- isEnhanced && originalDescription !== null && /* @__PURE__ */ jsxs3(
5171
+ isEnhanced && originalDescription !== null && /* @__PURE__ */ jsxs4(
4534
5172
  "div",
4535
5173
  {
4536
5174
  style: {
@@ -4544,7 +5182,7 @@ function ReportDialog({
4544
5182
  border: `1px solid ${t2.accent}40`
4545
5183
  },
4546
5184
  children: [
4547
- /* @__PURE__ */ jsx3(
5185
+ /* @__PURE__ */ jsx4(
4548
5186
  "svg",
4549
5187
  {
4550
5188
  width: "12",
@@ -4552,7 +5190,7 @@ function ReportDialog({
4552
5190
  viewBox: "0 0 24 24",
4553
5191
  fill: "none",
4554
5192
  style: { flexShrink: 0 },
4555
- children: /* @__PURE__ */ jsx3(
5193
+ children: /* @__PURE__ */ jsx4(
4556
5194
  "path",
4557
5195
  {
4558
5196
  d: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z",
@@ -4563,7 +5201,7 @@ function ReportDialog({
4563
5201
  )
4564
5202
  }
4565
5203
  ),
4566
- /* @__PURE__ */ jsx3(
5204
+ /* @__PURE__ */ jsx4(
4567
5205
  "span",
4568
5206
  {
4569
5207
  style: {
@@ -4574,7 +5212,7 @@ function ReportDialog({
4574
5212
  children: "AI enhanced"
4575
5213
  }
4576
5214
  ),
4577
- /* @__PURE__ */ jsx3(
5215
+ /* @__PURE__ */ jsx4(
4578
5216
  "button",
4579
5217
  {
4580
5218
  type: "button",
@@ -4596,7 +5234,7 @@ function ReportDialog({
4596
5234
  children: "Keep"
4597
5235
  }
4598
5236
  ),
4599
- /* @__PURE__ */ jsx3(
5237
+ /* @__PURE__ */ jsx4(
4600
5238
  "button",
4601
5239
  {
4602
5240
  type: "button",
@@ -4622,7 +5260,7 @@ function ReportDialog({
4622
5260
  ]
4623
5261
  }
4624
5262
  ),
4625
- voiceError && /* @__PURE__ */ jsx3(
5263
+ voiceError && /* @__PURE__ */ jsx4(
4626
5264
  "p",
4627
5265
  {
4628
5266
  role: "alert",
@@ -4636,7 +5274,7 @@ function ReportDialog({
4636
5274
  children: voiceError
4637
5275
  }
4638
5276
  ),
4639
- assistNotice && /* @__PURE__ */ jsx3(
5277
+ assistNotice && /* @__PURE__ */ jsx4(
4640
5278
  "p",
4641
5279
  {
4642
5280
  style: {
@@ -4649,8 +5287,8 @@ function ReportDialog({
4649
5287
  children: assistNotice
4650
5288
  }
4651
5289
  ),
4652
- !isRating && /* @__PURE__ */ jsxs3("div", { style: { marginTop: "10px" }, children: [
4653
- /* @__PURE__ */ jsxs3(
5290
+ !isRating && /* @__PURE__ */ jsxs4("div", { style: { marginTop: "10px" }, children: [
5291
+ /* @__PURE__ */ jsxs4(
4654
5292
  "span",
4655
5293
  {
4656
5294
  style: {
@@ -4666,7 +5304,7 @@ function ReportDialog({
4666
5304
  ]
4667
5305
  }
4668
5306
  ),
4669
- screenshots.length > 0 && /* @__PURE__ */ jsx3(
5307
+ (screenshots.length > 0 || shotPending) && /* @__PURE__ */ jsxs4(
4670
5308
  "div",
4671
5309
  {
4672
5310
  style: {
@@ -4675,132 +5313,159 @@ function ReportDialog({
4675
5313
  gap: "8px",
4676
5314
  marginBottom: "8px"
4677
5315
  },
4678
- children: screenshots.map((src, i) => /* @__PURE__ */ jsxs3(
4679
- "div",
4680
- {
4681
- style: {
4682
- position: "relative",
4683
- width: "56px",
4684
- height: "56px"
4685
- },
4686
- children: [
4687
- /* @__PURE__ */ jsx3(
4688
- "img",
4689
- {
4690
- src,
4691
- alt: `Screenshot ${i + 1}`,
4692
- onClick: () => openPreview(i),
4693
- style: {
4694
- width: "100%",
4695
- height: "100%",
4696
- borderRadius: "6px",
4697
- border: `1px solid ${t2.border}`,
4698
- objectFit: "cover",
4699
- objectPosition: "top",
4700
- cursor: "zoom-in",
4701
- display: "block"
4702
- }
4703
- }
4704
- ),
4705
- /* @__PURE__ */ jsx3(
4706
- "button",
4707
- {
4708
- type: "button",
4709
- onClick: () => setScreenshots(
4710
- (prev) => prev.filter((_, idx) => idx !== i)
4711
- ),
4712
- "aria-label": `Remove screenshot ${i + 1}`,
4713
- style: {
4714
- position: "absolute",
4715
- top: "-6px",
4716
- right: "-6px",
4717
- width: "17px",
4718
- height: "17px",
4719
- borderRadius: "50%",
4720
- border: "none",
4721
- background: "#ef4444",
4722
- color: "#fff",
4723
- fontSize: "11px",
4724
- lineHeight: 1,
4725
- padding: 0,
4726
- cursor: "pointer",
4727
- display: "flex",
4728
- alignItems: "center",
4729
- justifyContent: "center"
4730
- },
4731
- children: /* @__PURE__ */ jsx3(
4732
- "svg",
4733
- {
4734
- width: "8",
4735
- height: "8",
4736
- viewBox: "0 0 10 10",
4737
- fill: "none",
4738
- children: /* @__PURE__ */ jsx3(
4739
- "path",
4740
- {
4741
- d: "M1 1L9 9M9 1L1 9",
4742
- stroke: "currentColor",
4743
- strokeWidth: "1.5",
4744
- strokeLinecap: "round"
4745
- }
4746
- )
4747
- }
4748
- )
4749
- }
4750
- ),
4751
- /* @__PURE__ */ jsx3(
4752
- "button",
4753
- {
4754
- type: "button",
4755
- onClick: () => setAnnotatingIndex(i),
4756
- "aria-label": `Annotate screenshot ${i + 1}`,
4757
- title: "Annotate",
4758
- style: {
4759
- position: "absolute",
4760
- top: "50%",
4761
- left: "50%",
4762
- transform: "translate(-50%, -50%)",
4763
- width: "24px",
4764
- height: "24px",
4765
- borderRadius: "50%",
4766
- border: "none",
4767
- background: t2.accent,
4768
- color: t2.accentText,
4769
- padding: 0,
4770
- cursor: "pointer",
4771
- display: "flex",
4772
- alignItems: "center",
4773
- justifyContent: "center",
4774
- boxShadow: "0 2px 8px rgba(0,0,0,0.45)"
4775
- },
4776
- children: /* @__PURE__ */ jsx3(
4777
- "svg",
4778
- {
4779
- width: "12",
4780
- height: "12",
4781
- viewBox: "0 0 24 24",
4782
- fill: "none",
4783
- children: /* @__PURE__ */ jsx3(
4784
- "path",
4785
- {
4786
- d: "M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z",
4787
- stroke: "currentColor",
4788
- strokeWidth: "2.2",
4789
- strokeLinecap: "round",
4790
- strokeLinejoin: "round"
4791
- }
4792
- )
5316
+ children: [
5317
+ shotPending && /* @__PURE__ */ jsx4(
5318
+ "div",
5319
+ {
5320
+ role: "status",
5321
+ "aria-label": "Capturing screenshot",
5322
+ title: "Capturing a screenshot of the page\u2026",
5323
+ style: {
5324
+ width: "56px",
5325
+ height: "56px",
5326
+ borderRadius: "6px",
5327
+ border: `1px dashed ${t2.border}`,
5328
+ display: "flex",
5329
+ alignItems: "center",
5330
+ justifyContent: "center",
5331
+ padding: "4px",
5332
+ boxSizing: "border-box",
5333
+ fontSize: "9px",
5334
+ lineHeight: 1.2,
5335
+ textAlign: "center",
5336
+ color: t2.textMuted,
5337
+ animation: "gg-pulse 1.4s ease-in-out infinite"
5338
+ },
5339
+ children: "Capturing\u2026"
5340
+ }
5341
+ ),
5342
+ screenshots.map((src, i) => /* @__PURE__ */ jsxs4(
5343
+ "div",
5344
+ {
5345
+ style: {
5346
+ position: "relative",
5347
+ width: "56px",
5348
+ height: "56px"
5349
+ },
5350
+ children: [
5351
+ /* @__PURE__ */ jsx4(
5352
+ "img",
5353
+ {
5354
+ src,
5355
+ alt: `Screenshot ${i + 1}`,
5356
+ onClick: () => openPreview(i),
5357
+ style: {
5358
+ width: "100%",
5359
+ height: "100%",
5360
+ borderRadius: "6px",
5361
+ border: `1px solid ${t2.border}`,
5362
+ objectFit: "cover",
5363
+ objectPosition: "top",
5364
+ cursor: "zoom-in",
5365
+ display: "block"
4793
5366
  }
4794
- )
4795
- }
4796
- )
4797
- ]
4798
- },
4799
- i
4800
- ))
5367
+ }
5368
+ ),
5369
+ /* @__PURE__ */ jsx4(
5370
+ "button",
5371
+ {
5372
+ type: "button",
5373
+ onClick: () => setScreenshots(
5374
+ (prev) => prev.filter((_, idx) => idx !== i)
5375
+ ),
5376
+ "aria-label": `Remove screenshot ${i + 1}`,
5377
+ style: {
5378
+ position: "absolute",
5379
+ top: "-6px",
5380
+ right: "-6px",
5381
+ width: "17px",
5382
+ height: "17px",
5383
+ borderRadius: "50%",
5384
+ border: "none",
5385
+ background: "#ef4444",
5386
+ color: "#fff",
5387
+ fontSize: "11px",
5388
+ lineHeight: 1,
5389
+ padding: 0,
5390
+ cursor: "pointer",
5391
+ display: "flex",
5392
+ alignItems: "center",
5393
+ justifyContent: "center"
5394
+ },
5395
+ children: /* @__PURE__ */ jsx4(
5396
+ "svg",
5397
+ {
5398
+ width: "8",
5399
+ height: "8",
5400
+ viewBox: "0 0 10 10",
5401
+ fill: "none",
5402
+ children: /* @__PURE__ */ jsx4(
5403
+ "path",
5404
+ {
5405
+ d: "M1 1L9 9M9 1L1 9",
5406
+ stroke: "currentColor",
5407
+ strokeWidth: "1.5",
5408
+ strokeLinecap: "round"
5409
+ }
5410
+ )
5411
+ }
5412
+ )
5413
+ }
5414
+ ),
5415
+ /* @__PURE__ */ jsx4(
5416
+ "button",
5417
+ {
5418
+ type: "button",
5419
+ onClick: () => setAnnotatingIndex(i),
5420
+ "aria-label": `Annotate screenshot ${i + 1}`,
5421
+ title: "Annotate",
5422
+ style: {
5423
+ position: "absolute",
5424
+ top: "50%",
5425
+ left: "50%",
5426
+ transform: "translate(-50%, -50%)",
5427
+ width: "24px",
5428
+ height: "24px",
5429
+ borderRadius: "50%",
5430
+ border: "none",
5431
+ background: t2.accent,
5432
+ color: t2.accentText,
5433
+ padding: 0,
5434
+ cursor: "pointer",
5435
+ display: "flex",
5436
+ alignItems: "center",
5437
+ justifyContent: "center",
5438
+ boxShadow: "0 2px 8px rgba(0,0,0,0.45)"
5439
+ },
5440
+ children: /* @__PURE__ */ jsx4(
5441
+ "svg",
5442
+ {
5443
+ width: "12",
5444
+ height: "12",
5445
+ viewBox: "0 0 24 24",
5446
+ fill: "none",
5447
+ children: /* @__PURE__ */ jsx4(
5448
+ "path",
5449
+ {
5450
+ d: "M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z",
5451
+ stroke: "currentColor",
5452
+ strokeWidth: "2.2",
5453
+ strokeLinecap: "round",
5454
+ strokeLinejoin: "round"
5455
+ }
5456
+ )
5457
+ }
5458
+ )
5459
+ }
5460
+ )
5461
+ ]
5462
+ },
5463
+ i
5464
+ ))
5465
+ ]
4801
5466
  }
4802
5467
  ),
4803
- attachments.length > 0 && /* @__PURE__ */ jsx3(
5468
+ attachments.length > 0 && /* @__PURE__ */ jsx4(
4804
5469
  "div",
4805
5470
  {
4806
5471
  style: {
@@ -4809,7 +5474,7 @@ function ReportDialog({
4809
5474
  gap: "6px",
4810
5475
  marginBottom: "8px"
4811
5476
  },
4812
- children: attachments.map((a, i) => /* @__PURE__ */ jsxs3(
5477
+ children: attachments.map((a, i) => /* @__PURE__ */ jsxs4(
4813
5478
  "div",
4814
5479
  {
4815
5480
  style: {
@@ -4821,7 +5486,7 @@ function ReportDialog({
4821
5486
  border: `1px solid ${t2.border}`
4822
5487
  },
4823
5488
  children: [
4824
- /* @__PURE__ */ jsxs3(
5489
+ /* @__PURE__ */ jsxs4(
4825
5490
  "svg",
4826
5491
  {
4827
5492
  width: "14",
@@ -4830,7 +5495,7 @@ function ReportDialog({
4830
5495
  fill: "none",
4831
5496
  style: { flexShrink: 0, opacity: 0.6 },
4832
5497
  children: [
4833
- /* @__PURE__ */ jsx3(
5498
+ /* @__PURE__ */ jsx4(
4834
5499
  "path",
4835
5500
  {
4836
5501
  d: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z",
@@ -4840,7 +5505,7 @@ function ReportDialog({
4840
5505
  strokeLinejoin: "round"
4841
5506
  }
4842
5507
  ),
4843
- /* @__PURE__ */ jsx3(
5508
+ /* @__PURE__ */ jsx4(
4844
5509
  "path",
4845
5510
  {
4846
5511
  d: "M14 2v6h6",
@@ -4853,7 +5518,7 @@ function ReportDialog({
4853
5518
  ]
4854
5519
  }
4855
5520
  ),
4856
- /* @__PURE__ */ jsx3(
5521
+ /* @__PURE__ */ jsx4(
4857
5522
  "span",
4858
5523
  {
4859
5524
  style: {
@@ -4867,7 +5532,7 @@ function ReportDialog({
4867
5532
  children: a.name
4868
5533
  }
4869
5534
  ),
4870
- /* @__PURE__ */ jsxs3(
5535
+ /* @__PURE__ */ jsxs4(
4871
5536
  "span",
4872
5537
  {
4873
5538
  style: { fontSize: "10px", color: t2.textMuted },
@@ -4877,7 +5542,7 @@ function ReportDialog({
4877
5542
  ]
4878
5543
  }
4879
5544
  ),
4880
- /* @__PURE__ */ jsx3(
5545
+ /* @__PURE__ */ jsx4(
4881
5546
  "button",
4882
5547
  {
4883
5548
  type: "button",
@@ -4901,14 +5566,14 @@ function ReportDialog({
4901
5566
  justifyContent: "center",
4902
5567
  flexShrink: 0
4903
5568
  },
4904
- children: /* @__PURE__ */ jsx3(
5569
+ children: /* @__PURE__ */ jsx4(
4905
5570
  "svg",
4906
5571
  {
4907
5572
  width: "8",
4908
5573
  height: "8",
4909
5574
  viewBox: "0 0 10 10",
4910
5575
  fill: "none",
4911
- children: /* @__PURE__ */ jsx3(
5576
+ children: /* @__PURE__ */ jsx4(
4912
5577
  "path",
4913
5578
  {
4914
5579
  d: "M1 1L9 9M9 1L1 9",
@@ -4927,7 +5592,7 @@ function ReportDialog({
4927
5592
  ))
4928
5593
  }
4929
5594
  ),
4930
- /* @__PURE__ */ jsx3(
5595
+ /* @__PURE__ */ jsx4(
4931
5596
  "div",
4932
5597
  {
4933
5598
  onClick: () => {
@@ -4953,7 +5618,7 @@ function ReportDialog({
4953
5618
  background: screenshotDragOver ? isDark ? "rgba(34,211,238,0.06)" : "rgba(8,145,178,0.04)" : "transparent",
4954
5619
  transition: "border-color 0.15s ease, background 0.15s ease"
4955
5620
  },
4956
- children: screenshots.length + attachments.length > 0 ? /* @__PURE__ */ jsx3(
5621
+ children: screenshots.length + attachments.length > 0 ? /* @__PURE__ */ jsx4(
4957
5622
  "p",
4958
5623
  {
4959
5624
  style: {
@@ -4964,8 +5629,8 @@ function ReportDialog({
4964
5629
  },
4965
5630
  children: screenshotDragOver ? "Drop to attach" : "+ Add more \xB7 Drag & drop \xB7 Paste"
4966
5631
  }
4967
- ) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
4968
- /* @__PURE__ */ jsxs3(
5632
+ ) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
5633
+ /* @__PURE__ */ jsxs4(
4969
5634
  "svg",
4970
5635
  {
4971
5636
  width: "22",
@@ -4978,7 +5643,7 @@ function ReportDialog({
4978
5643
  opacity: 0.45
4979
5644
  },
4980
5645
  children: [
4981
- /* @__PURE__ */ jsx3(
5646
+ /* @__PURE__ */ jsx4(
4982
5647
  "rect",
4983
5648
  {
4984
5649
  x: "3",
@@ -4990,7 +5655,7 @@ function ReportDialog({
4990
5655
  strokeWidth: "1.5"
4991
5656
  }
4992
5657
  ),
4993
- /* @__PURE__ */ jsx3(
5658
+ /* @__PURE__ */ jsx4(
4994
5659
  "circle",
4995
5660
  {
4996
5661
  cx: "8.5",
@@ -5000,7 +5665,7 @@ function ReportDialog({
5000
5665
  strokeWidth: "1.5"
5001
5666
  }
5002
5667
  ),
5003
- /* @__PURE__ */ jsx3(
5668
+ /* @__PURE__ */ jsx4(
5004
5669
  "path",
5005
5670
  {
5006
5671
  d: "M21 15l-5-5L5 21",
@@ -5013,7 +5678,7 @@ function ReportDialog({
5013
5678
  ]
5014
5679
  }
5015
5680
  ),
5016
- /* @__PURE__ */ jsx3(
5681
+ /* @__PURE__ */ jsx4(
5017
5682
  "p",
5018
5683
  {
5019
5684
  style: {
@@ -5025,7 +5690,7 @@ function ReportDialog({
5025
5690
  children: screenshotDragOver ? "Drop to attach" : "Add screenshots or files"
5026
5691
  }
5027
5692
  ),
5028
- /* @__PURE__ */ jsx3(
5693
+ /* @__PURE__ */ jsx4(
5029
5694
  "p",
5030
5695
  {
5031
5696
  style: {
@@ -5040,8 +5705,8 @@ function ReportDialog({
5040
5705
  }
5041
5706
  )
5042
5707
  ] }),
5043
- showSeverity && reportType === "BUG" && /* @__PURE__ */ jsxs3("div", { style: { marginTop: "10px" }, children: [
5044
- /* @__PURE__ */ jsxs3(
5708
+ showSeverity && reportType === "BUG" && /* @__PURE__ */ jsxs4("div", { style: { marginTop: "10px" }, children: [
5709
+ /* @__PURE__ */ jsxs4(
5045
5710
  "span",
5046
5711
  {
5047
5712
  style: {
@@ -5054,7 +5719,7 @@ function ReportDialog({
5054
5719
  },
5055
5720
  children: [
5056
5721
  "How bad is it?",
5057
- /* @__PURE__ */ jsx3(
5722
+ /* @__PURE__ */ jsx4(
5058
5723
  "span",
5059
5724
  {
5060
5725
  style: {
@@ -5067,7 +5732,7 @@ function ReportDialog({
5067
5732
  ]
5068
5733
  }
5069
5734
  ),
5070
- /* @__PURE__ */ jsx3(
5735
+ /* @__PURE__ */ jsx4(
5071
5736
  "div",
5072
5737
  {
5073
5738
  role: "radiogroup",
@@ -5075,7 +5740,7 @@ function ReportDialog({
5075
5740
  style: { display: "flex", gap: "6px" },
5076
5741
  children: SEVERITY_LEVELS.map((s) => {
5077
5742
  const on = severity === s;
5078
- return /* @__PURE__ */ jsx3(
5743
+ return /* @__PURE__ */ jsx4(
5079
5744
  "button",
5080
5745
  {
5081
5746
  type: "button",
@@ -5116,7 +5781,7 @@ function ReportDialog({
5116
5781
  }
5117
5782
  )
5118
5783
  ] }),
5119
- validationError && /* @__PURE__ */ jsx3(
5784
+ validationError && /* @__PURE__ */ jsx4(
5120
5785
  "p",
5121
5786
  {
5122
5787
  style: {
@@ -5127,7 +5792,7 @@ function ReportDialog({
5127
5792
  children: validationError
5128
5793
  }
5129
5794
  ),
5130
- /* @__PURE__ */ jsx3(
5795
+ /* @__PURE__ */ jsx4(
5131
5796
  "button",
5132
5797
  {
5133
5798
  type: "button",
@@ -5147,14 +5812,14 @@ function ReportDialog({
5147
5812
  fontFamily: "inherit",
5148
5813
  transition: "background-color 0.15s ease"
5149
5814
  },
5150
- children: isSubmitting ? "Sending..." : isRating ? "Send Rating" : "Send Report"
5815
+ children: isSubmitting ? shotPending && !isRating ? "Attaching screenshot\u2026" : "Sending..." : isRating ? "Send Rating" : "Send Report"
5151
5816
  }
5152
5817
  )
5153
5818
  ] })
5154
5819
  ] })
5155
5820
  }
5156
5821
  ),
5157
- /* @__PURE__ */ jsxs3(
5822
+ /* @__PURE__ */ jsxs4(
5158
5823
  "div",
5159
5824
  {
5160
5825
  style: {
@@ -5166,8 +5831,35 @@ function ReportDialog({
5166
5831
  gap: "12px"
5167
5832
  },
5168
5833
  children: [
5169
- /* @__PURE__ */ jsx3(ReporterChip, { reporter, t: t2 }),
5170
- /* @__PURE__ */ jsx3(
5834
+ /* @__PURE__ */ jsx4(ReporterChip, { reporter, t: t2 }),
5835
+ reportGlitchgrabProblem ? /* @__PURE__ */ jsx4(
5836
+ "button",
5837
+ {
5838
+ type: "button",
5839
+ "data-gg-self-report": "",
5840
+ onClick: () => {
5841
+ setSelfReportPrefill("");
5842
+ setSelfReportFrom("form");
5843
+ },
5844
+ title: "Something wrong with this reporter itself? Tell the Glitchgrab team.",
5845
+ style: {
5846
+ fontSize: "11px",
5847
+ color: t2.textMuted,
5848
+ whiteSpace: "nowrap",
5849
+ flexShrink: 0,
5850
+ border: "none",
5851
+ background: "transparent",
5852
+ fontFamily: "inherit",
5853
+ cursor: "pointer",
5854
+ textDecoration: "underline",
5855
+ textUnderlineOffset: "2px",
5856
+ // A ~30px tap target without growing the footer.
5857
+ padding: "9px 0",
5858
+ margin: "-9px 0"
5859
+ },
5860
+ children: "Problem with Glitchgrab?"
5861
+ }
5862
+ ) : /* @__PURE__ */ jsx4(
5171
5863
  "span",
5172
5864
  {
5173
5865
  style: {
@@ -5189,7 +5881,7 @@ function ReportDialog({
5189
5881
  ),
5190
5882
  document.body
5191
5883
  ),
5192
- /* @__PURE__ */ jsx3(
5884
+ /* @__PURE__ */ jsx4(
5193
5885
  "input",
5194
5886
  {
5195
5887
  ref: fileInputRef,
@@ -5200,8 +5892,8 @@ function ReportDialog({
5200
5892
  style: { display: "none" }
5201
5893
  }
5202
5894
  ),
5203
- isOpen && previewIndex !== null && screenshots[previewIndex] && createPortal2(
5204
- /* @__PURE__ */ jsxs3(
5895
+ isOpen && previewIndex !== null && screenshots[previewIndex] && createPortal3(
5896
+ /* @__PURE__ */ jsxs4(
5205
5897
  "div",
5206
5898
  {
5207
5899
  "data-glitchgrab-layer": "",
@@ -5223,7 +5915,7 @@ function ReportDialog({
5223
5915
  },
5224
5916
  onMouseDown: (e) => e.stopPropagation(),
5225
5917
  children: [
5226
- /* @__PURE__ */ jsxs3(
5918
+ /* @__PURE__ */ jsxs4(
5227
5919
  "div",
5228
5920
  {
5229
5921
  ref: previewImgRef,
@@ -5235,7 +5927,7 @@ function ReportDialog({
5235
5927
  },
5236
5928
  onClick: (e) => e.stopPropagation(),
5237
5929
  children: [
5238
- /* @__PURE__ */ jsx3(
5930
+ /* @__PURE__ */ jsx4(
5239
5931
  "div",
5240
5932
  {
5241
5933
  ref: previewScrollRef,
@@ -5254,7 +5946,7 @@ function ReportDialog({
5254
5946
  touchAction: "none",
5255
5947
  cursor: "grab"
5256
5948
  } : { maxWidth: "100%", lineHeight: 0 },
5257
- children: /* @__PURE__ */ jsx3(
5949
+ children: /* @__PURE__ */ jsx4(
5258
5950
  "img",
5259
5951
  {
5260
5952
  ref: previewImgElRef,
@@ -5282,7 +5974,7 @@ function ReportDialog({
5282
5974
  )
5283
5975
  }
5284
5976
  ),
5285
- /* @__PURE__ */ jsxs3(
5977
+ /* @__PURE__ */ jsxs4(
5286
5978
  "button",
5287
5979
  {
5288
5980
  type: "button",
@@ -5310,7 +6002,7 @@ function ReportDialog({
5310
6002
  animation: "gg-pulse 2s ease-in-out infinite"
5311
6003
  },
5312
6004
  children: [
5313
- /* @__PURE__ */ jsx3("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx3(
6005
+ /* @__PURE__ */ jsx4("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx4(
5314
6006
  "path",
5315
6007
  {
5316
6008
  d: "M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z",
@@ -5327,7 +6019,7 @@ function ReportDialog({
5327
6019
  ]
5328
6020
  }
5329
6021
  ),
5330
- /* @__PURE__ */ jsx3(
6022
+ /* @__PURE__ */ jsx4(
5331
6023
  "div",
5332
6024
  {
5333
6025
  style: {
@@ -5336,7 +6028,7 @@ function ReportDialog({
5336
6028
  alignItems: "center",
5337
6029
  gap: "12px"
5338
6030
  },
5339
- children: /* @__PURE__ */ jsx3(
6031
+ children: /* @__PURE__ */ jsx4(
5340
6032
  "span",
5341
6033
  {
5342
6034
  style: {
@@ -5357,8 +6049,8 @@ function ReportDialog({
5357
6049
  ),
5358
6050
  document.body
5359
6051
  ),
5360
- isOpen && annotatingIndex !== null && screenshots[annotatingIndex] && createPortal2(
5361
- /* @__PURE__ */ jsx3(
6052
+ isOpen && annotatingIndex !== null && screenshots[annotatingIndex] && createPortal3(
6053
+ /* @__PURE__ */ jsx4(
5362
6054
  AnnotationCanvas,
5363
6055
  {
5364
6056
  imageSrc: screenshots[annotatingIndex],
@@ -5374,24 +6066,28 @@ function ReportDialog({
5374
6066
  ),
5375
6067
  document.body
5376
6068
  ),
5377
- isOpen && sheetUp && /* @__PURE__ */ jsx3(
6069
+ isOpen && selfReportFrom && reportGlitchgrabProblem && /* @__PURE__ */ jsx4(
6070
+ GlitchgrabProblemPanel,
6071
+ {
6072
+ send: reportGlitchgrabProblem,
6073
+ theme: layerTheme,
6074
+ surface: selfReportFrom,
6075
+ conversationId: aiConversationId,
6076
+ reportType,
6077
+ screenshots,
6078
+ initialText: selfReportPrefill,
6079
+ onClose: () => setSelfReportFrom(null)
6080
+ }
6081
+ ),
6082
+ isOpen && sheetUp && /* @__PURE__ */ jsx4(
5378
6083
  AssistSheet,
5379
6084
  {
5380
6085
  assist,
5381
- theme: {
5382
- bg: t2.bg,
5383
- bgSecondary: t2.bgSecondary,
5384
- border: t2.border,
5385
- text: t2.text,
5386
- textMuted: t2.textMuted,
5387
- inputBg: t2.inputBg,
5388
- inputBorder: t2.inputBorder,
5389
- accent: t2.accent,
5390
- accentText: t2.accentText
5391
- },
6086
+ theme: layerTheme,
5392
6087
  screenshots,
5393
6088
  pageShot,
5394
6089
  onAddImages: addFiles,
6090
+ onRemoveImage: (index) => setScreenshots((prev) => prev.filter((_, i) => i !== index)),
5395
6091
  attachmentCount: screenshots.length + attachments.length,
5396
6092
  context: { ...assistContext != null ? assistContext : {}, reportType },
5397
6093
  reportTypeLabel: getTypeLabel(reportType),
@@ -5429,6 +6125,10 @@ function ReportDialog({
5429
6125
  isSubmitting,
5430
6126
  submitted,
5431
6127
  onSend: () => void handleSubmit(),
6128
+ onReportGlitchgrabProblem: reportGlitchgrabProblem ? (prefill) => {
6129
+ setSelfReportPrefill(prefill != null ? prefill : "");
6130
+ setSelfReportFrom("assist");
6131
+ } : void 0,
5432
6132
  onDegrade: (message) => {
5433
6133
  setAssistOpen(false);
5434
6134
  setAssistUsed(true);
@@ -5475,7 +6175,7 @@ function getTypeIcon(type, color, size = 24) {
5475
6175
  };
5476
6176
  switch (type) {
5477
6177
  case "RATING":
5478
- return /* @__PURE__ */ jsx3("svg", { ...props, children: /* @__PURE__ */ jsx3(
6178
+ return /* @__PURE__ */ jsx4("svg", { ...props, children: /* @__PURE__ */ jsx4(
5479
6179
  "path",
5480
6180
  {
5481
6181
  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",
@@ -5485,7 +6185,7 @@ function getTypeIcon(type, color, size = 24) {
5485
6185
  }
5486
6186
  ) });
5487
6187
  case "BUG":
5488
- return /* @__PURE__ */ jsx3("svg", { ...props, children: /* @__PURE__ */ jsx3(
6188
+ return /* @__PURE__ */ jsx4("svg", { ...props, children: /* @__PURE__ */ jsx4(
5489
6189
  "path",
5490
6190
  {
5491
6191
  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",
@@ -5495,7 +6195,7 @@ function getTypeIcon(type, color, size = 24) {
5495
6195
  }
5496
6196
  ) });
5497
6197
  case "FEATURE_REQUEST":
5498
- return /* @__PURE__ */ jsx3("svg", { ...props, children: /* @__PURE__ */ jsx3(
6198
+ return /* @__PURE__ */ jsx4("svg", { ...props, children: /* @__PURE__ */ jsx4(
5499
6199
  "path",
5500
6200
  {
5501
6201
  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",
@@ -5505,8 +6205,8 @@ function getTypeIcon(type, color, size = 24) {
5505
6205
  }
5506
6206
  ) });
5507
6207
  case "UI_IMPROVEMENT":
5508
- return /* @__PURE__ */ jsxs3("svg", { ...props, children: [
5509
- /* @__PURE__ */ jsx3(
6208
+ return /* @__PURE__ */ jsxs4("svg", { ...props, children: [
6209
+ /* @__PURE__ */ jsx4(
5510
6210
  "rect",
5511
6211
  {
5512
6212
  x: "3",
@@ -5518,7 +6218,7 @@ function getTypeIcon(type, color, size = 24) {
5518
6218
  strokeWidth: "1.5"
5519
6219
  }
5520
6220
  ),
5521
- /* @__PURE__ */ jsx3(
6221
+ /* @__PURE__ */ jsx4(
5522
6222
  "path",
5523
6223
  {
5524
6224
  d: "M3 9h18M9 21V9",
@@ -5529,7 +6229,7 @@ function getTypeIcon(type, color, size = 24) {
5529
6229
  )
5530
6230
  ] });
5531
6231
  case "PERFORMANCE":
5532
- return /* @__PURE__ */ jsx3("svg", { ...props, children: /* @__PURE__ */ jsx3(
6232
+ return /* @__PURE__ */ jsx4("svg", { ...props, children: /* @__PURE__ */ jsx4(
5533
6233
  "path",
5534
6234
  {
5535
6235
  d: "M12 21a9 9 0 100-18 9 9 0 000 18zM12 12l4-4M12 7v.01",
@@ -5540,7 +6240,7 @@ function getTypeIcon(type, color, size = 24) {
5540
6240
  }
5541
6241
  ) });
5542
6242
  case "SECURITY":
5543
- return /* @__PURE__ */ jsx3("svg", { ...props, children: /* @__PURE__ */ jsx3(
6243
+ return /* @__PURE__ */ jsx4("svg", { ...props, children: /* @__PURE__ */ jsx4(
5544
6244
  "path",
5545
6245
  {
5546
6246
  d: "M12 3l7 3v5c0 4.5-3 8.5-7 10-4-1.5-7-5.5-7-10V6l7-3z",
@@ -5550,9 +6250,9 @@ function getTypeIcon(type, color, size = 24) {
5550
6250
  }
5551
6251
  ) });
5552
6252
  case "QUESTION":
5553
- return /* @__PURE__ */ jsxs3("svg", { ...props, children: [
5554
- /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "10", stroke: color, strokeWidth: "1.5" }),
5555
- /* @__PURE__ */ jsx3(
6253
+ return /* @__PURE__ */ jsxs4("svg", { ...props, children: [
6254
+ /* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "10", stroke: color, strokeWidth: "1.5" }),
6255
+ /* @__PURE__ */ jsx4(
5556
6256
  "path",
5557
6257
  {
5558
6258
  d: "M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3M12 17h.01",
@@ -5564,7 +6264,7 @@ function getTypeIcon(type, color, size = 24) {
5564
6264
  )
5565
6265
  ] });
5566
6266
  case "OTHER":
5567
- return /* @__PURE__ */ jsx3("svg", { ...props, children: /* @__PURE__ */ jsx3(
6267
+ return /* @__PURE__ */ jsx4("svg", { ...props, children: /* @__PURE__ */ jsx4(
5568
6268
  "path",
5569
6269
  {
5570
6270
  d: "M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2v10z",
@@ -5577,8 +6277,8 @@ function getTypeIcon(type, color, size = 24) {
5577
6277
  }
5578
6278
 
5579
6279
  // src/booking-dialog.tsx
5580
- import { useCallback, useEffect as useEffect4, useMemo, useState as useState4 } from "react";
5581
- import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
6280
+ import { useCallback, useEffect as useEffect5, useMemo as useMemo2, useState as useState5 } from "react";
6281
+ import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
5582
6282
  var t = {
5583
6283
  bg: "#141414",
5584
6284
  surface: "#1c1c1c",
@@ -5615,24 +6315,24 @@ function BookingDialog({
5615
6315
  onClose
5616
6316
  }) {
5617
6317
  var _a;
5618
- const [step, setStep] = useState4("slots");
5619
- const [slots, setSlots] = useState4(null);
5620
- const [heading, setHeading] = useState4({
6318
+ const [step, setStep] = useState5("slots");
6319
+ const [slots, setSlots] = useState5(null);
6320
+ const [heading, setHeading] = useState5({
5621
6321
  title: "Book a demo",
5622
6322
  description: null
5623
6323
  });
5624
- const [whatsappUrl, setWhatsappUrl] = useState4(null);
5625
- const [selected, setSelected] = useState4(null);
5626
- const [name, setName] = useState4("");
5627
- const [email, setEmail] = useState4("");
5628
- const [phone, setPhone] = useState4("");
5629
- const [note, setNote] = useState4("");
5630
- const [code, setCode] = useState4("");
5631
- const [bookingId, setBookingId] = useState4(null);
5632
- const [meetUrl, setMeetUrl] = useState4(null);
5633
- const [busy, setBusy] = useState4(false);
5634
- const [error, setError] = useState4(null);
5635
- const headers = useMemo(
6324
+ const [whatsappUrl, setWhatsappUrl] = useState5(null);
6325
+ const [selected, setSelected] = useState5(null);
6326
+ const [name, setName] = useState5("");
6327
+ const [email, setEmail] = useState5("");
6328
+ const [phone, setPhone] = useState5("");
6329
+ const [note, setNote] = useState5("");
6330
+ const [code, setCode] = useState5("");
6331
+ const [bookingId, setBookingId] = useState5(null);
6332
+ const [meetUrl, setMeetUrl] = useState5(null);
6333
+ const [busy, setBusy] = useState5(false);
6334
+ const [error, setError] = useState5(null);
6335
+ const headers = useMemo2(
5636
6336
  () => ({ Authorization: `Bearer ${token}`, "Content-Type": "application/json" }),
5637
6337
  [token]
5638
6338
  );
@@ -5661,7 +6361,7 @@ function BookingDialog({
5661
6361
  setSlots([]);
5662
6362
  }
5663
6363
  }, [baseUrl, headers]);
5664
- useEffect4(() => {
6364
+ useEffect5(() => {
5665
6365
  if (!open) return;
5666
6366
  setStep("slots");
5667
6367
  setSelected(null);
@@ -5670,7 +6370,7 @@ function BookingDialog({
5670
6370
  setError(null);
5671
6371
  void loadSlots();
5672
6372
  }, [open, loadSlots]);
5673
- useEffect4(() => {
6373
+ useEffect5(() => {
5674
6374
  if (!open) return;
5675
6375
  const onKey = (e) => {
5676
6376
  if (e.key === "Escape") onClose();
@@ -5740,7 +6440,7 @@ function BookingDialog({
5740
6440
  }
5741
6441
  }
5742
6442
  const canSubmitDetails = name.trim() && email.includes("@") && phone.replace(/\D/g, "").length >= 8;
5743
- return /* @__PURE__ */ jsx4(
6443
+ return /* @__PURE__ */ jsx5(
5744
6444
  "div",
5745
6445
  {
5746
6446
  onClick: (e) => {
@@ -5757,7 +6457,7 @@ function BookingDialog({
5757
6457
  padding: 16,
5758
6458
  fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif"
5759
6459
  },
5760
- children: /* @__PURE__ */ jsxs4(
6460
+ children: /* @__PURE__ */ jsxs5(
5761
6461
  "div",
5762
6462
  {
5763
6463
  role: "dialog",
@@ -5775,7 +6475,7 @@ function BookingDialog({
5775
6475
  overflow: "hidden"
5776
6476
  },
5777
6477
  children: [
5778
- /* @__PURE__ */ jsxs4(
6478
+ /* @__PURE__ */ jsxs5(
5779
6479
  "div",
5780
6480
  {
5781
6481
  style: {
@@ -5787,11 +6487,11 @@ function BookingDialog({
5787
6487
  gap: 12
5788
6488
  },
5789
6489
  children: [
5790
- /* @__PURE__ */ jsxs4("div", { children: [
5791
- /* @__PURE__ */ jsx4("div", { style: { fontSize: 15, fontWeight: 600 }, children: heading.title }),
5792
- heading.description && /* @__PURE__ */ jsx4("div", { style: { fontSize: 12, color: t.muted, marginTop: 2 }, children: heading.description })
6490
+ /* @__PURE__ */ jsxs5("div", { children: [
6491
+ /* @__PURE__ */ jsx5("div", { style: { fontSize: 15, fontWeight: 600 }, children: heading.title }),
6492
+ heading.description && /* @__PURE__ */ jsx5("div", { style: { fontSize: 12, color: t.muted, marginTop: 2 }, children: heading.description })
5793
6493
  ] }),
5794
- /* @__PURE__ */ jsx4(
6494
+ /* @__PURE__ */ jsx5(
5795
6495
  "button",
5796
6496
  {
5797
6497
  onClick: onClose,
@@ -5803,10 +6503,10 @@ function BookingDialog({
5803
6503
  ]
5804
6504
  }
5805
6505
  ),
5806
- /* @__PURE__ */ jsxs4("div", { style: { padding: 18, overflowY: "auto", flex: "1 1 auto" }, children: [
5807
- error && /* @__PURE__ */ jsx4("div", { style: { color: t.danger, fontSize: 12, marginBottom: 12, lineHeight: 1.5 }, children: error }),
5808
- step === "slots" && /* @__PURE__ */ jsxs4(Fragment3, { children: [
5809
- whatsappUrl && /* @__PURE__ */ jsxs4(
6506
+ /* @__PURE__ */ jsxs5("div", { style: { padding: 18, overflowY: "auto", flex: "1 1 auto" }, children: [
6507
+ error && /* @__PURE__ */ jsx5("div", { style: { color: t.danger, fontSize: 12, marginBottom: 12, lineHeight: 1.5 }, children: error }),
6508
+ step === "slots" && /* @__PURE__ */ jsxs5(Fragment4, { children: [
6509
+ whatsappUrl && /* @__PURE__ */ jsxs5(
5810
6510
  "a",
5811
6511
  {
5812
6512
  href: whatsappUrl,
@@ -5825,15 +6525,15 @@ function BookingDialog({
5825
6525
  },
5826
6526
  children: [
5827
6527
  "\u{1F4AC} Rather book on WhatsApp?",
5828
- /* @__PURE__ */ jsx4("span", { style: { display: "block", fontSize: 11, color: t.muted, marginTop: 2 }, children: "We'll ask the same questions in chat." })
6528
+ /* @__PURE__ */ jsx5("span", { style: { display: "block", fontSize: 11, color: t.muted, marginTop: 2 }, children: "We'll ask the same questions in chat." })
5829
6529
  ]
5830
6530
  }
5831
6531
  ),
5832
- slots === null && /* @__PURE__ */ jsx4("div", { style: { color: t.muted, fontSize: 13 }, children: "Finding times\u2026" }),
5833
- (slots == null ? void 0 : slots.length) === 0 && !error && /* @__PURE__ */ jsx4("div", { style: { color: t.muted, fontSize: 13 }, children: "No times available right now." }),
5834
- [...byDay.entries()].map(([day, daySlots]) => /* @__PURE__ */ jsxs4("div", { style: { marginBottom: 18 }, children: [
5835
- /* @__PURE__ */ jsx4("div", { style: { fontSize: 11, color: t.muted, marginBottom: 8, textTransform: "uppercase", letterSpacing: ".6px" }, children: formatDay(daySlots[0].startsAt) }),
5836
- /* @__PURE__ */ jsx4("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: daySlots.map((slot) => /* @__PURE__ */ jsx4(
6532
+ slots === null && /* @__PURE__ */ jsx5("div", { style: { color: t.muted, fontSize: 13 }, children: "Finding times\u2026" }),
6533
+ (slots == null ? void 0 : slots.length) === 0 && !error && /* @__PURE__ */ jsx5("div", { style: { color: t.muted, fontSize: 13 }, children: "No times available right now." }),
6534
+ [...byDay.entries()].map(([day, daySlots]) => /* @__PURE__ */ jsxs5("div", { style: { marginBottom: 18 }, children: [
6535
+ /* @__PURE__ */ jsx5("div", { style: { fontSize: 11, color: t.muted, marginBottom: 8, textTransform: "uppercase", letterSpacing: ".6px" }, children: formatDay(daySlots[0].startsAt) }),
6536
+ /* @__PURE__ */ jsx5("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: daySlots.map((slot) => /* @__PURE__ */ jsx5(
5837
6537
  "button",
5838
6538
  {
5839
6539
  onClick: () => {
@@ -5855,13 +6555,13 @@ function BookingDialog({
5855
6555
  )) })
5856
6556
  ] }, day))
5857
6557
  ] }),
5858
- step === "details" && selected && /* @__PURE__ */ jsxs4("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: [
5859
- /* @__PURE__ */ jsxs4("div", { style: { fontSize: 13, color: t.muted }, children: [
6558
+ step === "details" && selected && /* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: [
6559
+ /* @__PURE__ */ jsxs5("div", { style: { fontSize: 13, color: t.muted }, children: [
5860
6560
  formatDay(selected.startsAt),
5861
6561
  " \xB7 ",
5862
6562
  formatTime(selected.startsAt),
5863
6563
  " \xB7 ",
5864
- /* @__PURE__ */ jsx4(
6564
+ /* @__PURE__ */ jsx5(
5865
6565
  "button",
5866
6566
  {
5867
6567
  onClick: () => setStep("slots"),
@@ -5870,9 +6570,9 @@ function BookingDialog({
5870
6570
  }
5871
6571
  )
5872
6572
  ] }),
5873
- /* @__PURE__ */ jsx4(Field, { label: "Your name", value: name, onChange: setName }),
5874
- /* @__PURE__ */ jsx4(Field, { label: "Email", value: email, onChange: setEmail, type: "email" }),
5875
- /* @__PURE__ */ jsx4(
6573
+ /* @__PURE__ */ jsx5(Field, { label: "Your name", value: name, onChange: setName }),
6574
+ /* @__PURE__ */ jsx5(Field, { label: "Email", value: email, onChange: setEmail, type: "email" }),
6575
+ /* @__PURE__ */ jsx5(
5876
6576
  Field,
5877
6577
  {
5878
6578
  label: "Mobile number",
@@ -5882,8 +6582,8 @@ function BookingDialog({
5882
6582
  hint: "We send a code here to confirm, then a reminder before the call."
5883
6583
  }
5884
6584
  ),
5885
- /* @__PURE__ */ jsx4(Field, { label: "Anything we should know? (optional)", value: note, onChange: setNote }),
5886
- /* @__PURE__ */ jsx4(
6585
+ /* @__PURE__ */ jsx5(Field, { label: "Anything we should know? (optional)", value: note, onChange: setNote }),
6586
+ /* @__PURE__ */ jsx5(
5887
6587
  "button",
5888
6588
  {
5889
6589
  onClick: startBooking,
@@ -5893,10 +6593,10 @@ function BookingDialog({
5893
6593
  }
5894
6594
  )
5895
6595
  ] }),
5896
- step === "code" && /* @__PURE__ */ jsxs4("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: [
5897
- /* @__PURE__ */ jsx4("div", { style: { fontSize: 13, color: t.muted, lineHeight: 1.5 }, children: "We sent a 4-digit code to your phone. Your slot is held for 10 minutes." }),
5898
- /* @__PURE__ */ jsx4(Field, { label: "Code", value: code, onChange: setCode }),
5899
- /* @__PURE__ */ jsx4(
6596
+ step === "code" && /* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: [
6597
+ /* @__PURE__ */ jsx5("div", { style: { fontSize: 13, color: t.muted, lineHeight: 1.5 }, children: "We sent a 4-digit code to your phone. Your slot is held for 10 minutes." }),
6598
+ /* @__PURE__ */ jsx5(Field, { label: "Code", value: code, onChange: setCode }),
6599
+ /* @__PURE__ */ jsx5(
5900
6600
  "button",
5901
6601
  {
5902
6602
  onClick: confirmBooking,
@@ -5906,15 +6606,15 @@ function BookingDialog({
5906
6606
  }
5907
6607
  )
5908
6608
  ] }),
5909
- step === "done" && /* @__PURE__ */ jsxs4("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: [
5910
- /* @__PURE__ */ jsx4("div", { style: { fontSize: 15, fontWeight: 600 }, children: "You're booked." }),
5911
- /* @__PURE__ */ jsxs4("div", { style: { fontSize: 13, color: t.muted, lineHeight: 1.6 }, children: [
6609
+ step === "done" && /* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: [
6610
+ /* @__PURE__ */ jsx5("div", { style: { fontSize: 15, fontWeight: 600 }, children: "You're booked." }),
6611
+ /* @__PURE__ */ jsxs5("div", { style: { fontSize: 13, color: t.muted, lineHeight: 1.6 }, children: [
5912
6612
  selected && `${formatDay(selected.startsAt)} at ${formatTime(selected.startsAt)}. `,
5913
6613
  "A calendar invite is on its way to ",
5914
6614
  email,
5915
6615
  ", and we'll send a WhatsApp reminder before the call."
5916
6616
  ] }),
5917
- meetUrl && /* @__PURE__ */ jsx4("a", { href: meetUrl, target: "_blank", rel: "noreferrer", style: { ...primaryStyle(false), textAlign: "center", textDecoration: "none" }, children: "Open the meeting link" })
6617
+ meetUrl && /* @__PURE__ */ jsx5("a", { href: meetUrl, target: "_blank", rel: "noreferrer", style: { ...primaryStyle(false), textAlign: "center", textDecoration: "none" }, children: "Open the meeting link" })
5918
6618
  ] })
5919
6619
  ] })
5920
6620
  ]
@@ -5943,9 +6643,9 @@ function Field({
5943
6643
  type = "text",
5944
6644
  hint
5945
6645
  }) {
5946
- return /* @__PURE__ */ jsxs4("label", { style: { display: "block", fontSize: 11, color: t.muted }, children: [
6646
+ return /* @__PURE__ */ jsxs5("label", { style: { display: "block", fontSize: 11, color: t.muted }, children: [
5947
6647
  label,
5948
- /* @__PURE__ */ jsx4(
6648
+ /* @__PURE__ */ jsx5(
5949
6649
  "input",
5950
6650
  {
5951
6651
  type,
@@ -5966,7 +6666,7 @@ function Field({
5966
6666
  }
5967
6667
  }
5968
6668
  ),
5969
- hint && /* @__PURE__ */ jsx4("div", { style: { marginTop: 4, fontSize: 10, color: t.muted }, children: hint })
6669
+ hint && /* @__PURE__ */ jsx5("div", { style: { marginTop: 4, fontSize: 10, color: t.muted }, children: hint })
5970
6670
  ] });
5971
6671
  }
5972
6672
 
@@ -6107,7 +6807,7 @@ function matchesShortcut(e) {
6107
6807
  }
6108
6808
 
6109
6809
  // src/provider.tsx
6110
- import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
6810
+ import { Fragment as Fragment5, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
6111
6811
  var DEFAULT_BASE_URL2 = "https://glitchgrab.dev";
6112
6812
  var GlitchgrabContext = createContext(null);
6113
6813
  function useGlitchgrab() {
@@ -6119,7 +6819,7 @@ function useGlitchgrab() {
6119
6819
  }
6120
6820
  function GlitchgrabProviderInner({
6121
6821
  token,
6122
- session,
6822
+ session: sessionProp,
6123
6823
  baseUrl,
6124
6824
  onError,
6125
6825
  onReportSent,
@@ -6134,7 +6834,16 @@ function GlitchgrabProviderInner({
6134
6834
  context: appContext2,
6135
6835
  responseBodyOrigins: responseBodyOrigins2
6136
6836
  }) {
6137
- const visitedPagesRef = useRef4([]);
6837
+ const visitedPagesRef = useRef5([]);
6838
+ const sessionKey = sessionProp ? [
6839
+ sessionProp.userId,
6840
+ sessionProp.name,
6841
+ sessionProp.email,
6842
+ sessionProp.phone,
6843
+ sessionProp.avatarUrl,
6844
+ sessionProp.image
6845
+ ].map((v) => v == null ? "" : String(v)).join("\0") : "";
6846
+ const session = useMemo3(() => sessionProp, [sessionKey]);
6138
6847
  setRelease(release2);
6139
6848
  if (appContext2) setContexts(appContext2);
6140
6849
  registerCaptureConfig({
@@ -6146,12 +6855,12 @@ function GlitchgrabProviderInner({
6146
6855
  onError,
6147
6856
  onReportSent
6148
6857
  });
6149
- useEffect5(() => {
6858
+ useEffect6(() => {
6150
6859
  if (enableBreadcrumbs) {
6151
6860
  initBreadcrumbs(maxBreadcrumbs2, { responseBodyOrigins: responseBodyOrigins2 });
6152
6861
  }
6153
6862
  }, [enableBreadcrumbs, maxBreadcrumbs2, responseBodyOrigins2 == null ? void 0 : responseBodyOrigins2.join(",")]);
6154
- useEffect5(() => {
6863
+ useEffect6(() => {
6155
6864
  try {
6156
6865
  if (typeof window === "undefined") return;
6157
6866
  const trackPage = () => {
@@ -6188,7 +6897,7 @@ function GlitchgrabProviderInner({
6188
6897
  } catch (e) {
6189
6898
  }
6190
6899
  }, []);
6191
- useEffect5(() => {
6900
+ useEffect6(() => {
6192
6901
  try {
6193
6902
  if (typeof window === "undefined") return;
6194
6903
  if (process.env.NODE_ENV === "development") return;
@@ -6353,6 +7062,40 @@ function GlitchgrabProviderInner({
6353
7062
  (description, metadata) => report("BUG", description, metadata),
6354
7063
  [report]
6355
7064
  );
7065
+ const reportGlitchgrabProblem = useCallback2(
7066
+ async (params) => {
7067
+ var _a, _b;
7068
+ try {
7069
+ const context = captureContext(visitedPagesRef.current);
7070
+ const body = JSON.stringify({
7071
+ ...params,
7072
+ pageUrl: context.url,
7073
+ userAgent: context.userAgent,
7074
+ deviceInfo: (_a = context.deviceInfo) != null ? _a : void 0,
7075
+ visitedPages: context.visitedPages,
7076
+ breadcrumbs: context.breadcrumbs,
7077
+ ...(session == null ? void 0 : session.userId) ? { reporterId: session.userId } : {},
7078
+ ...(session == null ? void 0 : session.name) ? { reporterName: String(session.name) } : {},
7079
+ ...(session == null ? void 0 : session.email) ? { reporterEmail: String(session.email) } : {}
7080
+ });
7081
+ const res = await fetch(`${baseUrl}/api/v1/sdk/glitchgrab-report`, {
7082
+ method: "POST",
7083
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
7084
+ body,
7085
+ // keepalive caps the body at 64KB — screenshots blow past it.
7086
+ ...body.length < 6e4 ? { keepalive: true } : {}
7087
+ });
7088
+ const json = await res.json().catch(() => null);
7089
+ if (!res.ok || !(json == null ? void 0 : json.success)) {
7090
+ return { success: false, message: (_b = json == null ? void 0 : json.error) != null ? _b : "Couldn't send it" };
7091
+ }
7092
+ return { success: true, ...json.data };
7093
+ } catch (e) {
7094
+ return null;
7095
+ }
7096
+ },
7097
+ [token, baseUrl, session]
7098
+ );
6356
7099
  const feedback = useCallback2(
6357
7100
  async (rating, message, metadata) => {
6358
7101
  try {
@@ -6463,7 +7206,7 @@ function GlitchgrabProviderInner({
6463
7206
  window.dispatchEvent(new CustomEvent("glitchgrab:open-report", { detail: options }));
6464
7207
  }
6465
7208
  }, []);
6466
- useEffect5(() => {
7209
+ useEffect6(() => {
6467
7210
  try {
6468
7211
  if (typeof document === "undefined") return;
6469
7212
  document.documentElement.setAttribute("data-glitchgrab-sdk", "1");
@@ -6471,11 +7214,12 @@ function GlitchgrabProviderInner({
6471
7214
  } catch (e) {
6472
7215
  }
6473
7216
  }, []);
6474
- const [projectName, setProjectName] = useState5(null);
6475
- const [aiAssist, setAiAssist] = useState5(false);
6476
- const [bookingOpen, setBookingOpen] = useState5(false);
7217
+ const [projectName, setProjectName] = useState6(null);
7218
+ const [aiAssist, setAiAssist] = useState6(false);
7219
+ const [glitchgrabReport, setGlitchgrabReport] = useState6(false);
7220
+ const [bookingOpen, setBookingOpen] = useState6(false);
6477
7221
  const openBookingDialog = useCallback2(() => setBookingOpen(true), []);
6478
- useEffect5(() => {
7222
+ useEffect6(() => {
6479
7223
  let cancelled = false;
6480
7224
  fetch(`${baseUrl}/api/v1/sdk/project`, {
6481
7225
  headers: { Authorization: `Bearer ${token}` }
@@ -6484,13 +7228,14 @@ function GlitchgrabProviderInner({
6484
7228
  if (cancelled || !(json == null ? void 0 : json.success) || !((_a = json.data) == null ? void 0 : _a.name)) return;
6485
7229
  setProjectName(json.data.name);
6486
7230
  setAiAssist(json.data.aiAssist === true);
7231
+ setGlitchgrabReport(json.data.glitchgrabReport === true);
6487
7232
  }).catch(() => {
6488
7233
  });
6489
7234
  return () => {
6490
7235
  cancelled = true;
6491
7236
  };
6492
7237
  }, [baseUrl, token]);
6493
- useEffect5(() => {
7238
+ useEffect6(() => {
6494
7239
  try {
6495
7240
  if (typeof window === "undefined") return;
6496
7241
  const handleKeyDown = (e) => {
@@ -6504,7 +7249,7 @@ function GlitchgrabProviderInner({
6504
7249
  } catch (e) {
6505
7250
  }
6506
7251
  }, [openReportDialog]);
6507
- const reporter = useMemo2(() => {
7252
+ const reporter = useMemo3(() => {
6508
7253
  var _a;
6509
7254
  if (!session) return null;
6510
7255
  const avatar = (_a = session.avatarUrl) != null ? _a : session.image;
@@ -6514,11 +7259,11 @@ function GlitchgrabProviderInner({
6514
7259
  avatarUrl: typeof avatar === "string" ? avatar : null
6515
7260
  };
6516
7261
  }, [session]);
6517
- const [shortcutLabel, setShortcutLabel] = useState5(GLITCHGRAB_SHORTCUT2);
6518
- useEffect5(() => {
7262
+ const [shortcutLabel, setShortcutLabel] = useState6(GLITCHGRAB_SHORTCUT2);
7263
+ useEffect6(() => {
6519
7264
  setShortcutLabel(getShortcutLabel2());
6520
7265
  }, []);
6521
- return /* @__PURE__ */ jsxs5(
7266
+ return /* @__PURE__ */ jsxs6(
6522
7267
  GlitchgrabContext.Provider,
6523
7268
  {
6524
7269
  value: {
@@ -6538,7 +7283,7 @@ function GlitchgrabProviderInner({
6538
7283
  shortcutLabel
6539
7284
  },
6540
7285
  children: [
6541
- /* @__PURE__ */ jsx5(
7286
+ /* @__PURE__ */ jsx6(
6542
7287
  GlitchgrabErrorBoundary,
6543
7288
  {
6544
7289
  token,
@@ -6550,7 +7295,7 @@ function GlitchgrabProviderInner({
6550
7295
  children
6551
7296
  }
6552
7297
  ),
6553
- /* @__PURE__ */ jsx5(
7298
+ /* @__PURE__ */ jsx6(
6554
7299
  BookingDialog,
6555
7300
  {
6556
7301
  token,
@@ -6559,20 +7304,21 @@ function GlitchgrabProviderInner({
6559
7304
  onClose: () => setBookingOpen(false)
6560
7305
  }
6561
7306
  ),
6562
- /* @__PURE__ */ jsx5(
7307
+ /* @__PURE__ */ jsx6(
6563
7308
  ReportDialog,
6564
7309
  {
6565
7310
  report,
6566
7311
  sendFeedback: feedback,
6567
7312
  enhanceText: enhance,
6568
7313
  assist: aiAssist ? assist : void 0,
7314
+ reportGlitchgrabProblem: glitchgrabReport ? reportGlitchgrabProblem : void 0,
6569
7315
  transcribeAudio: transcribe,
6570
7316
  types,
6571
7317
  showSeverity,
6572
7318
  reporter,
6573
- headerSlot: projectName ? /* @__PURE__ */ jsxs5("div", { style: { fontSize: 11, color: "#9aa0a6" }, children: [
7319
+ headerSlot: projectName ? /* @__PURE__ */ jsxs6("div", { style: { fontSize: 11, color: "#9aa0a6" }, children: [
6574
7320
  "Reporting to ",
6575
- /* @__PURE__ */ jsx5("strong", { style: { color: "#e5e5e5" }, children: projectName })
7321
+ /* @__PURE__ */ jsx6("strong", { style: { color: "#e5e5e5" }, children: projectName })
6576
7322
  ] }) : null
6577
7323
  }
6578
7324
  )
@@ -6581,21 +7327,21 @@ function GlitchgrabProviderInner({
6581
7327
  );
6582
7328
  }
6583
7329
  function GlitchgrabProvider(props) {
6584
- if (!props.token) return /* @__PURE__ */ jsx5(Fragment4, { children: props.children });
7330
+ if (!props.token) return /* @__PURE__ */ jsx6(Fragment5, { children: props.children });
6585
7331
  const resolvedProps = {
6586
7332
  ...props,
6587
7333
  baseUrl: props.baseUrl || DEFAULT_BASE_URL2
6588
7334
  };
6589
7335
  try {
6590
- return /* @__PURE__ */ jsx5(GlitchgrabProviderInner, { ...resolvedProps });
7336
+ return /* @__PURE__ */ jsx6(GlitchgrabProviderInner, { ...resolvedProps });
6591
7337
  } catch (e) {
6592
- return /* @__PURE__ */ jsx5(Fragment4, { children: props.children });
7338
+ return /* @__PURE__ */ jsx6(Fragment5, { children: props.children });
6593
7339
  }
6594
7340
  }
6595
7341
 
6596
7342
  // src/report-button.tsx
6597
- import { useState as useState6 } from "react";
6598
- import { Fragment as Fragment5, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
7343
+ import { useState as useState7 } from "react";
7344
+ import { Fragment as Fragment6, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
6599
7345
  function useGlitchgrabSafe() {
6600
7346
  try {
6601
7347
  return useGlitchgrab();
@@ -6610,7 +7356,7 @@ function ReportButton({
6610
7356
  children
6611
7357
  }) {
6612
7358
  var _a, _b;
6613
- const [capturing, setCapturing] = useState6(false);
7359
+ const [capturing, setCapturing] = useState7(false);
6614
7360
  const glitchgrab = useGlitchgrabSafe();
6615
7361
  if (!glitchgrab) return null;
6616
7362
  const handleClick = async () => {
@@ -6619,7 +7365,7 @@ function ReportButton({
6619
7365
  setCapturing(false);
6620
7366
  };
6621
7367
  if (children) {
6622
- return /* @__PURE__ */ jsx6(Fragment5, { children: children({ onClick: handleClick, capturing }) });
7368
+ return /* @__PURE__ */ jsx7(Fragment6, { children: children({ onClick: handleClick, capturing }) });
6623
7369
  }
6624
7370
  const isTop = (_a = position == null ? void 0 : position.startsWith("top")) != null ? _a : false;
6625
7371
  const isLeft = (_b = position == null ? void 0 : position.endsWith("left")) != null ? _b : false;
@@ -6627,7 +7373,7 @@ function ReportButton({
6627
7373
  ...isLeft ? { left: "16px" } : { right: "16px" },
6628
7374
  ...isTop ? { top: "16px" } : { bottom: "16px" }
6629
7375
  };
6630
- return /* @__PURE__ */ jsxs6(
7376
+ return /* @__PURE__ */ jsxs7(
6631
7377
  "button",
6632
7378
  {
6633
7379
  type: "button",
@@ -6662,7 +7408,7 @@ function ReportButton({
6662
7408
  },
6663
7409
  "aria-label": label,
6664
7410
  children: [
6665
- /* @__PURE__ */ jsx6(
7411
+ /* @__PURE__ */ jsx7(
6666
7412
  "svg",
6667
7413
  {
6668
7414
  width: "16",
@@ -6670,7 +7416,7 @@ function ReportButton({
6670
7416
  viewBox: "0 0 16 16",
6671
7417
  fill: "none",
6672
7418
  style: { flexShrink: 0 },
6673
- children: /* @__PURE__ */ jsx6(
7419
+ children: /* @__PURE__ */ jsx7(
6674
7420
  "path",
6675
7421
  {
6676
7422
  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",
@@ -6686,15 +7432,15 @@ function ReportButton({
6686
7432
  }
6687
7433
 
6688
7434
  // src/book-demo-button.tsx
6689
- import { Fragment as Fragment6, jsx as jsx7 } from "react/jsx-runtime";
7435
+ import { Fragment as Fragment7, jsx as jsx8 } from "react/jsx-runtime";
6690
7436
  function BookDemoButton({
6691
7437
  label = "Book a demo",
6692
7438
  className,
6693
7439
  children
6694
7440
  }) {
6695
7441
  const { openBookingDialog } = useGlitchgrab();
6696
- if (children) return /* @__PURE__ */ jsx7(Fragment6, { children: children({ onClick: openBookingDialog }) });
6697
- return /* @__PURE__ */ jsx7(
7442
+ if (children) return /* @__PURE__ */ jsx8(Fragment7, { children: children({ onClick: openBookingDialog }) });
7443
+ return /* @__PURE__ */ jsx8(
6698
7444
  "button",
6699
7445
  {
6700
7446
  type: "button",
@@ -6716,7 +7462,7 @@ function BookDemoButton({
6716
7462
  }
6717
7463
 
6718
7464
  // src/feedback-button.tsx
6719
- import { Fragment as Fragment7, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
7465
+ import { Fragment as Fragment8, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
6720
7466
  function useGlitchgrabSafe2() {
6721
7467
  try {
6722
7468
  return useGlitchgrab();
@@ -6735,7 +7481,7 @@ function FeedbackButton({
6735
7481
  if (!glitchgrab) return null;
6736
7482
  const handleClick = () => glitchgrab.openFeedbackDialog();
6737
7483
  if (children) {
6738
- return /* @__PURE__ */ jsx8(Fragment7, { children: children({ onClick: handleClick }) });
7484
+ return /* @__PURE__ */ jsx9(Fragment8, { children: children({ onClick: handleClick }) });
6739
7485
  }
6740
7486
  const isTop = (_a = position == null ? void 0 : position.startsWith("top")) != null ? _a : false;
6741
7487
  const isLeft = (_b = position == null ? void 0 : position.endsWith("left")) != null ? _b : false;
@@ -6743,7 +7489,7 @@ function FeedbackButton({
6743
7489
  ...isLeft ? { left: "16px" } : { right: "16px" },
6744
7490
  ...isTop ? { top: "16px" } : { bottom: "16px" }
6745
7491
  };
6746
- return /* @__PURE__ */ jsxs7(
7492
+ return /* @__PURE__ */ jsxs8(
6747
7493
  "button",
6748
7494
  {
6749
7495
  type: "button",
@@ -6776,7 +7522,7 @@ function FeedbackButton({
6776
7522
  },
6777
7523
  "aria-label": label,
6778
7524
  children: [
6779
- /* @__PURE__ */ jsx8(
7525
+ /* @__PURE__ */ jsx9(
6780
7526
  "svg",
6781
7527
  {
6782
7528
  width: "16",
@@ -6785,7 +7531,7 @@ function FeedbackButton({
6785
7531
  fill: "none",
6786
7532
  style: { flexShrink: 0 },
6787
7533
  "aria-hidden": "true",
6788
- children: /* @__PURE__ */ jsx8(
7534
+ children: /* @__PURE__ */ jsx9(
6789
7535
  "path",
6790
7536
  {
6791
7537
  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",
@@ -6801,17 +7547,17 @@ function FeedbackButton({
6801
7547
  }
6802
7548
 
6803
7549
  // src/use-reports.ts
6804
- import { useState as useState7, useEffect as useEffect6, useCallback as useCallback3 } from "react";
7550
+ import { useState as useState8, useEffect as useEffect7, useCallback as useCallback3 } from "react";
6805
7551
  var BASE_URL = "https://glitchgrab.dev";
6806
7552
  function useGlitchgrabReports({
6807
7553
  token,
6808
7554
  userId,
6809
7555
  limit = 100
6810
7556
  }) {
6811
- const [reports, setReports] = useState7([]);
6812
- const [isLoading, setIsLoading] = useState7(true);
6813
- const [isFetching, setIsFetching] = useState7(false);
6814
- const [error, setError] = useState7(null);
7557
+ const [reports, setReports] = useState8([]);
7558
+ const [isLoading, setIsLoading] = useState8(true);
7559
+ const [isFetching, setIsFetching] = useState8(false);
7560
+ const [error, setError] = useState8(null);
6815
7561
  const fetchReports = useCallback3(async () => {
6816
7562
  var _a, _b;
6817
7563
  if (!token || !userId) {
@@ -6838,7 +7584,7 @@ function useGlitchgrabReports({
6838
7584
  setIsFetching(false);
6839
7585
  }
6840
7586
  }, [token, userId, limit]);
6841
- useEffect6(() => {
7587
+ useEffect7(() => {
6842
7588
  fetchReports();
6843
7589
  }, [fetchReports]);
6844
7590
  return { reports, isLoading, isFetching, error, refetch: fetchReports };
@@ -6875,8 +7621,8 @@ function useGlitchgrabActions({
6875
7621
  onSuccess,
6876
7622
  onError
6877
7623
  }) {
6878
- const [isPending, setIsPending] = useState7(false);
6879
- const [error, setError] = useState7(null);
7624
+ const [isPending, setIsPending] = useState8(false);
7625
+ const [error, setError] = useState8(null);
6880
7626
  const run = useCallback3(
6881
7627
  async (reportId, body) => {
6882
7628
  setIsPending(true);
@@ -6907,7 +7653,7 @@ function useGlitchgrabActions({
6907
7653
  }
6908
7654
 
6909
7655
  // src/use-feedback.ts
6910
- import { useState as useState8, useEffect as useEffect7, useCallback as useCallback4 } from "react";
7656
+ import { useState as useState9, useEffect as useEffect8, useCallback as useCallback4 } from "react";
6911
7657
  var DEFAULT_BASE_URL3 = "https://glitchgrab.dev";
6912
7658
  function buildUrl({
6913
7659
  approvedOnly,
@@ -6933,10 +7679,10 @@ async function fetchGlitchgrabFeedback(query) {
6933
7679
  }
6934
7680
  function useGlitchgrabFeedback(query) {
6935
7681
  const { token, approvedOnly, userId, minRating, limit, baseUrl } = query;
6936
- const [feedback, setFeedback] = useState8([]);
6937
- const [isLoading, setIsLoading] = useState8(true);
6938
- const [isFetching, setIsFetching] = useState8(false);
6939
- const [error, setError] = useState8(null);
7682
+ const [feedback, setFeedback] = useState9([]);
7683
+ const [isLoading, setIsLoading] = useState9(true);
7684
+ const [isFetching, setIsFetching] = useState9(false);
7685
+ const [error, setError] = useState9(null);
6940
7686
  const load = useCallback4(async () => {
6941
7687
  if (!token) {
6942
7688
  setIsLoading(false);
@@ -6961,7 +7707,7 @@ function useGlitchgrabFeedback(query) {
6961
7707
  setIsFetching(false);
6962
7708
  }
6963
7709
  }, [token, approvedOnly, userId, minRating, limit, baseUrl]);
6964
- useEffect7(() => {
7710
+ useEffect8(() => {
6965
7711
  load();
6966
7712
  }, [load]);
6967
7713
  return { feedback, isLoading, isFetching, error, refetch: load };