@designfever/web-review-kit 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,11 @@
1
1
  import {
2
2
  REVIEW_WORKFLOW_STATUS_OPTIONS,
3
+ clamp,
3
4
  createWebReviewKit,
4
5
  getNumberedReviewItems,
5
- normalizeReviewItemStatus
6
- } from "./chunk-6L2KJ7XL.js";
6
+ normalizeReviewItemStatus,
7
+ runWithAutoScrollBehavior
8
+ } from "./chunk-TWCSIBMY.js";
7
9
 
8
10
  // src/react-shell.tsx
9
11
  import React2 from "react";
@@ -68,10 +70,10 @@ function ensureReviewShellStyle() {
68
70
  --df-review-font-size-lg: 14px;
69
71
  --df-review-font-size-xl: 15px;
70
72
  --df-review-font-size-2xl: 18px;
71
- --df-review-font-weight-medium: 650;
72
- --df-review-font-weight-bold: 700;
73
- --df-review-font-weight-strong: 800;
74
- --df-review-font-weight-heavy: 900;
73
+ --df-review-font-weight-medium: 400;
74
+ --df-review-font-weight-bold: 500;
75
+ --df-review-font-weight-strong: 500;
76
+ --df-review-font-weight-heavy: 600;
75
77
  --df-review-line-height-tight: 1.25;
76
78
  --df-review-line-height-base: 1.42;
77
79
  --df-review-line-height-relaxed: 1.55;
@@ -88,7 +90,7 @@ function ensureReviewShellStyle() {
88
90
  --df-review-space-8: 32px;
89
91
  --df-review-control-height-sm: 32px;
90
92
  --df-review-control-height-md: 34px;
91
- --df-review-control-height-lg: 38px;
93
+ --df-review-control-height-lg: 34px;
92
94
  --df-review-radius-xs: 3px;
93
95
  --df-review-radius-sm: 6px;
94
96
  --df-review-radius-md: 8px;
@@ -262,7 +264,7 @@ function ensureReviewShellStyle() {
262
264
  .df-review-shell {
263
265
  --df-review-frame-gutter-x: var(--df-review-space-4);
264
266
  display: grid;
265
- grid-template-columns: minmax(0, 1fr) 0 32px;
267
+ grid-template-columns: minmax(0, 1fr) 0 48px;
266
268
  grid-template-rows: auto auto minmax(0, 1fr);
267
269
  width: 100%;
268
270
  height: 100%;
@@ -271,7 +273,7 @@ function ensureReviewShellStyle() {
271
273
  }
272
274
 
273
275
  .df-review-shell.is-list-visible {
274
- grid-template-columns: minmax(0, 1fr) clamp(320px, 28vw, 420px) 32px;
276
+ grid-template-columns: minmax(0, 1fr) clamp(320px, 28vw, 420px) 48px;
275
277
  }
276
278
 
277
279
  .df-review-topbar {
@@ -290,20 +292,6 @@ function ensureReviewShellStyle() {
290
292
  box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.025);
291
293
  }
292
294
 
293
- .df-review-presence-row {
294
- grid-column: 1;
295
- grid-row: 2;
296
- position: relative;
297
- z-index: 590;
298
- display: flex;
299
- align-items: center;
300
- justify-content: flex-start;
301
- min-width: 0;
302
- padding: var(--df-review-space-2) var(--df-review-frame-gutter-x);
303
- border-bottom: 1px solid var(--df-review-line-soft);
304
- background: var(--df-review-panel);
305
- }
306
-
307
295
  .df-review-address {
308
296
  display: grid;
309
297
  grid-template-columns: auto minmax(160px, 1fr) auto auto;
@@ -316,6 +304,7 @@ function ensureReviewShellStyle() {
316
304
 
317
305
  .df-review-address input {
318
306
  width: 100%;
307
+ height: var(--df-review-control-height-md);
319
308
  min-height: var(--df-review-control-height-md);
320
309
  border: 1px solid var(--df-review-line);
321
310
  border-radius: var(--df-review-radius-sm);
@@ -333,7 +322,6 @@ function ensureReviewShellStyle() {
333
322
  }
334
323
 
335
324
  .df-review-address button,
336
- .df-review-side-toggle,
337
325
  .df-review-presets button,
338
326
  .df-review-overlay-button,
339
327
  .df-review-mode-button,
@@ -342,6 +330,7 @@ function ensureReviewShellStyle() {
342
330
  .df-review-settings-actions button,
343
331
  .df-review-prompt-block-header button,
344
332
  .df-review-item-actions button {
333
+ height: var(--df-review-control-height-md);
345
334
  min-height: var(--df-review-control-height-md);
346
335
  border: 1px solid var(--df-review-line);
347
336
  border-radius: var(--df-review-radius-sm);
@@ -349,12 +338,11 @@ function ensureReviewShellStyle() {
349
338
  box-shadow: var(--df-review-shadow-control);
350
339
  color: var(--df-review-text);
351
340
  font-size: var(--df-review-font-size-sm);
352
- font-weight: 700;
341
+ font-weight: 500;
353
342
  transition: border-color 140ms ease, background 140ms ease, color 140ms ease, box-shadow 140ms ease, opacity 140ms ease;
354
343
  }
355
344
 
356
345
  .df-review-address button:hover,
357
- .df-review-side-toggle:hover,
358
346
  .df-review-presets button:hover,
359
347
  .df-review-overlay-button:hover,
360
348
  .df-review-mode-button:hover,
@@ -455,12 +443,13 @@ function ensureReviewShellStyle() {
455
443
 
456
444
  .df-review-sitemap-header strong {
457
445
  font-size: var(--df-review-font-size-lg);
446
+ font-weight: 600;
458
447
  }
459
448
 
460
449
  .df-review-sitemap-header span {
461
450
  color: var(--df-review-muted);
462
451
  font-size: var(--df-review-font-size-sm);
463
- font-weight: 700;
452
+ font-weight: 500;
464
453
  }
465
454
 
466
455
  .df-review-sitemap-header button {
@@ -474,7 +463,7 @@ function ensureReviewShellStyle() {
474
463
  background: var(--df-review-control);
475
464
  color: var(--df-review-text);
476
465
  font-size: var(--df-review-font-size-md);
477
- font-weight: 800;
466
+ font-weight: 500;
478
467
  }
479
468
 
480
469
  .df-review-sitemap-header button:hover {
@@ -502,7 +491,7 @@ function ensureReviewShellStyle() {
502
491
  background: var(--df-review-control);
503
492
  box-shadow: var(--df-review-shadow-control);
504
493
  font-size: var(--df-review-font-size-xs);
505
- font-weight: 850;
494
+ font-weight: 600;
506
495
  }
507
496
 
508
497
  .df-review-sitemap-list {
@@ -538,7 +527,7 @@ function ensureReviewShellStyle() {
538
527
  0 1px 0 var(--df-review-line);
539
528
  color: var(--df-review-muted);
540
529
  font-size: var(--df-review-font-size-xs);
541
- font-weight: 720;
530
+ font-weight: 500;
542
531
  letter-spacing: 0.03em;
543
532
  text-transform: uppercase;
544
533
  }
@@ -636,7 +625,7 @@ function ensureReviewShellStyle() {
636
625
  overflow-wrap: anywhere;
637
626
  color: var(--df-review-text);
638
627
  font-size: var(--df-review-font-size-md);
639
- font-weight: 650;
628
+ font-weight: 400;
640
629
  line-height: 1.35;
641
630
  }
642
631
 
@@ -648,7 +637,7 @@ function ensureReviewShellStyle() {
648
637
  flex: 0 0 auto;
649
638
  color: var(--df-review-muted);
650
639
  font-family: var(--df-review-font-mono);
651
- font-weight: 500;
640
+ font-weight: 400;
652
641
  white-space: pre;
653
642
  }
654
643
 
@@ -663,14 +652,14 @@ function ensureReviewShellStyle() {
663
652
  color: var(--df-review-muted);
664
653
  font-size: var(--df-review-font-size-sm);
665
654
  font-variant-numeric: tabular-nums;
666
- font-weight: 650;
655
+ font-weight: 400;
667
656
  line-height: 1;
668
657
  text-align: right;
669
658
  }
670
659
 
671
660
  .df-review-sitemap-cell.is-total {
672
661
  color: var(--df-review-accent);
673
- font-weight: 760;
662
+ font-weight: 500;
674
663
  }
675
664
 
676
665
  .df-review-sitemap-cell.is-total strong {
@@ -703,7 +692,7 @@ function ensureReviewShellStyle() {
703
692
  background: var(--df-review-chip-bg);
704
693
  color: var(--df-review-text);
705
694
  font-size: var(--df-review-font-size-xs);
706
- font-weight: 900;
695
+ font-weight: 600;
707
696
  line-height: 1.1;
708
697
  white-space: nowrap;
709
698
  }
@@ -775,12 +764,13 @@ function ensureReviewShellStyle() {
775
764
  .df-review-settings-header strong {
776
765
  color: var(--df-review-text);
777
766
  font-size: var(--df-review-font-size-lg);
767
+ font-weight: 600;
778
768
  }
779
769
 
780
770
  .df-review-settings-header span {
781
771
  color: var(--df-review-muted);
782
772
  font-size: var(--df-review-font-size-xs);
783
- font-weight: 800;
773
+ font-weight: 500;
784
774
  }
785
775
 
786
776
  .df-review-settings-header button {
@@ -790,7 +780,7 @@ function ensureReviewShellStyle() {
790
780
  min-width: 34px;
791
781
  padding: 0;
792
782
  font-size: var(--df-review-font-size-md);
793
- font-weight: 800;
783
+ font-weight: 500;
794
784
  }
795
785
 
796
786
  .df-review-settings-body {
@@ -816,7 +806,7 @@ function ensureReviewShellStyle() {
816
806
  .df-review-settings-label-row label {
817
807
  color: var(--df-review-muted);
818
808
  font-size: var(--df-review-font-size-sm);
819
- font-weight: 800;
809
+ font-weight: 500;
820
810
  }
821
811
 
822
812
  .df-review-settings-theme-options {
@@ -828,17 +818,32 @@ function ensureReviewShellStyle() {
828
818
  }
829
819
 
830
820
  .df-review-settings-theme-option {
821
+ display: inline-flex;
822
+ align-items: center;
823
+ justify-content: center;
824
+ gap: 7px;
831
825
  min-height: 30px;
832
826
  border: 1px solid var(--df-review-line);
833
827
  border-radius: var(--df-review-radius-sm);
834
- padding: 0 10px;
828
+ padding: 0 11px;
835
829
  color: var(--df-review-muted);
836
830
  background: var(--df-review-control);
837
831
  box-shadow: var(--df-review-shadow-control);
838
832
  font-size: var(--df-review-font-size-sm);
839
- font-weight: 800;
833
+ font-weight: 500;
840
834
  }
841
835
 
836
+ .df-review-settings-theme-option svg {
837
+ width: 15px;
838
+ height: 15px;
839
+ flex: 0 0 auto;
840
+ stroke-width: 2.2;
841
+ }
842
+
843
+ .df-review-settings-theme-option span {
844
+ color: inherit;
845
+ }
846
+
842
847
  .df-review-settings-theme-option:hover {
843
848
  border-color: var(--df-review-accent);
844
849
  background: var(--df-review-control-hover);
@@ -983,7 +988,7 @@ function ensureReviewShellStyle() {
983
988
  background: var(--df-review-chip-bg);
984
989
  color: var(--df-review-muted);
985
990
  font-size: var(--df-review-font-size-xs);
986
- font-weight: 700;
991
+ font-weight: 500;
987
992
  line-height: 1.55;
988
993
  }
989
994
 
@@ -999,7 +1004,7 @@ function ensureReviewShellStyle() {
999
1004
  margin: 0;
1000
1005
  color: var(--df-review-accent);
1001
1006
  font-size: var(--df-review-font-size-sm);
1002
- font-weight: 800;
1007
+ font-weight: 500;
1003
1008
  }
1004
1009
 
1005
1010
  .df-review-settings-actions {
@@ -1065,7 +1070,7 @@ function ensureReviewShellStyle() {
1065
1070
  margin: 0;
1066
1071
  color: var(--df-review-danger);
1067
1072
  font-size: var(--df-review-font-size-sm);
1068
- font-weight: 800;
1073
+ font-weight: 500;
1069
1074
  }
1070
1075
 
1071
1076
  .df-review-edit-actions {
@@ -1118,7 +1123,7 @@ function ensureReviewShellStyle() {
1118
1123
  box-shadow: var(--df-review-shadow-modal);
1119
1124
  color: var(--df-review-text);
1120
1125
  font-size: var(--df-review-font-size-sm);
1121
- font-weight: 800;
1126
+ font-weight: 500;
1122
1127
  line-height: 1.25;
1123
1128
  pointer-events: none;
1124
1129
  }
@@ -1142,13 +1147,14 @@ function ensureReviewShellStyle() {
1142
1147
  .df-review-prompt-header strong {
1143
1148
  color: var(--df-review-text);
1144
1149
  font-size: var(--df-review-font-size-lg);
1150
+ font-weight: 600;
1145
1151
  }
1146
1152
 
1147
1153
  .df-review-prompt-header span {
1148
1154
  overflow: hidden;
1149
1155
  color: var(--df-review-muted);
1150
1156
  font-size: var(--df-review-font-size-xs);
1151
- font-weight: 800;
1157
+ font-weight: 500;
1152
1158
  text-overflow: ellipsis;
1153
1159
  white-space: nowrap;
1154
1160
  }
@@ -1160,7 +1166,7 @@ function ensureReviewShellStyle() {
1160
1166
  min-width: 34px;
1161
1167
  padding: 0;
1162
1168
  font-size: var(--df-review-font-size-md);
1163
- font-weight: 800;
1169
+ font-weight: 500;
1164
1170
  }
1165
1171
 
1166
1172
  .df-review-prompt-body {
@@ -1194,13 +1200,13 @@ function ensureReviewShellStyle() {
1194
1200
  .df-review-prompt-block-header strong {
1195
1201
  color: var(--df-review-text);
1196
1202
  font-size: var(--df-review-font-size-sm);
1197
- font-weight: 900;
1203
+ font-weight: 600;
1198
1204
  }
1199
1205
 
1200
1206
  .df-review-prompt-block-header span {
1201
1207
  color: var(--df-review-muted);
1202
1208
  font-size: var(--df-review-font-size-xs);
1203
- font-weight: 800;
1209
+ font-weight: 500;
1204
1210
  }
1205
1211
 
1206
1212
  .df-review-prompt-block-header button {
@@ -1239,7 +1245,7 @@ function ensureReviewShellStyle() {
1239
1245
  color: var(--df-review-text);
1240
1246
  font-family: var(--df-review-font-mono);
1241
1247
  font-size: var(--df-review-font-size-xs);
1242
- font-weight: 600;
1248
+ font-weight: 400;
1243
1249
  line-height: 1.5;
1244
1250
  white-space: pre;
1245
1251
  }
@@ -1258,13 +1264,13 @@ function ensureReviewShellStyle() {
1258
1264
  .df-review-prompt-section-header strong {
1259
1265
  color: var(--df-review-text);
1260
1266
  font-size: var(--df-review-font-size-md);
1261
- font-weight: 900;
1267
+ font-weight: 600;
1262
1268
  }
1263
1269
 
1264
1270
  .df-review-prompt-section-header span {
1265
1271
  color: var(--df-review-muted);
1266
1272
  font-size: var(--df-review-font-size-xs);
1267
- font-weight: 800;
1273
+ font-weight: 500;
1268
1274
  }
1269
1275
 
1270
1276
  .df-review-prompt-about {
@@ -1293,14 +1299,14 @@ function ensureReviewShellStyle() {
1293
1299
  .df-review-prompt-about-grid strong {
1294
1300
  color: var(--df-review-text);
1295
1301
  font-size: var(--df-review-font-size-sm);
1296
- font-weight: 900;
1302
+ font-weight: 600;
1297
1303
  }
1298
1304
 
1299
1305
  .df-review-prompt-about-grid p {
1300
1306
  margin: 0;
1301
1307
  color: var(--df-review-muted);
1302
1308
  font-size: var(--df-review-font-size-sm);
1303
- font-weight: 700;
1309
+ font-weight: 500;
1304
1310
  line-height: 1.55;
1305
1311
  }
1306
1312
 
@@ -1330,8 +1336,9 @@ function ensureReviewShellStyle() {
1330
1336
  display: flex;
1331
1337
  align-items: center;
1332
1338
  gap: var(--df-review-space-1-5);
1333
- min-height: calc(var(--df-review-control-height-lg) + 6px);
1334
- padding: 3px;
1339
+ height: var(--df-review-control-height-md);
1340
+ min-height: var(--df-review-control-height-md);
1341
+ padding: 0;
1335
1342
  border: 1px solid var(--df-review-line-soft);
1336
1343
  border-radius: var(--df-review-radius-md);
1337
1344
  background: var(--df-review-card);
@@ -1343,28 +1350,50 @@ function ensureReviewShellStyle() {
1343
1350
  align-items: center;
1344
1351
  color: var(--df-review-line);
1345
1352
  font-size: var(--df-review-font-size-2xl);
1346
- font-weight: 700;
1353
+ font-weight: 500;
1347
1354
  line-height: 1;
1348
1355
  user-select: none;
1349
1356
  }
1350
1357
 
1351
- .df-review-active-size {
1358
+ .df-review-active-size {
1352
1359
  flex: 0 0 auto;
1353
1360
  display: inline-flex;
1354
1361
  align-items: center;
1355
- min-height: var(--df-review-control-height-lg);
1362
+ min-height: var(--df-review-control-height-md);
1356
1363
  color: var(--df-review-muted);
1357
1364
  font-size: var(--df-review-font-size-sm);
1358
1365
  font-variant-numeric: tabular-nums;
1359
- font-weight: 800;
1366
+ font-weight: 500;
1360
1367
  line-height: 1;
1361
1368
  }
1362
1369
 
1370
+ .df-review-preset-select {
1371
+ -webkit-appearance: none;
1372
+ appearance: none;
1373
+ display: none;
1374
+ height: var(--df-review-control-height-md);
1375
+ min-height: var(--df-review-control-height-md);
1376
+ min-width: 154px;
1377
+ border: 1px solid var(--df-review-line-soft);
1378
+ border-radius: var(--df-review-radius-md);
1379
+ padding: 0 42px 0 14px;
1380
+ color: var(--df-review-text);
1381
+ background-color: var(--df-review-control);
1382
+ background-image: url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m6 9 6 6 6-6' stroke='%23d7deea' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
1383
+ background-position: right 14px center;
1384
+ background-repeat: no-repeat;
1385
+ background-size: 18px 18px;
1386
+ box-shadow: var(--df-review-shadow-control);
1387
+ font-size: var(--df-review-font-size-sm);
1388
+ font-weight: 500;
1389
+ }
1390
+
1363
1391
  .df-review-presets button {
1364
1392
  display: inline-flex;
1365
1393
  align-items: center;
1366
1394
  gap: 7px;
1367
- min-height: var(--df-review-control-height-lg);
1395
+ height: var(--df-review-control-height-md);
1396
+ min-height: var(--df-review-control-height-md);
1368
1397
  padding: 0 11px 0 9px;
1369
1398
  border-color: transparent;
1370
1399
  background: transparent;
@@ -1389,7 +1418,7 @@ function ensureReviewShellStyle() {
1389
1418
  background: var(--df-review-line-soft);
1390
1419
  color: var(--df-review-muted);
1391
1420
  font-size: var(--df-review-font-size-2xs);
1392
- font-weight: 800;
1421
+ font-weight: 500;
1393
1422
  line-height: 16px;
1394
1423
  text-align: center;
1395
1424
  }
@@ -1415,6 +1444,7 @@ function ensureReviewShellStyle() {
1415
1444
  .df-review-preset-copy strong {
1416
1445
  color: var(--df-review-text);
1417
1446
  font-size: var(--df-review-font-size-sm);
1447
+ font-weight: 500;
1418
1448
  }
1419
1449
 
1420
1450
  .df-review-overlay-button,
@@ -1422,8 +1452,10 @@ function ensureReviewShellStyle() {
1422
1452
  position: relative;
1423
1453
  display: inline-grid;
1424
1454
  place-items: center;
1425
- width: 38px;
1426
- min-width: 38px;
1455
+ width: var(--df-review-control-height-md);
1456
+ min-width: var(--df-review-control-height-md);
1457
+ height: var(--df-review-control-height-md);
1458
+ min-height: var(--df-review-control-height-md);
1427
1459
  padding: 0;
1428
1460
  border-color: transparent;
1429
1461
  background: transparent;
@@ -1431,6 +1463,72 @@ function ensureReviewShellStyle() {
1431
1463
  color: var(--df-review-muted);
1432
1464
  }
1433
1465
 
1466
+ .df-review-overlays-menu {
1467
+ position: relative;
1468
+ display: none;
1469
+ flex: 0 0 auto;
1470
+ }
1471
+
1472
+ .df-review-overlays-menu summary {
1473
+ display: grid;
1474
+ place-items: center;
1475
+ width: var(--df-review-control-height-md);
1476
+ min-width: var(--df-review-control-height-md);
1477
+ height: var(--df-review-control-height-md);
1478
+ border: 1px solid var(--df-review-line-soft);
1479
+ border-radius: var(--df-review-radius-md);
1480
+ padding: 0;
1481
+ color: var(--df-review-muted);
1482
+ background: var(--df-review-card);
1483
+ box-shadow: var(--df-review-shadow-control);
1484
+ cursor: pointer;
1485
+ }
1486
+
1487
+ .df-review-overlays-menu summary::-webkit-details-marker {
1488
+ display: none;
1489
+ }
1490
+
1491
+ .df-review-overlays-menu summary::marker {
1492
+ content: '';
1493
+ }
1494
+
1495
+ .df-review-overlays-menu summary:hover,
1496
+ .df-review-overlays-menu[open] summary {
1497
+ border-color: var(--df-review-accent);
1498
+ background: var(--df-review-control-hover);
1499
+ color: var(--df-review-accent);
1500
+ }
1501
+
1502
+ .df-review-overlays-menu summary svg {
1503
+ width: 20px;
1504
+ height: 20px;
1505
+ fill: none;
1506
+ stroke: currentColor;
1507
+ stroke-linecap: round;
1508
+ stroke-linejoin: round;
1509
+ stroke-width: 1.9;
1510
+ }
1511
+
1512
+ .df-review-overlays-popover {
1513
+ position: absolute;
1514
+ top: calc(100% + 6px);
1515
+ right: 0;
1516
+ z-index: 700;
1517
+ display: none;
1518
+ align-items: center;
1519
+ gap: var(--df-review-space-1-5);
1520
+ min-height: var(--df-review-control-height-md);
1521
+ padding: 0;
1522
+ border: 1px solid var(--df-review-line-soft);
1523
+ border-radius: var(--df-review-radius-md);
1524
+ background: var(--df-review-card);
1525
+ box-shadow: var(--df-review-shadow-modal);
1526
+ }
1527
+
1528
+ .df-review-overlays-menu[open] .df-review-overlays-popover {
1529
+ display: flex;
1530
+ }
1531
+
1434
1532
  .df-review-overlay-button svg,
1435
1533
  .df-review-mode-button svg {
1436
1534
  width: 18px;
@@ -1466,33 +1564,46 @@ function ensureReviewShellStyle() {
1466
1564
 
1467
1565
  @container (max-width: 1040px) {
1468
1566
  .df-review-tools {
1469
- flex-direction: column;
1470
- align-items: stretch;
1471
- justify-content: flex-start;
1567
+ flex-direction: row;
1568
+ align-items: center;
1569
+ justify-content: space-between;
1472
1570
  }
1473
1571
 
1474
1572
  .df-review-tool-controls {
1475
- width: 100%;
1573
+ flex: 1 1 auto;
1574
+ width: auto;
1575
+ min-width: 0;
1576
+ flex-wrap: nowrap;
1476
1577
  }
1477
1578
 
1478
1579
  .df-review-presets {
1479
- flex-wrap: wrap;
1580
+ display: none;
1581
+ }
1582
+
1583
+ .df-review-preset-select {
1584
+ display: block;
1585
+ flex: 0 1 190px;
1586
+ width: clamp(154px, 26vw, 190px);
1480
1587
  }
1481
1588
 
1482
1589
  .df-review-overlays {
1483
- width: 100%;
1484
- justify-content: flex-start;
1590
+ display: none;
1485
1591
  }
1592
+
1593
+ .df-review-overlays-menu {
1594
+ display: block;
1595
+ }
1486
1596
  }
1487
1597
 
1488
1598
  .df-review-side-rail {
1489
1599
  grid-column: 3;
1490
1600
  grid-row: 1 / span 3;
1491
1601
  position: relative;
1492
- z-index: 600;
1602
+ z-index: 640;
1493
1603
  display: flex;
1604
+ flex-direction: column;
1494
1605
  align-items: stretch;
1495
- justify-content: center;
1606
+ justify-content: flex-start;
1496
1607
  min-width: 0;
1497
1608
  min-height: 0;
1498
1609
  border-left: 1px solid var(--df-review-line);
@@ -1500,49 +1611,166 @@ function ensureReviewShellStyle() {
1500
1611
  }
1501
1612
 
1502
1613
  .df-review-side-toggle {
1614
+ position: relative;
1615
+ flex: 0 0 58px;
1503
1616
  display: grid;
1504
- grid-template-rows: 28px auto;
1505
- align-items: start;
1506
- justify-items: center;
1507
- gap: 8px;
1617
+ place-items: center;
1508
1618
  width: 100%;
1509
- min-height: 100%;
1619
+ min-height: 58px;
1510
1620
  border: 0;
1511
1621
  border-radius: 0;
1512
- padding: 10px 0;
1622
+ padding: 0;
1513
1623
  background: transparent;
1514
1624
  color: var(--df-review-muted);
1625
+ transition: color 140ms ease, background 140ms ease;
1515
1626
  }
1516
1627
 
1517
1628
  .df-review-side-toggle:hover {
1518
- background: var(--df-review-accent-soft);
1519
1629
  color: var(--df-review-text);
1520
1630
  }
1521
1631
 
1632
+ .df-review-side-toggle.is-active {
1633
+ color: var(--df-review-accent);
1634
+ }
1635
+
1636
+ .df-review-side-toggle.is-active::after {
1637
+ position: absolute;
1638
+ top: 12px;
1639
+ right: 0;
1640
+ bottom: 12px;
1641
+ width: 3px;
1642
+ border-radius: 3px 0 0 3px;
1643
+ background: var(--df-review-accent);
1644
+ content: '';
1645
+ }
1646
+
1647
+ .df-review-side-toggle:focus-visible {
1648
+ outline: 0;
1649
+ color: var(--df-review-text);
1650
+ }
1651
+
1652
+ .df-review-side-toggle:focus-visible span {
1653
+ border-radius: 6px;
1654
+ outline: 2px solid var(--df-review-focus-ring);
1655
+ outline-offset: 3px;
1656
+ }
1657
+
1522
1658
  .df-review-side-toggle span {
1523
1659
  display: grid;
1524
1660
  place-items: center;
1525
- width: 20px;
1526
- height: 24px;
1661
+ width: 30px;
1662
+ height: 30px;
1527
1663
  line-height: 1;
1528
1664
  }
1529
1665
 
1530
1666
  .df-review-side-toggle svg {
1531
- width: 18px;
1532
- height: 18px;
1667
+ width: 30px;
1668
+ height: 30px;
1533
1669
  fill: none;
1534
1670
  stroke: currentColor;
1535
1671
  stroke-linecap: round;
1536
- stroke-width: 2;
1672
+ stroke-width: 1.55;
1537
1673
  }
1538
1674
 
1539
- .df-review-side-toggle strong {
1540
- writing-mode: vertical-rl;
1541
- text-orientation: mixed;
1542
- color: inherit;
1543
- font-size: var(--df-review-font-size-2xs);
1544
- font-weight: 900;
1545
- letter-spacing: 0.08em;
1675
+ .df-review-presence-overlay {
1676
+ position: relative;
1677
+ margin-top: auto;
1678
+ }
1679
+
1680
+ .df-review-presence-button {
1681
+ position: relative;
1682
+ display: grid;
1683
+ place-items: center;
1684
+ width: 100%;
1685
+ min-height: 58px;
1686
+ border: 0;
1687
+ border-radius: 0;
1688
+ padding: 0;
1689
+ color: var(--df-review-muted);
1690
+ background: transparent;
1691
+ }
1692
+
1693
+ .df-review-presence-button:hover,
1694
+ .df-review-presence-button[aria-expanded="true"] {
1695
+ color: var(--df-review-text);
1696
+ }
1697
+
1698
+ .df-review-presence-button:focus-visible {
1699
+ outline: 0;
1700
+ }
1701
+
1702
+ .df-review-presence-button:focus-visible svg {
1703
+ border-radius: 6px;
1704
+ outline: 2px solid var(--df-review-focus-ring);
1705
+ outline-offset: 3px;
1706
+ }
1707
+
1708
+ .df-review-presence-button svg {
1709
+ width: 30px;
1710
+ height: 30px;
1711
+ fill: none;
1712
+ stroke: currentColor;
1713
+ stroke-linecap: round;
1714
+ stroke-linejoin: round;
1715
+ stroke-width: 1.55;
1716
+ }
1717
+
1718
+ .df-review-presence-badge {
1719
+ position: absolute;
1720
+ top: 10px;
1721
+ right: 7px;
1722
+ display: grid;
1723
+ place-items: center;
1724
+ min-width: 17px;
1725
+ height: 17px;
1726
+ border: 1px solid var(--df-review-side-rail);
1727
+ border-radius: var(--df-review-radius-pill);
1728
+ padding: 0 4px;
1729
+ color: #17202c;
1730
+ background: var(--df-review-accent);
1731
+ font-size: var(--df-review-font-size-3xs);
1732
+ font-weight: 600;
1733
+ line-height: 1;
1734
+ pointer-events: none;
1735
+ }
1736
+
1737
+ .df-review-presence-list {
1738
+ position: absolute;
1739
+ right: calc(100% + 8px);
1740
+ bottom: 8px;
1741
+ display: grid;
1742
+ gap: 5px;
1743
+ min-width: 132px;
1744
+ max-width: 220px;
1745
+ border: 1px solid var(--df-review-line);
1746
+ border-radius: var(--df-review-radius-md);
1747
+ padding: 8px;
1748
+ background: var(--df-review-panel);
1749
+ box-shadow: var(--df-review-shadow-modal);
1750
+ }
1751
+
1752
+ .df-review-presence-chip {
1753
+ --df-review-presence-color: var(--df-review-accent);
1754
+ display: flex;
1755
+ align-items: center;
1756
+ min-width: 0;
1757
+ min-height: 24px;
1758
+ border-left: 2px solid var(--df-review-presence-color);
1759
+ border-radius: var(--df-review-radius-sm);
1760
+ padding: 0 8px;
1761
+ color: var(--df-review-text);
1762
+ background: var(--df-review-control);
1763
+ font-size: var(--df-review-font-size-xs);
1764
+ font-weight: 500;
1765
+ line-height: 1.1;
1766
+ overflow: hidden;
1767
+ text-overflow: ellipsis;
1768
+ white-space: nowrap;
1769
+ }
1770
+
1771
+ .df-review-presence-chip.is-self {
1772
+ color: var(--df-review-accent);
1773
+ background: var(--df-review-accent-soft);
1546
1774
  }
1547
1775
 
1548
1776
  .df-review-qa-panel {
@@ -1560,11 +1788,34 @@ function ensureReviewShellStyle() {
1560
1788
  linear-gradient(180deg, var(--df-review-panel), var(--df-review-bg));
1561
1789
  }
1562
1790
 
1563
- .df-review-shell:not(.is-list-visible) .df-review-qa-panel {
1791
+ .df-review-shell:not(.is-list-visible) .df-review-qa-panel,
1792
+ .df-review-qa-panel[aria-hidden="true"] {
1564
1793
  visibility: hidden;
1565
1794
  border-left: 0;
1795
+ pointer-events: none;
1566
1796
  }
1567
1797
 
1798
+ .df-review-source-tree-panel {
1799
+ grid-column: 2;
1800
+ grid-row: 1 / span 3;
1801
+ position: relative;
1802
+ z-index: 600;
1803
+ display: grid;
1804
+ min-width: 0;
1805
+ min-height: 0;
1806
+ overflow: hidden;
1807
+ border-left: 1px solid var(--df-review-line-soft);
1808
+ background:
1809
+ linear-gradient(180deg, var(--df-review-panel), var(--df-review-bg));
1810
+ }
1811
+
1812
+ .df-review-shell:not(.is-list-visible) .df-review-source-tree-panel,
1813
+ .df-review-source-tree-panel[aria-hidden="true"] {
1814
+ visibility: hidden;
1815
+ border-left: 0;
1816
+ pointer-events: none;
1817
+ }
1818
+
1568
1819
  .df-review-panel-body {
1569
1820
  display: grid;
1570
1821
  min-width: 0;
@@ -1581,14 +1832,16 @@ function ensureReviewShellStyle() {
1581
1832
 
1582
1833
  .df-review-list-header {
1583
1834
  display: grid;
1584
- grid-template-rows: auto auto;
1835
+ grid-template-rows:
1836
+ var(--df-review-control-height-md)
1837
+ var(--df-review-control-height-md);
1585
1838
  gap: var(--df-review-space-2);
1586
1839
  padding: var(--df-review-space-3) var(--df-review-frame-gutter-x);
1587
1840
  border-bottom: 1px solid var(--df-review-line-soft);
1588
1841
  background: var(--df-review-card);
1589
1842
  color: var(--df-review-muted);
1590
1843
  font-size: var(--df-review-font-size-sm);
1591
- font-weight: 800;
1844
+ font-weight: 500;
1592
1845
  }
1593
1846
 
1594
1847
  .df-review-list-toolbar {
@@ -1596,143 +1849,76 @@ function ensureReviewShellStyle() {
1596
1849
  grid-template-columns: minmax(0, 1fr) auto;
1597
1850
  align-items: center;
1598
1851
  gap: 8px;
1852
+ min-height: var(--df-review-control-height-md);
1599
1853
  min-width: 0;
1600
1854
  }
1601
1855
 
1602
1856
  .df-review-list-title {
1603
- display: flex;
1857
+ display: grid;
1858
+ grid-template-columns: minmax(0, 1fr) auto;
1604
1859
  align-items: center;
1605
1860
  gap: 8px;
1861
+ min-height: var(--df-review-control-height-md);
1606
1862
  min-width: 0;
1607
1863
  }
1608
1864
 
1609
- .df-review-list-title span {
1865
+ .df-review-list-meta {
1866
+ display: flex;
1867
+ align-items: center;
1868
+ gap: 8px;
1869
+ min-width: 0;
1870
+ }
1871
+
1872
+ .df-review-list-meta span {
1610
1873
  min-width: 0;
1611
1874
  overflow: hidden;
1612
1875
  text-overflow: ellipsis;
1613
1876
  white-space: nowrap;
1614
1877
  }
1615
1878
 
1616
- .df-review-list-title strong {
1617
- flex: 0 0 auto;
1618
- color: var(--df-review-muted);
1619
- font-size: var(--df-review-font-size-xs);
1620
- font-variant-numeric: tabular-nums;
1621
- }
1879
+ .df-review-list-meta strong {
1880
+ flex: 0 0 auto;
1881
+ color: var(--df-review-muted);
1882
+ font-size: var(--df-review-font-size-xs);
1883
+ font-variant-numeric: tabular-nums;
1884
+ font-weight: 500;
1885
+ }
1622
1886
 
1623
- .df-review-presence-overlay {
1887
+ .df-review-list-controls {
1624
1888
  display: flex;
1625
1889
  align-items: center;
1626
- flex-wrap: wrap;
1627
- gap: 5px;
1628
- max-width: 100%;
1629
- pointer-events: none;
1630
- }
1631
-
1632
- .df-review-presence-row .df-review-presence-overlay {
1633
- width: 100%;
1634
- max-width: 1440px;
1635
- margin: 0 auto;
1890
+ gap: 4px;
1636
1891
  }
1637
1892
 
1638
- .df-review-presence-chip {
1639
- --df-review-presence-color: var(--df-review-accent);
1640
- display: inline-flex;
1641
- align-items: center;
1642
- min-width: 0;
1643
- max-width: min(220px, calc(100% - 20px));
1644
- min-height: 24px;
1645
- border: 1px solid rgba(15, 23, 42, 0.12);
1646
- border-radius: var(--df-review-radius-pill);
1647
- padding: 0 8px;
1648
- color: #17202c;
1649
- background: rgba(255, 255, 255, 0.92);
1650
- box-shadow: 0 8px 22px rgba(15, 23, 42, 0.14);
1651
- font-size: var(--df-review-font-size-2xs);
1652
- font-weight: 900;
1653
- line-height: 1.1;
1654
- overflow: hidden;
1655
- text-overflow: ellipsis;
1656
- white-space: nowrap;
1657
- backdrop-filter: blur(8px);
1893
+ .df-review-source-select,
1894
+ .df-review-status-filter-select {
1895
+ height: var(--df-review-control-height-md);
1896
+ min-height: var(--df-review-control-height-md);
1897
+ border: 1px solid var(--df-review-line-soft);
1898
+ border-radius: var(--df-review-radius-sm);
1899
+ padding: 0 24px 0 8px;
1900
+ color: var(--df-review-text);
1901
+ background: var(--df-review-control);
1902
+ box-shadow: var(--df-review-shadow-control);
1903
+ font-size: var(--df-review-font-size-xs);
1904
+ font-weight: 500;
1658
1905
  }
1659
1906
 
1660
- .df-review-presence-row .df-review-presence-chip {
1661
- max-width: none;
1907
+ .df-review-source-select {
1908
+ width: 104px;
1662
1909
  }
1663
1910
 
1664
- .df-review-presence-chip.is-self {
1665
- border-color: var(--df-review-presence-color);
1666
- box-shadow:
1667
- inset 0 0 0 1px var(--df-review-presence-color),
1668
- 0 8px 22px rgba(15, 23, 42, 0.14);
1669
- }
1670
-
1671
- .df-review-presence-more {
1672
- display: inline-flex;
1673
- align-items: center;
1674
- justify-content: center;
1675
- min-width: 28px;
1676
- min-height: 24px;
1677
- border: 1px solid rgba(15, 23, 42, 0.12);
1678
- border-radius: var(--df-review-radius-pill);
1679
- padding: 0 8px;
1680
- color: #17202c;
1681
- background: rgba(255, 255, 255, 0.92);
1682
- box-shadow: 0 8px 22px rgba(15, 23, 42, 0.14);
1683
- cursor: pointer;
1684
- font: inherit;
1685
- font-size: var(--df-review-font-size-2xs);
1686
- font-weight: 900;
1687
- line-height: 1;
1688
- pointer-events: auto;
1689
- backdrop-filter: blur(8px);
1690
- }
1691
-
1692
- .df-review-presence-more:hover {
1693
- border-color: rgba(0, 102, 255, 0.42);
1694
- color: #005be8;
1695
- background: rgba(255, 255, 255, 0.98);
1696
- }
1697
-
1698
- .df-review-list-controls {
1699
- display: flex;
1700
- align-items: center;
1701
- gap: 4px;
1702
- }
1703
-
1704
- .df-review-source-select,
1705
- .df-review-status-filter-select {
1706
- min-height: 30px;
1707
- border: 1px solid var(--df-review-line-soft);
1708
- border-radius: var(--df-review-radius-sm);
1709
- padding: 0 24px 0 8px;
1710
- color: var(--df-review-text);
1711
- background: var(--df-review-control);
1712
- box-shadow: var(--df-review-shadow-control);
1713
- font-size: var(--df-review-font-size-xs);
1714
- font-weight: 800;
1715
- }
1716
-
1717
- .df-review-source-select {
1718
- width: 104px;
1719
- }
1720
-
1721
- .df-review-status-filter-select {
1722
- width: 124px;
1723
- }
1724
-
1725
- .df-review-list-title .df-review-status-filter-select {
1726
- margin-left: auto;
1911
+ .df-review-status-filter-select {
1912
+ width: 124px;
1727
1913
  }
1728
1914
 
1729
1915
  .df-review-source-refresh {
1730
1916
  position: relative;
1731
1917
  display: inline-grid;
1732
1918
  place-items: center;
1733
- width: 30px;
1734
- min-width: 30px;
1735
- height: 30px;
1919
+ width: var(--df-review-control-height-md);
1920
+ min-width: var(--df-review-control-height-md);
1921
+ height: var(--df-review-control-height-md);
1736
1922
  border: 1px solid var(--df-review-line-soft);
1737
1923
  border-radius: var(--df-review-radius-sm);
1738
1924
  padding: 0;
@@ -1742,16 +1928,18 @@ function ensureReviewShellStyle() {
1742
1928
  }
1743
1929
 
1744
1930
  .df-review-source-refresh svg {
1745
- width: 14px;
1746
- height: 14px;
1931
+ width: 16px;
1932
+ height: 16px;
1747
1933
  }
1748
1934
 
1749
1935
  .df-review-filter-tabs {
1750
1936
  display: flex;
1751
1937
  align-items: center;
1752
- gap: 2px;
1753
- height: 30px;
1754
- padding: 2px;
1938
+ justify-self: end;
1939
+ gap: var(--df-review-space-1-5);
1940
+ height: var(--df-review-control-height-md);
1941
+ min-height: var(--df-review-control-height-md);
1942
+ padding: 0;
1755
1943
  border: 1px solid var(--df-review-line-soft);
1756
1944
  border-radius: var(--df-review-radius-md);
1757
1945
  background: var(--df-review-card);
@@ -1762,11 +1950,11 @@ function ensureReviewShellStyle() {
1762
1950
  position: relative;
1763
1951
  display: grid;
1764
1952
  place-items: center;
1765
- width: 26px;
1766
- min-width: 26px;
1767
- height: 26px;
1953
+ width: var(--df-review-control-height-md);
1954
+ min-width: var(--df-review-control-height-md);
1955
+ height: var(--df-review-control-height-md);
1768
1956
  border: 0;
1769
- border-radius: 5px;
1957
+ border-radius: var(--df-review-radius-sm);
1770
1958
  background: transparent;
1771
1959
  color: var(--df-review-subtle);
1772
1960
  }
@@ -1799,19 +1987,19 @@ function ensureReviewShellStyle() {
1799
1987
  }
1800
1988
 
1801
1989
  .df-review-filter-icon svg {
1802
- width: 15px;
1803
- height: 15px;
1990
+ width: 18px;
1991
+ height: 18px;
1804
1992
  fill: none;
1805
1993
  stroke: currentColor;
1806
1994
  stroke-linecap: round;
1807
1995
  stroke-linejoin: round;
1808
- stroke-width: 2;
1996
+ stroke-width: 1.9;
1809
1997
  }
1810
1998
 
1811
1999
  .df-review-filter-count {
1812
2000
  color: currentColor;
1813
2001
  font-size: var(--df-review-font-size-3xs);
1814
- font-weight: 900;
2002
+ font-weight: 600;
1815
2003
  font-variant-numeric: tabular-nums;
1816
2004
  line-height: 1;
1817
2005
  }
@@ -1892,6 +2080,7 @@ function ensureReviewShellStyle() {
1892
2080
  .df-review-item-main strong {
1893
2081
  overflow-wrap: anywhere;
1894
2082
  font-size: var(--df-review-font-size-md);
2083
+ font-weight: 500;
1895
2084
  line-height: 1.35;
1896
2085
  }
1897
2086
 
@@ -1939,7 +2128,7 @@ function ensureReviewShellStyle() {
1939
2128
  border-radius: var(--df-review-radius-pill);
1940
2129
  padding: 0 7px;
1941
2130
  font-size: var(--df-review-font-size-2xs);
1942
- font-weight: 900;
2131
+ font-weight: 600;
1943
2132
  line-height: 1;
1944
2133
  text-transform: uppercase;
1945
2134
  }
@@ -2006,7 +2195,7 @@ function ensureReviewShellStyle() {
2006
2195
  border-radius: var(--df-review-radius-sm);
2007
2196
  padding: 0 11px;
2008
2197
  font-size: var(--df-review-font-size-xs);
2009
- font-weight: 750;
2198
+ font-weight: 500;
2010
2199
  text-transform: none;
2011
2200
  }
2012
2201
 
@@ -2019,7 +2208,7 @@ function ensureReviewShellStyle() {
2019
2208
  cursor: pointer;
2020
2209
  outline: 0;
2021
2210
  font-size: var(--df-review-font-size-xs);
2022
- font-weight: 750;
2211
+ font-weight: 500;
2023
2212
  text-transform: none;
2024
2213
  }
2025
2214
 
@@ -2244,7 +2433,7 @@ function ensureReviewShellStyle() {
2244
2433
 
2245
2434
  .df-review-item-submit-button span {
2246
2435
  font-size: var(--df-review-font-size-xs);
2247
- font-weight: 750;
2436
+ font-weight: 500;
2248
2437
  line-height: 1;
2249
2438
  text-transform: none;
2250
2439
  white-space: nowrap;
@@ -2416,6 +2605,9 @@ function ensureReviewShellStyle() {
2416
2605
  --df-review-source-popover-text: #edf3fb;
2417
2606
  --df-review-source-popover-muted: rgba(237, 243, 251, 0.68);
2418
2607
  --df-review-source-popover-subtle: rgba(237, 243, 251, 0.5);
2608
+ --df-review-source-popover-data: #f3b75f;
2609
+ --df-review-source-popover-data-muted: rgba(243, 183, 95, 0.78);
2610
+ --df-review-source-popover-data-subtle: rgba(243, 183, 95, 0.62);
2419
2611
  --df-review-source-popover-hover: rgba(124, 199, 255, 0.14);
2420
2612
  position: fixed;
2421
2613
  z-index: 890;
@@ -2427,7 +2619,7 @@ function ensureReviewShellStyle() {
2427
2619
  overflow: hidden;
2428
2620
  border: 1px solid var(--df-review-source-popover-line);
2429
2621
  border-radius: var(--df-review-radius-md);
2430
- padding: 8px 6px 6px;
2622
+ padding: 6px;
2431
2623
  color: var(--df-review-source-popover-text);
2432
2624
  color-scheme: dark;
2433
2625
  background: rgba(19, 24, 33, 0.96);
@@ -2450,77 +2642,411 @@ function ensureReviewShellStyle() {
2450
2642
  border: 1px solid transparent;
2451
2643
  border-radius: var(--df-review-radius-sm);
2452
2644
  padding: 0;
2453
- color: var(--df-review-source-popover-subtle);
2645
+ color: var(--df-review-source-popover-subtle);
2646
+ background: transparent;
2647
+ font-size: 16px;
2648
+ font-weight: 500;
2649
+ line-height: 1;
2650
+ }
2651
+
2652
+ .df-review-source-popover-close button:hover {
2653
+ border-color: var(--df-review-source-popover-line);
2654
+ color: var(--df-review-source-popover-text);
2655
+ background: var(--df-review-source-popover-hover);
2656
+ }
2657
+
2658
+ .df-review-source-candidate-list {
2659
+ display: grid;
2660
+ gap: 0;
2661
+ max-height: min(220px, calc(100vh - 96px));
2662
+ min-height: 0;
2663
+ overflow-x: hidden;
2664
+ overflow-y: auto;
2665
+ padding-right: 2px;
2666
+ scrollbar-gutter: stable;
2667
+ }
2668
+
2669
+ .df-review-source-candidate {
2670
+ display: grid;
2671
+ width: 100%;
2672
+ border: 0;
2673
+ border-top: 1px solid transparent;
2674
+ border-radius: var(--df-review-radius-sm);
2675
+ padding: 9px 30px 9px 8px;
2676
+ color: var(--df-review-source-popover-text);
2677
+ background: transparent;
2678
+ text-align: left;
2679
+ }
2680
+
2681
+ .df-review-source-candidate + .df-review-source-candidate {
2682
+ border-top-color: var(--df-review-source-popover-line);
2683
+ }
2684
+
2685
+ .df-review-source-candidate:hover {
2686
+ background: var(--df-review-source-popover-hover);
2687
+ }
2688
+
2689
+ .df-review-source-candidate-main {
2690
+ display: grid;
2691
+ gap: 1px;
2692
+ min-width: 0;
2693
+ }
2694
+
2695
+ .df-review-source-candidate-main strong,
2696
+ .df-review-source-candidate-main small {
2697
+ overflow: hidden;
2698
+ text-overflow: ellipsis;
2699
+ white-space: nowrap;
2700
+ }
2701
+
2702
+ .df-review-source-candidate-main strong {
2703
+ font-size: var(--df-review-font-size-xs);
2704
+ font-weight: 600;
2705
+ line-height: 1.2;
2706
+ }
2707
+
2708
+ .df-review-source-candidate-main span {
2709
+ overflow-wrap: anywhere;
2710
+ color: var(--df-review-source-popover-muted);
2711
+ font-family: var(--df-review-font-mono);
2712
+ font-size: var(--df-review-font-size-2xs);
2713
+ line-height: 1.24;
2714
+ white-space: normal;
2715
+ }
2716
+
2717
+ .df-review-source-candidate-main small {
2718
+ color: var(--df-review-source-popover-subtle);
2719
+ font-family: var(--df-review-font-mono);
2720
+ font-size: var(--df-review-font-size-2xs);
2721
+ line-height: 1.2;
2722
+ }
2723
+
2724
+ .df-review-source-candidate.is-data .df-review-source-candidate-main strong {
2725
+ color: var(--df-review-source-popover-data);
2726
+ }
2727
+
2728
+ .df-review-source-candidate.is-data .df-review-source-candidate-main span {
2729
+ color: var(--df-review-source-popover-data-muted);
2730
+ }
2731
+
2732
+ .df-review-source-candidate.is-data .df-review-source-candidate-main small {
2733
+ color: var(--df-review-source-popover-data-subtle);
2734
+ }
2735
+
2736
+ .df-review-section-outline {
2737
+ position: relative;
2738
+ z-index: 1;
2739
+ display: grid;
2740
+ grid-template-rows: auto minmax(0, 1fr);
2741
+ width: 100%;
2742
+ height: 100%;
2743
+ min-width: 0;
2744
+ min-height: 0;
2745
+ border: 0;
2746
+ border-radius: 0;
2747
+ color: var(--df-review-text);
2748
+ background: transparent;
2749
+ box-shadow: none;
2750
+ overflow: hidden;
2751
+ }
2752
+
2753
+ .df-review-section-outline-head {
2754
+ display: grid;
2755
+ grid-template-rows:
2756
+ var(--df-review-control-height-md)
2757
+ var(--df-review-control-height-md);
2758
+ align-items: center;
2759
+ gap: 8px;
2760
+ min-width: 0;
2761
+ padding: var(--df-review-space-3) var(--df-review-frame-gutter-x);
2762
+ border-bottom: 1px solid var(--df-review-line-soft);
2763
+ background: var(--df-review-card);
2764
+ color: var(--df-review-muted);
2765
+ }
2766
+
2767
+ .df-review-section-outline-head span {
2768
+ display: grid;
2769
+ gap: 2px;
2770
+ min-width: 0;
2771
+ }
2772
+
2773
+ .df-review-section-outline-head strong {
2774
+ overflow: hidden;
2775
+ color: var(--df-review-text);
2776
+ font-size: var(--df-review-font-size-lg);
2777
+ font-weight: 600;
2778
+ text-overflow: ellipsis;
2779
+ white-space: nowrap;
2780
+ }
2781
+
2782
+ .df-review-section-outline-head small {
2783
+ overflow: hidden;
2784
+ color: var(--df-review-muted);
2785
+ font-size: var(--df-review-font-size-xs);
2786
+ font-weight: 500;
2787
+ text-overflow: ellipsis;
2788
+ white-space: nowrap;
2789
+ }
2790
+
2791
+ .df-review-section-outline-filter {
2792
+ display: grid;
2793
+ grid-template-columns: 18px minmax(0, 1fr) auto;
2794
+ align-items: center;
2795
+ align-self: stretch;
2796
+ gap: 8px;
2797
+ min-width: 0;
2798
+ height: var(--df-review-control-height-md);
2799
+ min-height: var(--df-review-control-height-md);
2800
+ border: 1px solid var(--df-review-line-soft);
2801
+ border-radius: var(--df-review-radius-md);
2802
+ padding: 0 7px 0 11px;
2803
+ color: var(--df-review-muted);
2804
+ background: var(--df-review-control);
2805
+ box-shadow: var(--df-review-shadow-control);
2806
+ }
2807
+
2808
+ .df-review-section-outline-filter:focus-within {
2809
+ border-color: var(--df-review-accent);
2810
+ box-shadow: inset 0 0 0 1px var(--df-review-accent-hover);
2811
+ }
2812
+
2813
+ .df-review-section-outline-filter svg {
2814
+ width: 18px;
2815
+ height: 18px;
2816
+ fill: none;
2817
+ stroke: currentColor;
2818
+ stroke-linecap: round;
2819
+ stroke-linejoin: round;
2820
+ stroke-width: 1.9;
2821
+ }
2822
+
2823
+ .df-review-section-outline-filter input {
2824
+ width: 100%;
2825
+ min-width: 0;
2826
+ height: 100%;
2827
+ border: 0;
2828
+ padding: 0;
2829
+ color: var(--df-review-text);
2830
+ background: transparent;
2831
+ font-size: var(--df-review-font-size-xs);
2832
+ font-weight: 500;
2833
+ outline: 0;
2834
+ -webkit-appearance: none;
2835
+ appearance: none;
2836
+ }
2837
+
2838
+ .df-review-section-outline-filter input::placeholder {
2839
+ color: var(--df-review-subtle);
2840
+ }
2841
+
2842
+ .df-review-section-outline-filter input::-webkit-search-cancel-button,
2843
+ .df-review-section-outline-filter input::-webkit-search-decoration {
2844
+ display: none;
2845
+ -webkit-appearance: none;
2846
+ appearance: none;
2847
+ }
2848
+
2849
+ .df-review-section-outline-filter-clear {
2850
+ display: inline-grid;
2851
+ place-items: center;
2852
+ width: var(--df-review-control-height-md);
2853
+ height: var(--df-review-control-height-md);
2854
+ border: 0;
2855
+ border-radius: var(--df-review-radius-sm);
2856
+ padding: 0;
2857
+ color: var(--df-review-muted);
2858
+ background: transparent;
2859
+ cursor: pointer;
2860
+ }
2861
+
2862
+ .df-review-section-outline-filter-clear:hover,
2863
+ .df-review-section-outline-filter-clear:focus-visible {
2864
+ color: var(--df-review-text);
2865
+ background: var(--df-review-accent-soft);
2866
+ outline: 0;
2867
+ }
2868
+
2869
+ .df-review-section-outline-list {
2870
+ display: grid;
2871
+ align-content: start;
2872
+ gap: 2px;
2873
+ min-height: 0;
2874
+ overflow-y: auto;
2875
+ padding: 8px 1px 8px 15px;
2876
+ scrollbar-gutter: stable;
2877
+ }
2878
+
2879
+ .df-review-section-outline-item {
2880
+ display: grid;
2881
+ }
2882
+
2883
+ .df-review-section-outline-item.is-depth-1:not(:last-child) {
2884
+ margin-bottom: 7px;
2885
+ padding-bottom: 7px;
2886
+ border-bottom: 1px solid var(--df-review-line-soft);
2887
+ }
2888
+
2889
+ .df-review-section-outline-row {
2890
+ display: grid;
2891
+ grid-template-columns: 18px minmax(0, 1fr) auto;
2892
+ align-items: center;
2893
+ gap: 5px;
2894
+ border-radius: var(--df-review-radius-sm);
2895
+ padding: 7px 6px;
2896
+ }
2897
+
2898
+ .df-review-section-outline-row:hover {
2899
+ background: var(--df-review-accent-soft);
2900
+ }
2901
+
2902
+ .df-review-section-outline-toggle {
2903
+ display: grid;
2904
+ place-items: center;
2905
+ width: 18px;
2906
+ height: 18px;
2907
+ border: 0;
2908
+ border-radius: var(--df-review-radius-sm);
2909
+ padding: 0;
2910
+ color: var(--df-review-muted);
2911
+ background: transparent;
2912
+ }
2913
+
2914
+ .df-review-section-outline-toggle:hover {
2915
+ color: var(--df-review-text);
2916
+ background: var(--df-review-accent-soft);
2917
+ }
2918
+
2919
+ .df-review-section-outline-toggle svg {
2920
+ width: 13px;
2921
+ height: 13px;
2922
+ fill: none;
2923
+ stroke: currentColor;
2924
+ stroke-linecap: round;
2925
+ stroke-linejoin: round;
2926
+ stroke-width: 2.4;
2927
+ transition: transform 120ms ease;
2928
+ }
2929
+
2930
+ .df-review-section-outline-toggle.is-collapsed svg {
2931
+ transform: rotate(-90deg);
2932
+ }
2933
+
2934
+ .df-review-section-outline-toggle.is-placeholder {
2935
+ pointer-events: none;
2936
+ }
2937
+
2938
+ .df-review-section-outline-name {
2939
+ display: grid;
2940
+ gap: 2px;
2941
+ min-width: 0;
2942
+ overflow: visible;
2943
+ border: 0;
2944
+ padding: 0;
2945
+ color: var(--df-review-text);
2946
+ background: transparent;
2947
+ font-size: var(--df-review-font-size-sm);
2948
+ font-weight: 500;
2949
+ text-align: left;
2950
+ white-space: normal;
2951
+ cursor: pointer;
2952
+ }
2953
+
2954
+ .df-review-section-outline-name span,
2955
+ .df-review-section-outline-name small {
2956
+ overflow: visible;
2957
+ overflow-wrap: anywhere;
2958
+ text-overflow: clip;
2959
+ white-space: normal;
2960
+ }
2961
+
2962
+ .df-review-section-outline-name small {
2963
+ color: var(--df-review-muted);
2964
+ font-family: var(--df-review-font-mono);
2965
+ font-size: var(--df-review-font-size-xs);
2966
+ font-weight: 500;
2967
+ }
2968
+
2969
+ .df-review-section-outline-name:hover {
2970
+ color: var(--df-review-accent);
2971
+ }
2972
+
2973
+ .df-review-section-outline-links {
2974
+ display: inline-flex;
2975
+ align-items: center;
2976
+ justify-content: flex-end;
2977
+ gap: 2px;
2978
+ }
2979
+
2980
+ .df-review-section-outline-divider {
2981
+ color: var(--df-review-subtle);
2982
+ font-size: var(--df-review-font-size-xs);
2983
+ line-height: 1;
2984
+ user-select: none;
2985
+ }
2986
+
2987
+ .df-review-section-outline-link {
2988
+ display: inline-grid;
2989
+ place-items: center;
2990
+ width: 26px;
2991
+ height: 26px;
2992
+ border: 1px solid transparent;
2993
+ border-radius: var(--df-review-radius-sm);
2994
+ padding: 0;
2995
+ color: var(--df-review-muted);
2454
2996
  background: transparent;
2455
- font-size: 16px;
2456
- font-weight: 800;
2457
- line-height: 1;
2458
- }
2459
-
2460
- .df-review-source-popover-close button:hover {
2461
- border-color: var(--df-review-source-popover-line);
2462
- color: var(--df-review-source-popover-text);
2463
- background: var(--df-review-source-popover-hover);
2997
+ cursor: pointer;
2998
+ transition: border-color 140ms ease, background 140ms ease,
2999
+ color 140ms ease, opacity 140ms ease;
2464
3000
  }
2465
3001
 
2466
- .df-review-source-candidate-list {
2467
- display: grid;
2468
- gap: 0;
2469
- max-height: min(220px, calc(100vh - 96px));
2470
- min-height: 0;
2471
- overflow-x: hidden;
2472
- overflow-y: auto;
2473
- padding-right: 2px;
2474
- scrollbar-gutter: stable;
3002
+ .df-review-section-outline-link.is-dom-select {
3003
+ width: 26px;
3004
+ min-width: 26px;
3005
+ padding: 0;
2475
3006
  }
2476
3007
 
2477
- .df-review-source-candidate {
2478
- display: grid;
2479
- width: 100%;
2480
- min-height: 54px;
2481
- border: 0;
2482
- border-radius: var(--df-review-radius-sm);
2483
- padding: 6px 30px 6px 8px;
2484
- color: var(--df-review-source-popover-text);
2485
- background: transparent;
2486
- text-align: left;
3008
+ .df-review-section-outline-link.is-dom-select svg {
3009
+ width: 16px;
3010
+ height: 16px;
2487
3011
  }
2488
3012
 
2489
- .df-review-source-candidate:hover {
2490
- background: var(--df-review-source-popover-hover);
3013
+ .df-review-section-outline-link:hover {
3014
+ border-color: rgba(124, 199, 255, 0.34);
3015
+ color: var(--df-review-accent);
3016
+ background: var(--df-review-accent-soft);
2491
3017
  }
2492
3018
 
2493
- .df-review-source-candidate-main {
2494
- display: grid;
2495
- gap: 2px;
2496
- min-width: 0;
3019
+ .df-review-section-outline-link svg {
3020
+ width: 14px;
3021
+ height: 14px;
3022
+ fill: none;
3023
+ stroke: currentColor;
3024
+ stroke-linecap: round;
3025
+ stroke-linejoin: round;
3026
+ stroke-width: 2;
2497
3027
  }
2498
3028
 
2499
- .df-review-source-candidate-main strong,
2500
- .df-review-source-candidate-main small {
2501
- overflow: hidden;
2502
- text-overflow: ellipsis;
2503
- white-space: nowrap;
3029
+ .df-review-section-outline-link:disabled {
3030
+ color: var(--df-review-subtle);
3031
+ cursor: not-allowed;
3032
+ opacity: 0.42;
2504
3033
  }
2505
3034
 
2506
- .df-review-source-candidate-main strong {
2507
- font-size: var(--df-review-font-size-xs);
2508
- font-weight: 900;
3035
+ .df-review-section-outline-link:disabled:hover {
3036
+ border-color: transparent;
3037
+ color: var(--df-review-subtle);
3038
+ background: transparent;
2509
3039
  }
2510
3040
 
2511
- .df-review-source-candidate-main span {
2512
- overflow-wrap: anywhere;
2513
- color: var(--df-review-source-popover-muted);
2514
- font-family: var(--df-review-font-mono);
2515
- font-size: var(--df-review-font-size-2xs);
2516
- line-height: 1.25;
2517
- white-space: normal;
3041
+ .df-review-section-outline-children {
3042
+ display: grid;
2518
3043
  }
2519
3044
 
2520
- .df-review-source-candidate-main small {
2521
- color: var(--df-review-source-popover-subtle);
2522
- font-family: var(--df-review-font-mono);
2523
- font-size: var(--df-review-font-size-2xs);
3045
+ .df-review-section-outline-empty {
3046
+ padding: 14px 12px 16px;
3047
+ color: var(--df-review-muted);
3048
+ font-size: var(--df-review-font-size-xs);
3049
+ font-weight: 500;
2524
3050
  }
2525
3051
 
2526
3052
  .df-review-device-frame {
@@ -2617,13 +3143,13 @@ function ensureReviewShellStyle() {
2617
3143
  .df-review-ruler-frame-label strong {
2618
3144
  color: var(--df-review-color-ruler-label-text);
2619
3145
  font-size: var(--df-review-font-size-xs);
2620
- font-weight: 900;
3146
+ font-weight: 600;
2621
3147
  }
2622
3148
 
2623
3149
  .df-review-ruler-frame-label span {
2624
3150
  color: var(--df-review-color-ruler-label-text);
2625
3151
  font-size: var(--df-review-font-size-xs);
2626
- font-weight: 900;
3152
+ font-weight: 600;
2627
3153
  opacity: 0.78;
2628
3154
  }
2629
3155
 
@@ -2636,7 +3162,7 @@ function ensureReviewShellStyle() {
2636
3162
  background: var(--df-review-color-ruler-coord-bg);
2637
3163
  color: var(--df-review-color-ruler-coord-text);
2638
3164
  font-size: var(--df-review-font-size-xs);
2639
- font-weight: 900;
3165
+ font-weight: 600;
2640
3166
  line-height: 1;
2641
3167
  white-space: nowrap;
2642
3168
  pointer-events: none;
@@ -2714,7 +3240,7 @@ function ensureReviewShellStyle() {
2714
3240
  color: var(--df-review-color-ruler-popover-text);
2715
3241
  font-family: var(--df-review-font-mono);
2716
3242
  font-size: var(--df-review-font-size-lg);
2717
- font-weight: 900;
3243
+ font-weight: 600;
2718
3244
  line-height: 1;
2719
3245
  white-space: nowrap;
2720
3246
  letter-spacing: -0.02em;
@@ -2727,12 +3253,12 @@ function ensureReviewShellStyle() {
2727
3253
  @media (max-width: 860px) {
2728
3254
  .df-review-shell,
2729
3255
  .df-review-shell.is-list-visible {
2730
- grid-template-columns: minmax(0, 1fr) 0 32px;
3256
+ grid-template-columns: minmax(0, 1fr) 0 48px;
2731
3257
  grid-template-rows: auto auto minmax(0, 1fr);
2732
3258
  }
2733
3259
 
2734
3260
  .df-review-shell.is-list-visible {
2735
- grid-template-columns: minmax(0, 1fr) minmax(260px, 70vw) 32px;
3261
+ grid-template-columns: minmax(0, 1fr) minmax(260px, 70vw) 48px;
2736
3262
  }
2737
3263
 
2738
3264
  .df-review-qa-panel {
@@ -2741,7 +3267,7 @@ function ensureReviewShellStyle() {
2741
3267
  }
2742
3268
 
2743
3269
  .df-review-tools {
2744
- flex-wrap: wrap;
3270
+ flex-wrap: nowrap;
2745
3271
  }
2746
3272
 
2747
3273
  .df-review-tool-controls {
@@ -2771,11 +3297,19 @@ function ensureReviewShellStyle() {
2771
3297
  max-height: calc(100vh - 270px);
2772
3298
  }
2773
3299
 
2774
- .df-review-panel-body {
2775
- min-height: 0;
2776
- }
2777
- }
2778
- `;
3300
+ .df-review-panel-body {
3301
+ min-height: 0;
3302
+ }
3303
+ }
3304
+
3305
+ @media (hover: none) and (pointer: coarse) {
3306
+ .df-review-edit-textarea textarea,
3307
+ .df-review-preset-select,
3308
+ .df-review-prompt-block textarea {
3309
+ font-size: 16px;
3310
+ }
3311
+ }
3312
+ `;
2779
3313
  document.head.append(style);
2780
3314
  }
2781
3315
  }
@@ -2904,31 +3438,59 @@ var __iconNode = [
2904
3438
  ];
2905
3439
  var Bot = createLucideIcon("bot", __iconNode);
2906
3440
 
3441
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/chevron-down.mjs
3442
+ var __iconNode2 = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
3443
+ var ChevronDown = createLucideIcon("chevron-down", __iconNode2);
3444
+
2907
3445
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/circle-question-mark.mjs
2908
- var __iconNode2 = [
3446
+ var __iconNode3 = [
2909
3447
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
2910
3448
  ["path", { d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3", key: "1u773s" }],
2911
3449
  ["path", { d: "M12 17h.01", key: "p32p05" }]
2912
3450
  ];
2913
- var CircleQuestionMark = createLucideIcon("circle-question-mark", __iconNode2);
3451
+ var CircleQuestionMark = createLucideIcon("circle-question-mark", __iconNode3);
3452
+
3453
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/code-xml.mjs
3454
+ var __iconNode4 = [
3455
+ ["path", { d: "m18 16 4-4-4-4", key: "1inbqp" }],
3456
+ ["path", { d: "m6 8-4 4 4 4", key: "15zrgr" }],
3457
+ ["path", { d: "m14.5 4-5 16", key: "e7oirm" }]
3458
+ ];
3459
+ var CodeXml = createLucideIcon("code-xml", __iconNode4);
2914
3460
 
2915
3461
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/copy.mjs
2916
- var __iconNode3 = [
3462
+ var __iconNode5 = [
2917
3463
  ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
2918
3464
  ["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
2919
3465
  ];
2920
- var Copy = createLucideIcon("copy", __iconNode3);
3466
+ var Copy = createLucideIcon("copy", __iconNode5);
3467
+
3468
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/database.mjs
3469
+ var __iconNode6 = [
3470
+ ["ellipse", { cx: "12", cy: "5", rx: "9", ry: "3", key: "msslwz" }],
3471
+ ["path", { d: "M3 5V19A9 3 0 0 0 21 19V5", key: "1wlel7" }],
3472
+ ["path", { d: "M3 12A9 3 0 0 0 21 12", key: "mv7ke4" }]
3473
+ ];
3474
+ var Database = createLucideIcon("database", __iconNode6);
3475
+
3476
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/ellipsis.mjs
3477
+ var __iconNode7 = [
3478
+ ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
3479
+ ["circle", { cx: "19", cy: "12", r: "1", key: "1wjl8i" }],
3480
+ ["circle", { cx: "5", cy: "12", r: "1", key: "1pcz8c" }]
3481
+ ];
3482
+ var Ellipsis = createLucideIcon("ellipsis", __iconNode7);
2921
3483
 
2922
3484
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/external-link.mjs
2923
- var __iconNode4 = [
3485
+ var __iconNode8 = [
2924
3486
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
2925
3487
  ["path", { d: "M10 14 21 3", key: "gplh6r" }],
2926
3488
  ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
2927
3489
  ];
2928
- var ExternalLink = createLucideIcon("external-link", __iconNode4);
3490
+ var ExternalLink = createLucideIcon("external-link", __iconNode8);
2929
3491
 
2930
3492
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/eye-off.mjs
2931
- var __iconNode5 = [
3493
+ var __iconNode9 = [
2932
3494
  [
2933
3495
  "path",
2934
3496
  {
@@ -2946,10 +3508,10 @@ var __iconNode5 = [
2946
3508
  ],
2947
3509
  ["path", { d: "m2 2 20 20", key: "1ooewy" }]
2948
3510
  ];
2949
- var EyeOff = createLucideIcon("eye-off", __iconNode5);
3511
+ var EyeOff = createLucideIcon("eye-off", __iconNode9);
2950
3512
 
2951
3513
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/eye.mjs
2952
- var __iconNode6 = [
3514
+ var __iconNode10 = [
2953
3515
  [
2954
3516
  "path",
2955
3517
  {
@@ -2959,54 +3521,59 @@ var __iconNode6 = [
2959
3521
  ],
2960
3522
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
2961
3523
  ];
2962
- var Eye = createLucideIcon("eye", __iconNode6);
3524
+ var Eye = createLucideIcon("eye", __iconNode10);
2963
3525
 
2964
- // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/grip-vertical.mjs
2965
- var __iconNode7 = [
2966
- ["circle", { cx: "9", cy: "12", r: "1", key: "1vctgf" }],
2967
- ["circle", { cx: "9", cy: "5", r: "1", key: "hp0tcf" }],
2968
- ["circle", { cx: "9", cy: "19", r: "1", key: "fkjjf6" }],
2969
- ["circle", { cx: "15", cy: "12", r: "1", key: "1tmaij" }],
2970
- ["circle", { cx: "15", cy: "5", r: "1", key: "19l28e" }],
2971
- ["circle", { cx: "15", cy: "19", r: "1", key: "f4zoj3" }]
3526
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/file-text.mjs
3527
+ var __iconNode11 = [
3528
+ [
3529
+ "path",
3530
+ {
3531
+ d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
3532
+ key: "1oefj6"
3533
+ }
3534
+ ],
3535
+ ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }],
3536
+ ["path", { d: "M10 9H8", key: "b1mrlr" }],
3537
+ ["path", { d: "M16 13H8", key: "t4e002" }],
3538
+ ["path", { d: "M16 17H8", key: "z1uh3a" }]
2972
3539
  ];
2973
- var GripVertical = createLucideIcon("grip-vertical", __iconNode7);
3540
+ var FileText = createLucideIcon("file-text", __iconNode11);
2974
3541
 
2975
3542
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/image.mjs
2976
- var __iconNode8 = [
3543
+ var __iconNode12 = [
2977
3544
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
2978
3545
  ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
2979
3546
  ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
2980
3547
  ];
2981
- var Image = createLucideIcon("image", __iconNode8);
3548
+ var Image = createLucideIcon("image", __iconNode12);
2982
3549
 
2983
3550
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/layout-grid.mjs
2984
- var __iconNode9 = [
3551
+ var __iconNode13 = [
2985
3552
  ["rect", { width: "7", height: "7", x: "3", y: "3", rx: "1", key: "1g98yp" }],
2986
3553
  ["rect", { width: "7", height: "7", x: "14", y: "3", rx: "1", key: "6d4xhi" }],
2987
3554
  ["rect", { width: "7", height: "7", x: "14", y: "14", rx: "1", key: "nxv5o0" }],
2988
3555
  ["rect", { width: "7", height: "7", x: "3", y: "14", rx: "1", key: "1bb6yr" }]
2989
3556
  ];
2990
- var LayoutGrid = createLucideIcon("layout-grid", __iconNode9);
3557
+ var LayoutGrid = createLucideIcon("layout-grid", __iconNode13);
2991
3558
 
2992
3559
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/link-2.mjs
2993
- var __iconNode10 = [
3560
+ var __iconNode14 = [
2994
3561
  ["path", { d: "M9 17H7A5 5 0 0 1 7 7h2", key: "8i5ue5" }],
2995
3562
  ["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2", key: "1b9ql8" }],
2996
3563
  ["line", { x1: "8", x2: "16", y1: "12", y2: "12", key: "1jonct" }]
2997
3564
  ];
2998
- var Link2 = createLucideIcon("link-2", __iconNode10);
3565
+ var Link2 = createLucideIcon("link-2", __iconNode14);
2999
3566
 
3000
3567
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/list-filter.mjs
3001
- var __iconNode11 = [
3568
+ var __iconNode15 = [
3002
3569
  ["path", { d: "M2 5h20", key: "1fs1ex" }],
3003
3570
  ["path", { d: "M6 12h12", key: "8npq4p" }],
3004
3571
  ["path", { d: "M9 19h6", key: "456am0" }]
3005
3572
  ];
3006
- var ListFilter = createLucideIcon("list-filter", __iconNode11);
3573
+ var ListFilter = createLucideIcon("list-filter", __iconNode15);
3007
3574
 
3008
3575
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/map.mjs
3009
- var __iconNode12 = [
3576
+ var __iconNode16 = [
3010
3577
  [
3011
3578
  "path",
3012
3579
  {
@@ -3017,27 +3584,39 @@ var __iconNode12 = [
3017
3584
  ["path", { d: "M15 5.764v15", key: "1pn4in" }],
3018
3585
  ["path", { d: "M9 3.236v15", key: "1uimfh" }]
3019
3586
  ];
3020
- var Map2 = createLucideIcon("map", __iconNode12);
3587
+ var Map2 = createLucideIcon("map", __iconNode16);
3021
3588
 
3022
3589
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/maximize-2.mjs
3023
- var __iconNode13 = [
3590
+ var __iconNode17 = [
3024
3591
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
3025
3592
  ["path", { d: "m21 3-7 7", key: "1l2asr" }],
3026
3593
  ["path", { d: "m3 21 7-7", key: "tjx5ai" }],
3027
3594
  ["path", { d: "M9 21H3v-6", key: "wtvkvv" }]
3028
3595
  ];
3029
- var Maximize2 = createLucideIcon("maximize-2", __iconNode13);
3596
+ var Maximize2 = createLucideIcon("maximize-2", __iconNode17);
3030
3597
 
3031
3598
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/monitor.mjs
3032
- var __iconNode14 = [
3599
+ var __iconNode18 = [
3033
3600
  ["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
3034
3601
  ["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
3035
3602
  ["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
3036
3603
  ];
3037
- var Monitor = createLucideIcon("monitor", __iconNode14);
3604
+ var Monitor = createLucideIcon("monitor", __iconNode18);
3605
+
3606
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/moon.mjs
3607
+ var __iconNode19 = [
3608
+ [
3609
+ "path",
3610
+ {
3611
+ d: "M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401",
3612
+ key: "kfwtm"
3613
+ }
3614
+ ]
3615
+ ];
3616
+ var Moon = createLucideIcon("moon", __iconNode19);
3038
3617
 
3039
3618
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/pencil.mjs
3040
- var __iconNode15 = [
3619
+ var __iconNode20 = [
3041
3620
  [
3042
3621
  "path",
3043
3622
  {
@@ -3047,25 +3626,25 @@ var __iconNode15 = [
3047
3626
  ],
3048
3627
  ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
3049
3628
  ];
3050
- var Pencil = createLucideIcon("pencil", __iconNode15);
3629
+ var Pencil = createLucideIcon("pencil", __iconNode20);
3051
3630
 
3052
3631
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/rectangle-horizontal.mjs
3053
- var __iconNode16 = [
3632
+ var __iconNode21 = [
3054
3633
  ["rect", { width: "20", height: "12", x: "2", y: "6", rx: "2", key: "9lu3g6" }]
3055
3634
  ];
3056
- var RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode16);
3635
+ var RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode21);
3057
3636
 
3058
3637
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/refresh-cw.mjs
3059
- var __iconNode17 = [
3638
+ var __iconNode22 = [
3060
3639
  ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
3061
3640
  ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
3062
3641
  ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
3063
3642
  ["path", { d: "M8 16H3v5", key: "1cv678" }]
3064
3643
  ];
3065
- var RefreshCw = createLucideIcon("refresh-cw", __iconNode17);
3644
+ var RefreshCw = createLucideIcon("refresh-cw", __iconNode22);
3066
3645
 
3067
3646
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/ruler.mjs
3068
- var __iconNode18 = [
3647
+ var __iconNode23 = [
3069
3648
  [
3070
3649
  "path",
3071
3650
  {
@@ -3078,19 +3657,26 @@ var __iconNode18 = [
3078
3657
  ["path", { d: "m8.5 6.5 2-2", key: "vc6u1g" }],
3079
3658
  ["path", { d: "m17.5 15.5 2-2", key: "wo5hmg" }]
3080
3659
  ];
3081
- var Ruler = createLucideIcon("ruler", __iconNode18);
3660
+ var Ruler = createLucideIcon("ruler", __iconNode23);
3082
3661
 
3083
3662
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/scan.mjs
3084
- var __iconNode19 = [
3663
+ var __iconNode24 = [
3085
3664
  ["path", { d: "M3 7V5a2 2 0 0 1 2-2h2", key: "aa7l1z" }],
3086
3665
  ["path", { d: "M17 3h2a2 2 0 0 1 2 2v2", key: "4qcy5o" }],
3087
3666
  ["path", { d: "M21 17v2a2 2 0 0 1-2 2h-2", key: "6vwrx8" }],
3088
3667
  ["path", { d: "M7 21H5a2 2 0 0 1-2-2v-2", key: "ioqczr" }]
3089
3668
  ];
3090
- var Scan = createLucideIcon("scan", __iconNode19);
3669
+ var Scan = createLucideIcon("scan", __iconNode24);
3670
+
3671
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/search.mjs
3672
+ var __iconNode25 = [
3673
+ ["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
3674
+ ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
3675
+ ];
3676
+ var Search = createLucideIcon("search", __iconNode25);
3091
3677
 
3092
3678
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/settings.mjs
3093
- var __iconNode20 = [
3679
+ var __iconNode26 = [
3094
3680
  [
3095
3681
  "path",
3096
3682
  {
@@ -3100,17 +3686,17 @@ var __iconNode20 = [
3100
3686
  ],
3101
3687
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
3102
3688
  ];
3103
- var Settings = createLucideIcon("settings", __iconNode20);
3689
+ var Settings = createLucideIcon("settings", __iconNode26);
3104
3690
 
3105
3691
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/smartphone.mjs
3106
- var __iconNode21 = [
3692
+ var __iconNode27 = [
3107
3693
  ["rect", { width: "14", height: "20", x: "5", y: "2", rx: "2", ry: "2", key: "1yt0o3" }],
3108
3694
  ["path", { d: "M12 18h.01", key: "mhygvu" }]
3109
3695
  ];
3110
- var Smartphone = createLucideIcon("smartphone", __iconNode21);
3696
+ var Smartphone = createLucideIcon("smartphone", __iconNode27);
3111
3697
 
3112
3698
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/square-mouse-pointer.mjs
3113
- var __iconNode22 = [
3699
+ var __iconNode28 = [
3114
3700
  [
3115
3701
  "path",
3116
3702
  {
@@ -3120,10 +3706,10 @@ var __iconNode22 = [
3120
3706
  ],
3121
3707
  ["path", { d: "M21 11V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h6", key: "14rsvq" }]
3122
3708
  ];
3123
- var SquareMousePointer = createLucideIcon("square-mouse-pointer", __iconNode22);
3709
+ var SquareMousePointer = createLucideIcon("square-mouse-pointer", __iconNode28);
3124
3710
 
3125
3711
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/sticky-note.mjs
3126
- var __iconNode23 = [
3712
+ var __iconNode29 = [
3127
3713
  [
3128
3714
  "path",
3129
3715
  {
@@ -3133,22 +3719,43 @@ var __iconNode23 = [
3133
3719
  ],
3134
3720
  ["path", { d: "M15 3v5a1 1 0 0 0 1 1h5", key: "6s6qgf" }]
3135
3721
  ];
3136
- var StickyNote = createLucideIcon("sticky-note", __iconNode23);
3722
+ var StickyNote = createLucideIcon("sticky-note", __iconNode29);
3723
+
3724
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/sun.mjs
3725
+ var __iconNode30 = [
3726
+ ["circle", { cx: "12", cy: "12", r: "4", key: "4exip2" }],
3727
+ ["path", { d: "M12 2v2", key: "tus03m" }],
3728
+ ["path", { d: "M12 20v2", key: "1lh1kg" }],
3729
+ ["path", { d: "m4.93 4.93 1.41 1.41", key: "149t6j" }],
3730
+ ["path", { d: "m17.66 17.66 1.41 1.41", key: "ptbguv" }],
3731
+ ["path", { d: "M2 12h2", key: "1t8f8n" }],
3732
+ ["path", { d: "M20 12h2", key: "1q8mjw" }],
3733
+ ["path", { d: "m6.34 17.66-1.41 1.41", key: "1m8zz5" }],
3734
+ ["path", { d: "m19.07 4.93-1.41 1.41", key: "1shlcs" }]
3735
+ ];
3736
+ var Sun = createLucideIcon("sun", __iconNode30);
3137
3737
 
3138
3738
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/upload.mjs
3139
- var __iconNode24 = [
3739
+ var __iconNode31 = [
3140
3740
  ["path", { d: "M12 3v12", key: "1x0j5s" }],
3141
3741
  ["path", { d: "m17 8-5-5-5 5", key: "7q97r8" }],
3142
3742
  ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }]
3143
3743
  ];
3144
- var Upload = createLucideIcon("upload", __iconNode24);
3744
+ var Upload = createLucideIcon("upload", __iconNode31);
3745
+
3746
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/user-round.mjs
3747
+ var __iconNode32 = [
3748
+ ["circle", { cx: "12", cy: "8", r: "5", key: "1hypcn" }],
3749
+ ["path", { d: "M20 21a8 8 0 0 0-16 0", key: "rfgkzh" }]
3750
+ ];
3751
+ var UserRound = createLucideIcon("user-round", __iconNode32);
3145
3752
 
3146
3753
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/x.mjs
3147
- var __iconNode25 = [
3754
+ var __iconNode33 = [
3148
3755
  ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
3149
3756
  ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
3150
3757
  ];
3151
- var X = createLucideIcon("x", __iconNode25);
3758
+ var X = createLucideIcon("x", __iconNode33);
3152
3759
 
3153
3760
  // src/react-shell/constants.ts
3154
3761
  var REVIEW_QA_FILTERS = [
@@ -3657,6 +4264,11 @@ var getSystemReviewTheme = () => {
3657
4264
 
3658
4265
  // src/react-shell/review/settings.modal.tsx
3659
4266
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
4267
+ var getReviewThemeIcon = (theme) => {
4268
+ if (theme === "light") return Sun;
4269
+ if (theme === "system") return Monitor;
4270
+ return Moon;
4271
+ };
3660
4272
  var ReviewSettingsModal = ({
3661
4273
  figmaTokenDraft,
3662
4274
  reviewUserIdDraft,
@@ -3716,20 +4328,28 @@ var ReviewSettingsModal = ({
3716
4328
  /* @__PURE__ */ jsxs2("div", { className: "df-review-settings-body", children: [
3717
4329
  /* @__PURE__ */ jsxs2("div", { className: "df-review-settings-row", children: [
3718
4330
  /* @__PURE__ */ jsx2("span", { children: "Theme" }),
3719
- /* @__PURE__ */ jsx2("div", { className: "df-review-settings-theme-options", children: REVIEW_THEME_OPTIONS.map((option) => /* @__PURE__ */ jsx2(
3720
- "button",
3721
- {
3722
- "aria-pressed": reviewThemeDraft === option.value,
3723
- className: `df-review-settings-theme-option${reviewThemeDraft === option.value ? " is-active" : ""}`,
3724
- type: "button",
3725
- onClick: () => {
3726
- onReviewThemeDraftChange(normalizeReviewTheme(option.value));
3727
- onClearStatus();
4331
+ /* @__PURE__ */ jsx2("div", { className: "df-review-settings-theme-options", children: REVIEW_THEME_OPTIONS.map((option) => {
4332
+ const ThemeIcon = getReviewThemeIcon(option.value);
4333
+ return /* @__PURE__ */ jsxs2(
4334
+ "button",
4335
+ {
4336
+ "aria-pressed": reviewThemeDraft === option.value,
4337
+ className: `df-review-settings-theme-option${reviewThemeDraft === option.value ? " is-active" : ""}`,
4338
+ type: "button",
4339
+ onClick: () => {
4340
+ onReviewThemeDraftChange(
4341
+ normalizeReviewTheme(option.value)
4342
+ );
4343
+ onClearStatus();
4344
+ },
4345
+ children: [
4346
+ /* @__PURE__ */ jsx2(ThemeIcon, { "aria-hidden": "true" }),
4347
+ /* @__PURE__ */ jsx2("span", { children: option.label })
4348
+ ]
3728
4349
  },
3729
- children: option.label
3730
- },
3731
- option.value
3732
- )) })
4350
+ option.value
4351
+ );
4352
+ }) })
3733
4353
  ] }),
3734
4354
  /* @__PURE__ */ jsxs2("div", { className: "df-review-settings-field", children: [
3735
4355
  /* @__PURE__ */ jsxs2("div", { className: "df-review-settings-label-row", children: [
@@ -4907,6 +5527,33 @@ var QaPanelHeader = ({
4907
5527
  }
4908
5528
  )
4909
5529
  ] }),
5530
+ /* @__PURE__ */ jsxs7(
5531
+ "select",
5532
+ {
5533
+ "aria-label": "QA status filter",
5534
+ className: "df-review-status-filter-select",
5535
+ value: qaStatusFilter,
5536
+ onChange: (event) => onQaStatusFilterChange(
5537
+ event.currentTarget.value
5538
+ ),
5539
+ children: [
5540
+ /* @__PURE__ */ jsx9("option", { value: "all", children: `All status (${qaStatusFilterCounts.get("all") ?? 0})` }),
5541
+ statusFilterOptions.map((statusOption) => /* @__PURE__ */ jsx9("option", { value: statusOption.value, children: `${statusOption.label} (${qaStatusFilterCounts.get(statusOption.value) ?? 0})` }, statusOption.value))
5542
+ ]
5543
+ }
5544
+ )
5545
+ ] }),
5546
+ /* @__PURE__ */ jsxs7("div", { className: "df-review-list-title", children: [
5547
+ /* @__PURE__ */ jsxs7("span", { className: "df-review-list-meta", children: [
5548
+ /* @__PURE__ */ jsx9("span", { children: isAllQaVisible ? `${label} QA \xB7 All pages` : `${label} QA` }),
5549
+ /* @__PURE__ */ jsx9(
5550
+ "strong",
5551
+ {
5552
+ title: `${activeRemainingItemCount} remaining of ${activeItemCount}`,
5553
+ children: !hasActiveFilter ? `${activeRemainingItemCount}/${activeItemCount}` : `${filteredItemCount}/${activeItemCount}`
5554
+ }
5555
+ )
5556
+ ] }),
4910
5557
  /* @__PURE__ */ jsx9("div", { className: "df-review-filter-tabs", "aria-label": "QA filters", children: REVIEW_QA_FILTERS.map((filter) => {
4911
5558
  const count = qaFilterCounts.get(filter.key) ?? 0;
4912
5559
  const isActive = qaFilter === filter.key;
@@ -4923,25 +5570,6 @@ var QaPanelHeader = ({
4923
5570
  filter.key
4924
5571
  );
4925
5572
  }) })
4926
- ] }),
4927
- /* @__PURE__ */ jsxs7("div", { className: "df-review-list-title", children: [
4928
- /* @__PURE__ */ jsx9("span", { children: isAllQaVisible ? `${label} QA \xB7 All pages` : `${label} QA` }),
4929
- /* @__PURE__ */ jsx9("strong", { title: `${activeRemainingItemCount} remaining of ${activeItemCount}`, children: !hasActiveFilter ? `${activeRemainingItemCount}/${activeItemCount}` : `${filteredItemCount}/${activeItemCount}` }),
4930
- /* @__PURE__ */ jsxs7(
4931
- "select",
4932
- {
4933
- "aria-label": "QA status filter",
4934
- className: "df-review-status-filter-select",
4935
- value: qaStatusFilter,
4936
- onChange: (event) => onQaStatusFilterChange(
4937
- event.currentTarget.value
4938
- ),
4939
- children: [
4940
- /* @__PURE__ */ jsx9("option", { value: "all", children: `All status (${qaStatusFilterCounts.get("all") ?? 0})` }),
4941
- statusFilterOptions.map((statusOption) => /* @__PURE__ */ jsx9("option", { value: statusOption.value, children: `${statusOption.label} (${qaStatusFilterCounts.get(statusOption.value) ?? 0})` }, statusOption.value))
4942
- ]
4943
- }
4944
- )
4945
5573
  ] })
4946
5574
  ] });
4947
5575
  };
@@ -5067,7 +5695,6 @@ var ReviewQaPanel = ({
5067
5695
  // src/react-shell/presence/overlay.tsx
5068
5696
  import { useState as useState3 } from "react";
5069
5697
  import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
5070
- var COLLAPSED_USER_COUNT = 1;
5071
5698
  var getPresenceName = (user) => user.displayName || user.userId;
5072
5699
  var PresenceOverlay = ({
5073
5700
  presenceSessionId,
@@ -5075,18 +5702,31 @@ var PresenceOverlay = ({
5075
5702
  }) => {
5076
5703
  const [isExpanded, setIsExpanded] = useState3(false);
5077
5704
  if (users.length === 0) return null;
5078
- const visibleUsers = isExpanded ? users : users.slice(0, COLLAPSED_USER_COUNT);
5079
- const hiddenUserCount = users.length - visibleUsers.length;
5080
5705
  return /* @__PURE__ */ jsxs9(
5081
5706
  "div",
5082
5707
  {
5083
5708
  "aria-label": `Review presence, ${users.length} online`,
5084
5709
  className: `df-review-presence-overlay${isExpanded ? " is-expanded" : ""}`,
5085
5710
  children: [
5086
- visibleUsers.map((user) => /* @__PURE__ */ jsx11(
5711
+ /* @__PURE__ */ jsxs9(
5712
+ "button",
5713
+ {
5714
+ "aria-label": `Show online reviewers, ${users.length} online`,
5715
+ "aria-expanded": isExpanded,
5716
+ className: "df-review-presence-button",
5717
+ type: "button",
5718
+ onClick: () => setIsExpanded((current) => !current),
5719
+ children: [
5720
+ /* @__PURE__ */ jsx11(UserRound, { "aria-hidden": "true" }),
5721
+ /* @__PURE__ */ jsx11("span", { className: "df-review-presence-badge", children: users.length })
5722
+ ]
5723
+ }
5724
+ ),
5725
+ isExpanded && /* @__PURE__ */ jsx11("div", { className: "df-review-presence-list", role: "list", children: users.map((user) => /* @__PURE__ */ jsx11(
5087
5726
  "span",
5088
5727
  {
5089
5728
  className: `df-review-presence-chip${user.sessionId === presenceSessionId ? " is-self" : ""}`,
5729
+ role: "listitem",
5090
5730
  style: {
5091
5731
  "--df-review-presence-color": user.color
5092
5732
  },
@@ -5094,21 +5734,7 @@ var PresenceOverlay = ({
5094
5734
  children: getPresenceName(user)
5095
5735
  },
5096
5736
  user.sessionId
5097
- )),
5098
- hiddenUserCount > 0 && /* @__PURE__ */ jsxs9(
5099
- "button",
5100
- {
5101
- "aria-label": `Show ${hiddenUserCount} more online reviewers`,
5102
- "aria-expanded": isExpanded,
5103
- className: "df-review-presence-more",
5104
- type: "button",
5105
- onClick: () => setIsExpanded(true),
5106
- children: [
5107
- "+",
5108
- hiddenUserCount
5109
- ]
5110
- }
5111
- )
5737
+ )) })
5112
5738
  ]
5113
5739
  }
5114
5740
  );
@@ -5125,28 +5751,173 @@ var SOURCE_SELECTOR = [
5125
5751
  "[data-section-index]",
5126
5752
  "[data-section-id]"
5127
5753
  ].join(", ");
5128
- var getSourceCandidates = (target) => {
5754
+ var SECTION_OUTLINE_ROOT_SELECTOR = [
5755
+ "[data-wrk-source-component]",
5756
+ "header[data-wrk-source-file]",
5757
+ "footer[data-wrk-source-file]",
5758
+ '[role="banner"][data-wrk-source-file]',
5759
+ '[role="contentinfo"][data-wrk-source-file]'
5760
+ ].join(", ");
5761
+ var matchesIgnore = (file, patterns) => {
5762
+ const normalized = file.replace(/\\/g, "/");
5763
+ return patterns.some(
5764
+ (pattern) => typeof pattern === "string" ? normalized.includes(pattern) : pattern.test(normalized)
5765
+ );
5766
+ };
5767
+ var getSourceCandidates = (target, options) => {
5129
5768
  const startElement = getEventElement(target);
5130
5769
  if (!startElement) return [];
5131
5770
  const candidates = [];
5132
5771
  const seen = /* @__PURE__ */ new Set();
5772
+ const add = (element2, source, depth2, kind) => {
5773
+ if (!source?.file) return;
5774
+ const key = getSourceFileCompareKey(source.file);
5775
+ if (!addSourceFileCompareKey(seen, key)) return;
5776
+ candidates.push(createSourceCandidate(element2, source, depth2, kind));
5777
+ };
5133
5778
  let element = startElement;
5134
5779
  let depth = 0;
5135
5780
  while (element && element.nodeType === 1) {
5136
- const source = getSourceHintFromElement(element);
5137
- if (source?.file) {
5138
- const key = getSourceCandidateKey(source);
5139
- if (!seen.has(key)) {
5140
- seen.add(key);
5141
- candidates.push(createSourceCandidate(element, source, depth));
5142
- }
5143
- }
5781
+ add(element, getSourceHintFromElement(element), depth, "source");
5782
+ add(element, getDataHintFromElement(element), 0, "data");
5144
5783
  if (element === element.ownerDocument.documentElement) break;
5145
5784
  element = element.parentElement;
5146
5785
  depth += 1;
5147
5786
  }
5148
- return candidates.slice(0, 8);
5149
- };
5787
+ const ignore = options?.ignore;
5788
+ const visible = candidates.filter(
5789
+ (candidate) => !isCoreOutlineNode(candidate.label, candidate.source.file) && !(ignore?.length && matchesIgnore(candidate.source.file ?? "", ignore))
5790
+ );
5791
+ return visible.slice(0, 8);
5792
+ };
5793
+ var getSectionOutline = (root, options) => {
5794
+ const maxDepth = options?.maxDepth ?? 9;
5795
+ return getSectionOutlineRoots(root, options).map((element, index) => {
5796
+ const source = getSourceHintFromElement(element);
5797
+ const label = getOutlineLabel(element, source, "section");
5798
+ const seen = /* @__PURE__ */ new Set();
5799
+ if (source?.file) {
5800
+ addSourceFileCompareKey(seen, getOutlineSourceKey(source));
5801
+ }
5802
+ return {
5803
+ id: `${label}-${index}`,
5804
+ label,
5805
+ depth: 1,
5806
+ filePath: getDisplaySourcePath(source?.file) ?? label,
5807
+ element,
5808
+ source,
5809
+ data: getDataHintFromElement(element),
5810
+ children: getSectionOutlineChildren(
5811
+ element,
5812
+ 2,
5813
+ maxDepth,
5814
+ seen,
5815
+ options
5816
+ )
5817
+ };
5818
+ });
5819
+ };
5820
+ function getSectionOutlineRoots(root, options) {
5821
+ return Array.from(root.querySelectorAll(SECTION_OUTLINE_ROOT_SELECTOR)).filter(
5822
+ (element) => {
5823
+ const source = getSourceHintFromElement(element);
5824
+ const label = getOutlineLabel(element, source, "");
5825
+ return !isSkippedOutlineNode(label, source?.file, options);
5826
+ }
5827
+ );
5828
+ }
5829
+ function getSectionOutlineChildren(parent, depth, maxDepth, seen, options) {
5830
+ if (depth > maxDepth) return [];
5831
+ const entries = [];
5832
+ for (const child of Array.from(parent.children)) {
5833
+ const source = getSourceHintFromElement(child);
5834
+ const label = getOutlineLabel(child, source, child.tagName.toLowerCase());
5835
+ const sourceKey = source?.file ? getOutlineSourceKey(source) : "";
5836
+ const isNewSource = Boolean(sourceKey) && !hasEquivalentSourceFileKey(seen, sourceKey);
5837
+ if (shouldStopOutlineBranch(label, source?.file, options)) continue;
5838
+ if (isHiddenOutlineNode(label, source?.file, options)) {
5839
+ entries.push(
5840
+ ...getSectionOutlineChildren(child, depth, maxDepth, seen, options)
5841
+ );
5842
+ continue;
5843
+ }
5844
+ if (source?.file && isNewSource) {
5845
+ const childSeen = new Set(seen);
5846
+ addSourceFileCompareKey(childSeen, sourceKey);
5847
+ entries.push({
5848
+ id: `${sourceKey}-${getElementOutlinePath(child)}-${entries.length}`,
5849
+ label,
5850
+ depth,
5851
+ filePath: getDisplaySourcePath(source.file) ?? source.file,
5852
+ element: child,
5853
+ source,
5854
+ data: getDataHintFromElement(child),
5855
+ children: getSectionOutlineChildren(
5856
+ child,
5857
+ depth + 1,
5858
+ maxDepth,
5859
+ childSeen,
5860
+ options
5861
+ )
5862
+ });
5863
+ continue;
5864
+ }
5865
+ entries.push(
5866
+ ...getSectionOutlineChildren(child, depth, maxDepth, seen, options)
5867
+ );
5868
+ }
5869
+ return entries;
5870
+ }
5871
+ function getElementOutlinePath(element) {
5872
+ const indices = [];
5873
+ let current = element;
5874
+ while (current?.parentElement) {
5875
+ indices.unshift(Array.from(current.parentElement.children).indexOf(current));
5876
+ current = current.parentElement;
5877
+ }
5878
+ return indices.join("-");
5879
+ }
5880
+ function getOutlineSourceKey(source) {
5881
+ return getSourceFileCompareKey(source.file);
5882
+ }
5883
+ function getSourceFileCompareKey(file) {
5884
+ return file?.trim().replace(/\\/g, "/") ?? "";
5885
+ }
5886
+ function addSourceFileCompareKey(seen, key) {
5887
+ if (!key || hasEquivalentSourceFileKey(seen, key)) return false;
5888
+ seen.add(key);
5889
+ return true;
5890
+ }
5891
+ function hasEquivalentSourceFileKey(seen, key) {
5892
+ for (const seenKey of seen) {
5893
+ if (isEquivalentSourceFileKey(seenKey, key)) return true;
5894
+ }
5895
+ return false;
5896
+ }
5897
+ function isEquivalentSourceFileKey(a, b) {
5898
+ return a === b || a.endsWith(`/${b}`) || b.endsWith(`/${a}`);
5899
+ }
5900
+ function getOutlineLabel(element, source, fallback) {
5901
+ return source?.component?.trim() || getComponentNameFromSourceFile(source?.file) || element.id.trim() || fallback;
5902
+ }
5903
+ function isHiddenOutlineNode(label, file, options) {
5904
+ const ignore = options?.ignore;
5905
+ const isIgnoredSource = file && ignore?.length ? matchesIgnore(file, ignore) : false;
5906
+ return isCoreOutlineNode(label, file) || isIgnoredSource;
5907
+ }
5908
+ function shouldStopOutlineBranch(label, file, options) {
5909
+ return !options?.includePlacer && isPlacerOutlineNode(label, file);
5910
+ }
5911
+ function isSkippedOutlineNode(label, file, options) {
5912
+ return shouldStopOutlineBranch(label, file, options) || isHiddenOutlineNode(label, file, options);
5913
+ }
5914
+ function isCoreOutlineNode(label, file) {
5915
+ const text = `${label} ${file ?? ""}`.toLowerCase();
5916
+ return text.includes("core.section") || text.includes("core.content") || text.includes("core.column") || ["coresection", "corecontent", "corecolumn"].includes(label.toLowerCase());
5917
+ }
5918
+ function isPlacerOutlineNode(label, file) {
5919
+ return `${label} ${file ?? ""}`.toLowerCase().includes("placer");
5920
+ }
5150
5921
  var getSourceOpenUrl = (source, options) => {
5151
5922
  const normalizedOptions = normalizeSourceOpenOptions(options);
5152
5923
  const file = source?.file?.trim();
@@ -5185,6 +5956,18 @@ var openSourceInEditor = (source, options) => {
5185
5956
  window.open(url, "_blank", "noreferrer");
5186
5957
  return true;
5187
5958
  };
5959
+ function getDataHintFromElement(element) {
5960
+ const file = getSourceAttribute(element, "data-wrk-data-file");
5961
+ if (!file) return void 0;
5962
+ return {
5963
+ component: void 0,
5964
+ file,
5965
+ line: getSourceAttribute(element, "data-wrk-data-line"),
5966
+ column: void 0,
5967
+ sectionId: void 0,
5968
+ sectionIndex: void 0
5969
+ };
5970
+ }
5188
5971
  function getSourceHintFromElement(element) {
5189
5972
  const source = {
5190
5973
  component: getSourceAttribute(
@@ -5200,7 +5983,7 @@ function getSourceHintFromElement(element) {
5200
5983
  };
5201
5984
  return Object.values(source).some(Boolean) ? source : void 0;
5202
5985
  }
5203
- function createSourceCandidate(element, source, depth) {
5986
+ function createSourceCandidate(element, source, depth, kind) {
5204
5987
  const confidence = getSourceConfidence(source, depth);
5205
5988
  const fileName = source.file?.split(/[\\/]/).pop() ?? source.file ?? "source";
5206
5989
  const component = source.component?.trim();
@@ -5210,7 +5993,7 @@ function createSourceCandidate(element, source, depth) {
5210
5993
  const column = getSourcePosition(source.column);
5211
5994
  const position = line ? `:${line}${column ? `:${column}` : ""}` : "";
5212
5995
  return {
5213
- id: getSourceCandidateKey(source),
5996
+ id: `${kind}:${getSourceCandidateKey(source)}`,
5214
5997
  depth,
5215
5998
  element,
5216
5999
  filePath: getDisplaySourcePath(source.file) ?? fileName,
@@ -5219,6 +6002,7 @@ function createSourceCandidate(element, source, depth) {
5219
6002
  positionLabel: line ? `${line}:${column ?? 1}` : "",
5220
6003
  confidence,
5221
6004
  confidenceLabel: confidence >= 0.82 ? "high" : confidence >= 0.58 ? "medium" : "low",
6005
+ kind,
5222
6006
  usesPosition: confidence >= 0.72 && Boolean(line),
5223
6007
  source
5224
6008
  };
@@ -5242,7 +6026,7 @@ function getDisplaySourcePath(file) {
5242
6026
  const normalizedFile = file?.trim().replace(/\\/g, "/");
5243
6027
  if (!normalizedFile) return void 0;
5244
6028
  const sourceRootMatch = normalizedFile.match(
5245
- /(?:^|\/)((?:dev\/)?src\/.+|app\/.+|pages\/.+|components\/.+)$/
6029
+ /(?:^|\/)((?:dev\/)?src\/.+|app\/.+|pages?\/.+|components\/.+)$/
5246
6030
  );
5247
6031
  return sourceRootMatch?.[1] ?? normalizedFile;
5248
6032
  }
@@ -5733,6 +6517,7 @@ var ViewportPresetIcon = ({
5733
6517
  }) => {
5734
6518
  return /* @__PURE__ */ jsx16(ReviewScopeIcon2, { scope: getViewportPresetKind(preset) });
5735
6519
  };
6520
+ var getPresetSelectValue = (preset) => `${preset.label}:${preset.width}x${preset.height}`;
5736
6521
  var ReviewTopbar = ({
5737
6522
  draftTarget,
5738
6523
  copyLabel,
@@ -5753,6 +6538,13 @@ var ReviewTopbar = ({
5753
6538
  onOpenInitialPrompt,
5754
6539
  onOpenSettings
5755
6540
  }) => {
6541
+ const selectedPresetValue = getPresetSelectValue(size);
6542
+ const handlePresetSelectChange = (event) => {
6543
+ const nextPreset = viewportPresets.find(
6544
+ (preset) => getPresetSelectValue(preset) === event.currentTarget.value
6545
+ );
6546
+ if (nextPreset) onSizeChange(nextPreset);
6547
+ };
5756
6548
  return /* @__PURE__ */ jsxs14("header", { className: "df-review-topbar", children: [
5757
6549
  /* @__PURE__ */ jsxs14(
5758
6550
  "form",
@@ -5802,6 +6594,27 @@ var ReviewTopbar = ({
5802
6594
  },
5803
6595
  preset.label
5804
6596
  )) }),
6597
+ /* @__PURE__ */ jsx16(
6598
+ "select",
6599
+ {
6600
+ "aria-label": "Viewport preset",
6601
+ className: "df-review-preset-select",
6602
+ value: selectedPresetValue,
6603
+ onChange: handlePresetSelectChange,
6604
+ children: viewportPresets.map((preset) => {
6605
+ const scope = getViewportPresetKind(preset);
6606
+ const count = presetScopeCounts.get(scope) ?? 0;
6607
+ return /* @__PURE__ */ jsx16(
6608
+ "option",
6609
+ {
6610
+ value: getPresetSelectValue(preset),
6611
+ children: `${preset.label} (${count})`
6612
+ },
6613
+ getPresetSelectValue(preset)
6614
+ );
6615
+ })
6616
+ }
6617
+ ),
5805
6618
  /* @__PURE__ */ jsx16("span", { className: "df-review-tool-divider", "aria-hidden": "true", children: "|" }),
5806
6619
  /* @__PURE__ */ jsxs14("span", { className: "df-review-active-size", children: [
5807
6620
  size.width,
@@ -5863,6 +6676,64 @@ var ReviewTopbar = ({
5863
6676
  children: /* @__PURE__ */ jsx16(Settings, { "aria-hidden": "true" })
5864
6677
  }
5865
6678
  )
6679
+ ] }),
6680
+ /* @__PURE__ */ jsxs14("details", { className: "df-review-overlays-menu", children: [
6681
+ /* @__PURE__ */ jsx16("summary", { "aria-label": "Open target tools", title: "Tools", children: /* @__PURE__ */ jsx16(Ellipsis, { "aria-hidden": "true" }) }),
6682
+ /* @__PURE__ */ jsxs14("div", { className: "df-review-overlays-popover", "aria-label": "Target tools", children: [
6683
+ isRulerAvailable && /* @__PURE__ */ jsx16(
6684
+ "button",
6685
+ {
6686
+ "aria-label": "Toggle ruler",
6687
+ className: `df-review-overlay-button is-ruler${isRulerVisible ? " is-active" : ""}`,
6688
+ type: "button",
6689
+ onClick: onToggleRuler,
6690
+ children: /* @__PURE__ */ jsx16(Ruler, { "aria-hidden": "true" })
6691
+ }
6692
+ ),
6693
+ /* @__PURE__ */ jsx16(
6694
+ "button",
6695
+ {
6696
+ "aria-label": "Toggle grid overlay",
6697
+ className: `df-review-overlay-button is-grid${targetOverlayState.grid ? " is-active" : ""}`,
6698
+ type: "button",
6699
+ onClick: () => onToggleTargetOverlay("grid"),
6700
+ children: /* @__PURE__ */ jsx16(LayoutGrid, { "aria-hidden": "true" })
6701
+ }
6702
+ ),
6703
+ /* @__PURE__ */ jsx16(
6704
+ "button",
6705
+ {
6706
+ "aria-disabled": !isFigmaOverlayAvailable,
6707
+ "aria-label": isFigmaOverlayAvailable ? "Toggle Figma overlay" : FIGMA_OVERLAY_UNAVAILABLE_MESSAGE,
6708
+ className: `df-review-overlay-button is-figma${targetOverlayState.figma ? " is-active" : ""}${isFigmaOverlayAvailable ? "" : " is-disabled"}`,
6709
+ disabled: !isFigmaOverlayAvailable,
6710
+ type: "button",
6711
+ onClick: () => onToggleTargetOverlay("figma"),
6712
+ children: /* @__PURE__ */ jsx16(Image, { "aria-hidden": "true" })
6713
+ }
6714
+ ),
6715
+ /* @__PURE__ */ jsx16("span", { className: "df-review-tool-divider", "aria-hidden": "true", children: "|" }),
6716
+ /* @__PURE__ */ jsx16(
6717
+ "button",
6718
+ {
6719
+ "aria-label": "Open initial prompt",
6720
+ className: "df-review-overlay-button is-prompt",
6721
+ type: "button",
6722
+ onClick: onOpenInitialPrompt,
6723
+ children: /* @__PURE__ */ jsx16(CircleQuestionMark, { "aria-hidden": "true" })
6724
+ }
6725
+ ),
6726
+ /* @__PURE__ */ jsx16(
6727
+ "button",
6728
+ {
6729
+ "aria-label": "Open settings",
6730
+ className: "df-review-overlay-button is-settings",
6731
+ type: "button",
6732
+ onClick: onOpenSettings,
6733
+ children: /* @__PURE__ */ jsx16(Settings, { "aria-hidden": "true" })
6734
+ }
6735
+ )
6736
+ ] })
5866
6737
  ] })
5867
6738
  ] })
5868
6739
  ] });
@@ -5877,7 +6748,7 @@ import {
5877
6748
  import {
5878
6749
  useCallback
5879
6750
  } from "react";
5880
- function runWithAutoScrollBehavior(targetDocument, callback) {
6751
+ function runWithAutoScrollBehavior2(targetDocument, callback) {
5881
6752
  const elements = [
5882
6753
  targetDocument?.documentElement,
5883
6754
  targetDocument?.body
@@ -5978,7 +6849,7 @@ var useReviewItemRestore = ({
5978
6849
  isCurrentRestore
5979
6850
  );
5980
6851
  if (!isCurrentRestore()) return false;
5981
- runWithAutoScrollBehavior(targetDocument, () => {
6852
+ runWithAutoScrollBehavior2(targetDocument, () => {
5982
6853
  setDocumentScrollInstantly(
5983
6854
  targetWindow,
5984
6855
  targetDocument,
@@ -7464,8 +8335,18 @@ var useReviewShellData = ({
7464
8335
  [qaStatusFilter, scopeFilteredNumberedActiveItems]
7465
8336
  );
7466
8337
  const hiddenOverlayItemIdList = useMemo5(
7467
- () => Array.from(hiddenOverlayItemIds),
7468
- [hiddenOverlayItemIds]
8338
+ () => {
8339
+ const nextHiddenItemIds = new Set(hiddenOverlayItemIds);
8340
+ if (qaStatusFilter !== "all") {
8341
+ activeItems.forEach((item) => {
8342
+ if (normalizeReviewItemStatus(item.status) !== qaStatusFilter) {
8343
+ nextHiddenItemIds.add(item.id);
8344
+ }
8345
+ });
8346
+ }
8347
+ return Array.from(nextHiddenItemIds);
8348
+ },
8349
+ [activeItems, hiddenOverlayItemIds, qaStatusFilter]
7469
8350
  );
7470
8351
  const qaFilterCounts = useMemo5(() => {
7471
8352
  const counts = /* @__PURE__ */ new Map();
@@ -8203,6 +9084,112 @@ var getReviewModeWriteMode = (mode) => {
8203
9084
  var SOURCE_PANEL_MAX_WIDTH = 440;
8204
9085
  var SOURCE_PANEL_MIN_WIDTH = 240;
8205
9086
  var SOURCE_PANEL_MAX_HEIGHT = 260;
9087
+ var SOURCE_TREE_PANEL_CLOSE_DELAY_MS = 180;
9088
+ var waitForFrame = (targetWindow) => new Promise((resolve) => {
9089
+ (targetWindow ?? window).requestAnimationFrame(() => resolve());
9090
+ });
9091
+ var waitForMs = (ms) => new Promise((resolve) => {
9092
+ window.setTimeout(resolve, ms);
9093
+ });
9094
+ var getScrollElement = (targetDocument) => targetDocument.scrollingElement;
9095
+ var scrollElementInTarget = (element, block) => {
9096
+ const targetWindow = element.ownerDocument.defaultView;
9097
+ if (!targetWindow) return;
9098
+ const targetDocument = element.ownerDocument;
9099
+ const scrollElement = getScrollElement(targetDocument);
9100
+ const rect = element.getBoundingClientRect();
9101
+ const currentLeft = scrollElement?.scrollLeft ?? targetWindow.scrollX;
9102
+ const currentTop = scrollElement?.scrollTop ?? targetWindow.scrollY;
9103
+ const clientWidth = scrollElement?.clientWidth ?? targetWindow.innerWidth;
9104
+ const clientHeight = scrollElement?.clientHeight ?? targetWindow.innerHeight;
9105
+ const scrollWidth = scrollElement?.scrollWidth ?? targetDocument.documentElement.scrollWidth;
9106
+ const scrollHeight = scrollElement?.scrollHeight ?? targetDocument.documentElement.scrollHeight;
9107
+ const nextLeft = clamp(
9108
+ currentLeft + rect.left + rect.width / 2 - clientWidth / 2,
9109
+ 0,
9110
+ Math.max(0, scrollWidth - clientWidth)
9111
+ );
9112
+ const nextTop = block === "center" ? clamp(
9113
+ currentTop + rect.top + rect.height / 2 - clientHeight / 2,
9114
+ 0,
9115
+ Math.max(0, scrollHeight - clientHeight)
9116
+ ) : clamp(
9117
+ currentTop + rect.top,
9118
+ 0,
9119
+ Math.max(0, scrollHeight - clientHeight)
9120
+ );
9121
+ runWithAutoScrollBehavior(targetDocument, () => {
9122
+ if (scrollElement) {
9123
+ scrollElement.scrollLeft = Math.round(nextLeft);
9124
+ scrollElement.scrollTop = Math.round(nextTop);
9125
+ return;
9126
+ }
9127
+ targetWindow.scrollTo(Math.round(nextLeft), Math.round(nextTop));
9128
+ });
9129
+ };
9130
+ var centerFrameScrollOnElement = (frameScroll, frame, element) => {
9131
+ if (!frameScroll || !frame) return;
9132
+ const frameScrollRect = frameScroll.getBoundingClientRect();
9133
+ const frameRect = frame.getBoundingClientRect();
9134
+ const elementRect = element.getBoundingClientRect();
9135
+ const elementHostCenterX = frameRect.left + elementRect.left + elementRect.width / 2;
9136
+ const elementHostCenterY = frameRect.top + elementRect.top + elementRect.height / 2;
9137
+ const visibleCenterX = frameScrollRect.left + frameScrollRect.width / 2;
9138
+ const visibleCenterY = frameScrollRect.top + frameScrollRect.height / 2;
9139
+ const nextLeft = clamp(
9140
+ frameScroll.scrollLeft + elementHostCenterX - visibleCenterX,
9141
+ 0,
9142
+ Math.max(0, frameScroll.scrollWidth - frameScroll.clientWidth)
9143
+ );
9144
+ const nextTop = clamp(
9145
+ frameScroll.scrollTop + elementHostCenterY - visibleCenterY,
9146
+ 0,
9147
+ Math.max(0, frameScroll.scrollHeight - frameScroll.clientHeight)
9148
+ );
9149
+ const previousScrollBehavior = frameScroll.style.scrollBehavior;
9150
+ frameScroll.style.scrollBehavior = "auto";
9151
+ frameScroll.scrollLeft = Math.round(nextLeft);
9152
+ frameScroll.scrollTop = Math.round(nextTop);
9153
+ frameScroll.style.scrollBehavior = previousScrollBehavior;
9154
+ };
9155
+ var getSectionOutlineFilterTerms = (value) => value.trim().toLowerCase().split(/\s+/).filter(Boolean);
9156
+ var getSectionOutlineEntryCount = (entries) => entries.reduce(
9157
+ (count, entry) => count + 1 + getSectionOutlineEntryCount(entry.children),
9158
+ 0
9159
+ );
9160
+ var DEFAULT_COLLAPSED_ROOT_LABELS = /* @__PURE__ */ new Set(["FrameHeader", "FrameFooter"]);
9161
+ var getDefaultCollapsedSectionOutlineIds = (entries) => {
9162
+ const collapsedIds = /* @__PURE__ */ new Set();
9163
+ const visit = (entry) => {
9164
+ const shouldCollapseRoot = entry.depth === 1 && DEFAULT_COLLAPSED_ROOT_LABELS.has(entry.label);
9165
+ if ((entry.depth >= 2 || shouldCollapseRoot) && entry.children.length > 0) {
9166
+ collapsedIds.add(entry.id);
9167
+ }
9168
+ entry.children.forEach(visit);
9169
+ };
9170
+ entries.forEach(visit);
9171
+ return collapsedIds;
9172
+ };
9173
+ var matchesSectionOutlineFilter = (entry, terms) => {
9174
+ if (terms.length === 0) return true;
9175
+ const text = [
9176
+ entry.label,
9177
+ entry.filePath,
9178
+ entry.source?.file,
9179
+ entry.data?.file
9180
+ ].filter(Boolean).join(" ").toLowerCase();
9181
+ return terms.every((term) => text.includes(term));
9182
+ };
9183
+ var filterSectionOutlineEntries = (entries, terms) => {
9184
+ if (terms.length === 0) return entries;
9185
+ return entries.flatMap((entry) => {
9186
+ const children = filterSectionOutlineEntries(entry.children, terms);
9187
+ if (!matchesSectionOutlineFilter(entry, terms) && children.length === 0) {
9188
+ return [];
9189
+ }
9190
+ return [{ ...entry, children }];
9191
+ });
9192
+ };
8206
9193
  var ReviewShell = ({
8207
9194
  projectId,
8208
9195
  pages,
@@ -8274,7 +9261,11 @@ var ReviewShell = ({
8274
9261
  });
8275
9262
  const sourceShortcutCleanupRef = useRef5(null);
8276
9263
  const sourceInspectorInteractionRef = useRef5(false);
9264
+ const [sidePanel, setSidePanel] = useState10("qa");
8277
9265
  const [sourceInspectorState, setSourceInspectorState] = useState10(null);
9266
+ const [sectionOutline, setSectionOutline] = useState10(null);
9267
+ const [sectionOutlineFilter, setSectionOutlineFilter] = useState10("");
9268
+ const [collapsedSectionOutlineIds, setCollapsedSectionOutlineIds] = useState10(() => /* @__PURE__ */ new Set());
8278
9269
  const [isAllQaVisible, setIsAllQaVisible] = useState10(false);
8279
9270
  const sourceOpenOptions = useMemo7(
8280
9271
  () => ({
@@ -8283,7 +9274,42 @@ var ReviewShell = ({
8283
9274
  }),
8284
9275
  [sourceInspector, sourceRoot]
8285
9276
  );
9277
+ const sourceCandidateOptions = useMemo7(
9278
+ () => ({
9279
+ ignore: sourceInspector?.ignore,
9280
+ includePlacer: sourceInspector?.includePlacer
9281
+ }),
9282
+ [sourceInspector]
9283
+ );
9284
+ const sectionOutlineOptions = useMemo7(
9285
+ () => ({
9286
+ includePlacer: sourceInspector?.includePlacer,
9287
+ ignore: sourceInspector?.ignore,
9288
+ maxDepth: sourceInspector?.maxDepth
9289
+ }),
9290
+ [sourceInspector]
9291
+ );
8286
9292
  const isSourceInspectorEnabled = sourceInspector?.enabled !== false;
9293
+ const isSourceTreeHoverOutlineEnabled = sourceInspector?.hoverOutline !== false;
9294
+ const isQaPanelVisible = isListVisible && sidePanel === "qa";
9295
+ const isSourceTreePanelVisible = isSourceInspectorEnabled && isListVisible && sidePanel === "source";
9296
+ const sectionOutlineFilterTerms = useMemo7(
9297
+ () => getSectionOutlineFilterTerms(sectionOutlineFilter),
9298
+ [sectionOutlineFilter]
9299
+ );
9300
+ const filteredSectionOutline = useMemo7(
9301
+ () => sectionOutline ? filterSectionOutlineEntries(sectionOutline, sectionOutlineFilterTerms) : [],
9302
+ [sectionOutline, sectionOutlineFilterTerms]
9303
+ );
9304
+ const sectionOutlineTotalCount = useMemo7(
9305
+ () => getSectionOutlineEntryCount(sectionOutline ?? []),
9306
+ [sectionOutline]
9307
+ );
9308
+ const filteredSectionOutlineCount = useMemo7(
9309
+ () => getSectionOutlineEntryCount(filteredSectionOutline),
9310
+ [filteredSectionOutline]
9311
+ );
9312
+ const isSectionOutlineFiltering = sectionOutlineFilterTerms.length > 0;
8287
9313
  const {
8288
9314
  activeItems,
8289
9315
  activeRemainingItemCount,
@@ -8619,6 +9645,12 @@ var ReviewShell = ({
8619
9645
  sourceInspectorInteractionRef.current = false;
8620
9646
  setSourceInspectorState(null);
8621
9647
  }, []);
9648
+ useEffect10(() => {
9649
+ clearSourceInspector();
9650
+ setSectionOutlineFilter("");
9651
+ setCollapsedSectionOutlineIds(/* @__PURE__ */ new Set());
9652
+ setSectionOutline(null);
9653
+ }, [clearSourceInspector, targetSrc]);
8622
9654
  const getSourceInspectorRect = useCallback11(
8623
9655
  (element) => {
8624
9656
  const frame = iframeRef.current;
@@ -8672,13 +9704,15 @@ var ReviewShell = ({
8672
9704
  );
8673
9705
  const showSourceInspectorForTarget = useCallback11(
8674
9706
  (target2, isPinned = false) => {
8675
- const candidates = getSourceCandidates(target2).map((candidate) => ({
8676
- ...candidate,
8677
- openUrl: getSourceOpenUrl(candidate.source, {
8678
- ...sourceOpenOptions,
8679
- omitPosition: !candidate.usesPosition
9707
+ const candidates = getSourceCandidates(target2, sourceCandidateOptions).map(
9708
+ (candidate) => ({
9709
+ ...candidate,
9710
+ openUrl: getSourceOpenUrl(candidate.source, {
9711
+ ...sourceOpenOptions,
9712
+ omitPosition: !candidate.usesPosition
9713
+ })
8680
9714
  })
8681
- }));
9715
+ );
8682
9716
  const firstCandidate = candidates[0];
8683
9717
  const rect = firstCandidate ? getSourceInspectorRect(firstCandidate.element) : null;
8684
9718
  if (!firstCandidate || !rect) {
@@ -8700,12 +9734,16 @@ var ReviewShell = ({
8700
9734
  [
8701
9735
  getSourceInspectorPanelPosition,
8702
9736
  getSourceInspectorRect,
9737
+ sourceCandidateOptions,
8703
9738
  sourceOpenOptions
8704
9739
  ]
8705
9740
  );
8706
9741
  const showSourceOutlineForTarget = useCallback11(
8707
9742
  (target2) => {
8708
- const firstCandidate = getSourceCandidates(target2)[0];
9743
+ const firstCandidate = getSourceCandidates(
9744
+ target2,
9745
+ sourceCandidateOptions
9746
+ )[0];
8709
9747
  const rect = firstCandidate ? getSourceInspectorRect(firstCandidate.element) : null;
8710
9748
  if (!firstCandidate || !rect) {
8711
9749
  setSourceInspectorState(null);
@@ -8722,8 +9760,35 @@ var ReviewShell = ({
8722
9760
  });
8723
9761
  return firstCandidate;
8724
9762
  },
8725
- [getSourceInspectorRect]
9763
+ [getSourceInspectorRect, sourceCandidateOptions]
9764
+ );
9765
+ const showSourceOutlineForElement = useCallback11(
9766
+ (element) => {
9767
+ if (!isSourceTreeHoverOutlineEnabled) return;
9768
+ const rect = getSourceInspectorRect(element);
9769
+ if (!rect) {
9770
+ setSourceInspectorState(
9771
+ (current) => current?.isPinned ? current : null
9772
+ );
9773
+ return;
9774
+ }
9775
+ setSourceInspectorState(
9776
+ (current) => current?.isPinned ? current : {
9777
+ candidates: [],
9778
+ isPinned: false,
9779
+ panelLeft: 0,
9780
+ panelMaxWidth: SOURCE_PANEL_MAX_WIDTH,
9781
+ panelRight: null,
9782
+ panelTop: 0,
9783
+ rect
9784
+ }
9785
+ );
9786
+ },
9787
+ [getSourceInspectorRect, isSourceTreeHoverOutlineEnabled]
8726
9788
  );
9789
+ const clearSourceOutlineHover = useCallback11(() => {
9790
+ setSourceInspectorState((current) => current?.isPinned ? current : null);
9791
+ }, []);
8727
9792
  const openSourceCandidate = useCallback11(
8728
9793
  (candidate) => {
8729
9794
  const didOpen = openSourceInEditor(candidate.source, {
@@ -8735,6 +9800,153 @@ var ReviewShell = ({
8735
9800
  },
8736
9801
  [clearSourceInspector, showToast, sourceOpenOptions]
8737
9802
  );
9803
+ const getCurrentSectionOutline = useCallback11(
9804
+ () => {
9805
+ let frameDocument = null;
9806
+ try {
9807
+ frameDocument = iframeRef.current?.contentDocument ?? null;
9808
+ } catch {
9809
+ frameDocument = null;
9810
+ }
9811
+ return frameDocument ? getSectionOutline(frameDocument, sectionOutlineOptions) : [];
9812
+ },
9813
+ [iframeRef, sectionOutlineOptions]
9814
+ );
9815
+ const setSectionOutlineWithDefaultCollapse = useCallback11(
9816
+ (nextSectionOutline) => {
9817
+ setSectionOutline(nextSectionOutline);
9818
+ setCollapsedSectionOutlineIds(
9819
+ getDefaultCollapsedSectionOutlineIds(nextSectionOutline)
9820
+ );
9821
+ },
9822
+ []
9823
+ );
9824
+ useEffect10(() => {
9825
+ if (sidePanel !== "source" || !isListVisible) return void 0;
9826
+ const refreshSectionOutline = () => {
9827
+ setSectionOutlineWithDefaultCollapse(getCurrentSectionOutline());
9828
+ };
9829
+ const animationFrame = window.requestAnimationFrame(refreshSectionOutline);
9830
+ const firstTimeout = window.setTimeout(refreshSectionOutline, 120);
9831
+ const secondTimeout = window.setTimeout(refreshSectionOutline, 500);
9832
+ return () => {
9833
+ window.cancelAnimationFrame(animationFrame);
9834
+ window.clearTimeout(firstTimeout);
9835
+ window.clearTimeout(secondTimeout);
9836
+ };
9837
+ }, [
9838
+ getCurrentSectionOutline,
9839
+ isListVisible,
9840
+ setSectionOutlineWithDefaultCollapse,
9841
+ sidePanel,
9842
+ targetSrc
9843
+ ]);
9844
+ const toggleQaPanel = useCallback11(() => {
9845
+ setSidePanel("qa");
9846
+ setIsListVisible((current) => sidePanel === "qa" ? !current : true);
9847
+ }, [setIsListVisible, sidePanel]);
9848
+ const toggleSourceTreePanel = useCallback11(() => {
9849
+ if (!isSourceInspectorEnabled) return;
9850
+ if (sidePanel === "source" && isListVisible) {
9851
+ setIsListVisible(false);
9852
+ return;
9853
+ }
9854
+ setSidePanel("source");
9855
+ setSectionOutlineWithDefaultCollapse(getCurrentSectionOutline());
9856
+ setIsListVisible(true);
9857
+ }, [
9858
+ getCurrentSectionOutline,
9859
+ isListVisible,
9860
+ isSourceInspectorEnabled,
9861
+ setSectionOutlineWithDefaultCollapse,
9862
+ setIsListVisible,
9863
+ sidePanel
9864
+ ]);
9865
+ const toggleSectionOutlineEntry = useCallback11((entryId) => {
9866
+ setCollapsedSectionOutlineIds((current) => {
9867
+ const next = new Set(current);
9868
+ if (next.has(entryId)) {
9869
+ next.delete(entryId);
9870
+ } else {
9871
+ next.add(entryId);
9872
+ }
9873
+ return next;
9874
+ });
9875
+ }, []);
9876
+ const scrollToSection = useCallback11((entry) => {
9877
+ scrollElementInTarget(entry.element, "start");
9878
+ centerFrameScrollOnElement(
9879
+ frameScrollRef.current,
9880
+ iframeRef.current,
9881
+ entry.element
9882
+ );
9883
+ }, [frameScrollRef, iframeRef]);
9884
+ const openSectionSource = useCallback11(
9885
+ (entry) => {
9886
+ const didOpen = openSourceInEditor(entry.source, {
9887
+ ...sourceOpenOptions,
9888
+ omitPosition: true
9889
+ });
9890
+ showToast(didOpen ? "Source opened" : "Source root required");
9891
+ },
9892
+ [showToast, sourceOpenOptions]
9893
+ );
9894
+ const openSectionData = useCallback11(
9895
+ (entry) => {
9896
+ const didOpen = openSourceInEditor(entry.data, sourceOpenOptions);
9897
+ showToast(didOpen ? "Data opened" : "Data hint not found");
9898
+ },
9899
+ [showToast, sourceOpenOptions]
9900
+ );
9901
+ const startSectionDomReview = useCallback11(
9902
+ (entry) => {
9903
+ if (!canWriteDom) {
9904
+ showToast("DOM QA unavailable");
9905
+ return;
9906
+ }
9907
+ clearSourceInspector();
9908
+ setIsListVisible(false);
9909
+ let targetWindow = null;
9910
+ try {
9911
+ targetWindow = entry.element.ownerDocument.defaultView ?? iframeRef.current?.contentWindow ?? null;
9912
+ } catch {
9913
+ targetWindow = null;
9914
+ }
9915
+ void waitForMs(SOURCE_TREE_PANEL_CLOSE_DELAY_MS).then(async () => {
9916
+ initReviewKit();
9917
+ await waitForFrame(targetWindow);
9918
+ const controller = controllerRef.current;
9919
+ if (!controller) {
9920
+ showToast("DOM QA unavailable");
9921
+ return;
9922
+ }
9923
+ scrollElementInTarget(entry.element, "center");
9924
+ await waitForFrame(targetWindow);
9925
+ centerFrameScrollOnElement(
9926
+ frameScrollRef.current,
9927
+ iframeRef.current,
9928
+ entry.element
9929
+ );
9930
+ await waitForFrame(targetWindow);
9931
+ await controller.startElementReview(entry.element);
9932
+ await waitForFrame(targetWindow);
9933
+ setMode(controller.getMode());
9934
+ }).catch(() => {
9935
+ setMode(controllerRef.current?.getMode() ?? "idle");
9936
+ });
9937
+ },
9938
+ [
9939
+ canWriteDom,
9940
+ clearSourceInspector,
9941
+ controllerRef,
9942
+ frameScrollRef,
9943
+ iframeRef,
9944
+ initReviewKit,
9945
+ setIsListVisible,
9946
+ setMode,
9947
+ showToast
9948
+ ]
9949
+ );
8738
9950
  const cleanupSourceOpenShortcut = useCallback11(() => {
8739
9951
  sourceShortcutCleanupRef.current?.();
8740
9952
  sourceShortcutCleanupRef.current = null;
@@ -8782,7 +9994,7 @@ var ReviewShell = ({
8782
9994
  background: rgba(15, 23, 42, 0.86) !important;
8783
9995
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.24) !important;
8784
9996
  content: "Source select" !important;
8785
- font: 700 12px/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
9997
+ font: 500 12px/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
8786
9998
  pointer-events: none !important;
8787
9999
  }
8788
10000
 
@@ -8799,7 +10011,7 @@ var ReviewShell = ({
8799
10011
  color: #ffffff !important;
8800
10012
  background: rgba(15, 23, 42, 0.9) !important;
8801
10013
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.28) !important;
8802
- font: 800 11px/1.35 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace !important;
10014
+ font: 500 11px/1.35 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace !important;
8803
10015
  overflow-wrap: anywhere !important;
8804
10016
  pointer-events: none !important;
8805
10017
  white-space: normal !important;
@@ -8900,8 +10112,9 @@ var ReviewShell = ({
8900
10112
  }
8901
10113
  };
8902
10114
  const handleMouseMove = (event) => {
10115
+ if (isSourcePanelPinned) return;
8903
10116
  lastSourceTarget = event.target;
8904
- const candidates = getSourceCandidates(event.target);
10117
+ const candidates = getSourceCandidates(event.target, sourceCandidateOptions);
8905
10118
  const sourceElement = candidates[0]?.element ?? null;
8906
10119
  if (event.altKey && !isSourceSelecting) {
8907
10120
  setSourceSelecting(true);
@@ -8935,6 +10148,7 @@ var ReviewShell = ({
8935
10148
  return;
8936
10149
  }
8937
10150
  if (!isOptionKeyEvent(event)) return;
10151
+ if (isSourcePanelPinned) return;
8938
10152
  cancelReviewMode();
8939
10153
  setSourceSelecting(true);
8940
10154
  };
@@ -8985,6 +10199,7 @@ var ReviewShell = ({
8985
10199
  iframeRef,
8986
10200
  isSourceInspectorEnabled,
8987
10201
  showToast,
10202
+ sourceCandidateOptions,
8988
10203
  showSourceOutlineForTarget,
8989
10204
  showSourceInspectorForTarget
8990
10205
  ]);
@@ -8999,12 +10214,19 @@ var ReviewShell = ({
8999
10214
  mode === "element"
9000
10215
  );
9001
10216
  bindSourceOpenShortcut();
10217
+ if (sidePanel === "source" && isListVisible) {
10218
+ setSectionOutlineWithDefaultCollapse(getCurrentSectionOutline());
10219
+ }
9002
10220
  }, [
9003
10221
  bindSourceOpenShortcut,
10222
+ getCurrentSectionOutline,
9004
10223
  iframeRef,
9005
10224
  initReviewKit,
10225
+ isListVisible,
9006
10226
  mode,
9007
- refreshTargetFigmaConfig
10227
+ refreshTargetFigmaConfig,
10228
+ setSectionOutlineWithDefaultCollapse,
10229
+ sidePanel
9008
10230
  ]);
9009
10231
  useEffect10(() => {
9010
10232
  const frame = window.requestAnimationFrame(bindSourceOpenShortcut);
@@ -9085,6 +10307,112 @@ var ReviewShell = ({
9085
10307
  onRefreshReviewData: refreshReviewData2,
9086
10308
  onToast: showToast
9087
10309
  });
10310
+ const renderSectionOutlineEntry = (entry) => {
10311
+ const hasChildren = entry.children.length > 0;
10312
+ const isCollapsed = !isSectionOutlineFiltering && collapsedSectionOutlineIds.has(entry.id);
10313
+ return /* @__PURE__ */ jsxs15(
10314
+ "div",
10315
+ {
10316
+ className: `df-review-section-outline-item is-depth-${entry.depth}`,
10317
+ children: [
10318
+ /* @__PURE__ */ jsxs15(
10319
+ "div",
10320
+ {
10321
+ className: "df-review-section-outline-row",
10322
+ style: { paddingLeft: `${Math.max(0, entry.depth - 1) * 12 + 6}px` },
10323
+ onMouseEnter: () => showSourceOutlineForElement(entry.element),
10324
+ onMouseLeave: clearSourceOutlineHover,
10325
+ onMouseOver: () => showSourceOutlineForElement(entry.element),
10326
+ onMouseOut: (event) => {
10327
+ if (event.relatedTarget instanceof Node && event.currentTarget.contains(event.relatedTarget)) {
10328
+ return;
10329
+ }
10330
+ clearSourceOutlineHover();
10331
+ },
10332
+ onPointerEnter: () => showSourceOutlineForElement(entry.element),
10333
+ onPointerLeave: clearSourceOutlineHover,
10334
+ children: [
10335
+ hasChildren ? /* @__PURE__ */ jsx17(
10336
+ "button",
10337
+ {
10338
+ "aria-label": isCollapsed ? `Expand ${entry.label}` : `Collapse ${entry.label}`,
10339
+ "aria-expanded": !isCollapsed,
10340
+ className: `df-review-section-outline-toggle${isCollapsed ? " is-collapsed" : ""}`,
10341
+ type: "button",
10342
+ onClick: () => toggleSectionOutlineEntry(entry.id),
10343
+ children: /* @__PURE__ */ jsx17(ChevronDown, { "aria-hidden": "true" })
10344
+ }
10345
+ ) : /* @__PURE__ */ jsx17(
10346
+ "span",
10347
+ {
10348
+ "aria-hidden": "true",
10349
+ className: "df-review-section-outline-toggle is-placeholder"
10350
+ }
10351
+ ),
10352
+ /* @__PURE__ */ jsx17(
10353
+ "button",
10354
+ {
10355
+ className: "df-review-section-outline-name",
10356
+ type: "button",
10357
+ onClick: () => scrollToSection(entry),
10358
+ children: /* @__PURE__ */ jsx17("span", { children: entry.label })
10359
+ }
10360
+ ),
10361
+ /* @__PURE__ */ jsxs15("span", { className: "df-review-section-outline-links", children: [
10362
+ /* @__PURE__ */ jsx17(
10363
+ "button",
10364
+ {
10365
+ "aria-label": `Open ${entry.label} data`,
10366
+ className: "df-review-section-outline-link",
10367
+ title: "Open data",
10368
+ type: "button",
10369
+ disabled: !entry.data?.file,
10370
+ onClick: () => openSectionData(entry),
10371
+ children: /* @__PURE__ */ jsx17(Database, { "aria-hidden": "true" })
10372
+ }
10373
+ ),
10374
+ /* @__PURE__ */ jsx17(
10375
+ "button",
10376
+ {
10377
+ "aria-label": `Open ${entry.label} source`,
10378
+ className: "df-review-section-outline-link",
10379
+ title: "Open source",
10380
+ type: "button",
10381
+ disabled: !entry.source?.file,
10382
+ onClick: () => openSectionSource(entry),
10383
+ children: /* @__PURE__ */ jsx17(CodeXml, { "aria-hidden": "true" })
10384
+ }
10385
+ ),
10386
+ /* @__PURE__ */ jsx17(
10387
+ "span",
10388
+ {
10389
+ "aria-hidden": "true",
10390
+ className: "df-review-section-outline-divider",
10391
+ children: "|"
10392
+ }
10393
+ ),
10394
+ /* @__PURE__ */ jsx17(
10395
+ "button",
10396
+ {
10397
+ "aria-label": `Start DOM QA for ${entry.label}`,
10398
+ className: "df-review-section-outline-link is-dom-select",
10399
+ title: "DOM select",
10400
+ type: "button",
10401
+ disabled: !canWriteDom,
10402
+ onClick: () => startSectionDomReview(entry),
10403
+ children: /* @__PURE__ */ jsx17(SquareMousePointer, { "aria-hidden": "true" })
10404
+ }
10405
+ )
10406
+ ] })
10407
+ ]
10408
+ }
10409
+ ),
10410
+ hasChildren && !isCollapsed && /* @__PURE__ */ jsx17("div", { className: "df-review-section-outline-children", children: entry.children.map(renderSectionOutlineEntry) })
10411
+ ]
10412
+ },
10413
+ entry.id
10414
+ );
10415
+ };
9088
10416
  return /* @__PURE__ */ jsxs15(
9089
10417
  "div",
9090
10418
  {
@@ -9115,13 +10443,6 @@ var ReviewShell = ({
9115
10443
  onOpenSettings: openFigmaSettings
9116
10444
  }
9117
10445
  ),
9118
- currentPagePresenceUsers.length > 0 && /* @__PURE__ */ jsx17("div", { className: "df-review-presence-row", children: /* @__PURE__ */ jsx17(
9119
- PresenceOverlay,
9120
- {
9121
- presenceSessionId,
9122
- users: currentPagePresenceUsers
9123
- }
9124
- ) }),
9125
10446
  isSitemapOpen && /* @__PURE__ */ jsx17(
9126
10447
  SitemapModal,
9127
10448
  {
@@ -9174,19 +10495,40 @@ var ReviewShell = ({
9174
10495
  }
9175
10496
  ),
9176
10497
  toastMessage && /* @__PURE__ */ jsx17("div", { className: "df-review-copy-toast", role: "status", children: toastMessage }),
9177
- /* @__PURE__ */ jsx17("div", { className: "df-review-side-rail", children: /* @__PURE__ */ jsxs15(
9178
- "button",
9179
- {
9180
- "aria-label": isListVisible ? "Hide QA list" : "Show QA list",
9181
- className: "df-review-side-toggle",
9182
- type: "button",
9183
- onClick: () => setIsListVisible((current) => !current),
9184
- children: [
9185
- /* @__PURE__ */ jsx17("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx17(GripVertical, {}) }),
9186
- /* @__PURE__ */ jsx17("strong", { children: "QA" })
9187
- ]
9188
- }
9189
- ) }),
10498
+ /* @__PURE__ */ jsxs15("div", { className: "df-review-side-rail", children: [
10499
+ /* @__PURE__ */ jsx17(
10500
+ "button",
10501
+ {
10502
+ "aria-label": isQaPanelVisible ? "Hide QA list" : "Show QA list",
10503
+ "aria-pressed": isQaPanelVisible,
10504
+ className: `df-review-side-toggle${isQaPanelVisible ? " is-active" : ""}`,
10505
+ type: "button",
10506
+ onClick: toggleQaPanel,
10507
+ title: "QA",
10508
+ children: /* @__PURE__ */ jsx17("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx17(FileText, {}) })
10509
+ }
10510
+ ),
10511
+ isSourceInspectorEnabled && /* @__PURE__ */ jsx17(
10512
+ "button",
10513
+ {
10514
+ "aria-controls": "df-review-section-outline",
10515
+ "aria-label": isSourceTreePanelVisible ? "Hide source tree" : "Show source tree",
10516
+ "aria-pressed": isSourceTreePanelVisible,
10517
+ className: `df-review-side-toggle${isSourceTreePanelVisible ? " is-active" : ""}`,
10518
+ type: "button",
10519
+ onClick: toggleSourceTreePanel,
10520
+ title: "Source Tree",
10521
+ children: /* @__PURE__ */ jsx17("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx17(Search, {}) })
10522
+ }
10523
+ ),
10524
+ currentPagePresenceUsers.length > 0 && /* @__PURE__ */ jsx17(
10525
+ PresenceOverlay,
10526
+ {
10527
+ presenceSessionId,
10528
+ users: currentPagePresenceUsers
10529
+ }
10530
+ )
10531
+ ] }),
9190
10532
  /* @__PURE__ */ jsx17(
9191
10533
  ReviewQaPanel,
9192
10534
  {
@@ -9197,7 +10539,7 @@ var ReviewShell = ({
9197
10539
  filteredNumberedActiveItems,
9198
10540
  getItemPresetScope,
9199
10541
  hiddenOverlayItemIds,
9200
- isListVisible,
10542
+ isListVisible: isQaPanelVisible,
9201
10543
  isAllQaVisible,
9202
10544
  isRemoteSource,
9203
10545
  copiedPromptKey,
@@ -9225,6 +10567,49 @@ var ReviewShell = ({
9225
10567
  onToggleItemOverlayVisibility: toggleItemOverlayVisibility
9226
10568
  }
9227
10569
  ),
10570
+ isSourceInspectorEnabled && /* @__PURE__ */ jsx17(
10571
+ "aside",
10572
+ {
10573
+ className: "df-review-source-tree-panel",
10574
+ "aria-hidden": !isSourceTreePanelVisible,
10575
+ children: /* @__PURE__ */ jsxs15("div", { id: "df-review-section-outline", className: "df-review-section-outline", children: [
10576
+ /* @__PURE__ */ jsxs15("div", { className: "df-review-section-outline-head", children: [
10577
+ /* @__PURE__ */ jsxs15("span", { children: [
10578
+ /* @__PURE__ */ jsx17("strong", { children: "Source Tree" }),
10579
+ /* @__PURE__ */ jsx17("small", { children: isSectionOutlineFiltering ? `${filteredSectionOutlineCount} / ${sectionOutlineTotalCount} results` : `${sectionOutline?.length ?? 0} roots` })
10580
+ ] }),
10581
+ /* @__PURE__ */ jsxs15("div", { className: "df-review-section-outline-filter", children: [
10582
+ /* @__PURE__ */ jsx17(Search, { "aria-hidden": "true" }),
10583
+ /* @__PURE__ */ jsx17(
10584
+ "input",
10585
+ {
10586
+ "aria-label": "Filter source tree",
10587
+ type: "text",
10588
+ value: sectionOutlineFilter,
10589
+ placeholder: "Filter",
10590
+ autoComplete: "off",
10591
+ enterKeyHint: "search",
10592
+ spellCheck: false,
10593
+ onChange: (event) => setSectionOutlineFilter(event.currentTarget.value)
10594
+ }
10595
+ ),
10596
+ sectionOutlineFilter && /* @__PURE__ */ jsx17(
10597
+ "button",
10598
+ {
10599
+ "aria-label": "Clear source tree filter",
10600
+ className: "df-review-section-outline-filter-clear",
10601
+ type: "button",
10602
+ onMouseDown: (event) => event.preventDefault(),
10603
+ onClick: () => setSectionOutlineFilter(""),
10604
+ children: /* @__PURE__ */ jsx17(X, { "aria-hidden": "true" })
10605
+ }
10606
+ )
10607
+ ] })
10608
+ ] }),
10609
+ filteredSectionOutline.length > 0 ? /* @__PURE__ */ jsx17("div", { className: "df-review-section-outline-list", children: filteredSectionOutline.map(renderSectionOutlineEntry) }) : /* @__PURE__ */ jsx17("div", { className: "df-review-section-outline-empty", children: isSectionOutlineFiltering ? "No source matches" : "No sections found" })
10610
+ ] })
10611
+ }
10612
+ ),
9228
10613
  /* @__PURE__ */ jsx17(
9229
10614
  ReviewTargetFrame,
9230
10615
  {
@@ -9296,7 +10681,7 @@ var ReviewShell = ({
9296
10681
  /* @__PURE__ */ jsx17("div", { className: "df-review-source-candidate-list", children: sourceInspectorState.candidates.map((candidate) => /* @__PURE__ */ jsx17(
9297
10682
  "button",
9298
10683
  {
9299
- className: "df-review-source-candidate",
10684
+ className: `df-review-source-candidate is-${candidate.kind}`,
9300
10685
  type: "button",
9301
10686
  onClick: (event) => {
9302
10687
  event.preventDefault();
@@ -9306,7 +10691,7 @@ var ReviewShell = ({
9306
10691
  children: /* @__PURE__ */ jsxs15("span", { className: "df-review-source-candidate-main", children: [
9307
10692
  /* @__PURE__ */ jsx17("strong", { children: candidate.label }),
9308
10693
  /* @__PURE__ */ jsx17("span", { children: candidate.filePath }),
9309
- /* @__PURE__ */ jsx17("small", { children: candidate.positionLabel || (candidate.usesPosition ? "" : "file only") })
10694
+ /* @__PURE__ */ jsx17("small", { children: candidate.positionLabel || "-:-" })
9310
10695
  ] })
9311
10696
  },
9312
10697
  candidate.id
@@ -9529,12 +10914,16 @@ lucide-react/dist/esm/context.mjs:
9529
10914
  lucide-react/dist/esm/Icon.mjs:
9530
10915
  lucide-react/dist/esm/createLucideIcon.mjs:
9531
10916
  lucide-react/dist/esm/icons/bot.mjs:
10917
+ lucide-react/dist/esm/icons/chevron-down.mjs:
9532
10918
  lucide-react/dist/esm/icons/circle-question-mark.mjs:
10919
+ lucide-react/dist/esm/icons/code-xml.mjs:
9533
10920
  lucide-react/dist/esm/icons/copy.mjs:
10921
+ lucide-react/dist/esm/icons/database.mjs:
10922
+ lucide-react/dist/esm/icons/ellipsis.mjs:
9534
10923
  lucide-react/dist/esm/icons/external-link.mjs:
9535
10924
  lucide-react/dist/esm/icons/eye-off.mjs:
9536
10925
  lucide-react/dist/esm/icons/eye.mjs:
9537
- lucide-react/dist/esm/icons/grip-vertical.mjs:
10926
+ lucide-react/dist/esm/icons/file-text.mjs:
9538
10927
  lucide-react/dist/esm/icons/image.mjs:
9539
10928
  lucide-react/dist/esm/icons/layout-grid.mjs:
9540
10929
  lucide-react/dist/esm/icons/link-2.mjs:
@@ -9542,16 +10931,20 @@ lucide-react/dist/esm/icons/list-filter.mjs:
9542
10931
  lucide-react/dist/esm/icons/map.mjs:
9543
10932
  lucide-react/dist/esm/icons/maximize-2.mjs:
9544
10933
  lucide-react/dist/esm/icons/monitor.mjs:
10934
+ lucide-react/dist/esm/icons/moon.mjs:
9545
10935
  lucide-react/dist/esm/icons/pencil.mjs:
9546
10936
  lucide-react/dist/esm/icons/rectangle-horizontal.mjs:
9547
10937
  lucide-react/dist/esm/icons/refresh-cw.mjs:
9548
10938
  lucide-react/dist/esm/icons/ruler.mjs:
9549
10939
  lucide-react/dist/esm/icons/scan.mjs:
10940
+ lucide-react/dist/esm/icons/search.mjs:
9550
10941
  lucide-react/dist/esm/icons/settings.mjs:
9551
10942
  lucide-react/dist/esm/icons/smartphone.mjs:
9552
10943
  lucide-react/dist/esm/icons/square-mouse-pointer.mjs:
9553
10944
  lucide-react/dist/esm/icons/sticky-note.mjs:
10945
+ lucide-react/dist/esm/icons/sun.mjs:
9554
10946
  lucide-react/dist/esm/icons/upload.mjs:
10947
+ lucide-react/dist/esm/icons/user-round.mjs:
9555
10948
  lucide-react/dist/esm/icons/x.mjs:
9556
10949
  lucide-react/dist/esm/lucide-react.mjs:
9557
10950
  (**