browsertrack 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/.github/workflows/docs.yml +54 -0
  2. package/AGENTS.md +133 -0
  3. package/README.md +1 -1
  4. package/dist/{chunk-6A7FFDIB.js → chunk-6VA7GBAO.js} +29 -4
  5. package/dist/chunk-6VA7GBAO.js.map +1 -0
  6. package/dist/{chunk-ANMR5WBH.js → chunk-G2Y3CXCY.js} +2 -2
  7. package/dist/{chunk-BSKNG4V7.js → chunk-ILRYKMME.js} +30 -1
  8. package/dist/chunk-ILRYKMME.js.map +1 -0
  9. package/dist/{chunk-X7C5CHBO.js → chunk-SKCMT2DE.js} +637 -76
  10. package/dist/chunk-SKCMT2DE.js.map +1 -0
  11. package/dist/{chunk-ZLNGOOH2.js → chunk-SPCIROIU.js} +65 -3
  12. package/dist/chunk-SPCIROIU.js.map +1 -0
  13. package/dist/cli/index.js +115 -2
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/client/index.cjs +637 -75
  16. package/dist/client/index.d.ts +16 -2
  17. package/dist/client/index.js +2 -2
  18. package/dist/client.iife.js +393 -72
  19. package/dist/core/index.d.ts +12 -4
  20. package/dist/core/index.js +9 -3
  21. package/dist/daemon/index.d.ts +1 -1
  22. package/dist/daemon/index.js +3 -3
  23. package/dist/{engine-DKloFjvs.d.ts → engine-CeT9URuN.d.ts} +4 -0
  24. package/dist/index.d.ts +4 -3
  25. package/dist/index.js +13 -7
  26. package/dist/mcp/index.d.ts +2 -2
  27. package/dist/mcp/index.js +2 -2
  28. package/dist/{server-CN-se8td.d.ts → server-Dd8NX2Mk.d.ts} +1 -1
  29. package/docboot.config.js +16 -0
  30. package/docs/cli.md +51 -0
  31. package/docs/closed-loop-verification.md +57 -0
  32. package/docs/getting-started.md +122 -0
  33. package/docs/incidents-diagnostics.md +61 -0
  34. package/docs/index.md +46 -0
  35. package/docs/mcp-reference.md +128 -0
  36. package/docs/security-privacy.md +32 -0
  37. package/docs/visual-notes.md +67 -0
  38. package/package.json +6 -2
  39. package/packages/client/package.json +2 -2
  40. package/packages/client/src/notes/inspector.ts +689 -79
  41. package/packages/client/src/transport/websocket.ts +15 -0
  42. package/packages/core/package.json +3 -0
  43. package/packages/core/src/redaction.ts +40 -5
  44. package/packages/daemon/src/server/ws.ts +72 -1
  45. package/packages/daemon/src/session/manager.ts +21 -0
  46. package/packages/daemon/src/storage/db.ts +10 -1
  47. package/test/client/interceptors.test.ts +61 -0
  48. package/test/core/redaction.test.ts +12 -0
  49. package/dist/chunk-6A7FFDIB.js.map +0 -1
  50. package/dist/chunk-BSKNG4V7.js.map +0 -1
  51. package/dist/chunk-X7C5CHBO.js.map +0 -1
  52. package/dist/chunk-ZLNGOOH2.js.map +0 -1
  53. package/packages/core/dist/index.d.ts +0 -317
  54. package/packages/core/dist/index.js +0 -221
  55. /package/dist/{chunk-ANMR5WBH.js.map → chunk-G2Y3CXCY.js.map} +0 -0
@@ -58,6 +58,8 @@ var BreadcrumbBuffer = class {
58
58
  };
59
59
 
60
60
  // packages/core/src/redaction.ts
61
+ var import_redact = require("@visulima/redact");
62
+ var REDACTED_PLACEHOLDER = "[REDACTED]";
61
63
  var SENSITIVE_KEY_PATTERNS = [
62
64
  /^authorization$/i,
63
65
  /^cookie$/i,
@@ -87,7 +89,6 @@ var SENSITIVE_QUERY_PARAMS = [
87
89
  "code",
88
90
  "signature"
89
91
  ];
90
- var REDACTED_PLACEHOLDER = "[REDACTED]";
91
92
  function isSensitiveKey(key) {
92
93
  if (!key) return false;
93
94
  const cleaned = key.replace(/[-_]/g, "");
@@ -1020,6 +1021,7 @@ var WebSocketTransport = class {
1020
1021
  __publicField(this, "maxReconnectDelay", 1e4);
1021
1022
  __publicField(this, "reconnectTimer", null);
1022
1023
  __publicField(this, "commandHandler");
1024
+ __publicField(this, "messageListeners", []);
1023
1025
  __publicField(this, "isDestroyed", false);
1024
1026
  this.wsUrl = options.url || "ws://127.0.0.1:7331";
1025
1027
  this.projectId = options.projectId;
@@ -1028,6 +1030,12 @@ var WebSocketTransport = class {
1028
1030
  setCommandHandler(handler) {
1029
1031
  this.commandHandler = handler;
1030
1032
  }
1033
+ onMessage(listener) {
1034
+ this.messageListeners.push(listener);
1035
+ return () => {
1036
+ this.messageListeners = this.messageListeners.filter((l) => l !== listener);
1037
+ };
1038
+ }
1031
1039
  getSessionId() {
1032
1040
  return this.sessionId;
1033
1041
  }
@@ -1051,6 +1059,12 @@ var WebSocketTransport = class {
1051
1059
  const raw = typeof event.data === "string" ? event.data : "";
1052
1060
  if (!raw) return;
1053
1061
  const msg = JSON.parse(raw);
1062
+ for (const listener of this.messageListeners) {
1063
+ try {
1064
+ listener(msg);
1065
+ } catch {
1066
+ }
1067
+ }
1054
1068
  if (msg.type === "hello_ack") {
1055
1069
  this.sessionId = msg.sessionId;
1056
1070
  if (this.debug) {
@@ -1165,8 +1179,11 @@ var NoteInspector = class {
1165
1179
  __publicField(this, "highlightOverlay", null);
1166
1180
  __publicField(this, "regionOverlay", null);
1167
1181
  __publicField(this, "regionBox", null);
1182
+ __publicField(this, "regionBanner", null);
1183
+ __publicField(this, "markersContainer", null);
1168
1184
  __publicField(this, "toolbarElement", null);
1169
1185
  __publicField(this, "modalOverlay", null);
1186
+ __publicField(this, "cardOverlay", null);
1170
1187
  __publicField(this, "activeMode", "idle");
1171
1188
  __publicField(this, "hoveredElement", null);
1172
1189
  __publicField(this, "selectedElement", null);
@@ -1174,6 +1191,8 @@ var NoteInspector = class {
1174
1191
  __publicField(this, "isDraggingRegion", false);
1175
1192
  __publicField(this, "dragStartX", 0);
1176
1193
  __publicField(this, "dragStartY", 0);
1194
+ __publicField(this, "savedNotes", []);
1195
+ __publicField(this, "showMarkers", true);
1177
1196
  __publicField(this, "cleanups", []);
1178
1197
  this.transport = transport;
1179
1198
  this.screenshotDriver = screenshotDriver;
@@ -1193,8 +1212,19 @@ var NoteInspector = class {
1193
1212
  } else {
1194
1213
  this.ensureContainer();
1195
1214
  }
1215
+ const unsubscribe = this.transport.onMessage((msg) => {
1216
+ if (msg && msg.type === "notes_sync" && Array.isArray(msg.notes)) {
1217
+ this.syncNotes(msg.notes);
1218
+ }
1219
+ });
1220
+ this.cleanups.push(unsubscribe);
1196
1221
  this.setupListeners();
1197
1222
  }
1223
+ syncNotes(notes) {
1224
+ this.savedNotes = notes;
1225
+ this.updateToolbarCount();
1226
+ this.renderMarkers();
1227
+ }
1198
1228
  setMode(mode) {
1199
1229
  this.activeMode = mode;
1200
1230
  this.updateToolbarState();
@@ -1222,16 +1252,17 @@ var NoteInspector = class {
1222
1252
  const style = document.createElement("style");
1223
1253
  style.textContent = `
1224
1254
  :host {
1225
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
1255
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
1226
1256
  color-scheme: dark;
1227
1257
  -webkit-font-smoothing: antialiased;
1258
+ -moz-osx-font-smoothing: grayscale;
1228
1259
  }
1229
1260
 
1230
1261
  /* 1. Element Highlight Overlay */
1231
1262
  .bt-highlight {
1232
1263
  position: fixed;
1233
1264
  border: 2px solid #3b82f6;
1234
- background: rgba(59, 130, 246, 0.15);
1265
+ background: rgba(59, 130, 246, 0.16);
1235
1266
  border-radius: 4px;
1236
1267
  pointer-events: none;
1237
1268
  transition: all 0.05s ease-out;
@@ -1241,18 +1272,19 @@ var NoteInspector = class {
1241
1272
 
1242
1273
  .bt-badge {
1243
1274
  position: absolute;
1244
- top: -24px;
1275
+ top: -26px;
1245
1276
  left: 0;
1246
- background: #1e293b;
1277
+ background: #0f172a;
1247
1278
  color: #38bdf8;
1248
1279
  border: 1px solid #3b82f6;
1249
1280
  font-size: 11px;
1250
1281
  font-weight: 600;
1251
- padding: 2px 6px;
1252
- border-radius: 3px;
1282
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1283
+ padding: 2px 7px;
1284
+ border-radius: 4px;
1253
1285
  white-space: nowrap;
1254
1286
  pointer-events: none;
1255
- box-shadow: 0 2px 4px rgba(0,0,0,0.3);
1287
+ box-shadow: 0 4px 6px -1px rgba(0,0,0,0.5);
1256
1288
  }
1257
1289
 
1258
1290
  /* 2. Region Selection Overlay */
@@ -1264,7 +1296,8 @@ var NoteInspector = class {
1264
1296
  cursor: crosshair;
1265
1297
  z-index: 2147483642;
1266
1298
  pointer-events: auto;
1267
- background: rgba(15, 23, 42, 0.2);
1299
+ background: rgba(15, 23, 42, 0.25);
1300
+ user-select: none;
1268
1301
  }
1269
1302
 
1270
1303
  .bt-region-box {
@@ -1278,32 +1311,171 @@ var NoteInspector = class {
1278
1311
 
1279
1312
  .bt-region-badge {
1280
1313
  position: absolute;
1281
- top: -24px;
1314
+ top: -26px;
1282
1315
  left: 0;
1283
1316
  background: #0f172a;
1284
1317
  color: #38bdf8;
1285
1318
  border: 1px solid #0284c7;
1286
1319
  font-size: 11px;
1287
1320
  font-weight: 600;
1288
- padding: 2px 6px;
1289
- border-radius: 3px;
1321
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1322
+ padding: 2px 7px;
1323
+ border-radius: 4px;
1290
1324
  white-space: nowrap;
1291
1325
  pointer-events: none;
1326
+ box-shadow: 0 4px 6px -1px rgba(0,0,0,0.5);
1327
+ }
1328
+
1329
+ .bt-region-banner {
1330
+ position: fixed;
1331
+ top: 20px;
1332
+ left: 50%;
1333
+ transform: translateX(-50%);
1334
+ background: #0f172a;
1335
+ color: #f8fafc;
1336
+ border: 1px solid #0284c7;
1337
+ border-radius: 30px;
1338
+ padding: 8px 16px;
1339
+ display: flex;
1340
+ align-items: center;
1341
+ gap: 12px;
1342
+ box-shadow: 0 10px 25px -5px rgba(0,0,0,0.6);
1343
+ font-size: 12.5px;
1344
+ font-weight: 500;
1345
+ pointer-events: auto;
1346
+ z-index: 2147483645;
1347
+ user-select: none;
1348
+ }
1349
+
1350
+ .bt-region-cancel-btn {
1351
+ background: rgba(239, 68, 68, 0.15);
1352
+ color: #fca5a5;
1353
+ border: 1px solid rgba(239, 68, 68, 0.4);
1354
+ padding: 3px 10px;
1355
+ border-radius: 20px;
1356
+ font-size: 11px;
1357
+ font-weight: 600;
1358
+ cursor: pointer;
1359
+ transition: all 0.15s ease;
1360
+ display: inline-flex;
1361
+ align-items: center;
1362
+ gap: 4px;
1363
+ font-family: inherit;
1364
+ }
1365
+
1366
+ .bt-region-cancel-btn:hover {
1367
+ background: rgba(239, 68, 68, 0.3);
1368
+ color: #ffffff;
1369
+ }
1370
+
1371
+ /* 3. Note Markers on Page */
1372
+ .bt-markers-layer {
1373
+ position: fixed;
1374
+ top: 0;
1375
+ left: 0;
1376
+ width: 0;
1377
+ height: 0;
1378
+ pointer-events: none;
1379
+ z-index: 2147483638;
1380
+ }
1381
+
1382
+ .bt-note-marker {
1383
+ position: fixed;
1384
+ pointer-events: auto;
1385
+ background: linear-gradient(135deg, #2563eb, #1d4ed8);
1386
+ color: #ffffff;
1387
+ border: 2px solid #ffffff;
1388
+ box-shadow: 0 4px 12px rgba(0,0,0,0.5), 0 0 0 1px rgba(37,99,235,0.4);
1389
+ border-radius: 999px;
1390
+ height: 26px;
1391
+ min-width: 26px;
1392
+ padding: 0 7px;
1393
+ display: inline-flex;
1394
+ align-items: center;
1395
+ justify-content: center;
1396
+ gap: 4px;
1397
+ cursor: pointer;
1398
+ font-size: 11px;
1399
+ font-weight: 700;
1400
+ user-select: none;
1401
+ transition: transform 0.15s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.15s ease;
1402
+ animation: bt-pop-in 0.2s ease-out;
1403
+ box-sizing: border-box;
1404
+ z-index: 2147483641;
1405
+ }
1406
+
1407
+ @keyframes bt-pop-in {
1408
+ 0% { transform: scale(0.6); opacity: 0; }
1409
+ 100% { transform: scale(1); opacity: 1; }
1410
+ }
1411
+
1412
+ .bt-note-marker:hover {
1413
+ transform: scale(1.15) translateY(-2px);
1414
+ box-shadow: 0 8px 20px rgba(37,99,235,0.6), 0 0 0 2px #60a5fa;
1415
+ }
1416
+
1417
+ .bt-marker-resolved {
1418
+ background: linear-gradient(135deg, #475569, #334155);
1419
+ border-color: #94a3b8;
1420
+ opacity: 0.75;
1421
+ }
1422
+
1423
+ .bt-region-marker-box {
1424
+ position: fixed;
1425
+ border: 2px dashed #0284c7;
1426
+ background: rgba(14, 165, 233, 0.08);
1427
+ pointer-events: none;
1428
+ box-sizing: border-box;
1429
+ border-radius: 6px;
1430
+ z-index: 2147483639;
1431
+ }
1432
+
1433
+ .bt-page-notes-dock {
1434
+ position: fixed;
1435
+ top: 16px;
1436
+ right: 16px;
1437
+ display: flex;
1438
+ flex-direction: column;
1439
+ gap: 6px;
1440
+ pointer-events: none;
1441
+ z-index: 2147483641;
1292
1442
  }
1293
1443
 
1294
- /* 3. Floating Quick Toolbar */
1444
+ .bt-page-note-pill {
1445
+ background: #0f172a;
1446
+ color: #c084fc;
1447
+ border: 1px solid #7e22ce;
1448
+ border-radius: 20px;
1449
+ padding: 5px 12px;
1450
+ font-size: 11.5px;
1451
+ font-weight: 600;
1452
+ display: inline-flex;
1453
+ align-items: center;
1454
+ gap: 6px;
1455
+ box-shadow: 0 4px 12px rgba(0,0,0,0.5);
1456
+ cursor: pointer;
1457
+ pointer-events: auto;
1458
+ transition: all 0.15s ease;
1459
+ }
1460
+
1461
+ .bt-page-note-pill:hover {
1462
+ background: #1e1b4b;
1463
+ transform: translateY(-1px);
1464
+ }
1465
+
1466
+ /* 4. Floating Quick Toolbar */
1295
1467
  .bt-toolbar {
1296
1468
  position: fixed;
1297
1469
  bottom: 20px;
1298
1470
  right: 20px;
1299
- background: #1e293b;
1471
+ background: #0f172a;
1300
1472
  border: 1px solid #334155;
1301
1473
  border-radius: 30px;
1302
1474
  padding: 4px 6px;
1303
1475
  display: flex;
1304
1476
  align-items: center;
1305
1477
  gap: 4px;
1306
- box-shadow: 0 10px 15px -3px rgba(0,0,0,0.5), 0 4px 6px -4px rgba(0,0,0,0.5);
1478
+ box-shadow: 0 10px 25px -3px rgba(0,0,0,0.6), 0 4px 6px -4px rgba(0,0,0,0.4);
1307
1479
  pointer-events: auto;
1308
1480
  z-index: 2147483646;
1309
1481
  user-select: none;
@@ -1316,17 +1488,18 @@ var NoteInspector = class {
1316
1488
  color: #94a3b8;
1317
1489
  font-size: 12px;
1318
1490
  font-weight: 500;
1319
- padding: 6px 10px;
1491
+ padding: 6px 12px;
1320
1492
  border-radius: 20px;
1321
1493
  cursor: pointer;
1322
1494
  display: flex;
1323
1495
  align-items: center;
1324
- gap: 5px;
1496
+ gap: 6px;
1325
1497
  transition: all 0.15s ease;
1498
+ font-family: inherit;
1326
1499
  }
1327
1500
 
1328
1501
  .bt-toolbar-btn:hover {
1329
- background: #334155;
1502
+ background: #1e293b;
1330
1503
  color: #f8fafc;
1331
1504
  }
1332
1505
 
@@ -1334,15 +1507,27 @@ var NoteInspector = class {
1334
1507
  background: #2563eb;
1335
1508
  color: #ffffff;
1336
1509
  font-weight: 600;
1510
+ box-shadow: 0 2px 6px rgba(37, 99, 235, 0.35);
1511
+ }
1512
+
1513
+ .bt-count-pill {
1514
+ background: rgba(255, 255, 255, 0.2);
1515
+ color: #ffffff;
1516
+ font-size: 10px;
1517
+ font-weight: 700;
1518
+ padding: 1px 6px;
1519
+ border-radius: 10px;
1520
+ line-height: 1.2;
1337
1521
  }
1338
1522
 
1339
1523
  .bt-toolbar-divider {
1340
1524
  width: 1px;
1341
1525
  height: 16px;
1342
1526
  background: #334155;
1527
+ margin: 0 2px;
1343
1528
  }
1344
1529
 
1345
- /* 4. Modal Backdrop & Editor */
1530
+ /* 5. Modals & Popover Card */
1346
1531
  .bt-modal-backdrop {
1347
1532
  position: fixed;
1348
1533
  top: 0;
@@ -1350,7 +1535,7 @@ var NoteInspector = class {
1350
1535
  width: 100vw;
1351
1536
  height: 100vh;
1352
1537
  background: rgba(15, 23, 42, 0.75);
1353
- backdrop-filter: blur(4px);
1538
+ backdrop-filter: blur(6px);
1354
1539
  display: flex;
1355
1540
  align-items: center;
1356
1541
  justify-content: center;
@@ -1358,20 +1543,26 @@ var NoteInspector = class {
1358
1543
  z-index: 2147483647;
1359
1544
  opacity: 1;
1360
1545
  box-sizing: border-box;
1546
+ animation: bt-fade-in 0.15s ease-out;
1547
+ }
1548
+
1549
+ @keyframes bt-fade-in {
1550
+ from { opacity: 0; transform: scale(0.98); }
1551
+ to { opacity: 1; transform: scale(1); }
1361
1552
  }
1362
1553
 
1363
1554
  .bt-modal {
1364
- background: #1e293b;
1555
+ background: #0f172a;
1365
1556
  color: #f8fafc;
1366
1557
  border: 1px solid #334155;
1367
- border-radius: 12px;
1368
- padding: 18px;
1369
- width: 420px;
1370
- max-width: 90vw;
1371
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.7), 0 8px 10px -6px rgba(0, 0, 0, 0.7);
1558
+ border-radius: 14px;
1559
+ padding: 20px;
1560
+ width: 450px;
1561
+ max-width: 92vw;
1562
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.8), 0 0 0 1px rgba(255, 255, 255, 0.05);
1372
1563
  display: flex;
1373
1564
  flex-direction: column;
1374
- gap: 12px;
1565
+ gap: 14px;
1375
1566
  box-sizing: border-box;
1376
1567
  }
1377
1568
 
@@ -1382,87 +1573,181 @@ var NoteInspector = class {
1382
1573
  }
1383
1574
 
1384
1575
  .bt-modal-title {
1385
- font-size: 14px;
1576
+ font-size: 14.5px;
1386
1577
  font-weight: 600;
1578
+ letter-spacing: -0.01em;
1387
1579
  display: flex;
1388
1580
  align-items: center;
1389
- gap: 6px;
1581
+ gap: 8px;
1390
1582
  color: #f8fafc;
1391
1583
  }
1392
1584
 
1393
1585
  .bt-mode-badge {
1394
1586
  font-size: 10px;
1395
1587
  font-weight: 700;
1588
+ letter-spacing: 0.05em;
1396
1589
  text-transform: uppercase;
1397
- background: rgba(59, 130, 246, 0.2);
1590
+ padding: 2px 7px;
1591
+ border-radius: 6px;
1592
+ }
1593
+
1594
+ .bt-badge-element {
1595
+ background: rgba(59, 130, 246, 0.15);
1398
1596
  color: #60a5fa;
1399
- border: 1px solid #3b82f6;
1400
- padding: 2px 6px;
1401
- border-radius: 4px;
1597
+ border: 1px solid rgba(59, 130, 246, 0.4);
1598
+ }
1599
+
1600
+ .bt-badge-region {
1601
+ background: rgba(14, 165, 233, 0.15);
1602
+ color: #38bdf8;
1603
+ border: 1px solid rgba(14, 165, 233, 0.4);
1604
+ }
1605
+
1606
+ .bt-badge-page {
1607
+ background: rgba(168, 85, 247, 0.15);
1608
+ color: #c084fc;
1609
+ border: 1px solid rgba(168, 85, 247, 0.4);
1610
+ }
1611
+
1612
+ .bt-badge-status-open {
1613
+ background: rgba(16, 185, 129, 0.15);
1614
+ color: #34d399;
1615
+ border: 1px solid rgba(16, 185, 129, 0.4);
1616
+ }
1617
+
1618
+ .bt-badge-status-resolved {
1619
+ background: rgba(100, 116, 139, 0.2);
1620
+ color: #94a3b8;
1621
+ border: 1px solid rgba(100, 116, 139, 0.4);
1402
1622
  }
1403
1623
 
1404
1624
  .bt-close-btn {
1405
1625
  background: transparent;
1406
1626
  border: none;
1407
1627
  color: #94a3b8;
1408
- font-size: 16px;
1628
+ font-size: 15px;
1409
1629
  cursor: pointer;
1410
- padding: 2px 6px;
1411
- border-radius: 4px;
1630
+ padding: 3px 7px;
1631
+ border-radius: 6px;
1632
+ transition: all 0.12s ease;
1633
+ display: flex;
1634
+ align-items: center;
1635
+ justify-content: center;
1412
1636
  }
1413
1637
  .bt-close-btn:hover {
1414
- background: #334155;
1638
+ background: #1e293b;
1415
1639
  color: #ffffff;
1416
1640
  }
1417
1641
 
1418
1642
  .bt-target-pill {
1419
- background: #0f172a;
1643
+ background: #090d16;
1420
1644
  color: #94a3b8;
1421
- border: 1px solid #334155;
1422
- border-radius: 6px;
1423
- padding: 6px 10px;
1645
+ border: 1px solid #1e293b;
1646
+ border-radius: 8px;
1647
+ padding: 8px 12px;
1424
1648
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1425
- font-size: 11px;
1649
+ font-size: 11.5px;
1650
+ display: flex;
1651
+ align-items: center;
1652
+ gap: 8px;
1653
+ overflow: hidden;
1654
+ }
1655
+
1656
+ .bt-pill-content {
1426
1657
  overflow: hidden;
1427
1658
  text-overflow: ellipsis;
1428
1659
  white-space: nowrap;
1660
+ color: #cbd5e1;
1661
+ }
1662
+
1663
+ .bt-note-message-box {
1664
+ background: #090d16;
1665
+ border: 1px solid #1e293b;
1666
+ border-radius: 8px;
1667
+ padding: 12px 14px;
1668
+ font-size: 13.5px;
1669
+ line-height: 1.5;
1670
+ color: #f1f5f9;
1671
+ white-space: pre-wrap;
1672
+ word-break: break-word;
1673
+ max-height: 180px;
1674
+ overflow-y: auto;
1429
1675
  }
1430
1676
 
1431
1677
  .bt-textarea {
1432
- background: #0f172a;
1678
+ background: #090d16;
1433
1679
  color: #f8fafc;
1434
1680
  border: 1px solid #334155;
1435
- border-radius: 6px;
1436
- padding: 10px;
1437
- font-size: 13px;
1681
+ border-radius: 8px;
1682
+ padding: 12px;
1683
+ font-size: 13.5px;
1684
+ line-height: 1.5;
1438
1685
  resize: vertical;
1439
- min-height: 85px;
1686
+ min-height: 95px;
1440
1687
  outline: none;
1441
1688
  box-sizing: border-box;
1442
1689
  width: 100%;
1443
1690
  font-family: inherit;
1691
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
1692
+ }
1693
+
1694
+ .bt-textarea::placeholder {
1695
+ color: #64748b;
1444
1696
  }
1445
1697
 
1446
1698
  .bt-textarea:focus {
1447
1699
  border-color: #3b82f6;
1448
- box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.25);
1700
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.25);
1701
+ }
1702
+
1703
+ .bt-modal-footer {
1704
+ display: flex;
1705
+ justify-content: space-between;
1706
+ align-items: center;
1707
+ gap: 12px;
1708
+ margin-top: 2px;
1709
+ }
1710
+
1711
+ .bt-kbd-hint {
1712
+ font-size: 11px;
1713
+ color: #64748b;
1714
+ display: flex;
1715
+ align-items: center;
1716
+ gap: 4px;
1717
+ user-select: none;
1718
+ }
1719
+
1720
+ .bt-kbd-hint kbd {
1721
+ background: #1e293b;
1722
+ color: #94a3b8;
1723
+ border: 1px solid #334155;
1724
+ border-radius: 4px;
1725
+ padding: 1px 5px;
1726
+ font-family: inherit;
1727
+ font-size: 10px;
1728
+ font-weight: 600;
1449
1729
  }
1450
1730
 
1451
1731
  .bt-modal-actions {
1452
1732
  display: flex;
1453
1733
  justify-content: flex-end;
1734
+ align-items: center;
1454
1735
  gap: 8px;
1455
1736
  }
1456
1737
 
1457
1738
  .bt-btn {
1458
- padding: 8px 14px;
1459
- border-radius: 6px;
1460
- font-size: 12px;
1739
+ padding: 8px 16px;
1740
+ border-radius: 7px;
1741
+ font-size: 12.5px;
1461
1742
  font-weight: 600;
1462
1743
  cursor: pointer;
1463
1744
  border: 1px solid transparent;
1464
- transition: all 0.1s ease;
1745
+ transition: all 0.15s ease;
1465
1746
  font-family: inherit;
1747
+ display: inline-flex;
1748
+ align-items: center;
1749
+ justify-content: center;
1750
+ gap: 6px;
1466
1751
  }
1467
1752
 
1468
1753
  .bt-btn-cancel {
@@ -1470,20 +1755,38 @@ var NoteInspector = class {
1470
1755
  color: #94a3b8;
1471
1756
  }
1472
1757
  .bt-btn-cancel:hover {
1473
- background: #334155;
1758
+ background: #1e293b;
1474
1759
  color: #f8fafc;
1475
1760
  }
1476
1761
 
1477
1762
  .bt-btn-save {
1478
1763
  background: #2563eb;
1479
1764
  color: #ffffff;
1765
+ box-shadow: 0 2px 6px rgba(37, 99, 235, 0.35);
1480
1766
  }
1481
1767
  .bt-btn-save:hover {
1482
1768
  background: #1d4ed8;
1769
+ box-shadow: 0 4px 10px rgba(37, 99, 235, 0.45);
1770
+ }
1771
+
1772
+ .bt-btn-resolve {
1773
+ background: rgba(16, 185, 129, 0.15);
1774
+ color: #6ee7b7;
1775
+ border: 1px solid rgba(16, 185, 129, 0.35);
1776
+ }
1777
+ .bt-btn-resolve:hover {
1778
+ background: rgba(16, 185, 129, 0.3);
1779
+ color: #ffffff;
1780
+ }
1781
+
1782
+ .bt-btn-delete {
1783
+ background: rgba(239, 68, 68, 0.15);
1784
+ color: #fca5a5;
1785
+ border: 1px solid rgba(239, 68, 68, 0.35);
1483
1786
  }
1484
- .bt-btn-save:disabled {
1485
- opacity: 0.6;
1486
- cursor: not-allowed;
1787
+ .bt-btn-delete:hover {
1788
+ background: rgba(239, 68, 68, 0.3);
1789
+ color: #ffffff;
1487
1790
  }
1488
1791
  `;
1489
1792
  this.shadowRoot.appendChild(style);
@@ -1491,6 +1794,9 @@ var NoteInspector = class {
1491
1794
  this.highlightOverlay.className = "bt-highlight";
1492
1795
  this.highlightOverlay.style.display = "none";
1493
1796
  this.shadowRoot.appendChild(this.highlightOverlay);
1797
+ this.markersContainer = document.createElement("div");
1798
+ this.markersContainer.className = "bt-markers-layer";
1799
+ this.shadowRoot.appendChild(this.markersContainer);
1494
1800
  if (this.options.showToolbar) {
1495
1801
  this.createToolbar();
1496
1802
  }
@@ -1517,19 +1823,33 @@ var NoteInspector = class {
1517
1823
  <button class="bt-toolbar-btn" id="bt-mode-page" title="Leave full-page note">
1518
1824
  <span>\u{1F4C4}</span> Page
1519
1825
  </button>
1826
+ <div class="bt-toolbar-divider"></div>
1827
+ <button class="bt-toolbar-btn active" id="bt-toggle-notes" title="Toggle visible note markers on screen">
1828
+ <span>\u{1F4CC}</span> Notes <span class="bt-count-pill" id="bt-notes-count">0</span>
1829
+ </button>
1520
1830
  `;
1521
1831
  const btnElement = this.toolbarElement.querySelector("#bt-mode-element");
1522
1832
  const btnRegion = this.toolbarElement.querySelector("#bt-mode-region");
1523
1833
  const btnPage = this.toolbarElement.querySelector("#bt-mode-page");
1524
- btnElement.onclick = () => {
1834
+ const btnToggleNotes = this.toolbarElement.querySelector("#bt-toggle-notes");
1835
+ btnElement.onclick = (e) => {
1836
+ e.stopPropagation();
1525
1837
  this.setMode(this.activeMode === "element" ? "idle" : "element");
1526
1838
  };
1527
- btnRegion.onclick = () => {
1839
+ btnRegion.onclick = (e) => {
1840
+ e.stopPropagation();
1528
1841
  this.setMode(this.activeMode === "region" ? "idle" : "region");
1529
1842
  };
1530
- btnPage.onclick = () => {
1843
+ btnPage.onclick = (e) => {
1844
+ e.stopPropagation();
1531
1845
  this.setMode("page");
1532
1846
  };
1847
+ btnToggleNotes.onclick = (e) => {
1848
+ e.stopPropagation();
1849
+ this.showMarkers = !this.showMarkers;
1850
+ btnToggleNotes.classList.toggle("active", this.showMarkers);
1851
+ this.renderMarkers();
1852
+ };
1533
1853
  this.shadowRoot.appendChild(this.toolbarElement);
1534
1854
  }
1535
1855
  updateToolbarState() {
@@ -1541,9 +1861,186 @@ var NoteInspector = class {
1541
1861
  btnRegion?.classList.toggle("active", this.activeMode === "region");
1542
1862
  btnPage?.classList.toggle("active", this.activeMode === "page");
1543
1863
  }
1864
+ updateToolbarCount() {
1865
+ if (!this.toolbarElement) return;
1866
+ const countEl = this.toolbarElement.querySelector("#bt-notes-count");
1867
+ if (countEl) {
1868
+ const openCount = this.savedNotes.filter((n) => n.status === "OPEN").length;
1869
+ countEl.textContent = String(openCount);
1870
+ }
1871
+ }
1872
+ renderMarkers() {
1873
+ const root = this.ensureContainer();
1874
+ if (!root || !this.markersContainer) return;
1875
+ this.markersContainer.innerHTML = "";
1876
+ if (!this.showMarkers) return;
1877
+ const currentPath = window.location.pathname;
1878
+ const activeNotes = this.savedNotes.filter(
1879
+ (n) => n.status === "OPEN" && (n.route === currentPath || !n.route || n.route === "/" || window.location.href.includes(n.route))
1880
+ );
1881
+ const pageNotes = [];
1882
+ activeNotes.forEach((note, index) => {
1883
+ if (note.type === "page") {
1884
+ pageNotes.push(note);
1885
+ return;
1886
+ }
1887
+ if (note.type === "region" && note.region) {
1888
+ const regBox = document.createElement("div");
1889
+ regBox.className = "bt-region-marker-box";
1890
+ regBox.style.left = `${note.region.x}px`;
1891
+ regBox.style.top = `${note.region.y}px`;
1892
+ regBox.style.width = `${note.region.width}px`;
1893
+ regBox.style.height = `${note.region.height}px`;
1894
+ this.markersContainer.appendChild(regBox);
1895
+ const pin = document.createElement("div");
1896
+ pin.className = "bt-note-marker";
1897
+ pin.style.left = `${Math.max(4, note.region.x - 12)}px`;
1898
+ pin.style.top = `${Math.max(4, note.region.y - 12)}px`;
1899
+ pin.title = note.message;
1900
+ pin.innerHTML = `<span>\u{1F4D0}</span> <span>#${index + 1}</span>`;
1901
+ pin.onclick = (e) => {
1902
+ e.stopPropagation();
1903
+ this.openNoteCard(note);
1904
+ };
1905
+ this.markersContainer.appendChild(pin);
1906
+ return;
1907
+ }
1908
+ let targetEl = null;
1909
+ if (note.target?.selector) {
1910
+ try {
1911
+ targetEl = document.querySelector(note.target.selector);
1912
+ } catch {
1913
+ }
1914
+ }
1915
+ const rect = targetEl ? targetEl.getBoundingClientRect() : note.target?.boundingRect;
1916
+ if (rect) {
1917
+ const pin = document.createElement("div");
1918
+ pin.className = "bt-note-marker";
1919
+ pin.setAttribute("data-note-id", note.id);
1920
+ pin.title = note.message;
1921
+ pin.style.left = `${Math.max(4, rect.left - 10)}px`;
1922
+ pin.style.top = `${Math.max(4, rect.top - 12)}px`;
1923
+ pin.innerHTML = `<span>\u{1F4DD}</span> <span>#${index + 1}</span>`;
1924
+ pin.onclick = (e) => {
1925
+ e.stopPropagation();
1926
+ this.openNoteCard(note);
1927
+ };
1928
+ if (targetEl) {
1929
+ pin.onmouseenter = () => this.updateHighlight(targetEl);
1930
+ pin.onmouseleave = () => this.hideHighlight();
1931
+ }
1932
+ this.markersContainer.appendChild(pin);
1933
+ }
1934
+ });
1935
+ if (pageNotes.length > 0) {
1936
+ const pageDock = document.createElement("div");
1937
+ pageDock.className = "bt-page-notes-dock";
1938
+ pageNotes.forEach((pNote, idx) => {
1939
+ const pill = document.createElement("div");
1940
+ pill.className = "bt-page-note-pill";
1941
+ pill.innerHTML = `<span>\u{1F4C4}</span> <span>Page Note (${truncate(pNote.message, 25)})</span>`;
1942
+ pill.onclick = (e) => {
1943
+ e.stopPropagation();
1944
+ this.openNoteCard(pNote);
1945
+ };
1946
+ pageDock.appendChild(pill);
1947
+ });
1948
+ this.markersContainer.appendChild(pageDock);
1949
+ }
1950
+ }
1951
+ updateMarkerPositions() {
1952
+ if (!this.showMarkers || !this.markersContainer) return;
1953
+ this.renderMarkers();
1954
+ }
1955
+ openNoteCard(note) {
1956
+ const root = this.ensureContainer();
1957
+ if (!root) return;
1958
+ if (this.cardOverlay && this.cardOverlay.parentElement) {
1959
+ this.cardOverlay.parentElement.removeChild(this.cardOverlay);
1960
+ this.cardOverlay = null;
1961
+ }
1962
+ const backdrop = document.createElement("div");
1963
+ backdrop.className = "bt-modal-backdrop";
1964
+ this.cardOverlay = backdrop;
1965
+ const badgeClass = `bt-badge-${note.type.toLowerCase()}`;
1966
+ const statusClass = note.status === "OPEN" ? "bt-badge-status-open" : "bt-badge-status-resolved";
1967
+ const icon = note.type === "region" ? "\u{1F4D0}" : note.type === "page" ? "\u{1F4C4}" : "\u{1F3AF}";
1968
+ const contextText = note.type === "region" && note.region ? `Region: ${note.region.width} \xD7 ${note.region.height} px \xB7 Route: ${note.route}` : note.type === "page" ? `Page Note \xB7 Route: ${note.route}` : `${note.target?.selector || "Element"} (${note.target?.boundingRect?.width || 0}\xD7${note.target?.boundingRect?.height || 0}px) \xB7 ${note.route}`;
1969
+ const formattedDate = new Date(note.createdAt).toLocaleString();
1970
+ backdrop.innerHTML = `
1971
+ <div class="bt-modal">
1972
+ <div class="bt-modal-header">
1973
+ <div class="bt-modal-title">
1974
+ <span>${icon} Visual Note Details</span>
1975
+ <span class="bt-mode-badge ${badgeClass}">${note.type.toUpperCase()}</span>
1976
+ <span class="bt-mode-badge ${statusClass}">${note.status}</span>
1977
+ </div>
1978
+ <button class="bt-close-btn" id="btn-card-close" title="Close (Esc)">\u2715</button>
1979
+ </div>
1980
+
1981
+ <div class="bt-target-pill" title="${contextText}">
1982
+ <span>\u{1F3F7}\uFE0F</span>
1983
+ <span class="bt-pill-content">${contextText}</span>
1984
+ </div>
1985
+
1986
+ <div class="bt-note-message-box">${note.message}</div>
1987
+
1988
+ <div style="font-size: 11px; color: #64748b; display: flex; justify-content: space-between; padding: 0 2px;">
1989
+ <span>Created: ${formattedDate}</span>
1990
+ <span>ID: <code style="font-family: monospace; color: #94a3b8;">${note.id}</code></span>
1991
+ </div>
1992
+
1993
+ <div class="bt-modal-footer">
1994
+ <button class="bt-btn bt-btn-delete" id="btn-card-delete" title="Delete this note">
1995
+ <span>\u{1F5D1}\uFE0F</span> Delete
1996
+ </button>
1997
+ <div class="bt-modal-actions">
1998
+ <button class="bt-btn bt-btn-cancel" id="btn-card-dismiss">Close</button>
1999
+ <button class="bt-btn ${note.status === "OPEN" ? "bt-btn-resolve" : "bt-btn-save"}" id="btn-card-resolve">
2000
+ ${note.status === "OPEN" ? "<span>\u2705</span> Resolve Note" : "<span>\u21BA</span> Reopen"}
2001
+ </button>
2002
+ </div>
2003
+ </div>
2004
+ </div>
2005
+ `;
2006
+ const btnClose = backdrop.querySelector("#btn-card-close");
2007
+ const btnDismiss = backdrop.querySelector("#btn-card-dismiss");
2008
+ const btnResolve = backdrop.querySelector("#btn-card-resolve");
2009
+ const btnDelete = backdrop.querySelector("#btn-card-delete");
2010
+ const closeCard = () => {
2011
+ if (this.cardOverlay) {
2012
+ root.removeChild(this.cardOverlay);
2013
+ this.cardOverlay = null;
2014
+ this.hideHighlight();
2015
+ }
2016
+ };
2017
+ btnClose.onclick = closeCard;
2018
+ btnDismiss.onclick = closeCard;
2019
+ backdrop.onclick = (e) => {
2020
+ if (e.target === backdrop) closeCard();
2021
+ };
2022
+ btnResolve.onclick = () => {
2023
+ if (note.status === "OPEN") {
2024
+ this.transport.send({ type: "resolve_note", noteId: note.id });
2025
+ } else {
2026
+ this.transport.send({ type: "reopen_note", noteId: note.id });
2027
+ }
2028
+ closeCard();
2029
+ };
2030
+ btnDelete.onclick = () => {
2031
+ this.transport.send({ type: "delete_note", noteId: note.id });
2032
+ closeCard();
2033
+ };
2034
+ root.appendChild(backdrop);
2035
+ }
1544
2036
  setupListeners() {
1545
2037
  const onMouseMove = (e) => {
1546
- if (this.modalOverlay || this.isDraggingRegion || this.activeMode === "region") return;
2038
+ if (this.modalOverlay || this.cardOverlay || this.isDraggingRegion || this.activeMode === "region") return;
2039
+ const path = e.composedPath ? e.composedPath() : [];
2040
+ if (this.container && path.includes(this.container)) {
2041
+ this.hideHighlight();
2042
+ return;
2043
+ }
1547
2044
  if (e.altKey || this.activeMode === "element") {
1548
2045
  const target = document.elementFromPoint(e.clientX, e.clientY);
1549
2046
  if (target && target !== this.container && !this.container?.contains(target)) {
@@ -1557,7 +2054,12 @@ var NoteInspector = class {
1557
2054
  }
1558
2055
  };
1559
2056
  const onClick = (e) => {
1560
- if (this.modalOverlay || this.activeMode === "region") return;
2057
+ if (this.modalOverlay || this.cardOverlay) return;
2058
+ const path = e.composedPath ? e.composedPath() : [];
2059
+ if (this.container && path.includes(this.container)) {
2060
+ return;
2061
+ }
2062
+ if (this.activeMode === "region") return;
1561
2063
  if (e.altKey || this.activeMode === "element") {
1562
2064
  e.preventDefault();
1563
2065
  e.stopPropagation();
@@ -1571,18 +2073,39 @@ var NoteInspector = class {
1571
2073
  }
1572
2074
  }
1573
2075
  };
2076
+ const onKeyDown = (e) => {
2077
+ if (e.key === "Escape") {
2078
+ if (this.cardOverlay && this.cardOverlay.parentElement && this.shadowRoot) {
2079
+ this.shadowRoot.removeChild(this.cardOverlay);
2080
+ this.cardOverlay = null;
2081
+ } else if (this.activeMode === "region" || this.activeMode === "element") {
2082
+ this.setMode("idle");
2083
+ }
2084
+ }
2085
+ };
1574
2086
  const onKeyUp = (e) => {
1575
- if (e.key === "Alt" && !this.modalOverlay && this.activeMode !== "element") {
2087
+ if (e.key === "Alt" && !this.modalOverlay && !this.cardOverlay && this.activeMode !== "element") {
1576
2088
  this.hideHighlight();
1577
2089
  }
1578
2090
  };
2091
+ const onScrollOrResize = () => {
2092
+ requestAnimationFrame(() => {
2093
+ this.updateMarkerPositions();
2094
+ });
2095
+ };
1579
2096
  window.addEventListener("mousemove", onMouseMove, { capture: true, passive: true });
1580
2097
  window.addEventListener("click", onClick, { capture: true });
2098
+ window.addEventListener("keydown", onKeyDown, { capture: true });
1581
2099
  window.addEventListener("keyup", onKeyUp, { capture: true });
2100
+ window.addEventListener("scroll", onScrollOrResize, { capture: true, passive: true });
2101
+ window.addEventListener("resize", onScrollOrResize, { passive: true });
1582
2102
  this.cleanups.push(() => {
1583
2103
  window.removeEventListener("mousemove", onMouseMove, { capture: true });
1584
2104
  window.removeEventListener("click", onClick, { capture: true });
2105
+ window.removeEventListener("keydown", onKeyDown, { capture: true });
1585
2106
  window.removeEventListener("keyup", onKeyUp, { capture: true });
2107
+ window.removeEventListener("scroll", onScrollOrResize, { capture: true });
2108
+ window.removeEventListener("resize", onScrollOrResize);
1586
2109
  });
1587
2110
  }
1588
2111
  showRegionOverlay() {
@@ -1595,7 +2118,26 @@ var NoteInspector = class {
1595
2118
  this.regionBox.className = "bt-region-box";
1596
2119
  this.regionBox.style.display = "none";
1597
2120
  this.regionOverlay.appendChild(this.regionBox);
2121
+ this.regionBanner = document.createElement("div");
2122
+ this.regionBanner.className = "bt-region-banner";
2123
+ this.regionBanner.innerHTML = `
2124
+ <span>\u{1F4D0} Drag rectangle on screen to select region</span>
2125
+ <button class="bt-region-cancel-btn" id="bt-region-cancel">\u2715 Cancel (Esc)</button>
2126
+ `;
2127
+ const btnCancel = this.regionBanner.querySelector("#bt-region-cancel");
2128
+ btnCancel.onclick = (e) => {
2129
+ e.stopPropagation();
2130
+ this.setMode("idle");
2131
+ };
2132
+ this.regionOverlay.appendChild(this.regionBanner);
2133
+ this.regionOverlay.oncontextmenu = (e) => {
2134
+ e.preventDefault();
2135
+ this.setMode("idle");
2136
+ };
1598
2137
  this.regionOverlay.onmousedown = (e) => {
2138
+ const path = e.composedPath ? e.composedPath() : [];
2139
+ if (this.regionBanner && path.includes(this.regionBanner)) return;
2140
+ if (this.toolbarElement && path.includes(this.toolbarElement)) return;
1599
2141
  this.isDraggingRegion = true;
1600
2142
  this.dragStartX = e.clientX;
1601
2143
  this.dragStartY = e.clientY;
@@ -1636,7 +2178,7 @@ var NoteInspector = class {
1636
2178
  const top = Math.min(this.dragStartY, currentY);
1637
2179
  const width = Math.abs(currentX - this.dragStartX);
1638
2180
  const height = Math.abs(currentY - this.dragStartY);
1639
- if (width > 20 && height > 20) {
2181
+ if (width > 15 && height > 15) {
1640
2182
  this.selectedRegion = {
1641
2183
  x: Math.round(left),
1642
2184
  y: Math.round(top),
@@ -1652,11 +2194,16 @@ var NoteInspector = class {
1652
2194
  }
1653
2195
  };
1654
2196
  }
1655
- root.appendChild(this.regionOverlay);
2197
+ if (this.toolbarElement && this.toolbarElement.parentNode === root) {
2198
+ root.insertBefore(this.regionOverlay, this.toolbarElement);
2199
+ } else {
2200
+ root.appendChild(this.regionOverlay);
2201
+ }
1656
2202
  }
1657
2203
  hideRegionOverlay() {
1658
- if (this.regionOverlay && this.regionOverlay.parentElement) {
1659
- this.regionOverlay.parentElement.removeChild(this.regionOverlay);
2204
+ this.isDraggingRegion = false;
2205
+ if (this.regionOverlay && this.regionOverlay.parentNode) {
2206
+ this.regionOverlay.parentNode.removeChild(this.regionOverlay);
1660
2207
  }
1661
2208
  if (this.regionBox) {
1662
2209
  this.regionBox.style.display = "none";
@@ -1695,7 +2242,7 @@ var NoteInspector = class {
1695
2242
  this.updateHighlight(targetEl);
1696
2243
  }
1697
2244
  this.renderNoteModal({
1698
- title: "\u{1F4DD} Add Visual Note",
2245
+ title: "Add Visual Note",
1699
2246
  modeBadge: noteType.toUpperCase(),
1700
2247
  pillText: noteType === "page" ? `Page Viewport: ${window.innerWidth} \xD7 ${window.innerHeight} px` : `${getSemanticSelector(targetEl)} (${Math.round(targetEl.getBoundingClientRect().width)}\xD7${Math.round(targetEl.getBoundingClientRect().height)}) \xB7 Viewport: ${window.innerWidth}\xD7${window.innerHeight}`,
1701
2248
  onSave: async (message) => {
@@ -1705,7 +2252,7 @@ var NoteInspector = class {
1705
2252
  }
1706
2253
  openRegionNoteEditor(region) {
1707
2254
  this.renderNoteModal({
1708
- title: "\u{1F4DD} Add Region Note",
2255
+ title: "Add Region Note",
1709
2256
  modeBadge: "REGION",
1710
2257
  pillText: `Selected Area: x:${region.x}, y:${region.y} (${region.width} \xD7 ${region.height} px)`,
1711
2258
  onSave: async (message) => {
@@ -1723,22 +2270,31 @@ var NoteInspector = class {
1723
2270
  const backdrop = document.createElement("div");
1724
2271
  backdrop.className = "bt-modal-backdrop";
1725
2272
  this.modalOverlay = backdrop;
2273
+ const badgeClass = `bt-badge-${options.modeBadge.toLowerCase()}`;
2274
+ const icon = options.modeBadge === "REGION" ? "\u{1F4D0}" : options.modeBadge === "PAGE" ? "\u{1F4C4}" : "\u{1F3AF}";
2275
+ const isMac = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
1726
2276
  backdrop.innerHTML = `
1727
2277
  <div class="bt-modal">
1728
2278
  <div class="bt-modal-header">
1729
2279
  <div class="bt-modal-title">
1730
- <span>${options.title}</span>
1731
- <span class="bt-mode-badge">${options.modeBadge}</span>
2280
+ <span>\u{1F4DD} ${options.title}</span>
2281
+ <span class="bt-mode-badge ${badgeClass}">${options.modeBadge}</span>
1732
2282
  </div>
1733
- <button class="bt-close-btn" id="btn-close" title="Close">\u2715</button>
2283
+ <button class="bt-close-btn" id="btn-close" title="Close (Esc)">\u2715</button>
1734
2284
  </div>
1735
2285
  <div class="bt-target-pill" title="${options.pillText}">
1736
- \u{1F3AF} ${options.pillText}
2286
+ <span>${icon}</span>
2287
+ <span class="bt-pill-content">${options.pillText}</span>
1737
2288
  </div>
1738
2289
  <textarea class="bt-textarea" placeholder="Describe the layout issue, styling bug, or note for AI agent..." autofocus></textarea>
1739
- <div class="bt-modal-actions">
1740
- <button class="bt-btn bt-btn-cancel" id="btn-cancel">Cancel</button>
1741
- <button class="bt-btn bt-btn-save" id="btn-save">Save Note</button>
2290
+ <div class="bt-modal-footer">
2291
+ <div class="bt-kbd-hint">
2292
+ <kbd>${isMac ? "\u2318" : "Ctrl"}+Enter</kbd> save \xB7 <kbd>Esc</kbd> cancel
2293
+ </div>
2294
+ <div class="bt-modal-actions">
2295
+ <button class="bt-btn bt-btn-cancel" id="btn-cancel">Cancel</button>
2296
+ <button class="bt-btn bt-btn-save" id="btn-save">Save Note</button>
2297
+ </div>
1742
2298
  </div>
1743
2299
  </div>
1744
2300
  `;
@@ -1958,6 +2514,12 @@ var NoteInspector = class {
1958
2514
  this.container = null;
1959
2515
  this.shadowRoot = null;
1960
2516
  this.toolbarElement = null;
2517
+ this.regionOverlay = null;
2518
+ this.regionBox = null;
2519
+ this.regionBanner = null;
2520
+ this.markersContainer = null;
2521
+ this.modalOverlay = null;
2522
+ this.cardOverlay = null;
1961
2523
  }
1962
2524
  };
1963
2525