@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.
@@ -101,10 +101,10 @@ function ensureReviewShellStyle() {
101
101
  --df-review-font-size-lg: 14px;
102
102
  --df-review-font-size-xl: 15px;
103
103
  --df-review-font-size-2xl: 18px;
104
- --df-review-font-weight-medium: 650;
105
- --df-review-font-weight-bold: 700;
106
- --df-review-font-weight-strong: 800;
107
- --df-review-font-weight-heavy: 900;
104
+ --df-review-font-weight-medium: 400;
105
+ --df-review-font-weight-bold: 500;
106
+ --df-review-font-weight-strong: 500;
107
+ --df-review-font-weight-heavy: 600;
108
108
  --df-review-line-height-tight: 1.25;
109
109
  --df-review-line-height-base: 1.42;
110
110
  --df-review-line-height-relaxed: 1.55;
@@ -121,7 +121,7 @@ function ensureReviewShellStyle() {
121
121
  --df-review-space-8: 32px;
122
122
  --df-review-control-height-sm: 32px;
123
123
  --df-review-control-height-md: 34px;
124
- --df-review-control-height-lg: 38px;
124
+ --df-review-control-height-lg: 34px;
125
125
  --df-review-radius-xs: 3px;
126
126
  --df-review-radius-sm: 6px;
127
127
  --df-review-radius-md: 8px;
@@ -295,7 +295,7 @@ function ensureReviewShellStyle() {
295
295
  .df-review-shell {
296
296
  --df-review-frame-gutter-x: var(--df-review-space-4);
297
297
  display: grid;
298
- grid-template-columns: minmax(0, 1fr) 0 32px;
298
+ grid-template-columns: minmax(0, 1fr) 0 48px;
299
299
  grid-template-rows: auto auto minmax(0, 1fr);
300
300
  width: 100%;
301
301
  height: 100%;
@@ -304,7 +304,7 @@ function ensureReviewShellStyle() {
304
304
  }
305
305
 
306
306
  .df-review-shell.is-list-visible {
307
- grid-template-columns: minmax(0, 1fr) clamp(320px, 28vw, 420px) 32px;
307
+ grid-template-columns: minmax(0, 1fr) clamp(320px, 28vw, 420px) 48px;
308
308
  }
309
309
 
310
310
  .df-review-topbar {
@@ -323,20 +323,6 @@ function ensureReviewShellStyle() {
323
323
  box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.025);
324
324
  }
325
325
 
326
- .df-review-presence-row {
327
- grid-column: 1;
328
- grid-row: 2;
329
- position: relative;
330
- z-index: 590;
331
- display: flex;
332
- align-items: center;
333
- justify-content: flex-start;
334
- min-width: 0;
335
- padding: var(--df-review-space-2) var(--df-review-frame-gutter-x);
336
- border-bottom: 1px solid var(--df-review-line-soft);
337
- background: var(--df-review-panel);
338
- }
339
-
340
326
  .df-review-address {
341
327
  display: grid;
342
328
  grid-template-columns: auto minmax(160px, 1fr) auto auto;
@@ -349,6 +335,7 @@ function ensureReviewShellStyle() {
349
335
 
350
336
  .df-review-address input {
351
337
  width: 100%;
338
+ height: var(--df-review-control-height-md);
352
339
  min-height: var(--df-review-control-height-md);
353
340
  border: 1px solid var(--df-review-line);
354
341
  border-radius: var(--df-review-radius-sm);
@@ -366,7 +353,6 @@ function ensureReviewShellStyle() {
366
353
  }
367
354
 
368
355
  .df-review-address button,
369
- .df-review-side-toggle,
370
356
  .df-review-presets button,
371
357
  .df-review-overlay-button,
372
358
  .df-review-mode-button,
@@ -375,6 +361,7 @@ function ensureReviewShellStyle() {
375
361
  .df-review-settings-actions button,
376
362
  .df-review-prompt-block-header button,
377
363
  .df-review-item-actions button {
364
+ height: var(--df-review-control-height-md);
378
365
  min-height: var(--df-review-control-height-md);
379
366
  border: 1px solid var(--df-review-line);
380
367
  border-radius: var(--df-review-radius-sm);
@@ -382,12 +369,11 @@ function ensureReviewShellStyle() {
382
369
  box-shadow: var(--df-review-shadow-control);
383
370
  color: var(--df-review-text);
384
371
  font-size: var(--df-review-font-size-sm);
385
- font-weight: 700;
372
+ font-weight: 500;
386
373
  transition: border-color 140ms ease, background 140ms ease, color 140ms ease, box-shadow 140ms ease, opacity 140ms ease;
387
374
  }
388
375
 
389
376
  .df-review-address button:hover,
390
- .df-review-side-toggle:hover,
391
377
  .df-review-presets button:hover,
392
378
  .df-review-overlay-button:hover,
393
379
  .df-review-mode-button:hover,
@@ -488,12 +474,13 @@ function ensureReviewShellStyle() {
488
474
 
489
475
  .df-review-sitemap-header strong {
490
476
  font-size: var(--df-review-font-size-lg);
477
+ font-weight: 600;
491
478
  }
492
479
 
493
480
  .df-review-sitemap-header span {
494
481
  color: var(--df-review-muted);
495
482
  font-size: var(--df-review-font-size-sm);
496
- font-weight: 700;
483
+ font-weight: 500;
497
484
  }
498
485
 
499
486
  .df-review-sitemap-header button {
@@ -507,7 +494,7 @@ function ensureReviewShellStyle() {
507
494
  background: var(--df-review-control);
508
495
  color: var(--df-review-text);
509
496
  font-size: var(--df-review-font-size-md);
510
- font-weight: 800;
497
+ font-weight: 500;
511
498
  }
512
499
 
513
500
  .df-review-sitemap-header button:hover {
@@ -535,7 +522,7 @@ function ensureReviewShellStyle() {
535
522
  background: var(--df-review-control);
536
523
  box-shadow: var(--df-review-shadow-control);
537
524
  font-size: var(--df-review-font-size-xs);
538
- font-weight: 850;
525
+ font-weight: 600;
539
526
  }
540
527
 
541
528
  .df-review-sitemap-list {
@@ -571,7 +558,7 @@ function ensureReviewShellStyle() {
571
558
  0 1px 0 var(--df-review-line);
572
559
  color: var(--df-review-muted);
573
560
  font-size: var(--df-review-font-size-xs);
574
- font-weight: 720;
561
+ font-weight: 500;
575
562
  letter-spacing: 0.03em;
576
563
  text-transform: uppercase;
577
564
  }
@@ -669,7 +656,7 @@ function ensureReviewShellStyle() {
669
656
  overflow-wrap: anywhere;
670
657
  color: var(--df-review-text);
671
658
  font-size: var(--df-review-font-size-md);
672
- font-weight: 650;
659
+ font-weight: 400;
673
660
  line-height: 1.35;
674
661
  }
675
662
 
@@ -681,7 +668,7 @@ function ensureReviewShellStyle() {
681
668
  flex: 0 0 auto;
682
669
  color: var(--df-review-muted);
683
670
  font-family: var(--df-review-font-mono);
684
- font-weight: 500;
671
+ font-weight: 400;
685
672
  white-space: pre;
686
673
  }
687
674
 
@@ -696,14 +683,14 @@ function ensureReviewShellStyle() {
696
683
  color: var(--df-review-muted);
697
684
  font-size: var(--df-review-font-size-sm);
698
685
  font-variant-numeric: tabular-nums;
699
- font-weight: 650;
686
+ font-weight: 400;
700
687
  line-height: 1;
701
688
  text-align: right;
702
689
  }
703
690
 
704
691
  .df-review-sitemap-cell.is-total {
705
692
  color: var(--df-review-accent);
706
- font-weight: 760;
693
+ font-weight: 500;
707
694
  }
708
695
 
709
696
  .df-review-sitemap-cell.is-total strong {
@@ -736,7 +723,7 @@ function ensureReviewShellStyle() {
736
723
  background: var(--df-review-chip-bg);
737
724
  color: var(--df-review-text);
738
725
  font-size: var(--df-review-font-size-xs);
739
- font-weight: 900;
726
+ font-weight: 600;
740
727
  line-height: 1.1;
741
728
  white-space: nowrap;
742
729
  }
@@ -808,12 +795,13 @@ function ensureReviewShellStyle() {
808
795
  .df-review-settings-header strong {
809
796
  color: var(--df-review-text);
810
797
  font-size: var(--df-review-font-size-lg);
798
+ font-weight: 600;
811
799
  }
812
800
 
813
801
  .df-review-settings-header span {
814
802
  color: var(--df-review-muted);
815
803
  font-size: var(--df-review-font-size-xs);
816
- font-weight: 800;
804
+ font-weight: 500;
817
805
  }
818
806
 
819
807
  .df-review-settings-header button {
@@ -823,7 +811,7 @@ function ensureReviewShellStyle() {
823
811
  min-width: 34px;
824
812
  padding: 0;
825
813
  font-size: var(--df-review-font-size-md);
826
- font-weight: 800;
814
+ font-weight: 500;
827
815
  }
828
816
 
829
817
  .df-review-settings-body {
@@ -849,7 +837,7 @@ function ensureReviewShellStyle() {
849
837
  .df-review-settings-label-row label {
850
838
  color: var(--df-review-muted);
851
839
  font-size: var(--df-review-font-size-sm);
852
- font-weight: 800;
840
+ font-weight: 500;
853
841
  }
854
842
 
855
843
  .df-review-settings-theme-options {
@@ -861,17 +849,32 @@ function ensureReviewShellStyle() {
861
849
  }
862
850
 
863
851
  .df-review-settings-theme-option {
852
+ display: inline-flex;
853
+ align-items: center;
854
+ justify-content: center;
855
+ gap: 7px;
864
856
  min-height: 30px;
865
857
  border: 1px solid var(--df-review-line);
866
858
  border-radius: var(--df-review-radius-sm);
867
- padding: 0 10px;
859
+ padding: 0 11px;
868
860
  color: var(--df-review-muted);
869
861
  background: var(--df-review-control);
870
862
  box-shadow: var(--df-review-shadow-control);
871
863
  font-size: var(--df-review-font-size-sm);
872
- font-weight: 800;
864
+ font-weight: 500;
873
865
  }
874
866
 
867
+ .df-review-settings-theme-option svg {
868
+ width: 15px;
869
+ height: 15px;
870
+ flex: 0 0 auto;
871
+ stroke-width: 2.2;
872
+ }
873
+
874
+ .df-review-settings-theme-option span {
875
+ color: inherit;
876
+ }
877
+
875
878
  .df-review-settings-theme-option:hover {
876
879
  border-color: var(--df-review-accent);
877
880
  background: var(--df-review-control-hover);
@@ -1016,7 +1019,7 @@ function ensureReviewShellStyle() {
1016
1019
  background: var(--df-review-chip-bg);
1017
1020
  color: var(--df-review-muted);
1018
1021
  font-size: var(--df-review-font-size-xs);
1019
- font-weight: 700;
1022
+ font-weight: 500;
1020
1023
  line-height: 1.55;
1021
1024
  }
1022
1025
 
@@ -1032,7 +1035,7 @@ function ensureReviewShellStyle() {
1032
1035
  margin: 0;
1033
1036
  color: var(--df-review-accent);
1034
1037
  font-size: var(--df-review-font-size-sm);
1035
- font-weight: 800;
1038
+ font-weight: 500;
1036
1039
  }
1037
1040
 
1038
1041
  .df-review-settings-actions {
@@ -1098,7 +1101,7 @@ function ensureReviewShellStyle() {
1098
1101
  margin: 0;
1099
1102
  color: var(--df-review-danger);
1100
1103
  font-size: var(--df-review-font-size-sm);
1101
- font-weight: 800;
1104
+ font-weight: 500;
1102
1105
  }
1103
1106
 
1104
1107
  .df-review-edit-actions {
@@ -1151,7 +1154,7 @@ function ensureReviewShellStyle() {
1151
1154
  box-shadow: var(--df-review-shadow-modal);
1152
1155
  color: var(--df-review-text);
1153
1156
  font-size: var(--df-review-font-size-sm);
1154
- font-weight: 800;
1157
+ font-weight: 500;
1155
1158
  line-height: 1.25;
1156
1159
  pointer-events: none;
1157
1160
  }
@@ -1175,13 +1178,14 @@ function ensureReviewShellStyle() {
1175
1178
  .df-review-prompt-header strong {
1176
1179
  color: var(--df-review-text);
1177
1180
  font-size: var(--df-review-font-size-lg);
1181
+ font-weight: 600;
1178
1182
  }
1179
1183
 
1180
1184
  .df-review-prompt-header span {
1181
1185
  overflow: hidden;
1182
1186
  color: var(--df-review-muted);
1183
1187
  font-size: var(--df-review-font-size-xs);
1184
- font-weight: 800;
1188
+ font-weight: 500;
1185
1189
  text-overflow: ellipsis;
1186
1190
  white-space: nowrap;
1187
1191
  }
@@ -1193,7 +1197,7 @@ function ensureReviewShellStyle() {
1193
1197
  min-width: 34px;
1194
1198
  padding: 0;
1195
1199
  font-size: var(--df-review-font-size-md);
1196
- font-weight: 800;
1200
+ font-weight: 500;
1197
1201
  }
1198
1202
 
1199
1203
  .df-review-prompt-body {
@@ -1227,13 +1231,13 @@ function ensureReviewShellStyle() {
1227
1231
  .df-review-prompt-block-header strong {
1228
1232
  color: var(--df-review-text);
1229
1233
  font-size: var(--df-review-font-size-sm);
1230
- font-weight: 900;
1234
+ font-weight: 600;
1231
1235
  }
1232
1236
 
1233
1237
  .df-review-prompt-block-header span {
1234
1238
  color: var(--df-review-muted);
1235
1239
  font-size: var(--df-review-font-size-xs);
1236
- font-weight: 800;
1240
+ font-weight: 500;
1237
1241
  }
1238
1242
 
1239
1243
  .df-review-prompt-block-header button {
@@ -1272,7 +1276,7 @@ function ensureReviewShellStyle() {
1272
1276
  color: var(--df-review-text);
1273
1277
  font-family: var(--df-review-font-mono);
1274
1278
  font-size: var(--df-review-font-size-xs);
1275
- font-weight: 600;
1279
+ font-weight: 400;
1276
1280
  line-height: 1.5;
1277
1281
  white-space: pre;
1278
1282
  }
@@ -1291,13 +1295,13 @@ function ensureReviewShellStyle() {
1291
1295
  .df-review-prompt-section-header strong {
1292
1296
  color: var(--df-review-text);
1293
1297
  font-size: var(--df-review-font-size-md);
1294
- font-weight: 900;
1298
+ font-weight: 600;
1295
1299
  }
1296
1300
 
1297
1301
  .df-review-prompt-section-header span {
1298
1302
  color: var(--df-review-muted);
1299
1303
  font-size: var(--df-review-font-size-xs);
1300
- font-weight: 800;
1304
+ font-weight: 500;
1301
1305
  }
1302
1306
 
1303
1307
  .df-review-prompt-about {
@@ -1326,14 +1330,14 @@ function ensureReviewShellStyle() {
1326
1330
  .df-review-prompt-about-grid strong {
1327
1331
  color: var(--df-review-text);
1328
1332
  font-size: var(--df-review-font-size-sm);
1329
- font-weight: 900;
1333
+ font-weight: 600;
1330
1334
  }
1331
1335
 
1332
1336
  .df-review-prompt-about-grid p {
1333
1337
  margin: 0;
1334
1338
  color: var(--df-review-muted);
1335
1339
  font-size: var(--df-review-font-size-sm);
1336
- font-weight: 700;
1340
+ font-weight: 500;
1337
1341
  line-height: 1.55;
1338
1342
  }
1339
1343
 
@@ -1363,8 +1367,9 @@ function ensureReviewShellStyle() {
1363
1367
  display: flex;
1364
1368
  align-items: center;
1365
1369
  gap: var(--df-review-space-1-5);
1366
- min-height: calc(var(--df-review-control-height-lg) + 6px);
1367
- padding: 3px;
1370
+ height: var(--df-review-control-height-md);
1371
+ min-height: var(--df-review-control-height-md);
1372
+ padding: 0;
1368
1373
  border: 1px solid var(--df-review-line-soft);
1369
1374
  border-radius: var(--df-review-radius-md);
1370
1375
  background: var(--df-review-card);
@@ -1376,28 +1381,50 @@ function ensureReviewShellStyle() {
1376
1381
  align-items: center;
1377
1382
  color: var(--df-review-line);
1378
1383
  font-size: var(--df-review-font-size-2xl);
1379
- font-weight: 700;
1384
+ font-weight: 500;
1380
1385
  line-height: 1;
1381
1386
  user-select: none;
1382
1387
  }
1383
1388
 
1384
- .df-review-active-size {
1389
+ .df-review-active-size {
1385
1390
  flex: 0 0 auto;
1386
1391
  display: inline-flex;
1387
1392
  align-items: center;
1388
- min-height: var(--df-review-control-height-lg);
1393
+ min-height: var(--df-review-control-height-md);
1389
1394
  color: var(--df-review-muted);
1390
1395
  font-size: var(--df-review-font-size-sm);
1391
1396
  font-variant-numeric: tabular-nums;
1392
- font-weight: 800;
1397
+ font-weight: 500;
1393
1398
  line-height: 1;
1394
1399
  }
1395
1400
 
1401
+ .df-review-preset-select {
1402
+ -webkit-appearance: none;
1403
+ appearance: none;
1404
+ display: none;
1405
+ height: var(--df-review-control-height-md);
1406
+ min-height: var(--df-review-control-height-md);
1407
+ min-width: 154px;
1408
+ border: 1px solid var(--df-review-line-soft);
1409
+ border-radius: var(--df-review-radius-md);
1410
+ padding: 0 42px 0 14px;
1411
+ color: var(--df-review-text);
1412
+ background-color: var(--df-review-control);
1413
+ 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");
1414
+ background-position: right 14px center;
1415
+ background-repeat: no-repeat;
1416
+ background-size: 18px 18px;
1417
+ box-shadow: var(--df-review-shadow-control);
1418
+ font-size: var(--df-review-font-size-sm);
1419
+ font-weight: 500;
1420
+ }
1421
+
1396
1422
  .df-review-presets button {
1397
1423
  display: inline-flex;
1398
1424
  align-items: center;
1399
1425
  gap: 7px;
1400
- min-height: var(--df-review-control-height-lg);
1426
+ height: var(--df-review-control-height-md);
1427
+ min-height: var(--df-review-control-height-md);
1401
1428
  padding: 0 11px 0 9px;
1402
1429
  border-color: transparent;
1403
1430
  background: transparent;
@@ -1422,7 +1449,7 @@ function ensureReviewShellStyle() {
1422
1449
  background: var(--df-review-line-soft);
1423
1450
  color: var(--df-review-muted);
1424
1451
  font-size: var(--df-review-font-size-2xs);
1425
- font-weight: 800;
1452
+ font-weight: 500;
1426
1453
  line-height: 16px;
1427
1454
  text-align: center;
1428
1455
  }
@@ -1448,6 +1475,7 @@ function ensureReviewShellStyle() {
1448
1475
  .df-review-preset-copy strong {
1449
1476
  color: var(--df-review-text);
1450
1477
  font-size: var(--df-review-font-size-sm);
1478
+ font-weight: 500;
1451
1479
  }
1452
1480
 
1453
1481
  .df-review-overlay-button,
@@ -1455,8 +1483,10 @@ function ensureReviewShellStyle() {
1455
1483
  position: relative;
1456
1484
  display: inline-grid;
1457
1485
  place-items: center;
1458
- width: 38px;
1459
- min-width: 38px;
1486
+ width: var(--df-review-control-height-md);
1487
+ min-width: var(--df-review-control-height-md);
1488
+ height: var(--df-review-control-height-md);
1489
+ min-height: var(--df-review-control-height-md);
1460
1490
  padding: 0;
1461
1491
  border-color: transparent;
1462
1492
  background: transparent;
@@ -1464,6 +1494,72 @@ function ensureReviewShellStyle() {
1464
1494
  color: var(--df-review-muted);
1465
1495
  }
1466
1496
 
1497
+ .df-review-overlays-menu {
1498
+ position: relative;
1499
+ display: none;
1500
+ flex: 0 0 auto;
1501
+ }
1502
+
1503
+ .df-review-overlays-menu summary {
1504
+ display: grid;
1505
+ place-items: center;
1506
+ width: var(--df-review-control-height-md);
1507
+ min-width: var(--df-review-control-height-md);
1508
+ height: var(--df-review-control-height-md);
1509
+ border: 1px solid var(--df-review-line-soft);
1510
+ border-radius: var(--df-review-radius-md);
1511
+ padding: 0;
1512
+ color: var(--df-review-muted);
1513
+ background: var(--df-review-card);
1514
+ box-shadow: var(--df-review-shadow-control);
1515
+ cursor: pointer;
1516
+ }
1517
+
1518
+ .df-review-overlays-menu summary::-webkit-details-marker {
1519
+ display: none;
1520
+ }
1521
+
1522
+ .df-review-overlays-menu summary::marker {
1523
+ content: '';
1524
+ }
1525
+
1526
+ .df-review-overlays-menu summary:hover,
1527
+ .df-review-overlays-menu[open] summary {
1528
+ border-color: var(--df-review-accent);
1529
+ background: var(--df-review-control-hover);
1530
+ color: var(--df-review-accent);
1531
+ }
1532
+
1533
+ .df-review-overlays-menu summary svg {
1534
+ width: 20px;
1535
+ height: 20px;
1536
+ fill: none;
1537
+ stroke: currentColor;
1538
+ stroke-linecap: round;
1539
+ stroke-linejoin: round;
1540
+ stroke-width: 1.9;
1541
+ }
1542
+
1543
+ .df-review-overlays-popover {
1544
+ position: absolute;
1545
+ top: calc(100% + 6px);
1546
+ right: 0;
1547
+ z-index: 700;
1548
+ display: none;
1549
+ align-items: center;
1550
+ gap: var(--df-review-space-1-5);
1551
+ min-height: var(--df-review-control-height-md);
1552
+ padding: 0;
1553
+ border: 1px solid var(--df-review-line-soft);
1554
+ border-radius: var(--df-review-radius-md);
1555
+ background: var(--df-review-card);
1556
+ box-shadow: var(--df-review-shadow-modal);
1557
+ }
1558
+
1559
+ .df-review-overlays-menu[open] .df-review-overlays-popover {
1560
+ display: flex;
1561
+ }
1562
+
1467
1563
  .df-review-overlay-button svg,
1468
1564
  .df-review-mode-button svg {
1469
1565
  width: 18px;
@@ -1499,33 +1595,46 @@ function ensureReviewShellStyle() {
1499
1595
 
1500
1596
  @container (max-width: 1040px) {
1501
1597
  .df-review-tools {
1502
- flex-direction: column;
1503
- align-items: stretch;
1504
- justify-content: flex-start;
1598
+ flex-direction: row;
1599
+ align-items: center;
1600
+ justify-content: space-between;
1505
1601
  }
1506
1602
 
1507
1603
  .df-review-tool-controls {
1508
- width: 100%;
1604
+ flex: 1 1 auto;
1605
+ width: auto;
1606
+ min-width: 0;
1607
+ flex-wrap: nowrap;
1509
1608
  }
1510
1609
 
1511
1610
  .df-review-presets {
1512
- flex-wrap: wrap;
1611
+ display: none;
1612
+ }
1613
+
1614
+ .df-review-preset-select {
1615
+ display: block;
1616
+ flex: 0 1 190px;
1617
+ width: clamp(154px, 26vw, 190px);
1513
1618
  }
1514
1619
 
1515
1620
  .df-review-overlays {
1516
- width: 100%;
1517
- justify-content: flex-start;
1621
+ display: none;
1518
1622
  }
1623
+
1624
+ .df-review-overlays-menu {
1625
+ display: block;
1626
+ }
1519
1627
  }
1520
1628
 
1521
1629
  .df-review-side-rail {
1522
1630
  grid-column: 3;
1523
1631
  grid-row: 1 / span 3;
1524
1632
  position: relative;
1525
- z-index: 600;
1633
+ z-index: 640;
1526
1634
  display: flex;
1635
+ flex-direction: column;
1527
1636
  align-items: stretch;
1528
- justify-content: center;
1637
+ justify-content: flex-start;
1529
1638
  min-width: 0;
1530
1639
  min-height: 0;
1531
1640
  border-left: 1px solid var(--df-review-line);
@@ -1533,49 +1642,166 @@ function ensureReviewShellStyle() {
1533
1642
  }
1534
1643
 
1535
1644
  .df-review-side-toggle {
1645
+ position: relative;
1646
+ flex: 0 0 58px;
1536
1647
  display: grid;
1537
- grid-template-rows: 28px auto;
1538
- align-items: start;
1539
- justify-items: center;
1540
- gap: 8px;
1648
+ place-items: center;
1541
1649
  width: 100%;
1542
- min-height: 100%;
1650
+ min-height: 58px;
1543
1651
  border: 0;
1544
1652
  border-radius: 0;
1545
- padding: 10px 0;
1653
+ padding: 0;
1546
1654
  background: transparent;
1547
1655
  color: var(--df-review-muted);
1656
+ transition: color 140ms ease, background 140ms ease;
1548
1657
  }
1549
1658
 
1550
1659
  .df-review-side-toggle:hover {
1551
- background: var(--df-review-accent-soft);
1552
1660
  color: var(--df-review-text);
1553
1661
  }
1554
1662
 
1663
+ .df-review-side-toggle.is-active {
1664
+ color: var(--df-review-accent);
1665
+ }
1666
+
1667
+ .df-review-side-toggle.is-active::after {
1668
+ position: absolute;
1669
+ top: 12px;
1670
+ right: 0;
1671
+ bottom: 12px;
1672
+ width: 3px;
1673
+ border-radius: 3px 0 0 3px;
1674
+ background: var(--df-review-accent);
1675
+ content: '';
1676
+ }
1677
+
1678
+ .df-review-side-toggle:focus-visible {
1679
+ outline: 0;
1680
+ color: var(--df-review-text);
1681
+ }
1682
+
1683
+ .df-review-side-toggle:focus-visible span {
1684
+ border-radius: 6px;
1685
+ outline: 2px solid var(--df-review-focus-ring);
1686
+ outline-offset: 3px;
1687
+ }
1688
+
1555
1689
  .df-review-side-toggle span {
1556
1690
  display: grid;
1557
1691
  place-items: center;
1558
- width: 20px;
1559
- height: 24px;
1692
+ width: 30px;
1693
+ height: 30px;
1560
1694
  line-height: 1;
1561
1695
  }
1562
1696
 
1563
1697
  .df-review-side-toggle svg {
1564
- width: 18px;
1565
- height: 18px;
1698
+ width: 30px;
1699
+ height: 30px;
1566
1700
  fill: none;
1567
1701
  stroke: currentColor;
1568
1702
  stroke-linecap: round;
1569
- stroke-width: 2;
1703
+ stroke-width: 1.55;
1570
1704
  }
1571
1705
 
1572
- .df-review-side-toggle strong {
1573
- writing-mode: vertical-rl;
1574
- text-orientation: mixed;
1575
- color: inherit;
1576
- font-size: var(--df-review-font-size-2xs);
1577
- font-weight: 900;
1578
- letter-spacing: 0.08em;
1706
+ .df-review-presence-overlay {
1707
+ position: relative;
1708
+ margin-top: auto;
1709
+ }
1710
+
1711
+ .df-review-presence-button {
1712
+ position: relative;
1713
+ display: grid;
1714
+ place-items: center;
1715
+ width: 100%;
1716
+ min-height: 58px;
1717
+ border: 0;
1718
+ border-radius: 0;
1719
+ padding: 0;
1720
+ color: var(--df-review-muted);
1721
+ background: transparent;
1722
+ }
1723
+
1724
+ .df-review-presence-button:hover,
1725
+ .df-review-presence-button[aria-expanded="true"] {
1726
+ color: var(--df-review-text);
1727
+ }
1728
+
1729
+ .df-review-presence-button:focus-visible {
1730
+ outline: 0;
1731
+ }
1732
+
1733
+ .df-review-presence-button:focus-visible svg {
1734
+ border-radius: 6px;
1735
+ outline: 2px solid var(--df-review-focus-ring);
1736
+ outline-offset: 3px;
1737
+ }
1738
+
1739
+ .df-review-presence-button svg {
1740
+ width: 30px;
1741
+ height: 30px;
1742
+ fill: none;
1743
+ stroke: currentColor;
1744
+ stroke-linecap: round;
1745
+ stroke-linejoin: round;
1746
+ stroke-width: 1.55;
1747
+ }
1748
+
1749
+ .df-review-presence-badge {
1750
+ position: absolute;
1751
+ top: 10px;
1752
+ right: 7px;
1753
+ display: grid;
1754
+ place-items: center;
1755
+ min-width: 17px;
1756
+ height: 17px;
1757
+ border: 1px solid var(--df-review-side-rail);
1758
+ border-radius: var(--df-review-radius-pill);
1759
+ padding: 0 4px;
1760
+ color: #17202c;
1761
+ background: var(--df-review-accent);
1762
+ font-size: var(--df-review-font-size-3xs);
1763
+ font-weight: 600;
1764
+ line-height: 1;
1765
+ pointer-events: none;
1766
+ }
1767
+
1768
+ .df-review-presence-list {
1769
+ position: absolute;
1770
+ right: calc(100% + 8px);
1771
+ bottom: 8px;
1772
+ display: grid;
1773
+ gap: 5px;
1774
+ min-width: 132px;
1775
+ max-width: 220px;
1776
+ border: 1px solid var(--df-review-line);
1777
+ border-radius: var(--df-review-radius-md);
1778
+ padding: 8px;
1779
+ background: var(--df-review-panel);
1780
+ box-shadow: var(--df-review-shadow-modal);
1781
+ }
1782
+
1783
+ .df-review-presence-chip {
1784
+ --df-review-presence-color: var(--df-review-accent);
1785
+ display: flex;
1786
+ align-items: center;
1787
+ min-width: 0;
1788
+ min-height: 24px;
1789
+ border-left: 2px solid var(--df-review-presence-color);
1790
+ border-radius: var(--df-review-radius-sm);
1791
+ padding: 0 8px;
1792
+ color: var(--df-review-text);
1793
+ background: var(--df-review-control);
1794
+ font-size: var(--df-review-font-size-xs);
1795
+ font-weight: 500;
1796
+ line-height: 1.1;
1797
+ overflow: hidden;
1798
+ text-overflow: ellipsis;
1799
+ white-space: nowrap;
1800
+ }
1801
+
1802
+ .df-review-presence-chip.is-self {
1803
+ color: var(--df-review-accent);
1804
+ background: var(--df-review-accent-soft);
1579
1805
  }
1580
1806
 
1581
1807
  .df-review-qa-panel {
@@ -1593,11 +1819,34 @@ function ensureReviewShellStyle() {
1593
1819
  linear-gradient(180deg, var(--df-review-panel), var(--df-review-bg));
1594
1820
  }
1595
1821
 
1596
- .df-review-shell:not(.is-list-visible) .df-review-qa-panel {
1822
+ .df-review-shell:not(.is-list-visible) .df-review-qa-panel,
1823
+ .df-review-qa-panel[aria-hidden="true"] {
1597
1824
  visibility: hidden;
1598
1825
  border-left: 0;
1826
+ pointer-events: none;
1599
1827
  }
1600
1828
 
1829
+ .df-review-source-tree-panel {
1830
+ grid-column: 2;
1831
+ grid-row: 1 / span 3;
1832
+ position: relative;
1833
+ z-index: 600;
1834
+ display: grid;
1835
+ min-width: 0;
1836
+ min-height: 0;
1837
+ overflow: hidden;
1838
+ border-left: 1px solid var(--df-review-line-soft);
1839
+ background:
1840
+ linear-gradient(180deg, var(--df-review-panel), var(--df-review-bg));
1841
+ }
1842
+
1843
+ .df-review-shell:not(.is-list-visible) .df-review-source-tree-panel,
1844
+ .df-review-source-tree-panel[aria-hidden="true"] {
1845
+ visibility: hidden;
1846
+ border-left: 0;
1847
+ pointer-events: none;
1848
+ }
1849
+
1601
1850
  .df-review-panel-body {
1602
1851
  display: grid;
1603
1852
  min-width: 0;
@@ -1614,14 +1863,16 @@ function ensureReviewShellStyle() {
1614
1863
 
1615
1864
  .df-review-list-header {
1616
1865
  display: grid;
1617
- grid-template-rows: auto auto;
1866
+ grid-template-rows:
1867
+ var(--df-review-control-height-md)
1868
+ var(--df-review-control-height-md);
1618
1869
  gap: var(--df-review-space-2);
1619
1870
  padding: var(--df-review-space-3) var(--df-review-frame-gutter-x);
1620
1871
  border-bottom: 1px solid var(--df-review-line-soft);
1621
1872
  background: var(--df-review-card);
1622
1873
  color: var(--df-review-muted);
1623
1874
  font-size: var(--df-review-font-size-sm);
1624
- font-weight: 800;
1875
+ font-weight: 500;
1625
1876
  }
1626
1877
 
1627
1878
  .df-review-list-toolbar {
@@ -1629,143 +1880,76 @@ function ensureReviewShellStyle() {
1629
1880
  grid-template-columns: minmax(0, 1fr) auto;
1630
1881
  align-items: center;
1631
1882
  gap: 8px;
1883
+ min-height: var(--df-review-control-height-md);
1632
1884
  min-width: 0;
1633
1885
  }
1634
1886
 
1635
1887
  .df-review-list-title {
1636
- display: flex;
1888
+ display: grid;
1889
+ grid-template-columns: minmax(0, 1fr) auto;
1637
1890
  align-items: center;
1638
1891
  gap: 8px;
1892
+ min-height: var(--df-review-control-height-md);
1639
1893
  min-width: 0;
1640
1894
  }
1641
1895
 
1642
- .df-review-list-title span {
1896
+ .df-review-list-meta {
1897
+ display: flex;
1898
+ align-items: center;
1899
+ gap: 8px;
1900
+ min-width: 0;
1901
+ }
1902
+
1903
+ .df-review-list-meta span {
1643
1904
  min-width: 0;
1644
1905
  overflow: hidden;
1645
1906
  text-overflow: ellipsis;
1646
1907
  white-space: nowrap;
1647
1908
  }
1648
1909
 
1649
- .df-review-list-title strong {
1650
- flex: 0 0 auto;
1651
- color: var(--df-review-muted);
1652
- font-size: var(--df-review-font-size-xs);
1653
- font-variant-numeric: tabular-nums;
1654
- }
1910
+ .df-review-list-meta strong {
1911
+ flex: 0 0 auto;
1912
+ color: var(--df-review-muted);
1913
+ font-size: var(--df-review-font-size-xs);
1914
+ font-variant-numeric: tabular-nums;
1915
+ font-weight: 500;
1916
+ }
1655
1917
 
1656
- .df-review-presence-overlay {
1918
+ .df-review-list-controls {
1657
1919
  display: flex;
1658
1920
  align-items: center;
1659
- flex-wrap: wrap;
1660
- gap: 5px;
1661
- max-width: 100%;
1662
- pointer-events: none;
1663
- }
1664
-
1665
- .df-review-presence-row .df-review-presence-overlay {
1666
- width: 100%;
1667
- max-width: 1440px;
1668
- margin: 0 auto;
1921
+ gap: 4px;
1669
1922
  }
1670
1923
 
1671
- .df-review-presence-chip {
1672
- --df-review-presence-color: var(--df-review-accent);
1673
- display: inline-flex;
1674
- align-items: center;
1675
- min-width: 0;
1676
- max-width: min(220px, calc(100% - 20px));
1677
- min-height: 24px;
1678
- border: 1px solid rgba(15, 23, 42, 0.12);
1679
- border-radius: var(--df-review-radius-pill);
1680
- padding: 0 8px;
1681
- color: #17202c;
1682
- background: rgba(255, 255, 255, 0.92);
1683
- box-shadow: 0 8px 22px rgba(15, 23, 42, 0.14);
1684
- font-size: var(--df-review-font-size-2xs);
1685
- font-weight: 900;
1686
- line-height: 1.1;
1687
- overflow: hidden;
1688
- text-overflow: ellipsis;
1689
- white-space: nowrap;
1690
- backdrop-filter: blur(8px);
1924
+ .df-review-source-select,
1925
+ .df-review-status-filter-select {
1926
+ height: var(--df-review-control-height-md);
1927
+ min-height: var(--df-review-control-height-md);
1928
+ border: 1px solid var(--df-review-line-soft);
1929
+ border-radius: var(--df-review-radius-sm);
1930
+ padding: 0 24px 0 8px;
1931
+ color: var(--df-review-text);
1932
+ background: var(--df-review-control);
1933
+ box-shadow: var(--df-review-shadow-control);
1934
+ font-size: var(--df-review-font-size-xs);
1935
+ font-weight: 500;
1691
1936
  }
1692
1937
 
1693
- .df-review-presence-row .df-review-presence-chip {
1694
- max-width: none;
1938
+ .df-review-source-select {
1939
+ width: 104px;
1695
1940
  }
1696
1941
 
1697
- .df-review-presence-chip.is-self {
1698
- border-color: var(--df-review-presence-color);
1699
- box-shadow:
1700
- inset 0 0 0 1px var(--df-review-presence-color),
1701
- 0 8px 22px rgba(15, 23, 42, 0.14);
1702
- }
1703
-
1704
- .df-review-presence-more {
1705
- display: inline-flex;
1706
- align-items: center;
1707
- justify-content: center;
1708
- min-width: 28px;
1709
- min-height: 24px;
1710
- border: 1px solid rgba(15, 23, 42, 0.12);
1711
- border-radius: var(--df-review-radius-pill);
1712
- padding: 0 8px;
1713
- color: #17202c;
1714
- background: rgba(255, 255, 255, 0.92);
1715
- box-shadow: 0 8px 22px rgba(15, 23, 42, 0.14);
1716
- cursor: pointer;
1717
- font: inherit;
1718
- font-size: var(--df-review-font-size-2xs);
1719
- font-weight: 900;
1720
- line-height: 1;
1721
- pointer-events: auto;
1722
- backdrop-filter: blur(8px);
1723
- }
1724
-
1725
- .df-review-presence-more:hover {
1726
- border-color: rgba(0, 102, 255, 0.42);
1727
- color: #005be8;
1728
- background: rgba(255, 255, 255, 0.98);
1729
- }
1730
-
1731
- .df-review-list-controls {
1732
- display: flex;
1733
- align-items: center;
1734
- gap: 4px;
1735
- }
1736
-
1737
- .df-review-source-select,
1738
- .df-review-status-filter-select {
1739
- min-height: 30px;
1740
- border: 1px solid var(--df-review-line-soft);
1741
- border-radius: var(--df-review-radius-sm);
1742
- padding: 0 24px 0 8px;
1743
- color: var(--df-review-text);
1744
- background: var(--df-review-control);
1745
- box-shadow: var(--df-review-shadow-control);
1746
- font-size: var(--df-review-font-size-xs);
1747
- font-weight: 800;
1748
- }
1749
-
1750
- .df-review-source-select {
1751
- width: 104px;
1752
- }
1753
-
1754
- .df-review-status-filter-select {
1755
- width: 124px;
1756
- }
1757
-
1758
- .df-review-list-title .df-review-status-filter-select {
1759
- margin-left: auto;
1942
+ .df-review-status-filter-select {
1943
+ width: 124px;
1760
1944
  }
1761
1945
 
1762
1946
  .df-review-source-refresh {
1763
1947
  position: relative;
1764
1948
  display: inline-grid;
1765
1949
  place-items: center;
1766
- width: 30px;
1767
- min-width: 30px;
1768
- height: 30px;
1950
+ width: var(--df-review-control-height-md);
1951
+ min-width: var(--df-review-control-height-md);
1952
+ height: var(--df-review-control-height-md);
1769
1953
  border: 1px solid var(--df-review-line-soft);
1770
1954
  border-radius: var(--df-review-radius-sm);
1771
1955
  padding: 0;
@@ -1775,16 +1959,18 @@ function ensureReviewShellStyle() {
1775
1959
  }
1776
1960
 
1777
1961
  .df-review-source-refresh svg {
1778
- width: 14px;
1779
- height: 14px;
1962
+ width: 16px;
1963
+ height: 16px;
1780
1964
  }
1781
1965
 
1782
1966
  .df-review-filter-tabs {
1783
1967
  display: flex;
1784
1968
  align-items: center;
1785
- gap: 2px;
1786
- height: 30px;
1787
- padding: 2px;
1969
+ justify-self: end;
1970
+ gap: var(--df-review-space-1-5);
1971
+ height: var(--df-review-control-height-md);
1972
+ min-height: var(--df-review-control-height-md);
1973
+ padding: 0;
1788
1974
  border: 1px solid var(--df-review-line-soft);
1789
1975
  border-radius: var(--df-review-radius-md);
1790
1976
  background: var(--df-review-card);
@@ -1795,11 +1981,11 @@ function ensureReviewShellStyle() {
1795
1981
  position: relative;
1796
1982
  display: grid;
1797
1983
  place-items: center;
1798
- width: 26px;
1799
- min-width: 26px;
1800
- height: 26px;
1984
+ width: var(--df-review-control-height-md);
1985
+ min-width: var(--df-review-control-height-md);
1986
+ height: var(--df-review-control-height-md);
1801
1987
  border: 0;
1802
- border-radius: 5px;
1988
+ border-radius: var(--df-review-radius-sm);
1803
1989
  background: transparent;
1804
1990
  color: var(--df-review-subtle);
1805
1991
  }
@@ -1832,19 +2018,19 @@ function ensureReviewShellStyle() {
1832
2018
  }
1833
2019
 
1834
2020
  .df-review-filter-icon svg {
1835
- width: 15px;
1836
- height: 15px;
2021
+ width: 18px;
2022
+ height: 18px;
1837
2023
  fill: none;
1838
2024
  stroke: currentColor;
1839
2025
  stroke-linecap: round;
1840
2026
  stroke-linejoin: round;
1841
- stroke-width: 2;
2027
+ stroke-width: 1.9;
1842
2028
  }
1843
2029
 
1844
2030
  .df-review-filter-count {
1845
2031
  color: currentColor;
1846
2032
  font-size: var(--df-review-font-size-3xs);
1847
- font-weight: 900;
2033
+ font-weight: 600;
1848
2034
  font-variant-numeric: tabular-nums;
1849
2035
  line-height: 1;
1850
2036
  }
@@ -1925,6 +2111,7 @@ function ensureReviewShellStyle() {
1925
2111
  .df-review-item-main strong {
1926
2112
  overflow-wrap: anywhere;
1927
2113
  font-size: var(--df-review-font-size-md);
2114
+ font-weight: 500;
1928
2115
  line-height: 1.35;
1929
2116
  }
1930
2117
 
@@ -1972,7 +2159,7 @@ function ensureReviewShellStyle() {
1972
2159
  border-radius: var(--df-review-radius-pill);
1973
2160
  padding: 0 7px;
1974
2161
  font-size: var(--df-review-font-size-2xs);
1975
- font-weight: 900;
2162
+ font-weight: 600;
1976
2163
  line-height: 1;
1977
2164
  text-transform: uppercase;
1978
2165
  }
@@ -2039,7 +2226,7 @@ function ensureReviewShellStyle() {
2039
2226
  border-radius: var(--df-review-radius-sm);
2040
2227
  padding: 0 11px;
2041
2228
  font-size: var(--df-review-font-size-xs);
2042
- font-weight: 750;
2229
+ font-weight: 500;
2043
2230
  text-transform: none;
2044
2231
  }
2045
2232
 
@@ -2052,7 +2239,7 @@ function ensureReviewShellStyle() {
2052
2239
  cursor: pointer;
2053
2240
  outline: 0;
2054
2241
  font-size: var(--df-review-font-size-xs);
2055
- font-weight: 750;
2242
+ font-weight: 500;
2056
2243
  text-transform: none;
2057
2244
  }
2058
2245
 
@@ -2277,7 +2464,7 @@ function ensureReviewShellStyle() {
2277
2464
 
2278
2465
  .df-review-item-submit-button span {
2279
2466
  font-size: var(--df-review-font-size-xs);
2280
- font-weight: 750;
2467
+ font-weight: 500;
2281
2468
  line-height: 1;
2282
2469
  text-transform: none;
2283
2470
  white-space: nowrap;
@@ -2449,6 +2636,9 @@ function ensureReviewShellStyle() {
2449
2636
  --df-review-source-popover-text: #edf3fb;
2450
2637
  --df-review-source-popover-muted: rgba(237, 243, 251, 0.68);
2451
2638
  --df-review-source-popover-subtle: rgba(237, 243, 251, 0.5);
2639
+ --df-review-source-popover-data: #f3b75f;
2640
+ --df-review-source-popover-data-muted: rgba(243, 183, 95, 0.78);
2641
+ --df-review-source-popover-data-subtle: rgba(243, 183, 95, 0.62);
2452
2642
  --df-review-source-popover-hover: rgba(124, 199, 255, 0.14);
2453
2643
  position: fixed;
2454
2644
  z-index: 890;
@@ -2460,7 +2650,7 @@ function ensureReviewShellStyle() {
2460
2650
  overflow: hidden;
2461
2651
  border: 1px solid var(--df-review-source-popover-line);
2462
2652
  border-radius: var(--df-review-radius-md);
2463
- padding: 8px 6px 6px;
2653
+ padding: 6px;
2464
2654
  color: var(--df-review-source-popover-text);
2465
2655
  color-scheme: dark;
2466
2656
  background: rgba(19, 24, 33, 0.96);
@@ -2486,7 +2676,7 @@ function ensureReviewShellStyle() {
2486
2676
  color: var(--df-review-source-popover-subtle);
2487
2677
  background: transparent;
2488
2678
  font-size: 16px;
2489
- font-weight: 800;
2679
+ font-weight: 500;
2490
2680
  line-height: 1;
2491
2681
  }
2492
2682
 
@@ -2510,22 +2700,26 @@ function ensureReviewShellStyle() {
2510
2700
  .df-review-source-candidate {
2511
2701
  display: grid;
2512
2702
  width: 100%;
2513
- min-height: 54px;
2514
2703
  border: 0;
2704
+ border-top: 1px solid transparent;
2515
2705
  border-radius: var(--df-review-radius-sm);
2516
- padding: 6px 30px 6px 8px;
2706
+ padding: 9px 30px 9px 8px;
2517
2707
  color: var(--df-review-source-popover-text);
2518
2708
  background: transparent;
2519
2709
  text-align: left;
2520
2710
  }
2521
2711
 
2712
+ .df-review-source-candidate + .df-review-source-candidate {
2713
+ border-top-color: var(--df-review-source-popover-line);
2714
+ }
2715
+
2522
2716
  .df-review-source-candidate:hover {
2523
2717
  background: var(--df-review-source-popover-hover);
2524
2718
  }
2525
2719
 
2526
2720
  .df-review-source-candidate-main {
2527
2721
  display: grid;
2528
- gap: 2px;
2722
+ gap: 1px;
2529
2723
  min-width: 0;
2530
2724
  }
2531
2725
 
@@ -2538,7 +2732,8 @@ function ensureReviewShellStyle() {
2538
2732
 
2539
2733
  .df-review-source-candidate-main strong {
2540
2734
  font-size: var(--df-review-font-size-xs);
2541
- font-weight: 900;
2735
+ font-weight: 600;
2736
+ line-height: 1.2;
2542
2737
  }
2543
2738
 
2544
2739
  .df-review-source-candidate-main span {
@@ -2546,7 +2741,7 @@ function ensureReviewShellStyle() {
2546
2741
  color: var(--df-review-source-popover-muted);
2547
2742
  font-family: var(--df-review-font-mono);
2548
2743
  font-size: var(--df-review-font-size-2xs);
2549
- line-height: 1.25;
2744
+ line-height: 1.24;
2550
2745
  white-space: normal;
2551
2746
  }
2552
2747
 
@@ -2554,6 +2749,335 @@ function ensureReviewShellStyle() {
2554
2749
  color: var(--df-review-source-popover-subtle);
2555
2750
  font-family: var(--df-review-font-mono);
2556
2751
  font-size: var(--df-review-font-size-2xs);
2752
+ line-height: 1.2;
2753
+ }
2754
+
2755
+ .df-review-source-candidate.is-data .df-review-source-candidate-main strong {
2756
+ color: var(--df-review-source-popover-data);
2757
+ }
2758
+
2759
+ .df-review-source-candidate.is-data .df-review-source-candidate-main span {
2760
+ color: var(--df-review-source-popover-data-muted);
2761
+ }
2762
+
2763
+ .df-review-source-candidate.is-data .df-review-source-candidate-main small {
2764
+ color: var(--df-review-source-popover-data-subtle);
2765
+ }
2766
+
2767
+ .df-review-section-outline {
2768
+ position: relative;
2769
+ z-index: 1;
2770
+ display: grid;
2771
+ grid-template-rows: auto minmax(0, 1fr);
2772
+ width: 100%;
2773
+ height: 100%;
2774
+ min-width: 0;
2775
+ min-height: 0;
2776
+ border: 0;
2777
+ border-radius: 0;
2778
+ color: var(--df-review-text);
2779
+ background: transparent;
2780
+ box-shadow: none;
2781
+ overflow: hidden;
2782
+ }
2783
+
2784
+ .df-review-section-outline-head {
2785
+ display: grid;
2786
+ grid-template-rows:
2787
+ var(--df-review-control-height-md)
2788
+ var(--df-review-control-height-md);
2789
+ align-items: center;
2790
+ gap: 8px;
2791
+ min-width: 0;
2792
+ padding: var(--df-review-space-3) var(--df-review-frame-gutter-x);
2793
+ border-bottom: 1px solid var(--df-review-line-soft);
2794
+ background: var(--df-review-card);
2795
+ color: var(--df-review-muted);
2796
+ }
2797
+
2798
+ .df-review-section-outline-head span {
2799
+ display: grid;
2800
+ gap: 2px;
2801
+ min-width: 0;
2802
+ }
2803
+
2804
+ .df-review-section-outline-head strong {
2805
+ overflow: hidden;
2806
+ color: var(--df-review-text);
2807
+ font-size: var(--df-review-font-size-lg);
2808
+ font-weight: 600;
2809
+ text-overflow: ellipsis;
2810
+ white-space: nowrap;
2811
+ }
2812
+
2813
+ .df-review-section-outline-head small {
2814
+ overflow: hidden;
2815
+ color: var(--df-review-muted);
2816
+ font-size: var(--df-review-font-size-xs);
2817
+ font-weight: 500;
2818
+ text-overflow: ellipsis;
2819
+ white-space: nowrap;
2820
+ }
2821
+
2822
+ .df-review-section-outline-filter {
2823
+ display: grid;
2824
+ grid-template-columns: 18px minmax(0, 1fr) auto;
2825
+ align-items: center;
2826
+ align-self: stretch;
2827
+ gap: 8px;
2828
+ min-width: 0;
2829
+ height: var(--df-review-control-height-md);
2830
+ min-height: var(--df-review-control-height-md);
2831
+ border: 1px solid var(--df-review-line-soft);
2832
+ border-radius: var(--df-review-radius-md);
2833
+ padding: 0 7px 0 11px;
2834
+ color: var(--df-review-muted);
2835
+ background: var(--df-review-control);
2836
+ box-shadow: var(--df-review-shadow-control);
2837
+ }
2838
+
2839
+ .df-review-section-outline-filter:focus-within {
2840
+ border-color: var(--df-review-accent);
2841
+ box-shadow: inset 0 0 0 1px var(--df-review-accent-hover);
2842
+ }
2843
+
2844
+ .df-review-section-outline-filter svg {
2845
+ width: 18px;
2846
+ height: 18px;
2847
+ fill: none;
2848
+ stroke: currentColor;
2849
+ stroke-linecap: round;
2850
+ stroke-linejoin: round;
2851
+ stroke-width: 1.9;
2852
+ }
2853
+
2854
+ .df-review-section-outline-filter input {
2855
+ width: 100%;
2856
+ min-width: 0;
2857
+ height: 100%;
2858
+ border: 0;
2859
+ padding: 0;
2860
+ color: var(--df-review-text);
2861
+ background: transparent;
2862
+ font-size: var(--df-review-font-size-xs);
2863
+ font-weight: 500;
2864
+ outline: 0;
2865
+ -webkit-appearance: none;
2866
+ appearance: none;
2867
+ }
2868
+
2869
+ .df-review-section-outline-filter input::placeholder {
2870
+ color: var(--df-review-subtle);
2871
+ }
2872
+
2873
+ .df-review-section-outline-filter input::-webkit-search-cancel-button,
2874
+ .df-review-section-outline-filter input::-webkit-search-decoration {
2875
+ display: none;
2876
+ -webkit-appearance: none;
2877
+ appearance: none;
2878
+ }
2879
+
2880
+ .df-review-section-outline-filter-clear {
2881
+ display: inline-grid;
2882
+ place-items: center;
2883
+ width: var(--df-review-control-height-md);
2884
+ height: var(--df-review-control-height-md);
2885
+ border: 0;
2886
+ border-radius: var(--df-review-radius-sm);
2887
+ padding: 0;
2888
+ color: var(--df-review-muted);
2889
+ background: transparent;
2890
+ cursor: pointer;
2891
+ }
2892
+
2893
+ .df-review-section-outline-filter-clear:hover,
2894
+ .df-review-section-outline-filter-clear:focus-visible {
2895
+ color: var(--df-review-text);
2896
+ background: var(--df-review-accent-soft);
2897
+ outline: 0;
2898
+ }
2899
+
2900
+ .df-review-section-outline-list {
2901
+ display: grid;
2902
+ align-content: start;
2903
+ gap: 2px;
2904
+ min-height: 0;
2905
+ overflow-y: auto;
2906
+ padding: 8px 1px 8px 15px;
2907
+ scrollbar-gutter: stable;
2908
+ }
2909
+
2910
+ .df-review-section-outline-item {
2911
+ display: grid;
2912
+ }
2913
+
2914
+ .df-review-section-outline-item.is-depth-1:not(:last-child) {
2915
+ margin-bottom: 7px;
2916
+ padding-bottom: 7px;
2917
+ border-bottom: 1px solid var(--df-review-line-soft);
2918
+ }
2919
+
2920
+ .df-review-section-outline-row {
2921
+ display: grid;
2922
+ grid-template-columns: 18px minmax(0, 1fr) auto;
2923
+ align-items: center;
2924
+ gap: 5px;
2925
+ border-radius: var(--df-review-radius-sm);
2926
+ padding: 7px 6px;
2927
+ }
2928
+
2929
+ .df-review-section-outline-row:hover {
2930
+ background: var(--df-review-accent-soft);
2931
+ }
2932
+
2933
+ .df-review-section-outline-toggle {
2934
+ display: grid;
2935
+ place-items: center;
2936
+ width: 18px;
2937
+ height: 18px;
2938
+ border: 0;
2939
+ border-radius: var(--df-review-radius-sm);
2940
+ padding: 0;
2941
+ color: var(--df-review-muted);
2942
+ background: transparent;
2943
+ }
2944
+
2945
+ .df-review-section-outline-toggle:hover {
2946
+ color: var(--df-review-text);
2947
+ background: var(--df-review-accent-soft);
2948
+ }
2949
+
2950
+ .df-review-section-outline-toggle svg {
2951
+ width: 13px;
2952
+ height: 13px;
2953
+ fill: none;
2954
+ stroke: currentColor;
2955
+ stroke-linecap: round;
2956
+ stroke-linejoin: round;
2957
+ stroke-width: 2.4;
2958
+ transition: transform 120ms ease;
2959
+ }
2960
+
2961
+ .df-review-section-outline-toggle.is-collapsed svg {
2962
+ transform: rotate(-90deg);
2963
+ }
2964
+
2965
+ .df-review-section-outline-toggle.is-placeholder {
2966
+ pointer-events: none;
2967
+ }
2968
+
2969
+ .df-review-section-outline-name {
2970
+ display: grid;
2971
+ gap: 2px;
2972
+ min-width: 0;
2973
+ overflow: visible;
2974
+ border: 0;
2975
+ padding: 0;
2976
+ color: var(--df-review-text);
2977
+ background: transparent;
2978
+ font-size: var(--df-review-font-size-sm);
2979
+ font-weight: 500;
2980
+ text-align: left;
2981
+ white-space: normal;
2982
+ cursor: pointer;
2983
+ }
2984
+
2985
+ .df-review-section-outline-name span,
2986
+ .df-review-section-outline-name small {
2987
+ overflow: visible;
2988
+ overflow-wrap: anywhere;
2989
+ text-overflow: clip;
2990
+ white-space: normal;
2991
+ }
2992
+
2993
+ .df-review-section-outline-name small {
2994
+ color: var(--df-review-muted);
2995
+ font-family: var(--df-review-font-mono);
2996
+ font-size: var(--df-review-font-size-xs);
2997
+ font-weight: 500;
2998
+ }
2999
+
3000
+ .df-review-section-outline-name:hover {
3001
+ color: var(--df-review-accent);
3002
+ }
3003
+
3004
+ .df-review-section-outline-links {
3005
+ display: inline-flex;
3006
+ align-items: center;
3007
+ justify-content: flex-end;
3008
+ gap: 2px;
3009
+ }
3010
+
3011
+ .df-review-section-outline-divider {
3012
+ color: var(--df-review-subtle);
3013
+ font-size: var(--df-review-font-size-xs);
3014
+ line-height: 1;
3015
+ user-select: none;
3016
+ }
3017
+
3018
+ .df-review-section-outline-link {
3019
+ display: inline-grid;
3020
+ place-items: center;
3021
+ width: 26px;
3022
+ height: 26px;
3023
+ border: 1px solid transparent;
3024
+ border-radius: var(--df-review-radius-sm);
3025
+ padding: 0;
3026
+ color: var(--df-review-muted);
3027
+ background: transparent;
3028
+ cursor: pointer;
3029
+ transition: border-color 140ms ease, background 140ms ease,
3030
+ color 140ms ease, opacity 140ms ease;
3031
+ }
3032
+
3033
+ .df-review-section-outline-link.is-dom-select {
3034
+ width: 26px;
3035
+ min-width: 26px;
3036
+ padding: 0;
3037
+ }
3038
+
3039
+ .df-review-section-outline-link.is-dom-select svg {
3040
+ width: 16px;
3041
+ height: 16px;
3042
+ }
3043
+
3044
+ .df-review-section-outline-link:hover {
3045
+ border-color: rgba(124, 199, 255, 0.34);
3046
+ color: var(--df-review-accent);
3047
+ background: var(--df-review-accent-soft);
3048
+ }
3049
+
3050
+ .df-review-section-outline-link svg {
3051
+ width: 14px;
3052
+ height: 14px;
3053
+ fill: none;
3054
+ stroke: currentColor;
3055
+ stroke-linecap: round;
3056
+ stroke-linejoin: round;
3057
+ stroke-width: 2;
3058
+ }
3059
+
3060
+ .df-review-section-outline-link:disabled {
3061
+ color: var(--df-review-subtle);
3062
+ cursor: not-allowed;
3063
+ opacity: 0.42;
3064
+ }
3065
+
3066
+ .df-review-section-outline-link:disabled:hover {
3067
+ border-color: transparent;
3068
+ color: var(--df-review-subtle);
3069
+ background: transparent;
3070
+ }
3071
+
3072
+ .df-review-section-outline-children {
3073
+ display: grid;
3074
+ }
3075
+
3076
+ .df-review-section-outline-empty {
3077
+ padding: 14px 12px 16px;
3078
+ color: var(--df-review-muted);
3079
+ font-size: var(--df-review-font-size-xs);
3080
+ font-weight: 500;
2557
3081
  }
2558
3082
 
2559
3083
  .df-review-device-frame {
@@ -2650,13 +3174,13 @@ function ensureReviewShellStyle() {
2650
3174
  .df-review-ruler-frame-label strong {
2651
3175
  color: var(--df-review-color-ruler-label-text);
2652
3176
  font-size: var(--df-review-font-size-xs);
2653
- font-weight: 900;
3177
+ font-weight: 600;
2654
3178
  }
2655
3179
 
2656
3180
  .df-review-ruler-frame-label span {
2657
3181
  color: var(--df-review-color-ruler-label-text);
2658
3182
  font-size: var(--df-review-font-size-xs);
2659
- font-weight: 900;
3183
+ font-weight: 600;
2660
3184
  opacity: 0.78;
2661
3185
  }
2662
3186
 
@@ -2669,7 +3193,7 @@ function ensureReviewShellStyle() {
2669
3193
  background: var(--df-review-color-ruler-coord-bg);
2670
3194
  color: var(--df-review-color-ruler-coord-text);
2671
3195
  font-size: var(--df-review-font-size-xs);
2672
- font-weight: 900;
3196
+ font-weight: 600;
2673
3197
  line-height: 1;
2674
3198
  white-space: nowrap;
2675
3199
  pointer-events: none;
@@ -2747,7 +3271,7 @@ function ensureReviewShellStyle() {
2747
3271
  color: var(--df-review-color-ruler-popover-text);
2748
3272
  font-family: var(--df-review-font-mono);
2749
3273
  font-size: var(--df-review-font-size-lg);
2750
- font-weight: 900;
3274
+ font-weight: 600;
2751
3275
  line-height: 1;
2752
3276
  white-space: nowrap;
2753
3277
  letter-spacing: -0.02em;
@@ -2760,12 +3284,12 @@ function ensureReviewShellStyle() {
2760
3284
  @media (max-width: 860px) {
2761
3285
  .df-review-shell,
2762
3286
  .df-review-shell.is-list-visible {
2763
- grid-template-columns: minmax(0, 1fr) 0 32px;
3287
+ grid-template-columns: minmax(0, 1fr) 0 48px;
2764
3288
  grid-template-rows: auto auto minmax(0, 1fr);
2765
3289
  }
2766
3290
 
2767
3291
  .df-review-shell.is-list-visible {
2768
- grid-template-columns: minmax(0, 1fr) minmax(260px, 70vw) 32px;
3292
+ grid-template-columns: minmax(0, 1fr) minmax(260px, 70vw) 48px;
2769
3293
  }
2770
3294
 
2771
3295
  .df-review-qa-panel {
@@ -2774,7 +3298,7 @@ function ensureReviewShellStyle() {
2774
3298
  }
2775
3299
 
2776
3300
  .df-review-tools {
2777
- flex-wrap: wrap;
3301
+ flex-wrap: nowrap;
2778
3302
  }
2779
3303
 
2780
3304
  .df-review-tool-controls {
@@ -2804,11 +3328,19 @@ function ensureReviewShellStyle() {
2804
3328
  max-height: calc(100vh - 270px);
2805
3329
  }
2806
3330
 
2807
- .df-review-panel-body {
2808
- min-height: 0;
2809
- }
2810
- }
2811
- `;
3331
+ .df-review-panel-body {
3332
+ min-height: 0;
3333
+ }
3334
+ }
3335
+
3336
+ @media (hover: none) and (pointer: coarse) {
3337
+ .df-review-edit-textarea textarea,
3338
+ .df-review-preset-select,
3339
+ .df-review-prompt-block textarea {
3340
+ font-size: 16px;
3341
+ }
3342
+ }
3343
+ `;
2812
3344
  document.head.append(style);
2813
3345
  }
2814
3346
  }
@@ -2931,31 +3463,59 @@ var __iconNode = [
2931
3463
  ];
2932
3464
  var Bot = createLucideIcon("bot", __iconNode);
2933
3465
 
3466
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/chevron-down.mjs
3467
+ var __iconNode2 = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
3468
+ var ChevronDown = createLucideIcon("chevron-down", __iconNode2);
3469
+
2934
3470
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/circle-question-mark.mjs
2935
- var __iconNode2 = [
3471
+ var __iconNode3 = [
2936
3472
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
2937
3473
  ["path", { d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3", key: "1u773s" }],
2938
3474
  ["path", { d: "M12 17h.01", key: "p32p05" }]
2939
3475
  ];
2940
- var CircleQuestionMark = createLucideIcon("circle-question-mark", __iconNode2);
3476
+ var CircleQuestionMark = createLucideIcon("circle-question-mark", __iconNode3);
3477
+
3478
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/code-xml.mjs
3479
+ var __iconNode4 = [
3480
+ ["path", { d: "m18 16 4-4-4-4", key: "1inbqp" }],
3481
+ ["path", { d: "m6 8-4 4 4 4", key: "15zrgr" }],
3482
+ ["path", { d: "m14.5 4-5 16", key: "e7oirm" }]
3483
+ ];
3484
+ var CodeXml = createLucideIcon("code-xml", __iconNode4);
2941
3485
 
2942
3486
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/copy.mjs
2943
- var __iconNode3 = [
3487
+ var __iconNode5 = [
2944
3488
  ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
2945
3489
  ["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" }]
2946
3490
  ];
2947
- var Copy = createLucideIcon("copy", __iconNode3);
3491
+ var Copy = createLucideIcon("copy", __iconNode5);
3492
+
3493
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/database.mjs
3494
+ var __iconNode6 = [
3495
+ ["ellipse", { cx: "12", cy: "5", rx: "9", ry: "3", key: "msslwz" }],
3496
+ ["path", { d: "M3 5V19A9 3 0 0 0 21 19V5", key: "1wlel7" }],
3497
+ ["path", { d: "M3 12A9 3 0 0 0 21 12", key: "mv7ke4" }]
3498
+ ];
3499
+ var Database = createLucideIcon("database", __iconNode6);
3500
+
3501
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/ellipsis.mjs
3502
+ var __iconNode7 = [
3503
+ ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
3504
+ ["circle", { cx: "19", cy: "12", r: "1", key: "1wjl8i" }],
3505
+ ["circle", { cx: "5", cy: "12", r: "1", key: "1pcz8c" }]
3506
+ ];
3507
+ var Ellipsis = createLucideIcon("ellipsis", __iconNode7);
2948
3508
 
2949
3509
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/external-link.mjs
2950
- var __iconNode4 = [
3510
+ var __iconNode8 = [
2951
3511
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
2952
3512
  ["path", { d: "M10 14 21 3", key: "gplh6r" }],
2953
3513
  ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
2954
3514
  ];
2955
- var ExternalLink = createLucideIcon("external-link", __iconNode4);
3515
+ var ExternalLink = createLucideIcon("external-link", __iconNode8);
2956
3516
 
2957
3517
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/eye-off.mjs
2958
- var __iconNode5 = [
3518
+ var __iconNode9 = [
2959
3519
  [
2960
3520
  "path",
2961
3521
  {
@@ -2973,10 +3533,10 @@ var __iconNode5 = [
2973
3533
  ],
2974
3534
  ["path", { d: "m2 2 20 20", key: "1ooewy" }]
2975
3535
  ];
2976
- var EyeOff = createLucideIcon("eye-off", __iconNode5);
3536
+ var EyeOff = createLucideIcon("eye-off", __iconNode9);
2977
3537
 
2978
3538
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/eye.mjs
2979
- var __iconNode6 = [
3539
+ var __iconNode10 = [
2980
3540
  [
2981
3541
  "path",
2982
3542
  {
@@ -2986,54 +3546,59 @@ var __iconNode6 = [
2986
3546
  ],
2987
3547
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
2988
3548
  ];
2989
- var Eye = createLucideIcon("eye", __iconNode6);
3549
+ var Eye = createLucideIcon("eye", __iconNode10);
2990
3550
 
2991
- // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/grip-vertical.mjs
2992
- var __iconNode7 = [
2993
- ["circle", { cx: "9", cy: "12", r: "1", key: "1vctgf" }],
2994
- ["circle", { cx: "9", cy: "5", r: "1", key: "hp0tcf" }],
2995
- ["circle", { cx: "9", cy: "19", r: "1", key: "fkjjf6" }],
2996
- ["circle", { cx: "15", cy: "12", r: "1", key: "1tmaij" }],
2997
- ["circle", { cx: "15", cy: "5", r: "1", key: "19l28e" }],
2998
- ["circle", { cx: "15", cy: "19", r: "1", key: "f4zoj3" }]
3551
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/file-text.mjs
3552
+ var __iconNode11 = [
3553
+ [
3554
+ "path",
3555
+ {
3556
+ 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",
3557
+ key: "1oefj6"
3558
+ }
3559
+ ],
3560
+ ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }],
3561
+ ["path", { d: "M10 9H8", key: "b1mrlr" }],
3562
+ ["path", { d: "M16 13H8", key: "t4e002" }],
3563
+ ["path", { d: "M16 17H8", key: "z1uh3a" }]
2999
3564
  ];
3000
- var GripVertical = createLucideIcon("grip-vertical", __iconNode7);
3565
+ var FileText = createLucideIcon("file-text", __iconNode11);
3001
3566
 
3002
3567
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/image.mjs
3003
- var __iconNode8 = [
3568
+ var __iconNode12 = [
3004
3569
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
3005
3570
  ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
3006
3571
  ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
3007
3572
  ];
3008
- var Image = createLucideIcon("image", __iconNode8);
3573
+ var Image = createLucideIcon("image", __iconNode12);
3009
3574
 
3010
3575
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/layout-grid.mjs
3011
- var __iconNode9 = [
3576
+ var __iconNode13 = [
3012
3577
  ["rect", { width: "7", height: "7", x: "3", y: "3", rx: "1", key: "1g98yp" }],
3013
3578
  ["rect", { width: "7", height: "7", x: "14", y: "3", rx: "1", key: "6d4xhi" }],
3014
3579
  ["rect", { width: "7", height: "7", x: "14", y: "14", rx: "1", key: "nxv5o0" }],
3015
3580
  ["rect", { width: "7", height: "7", x: "3", y: "14", rx: "1", key: "1bb6yr" }]
3016
3581
  ];
3017
- var LayoutGrid = createLucideIcon("layout-grid", __iconNode9);
3582
+ var LayoutGrid = createLucideIcon("layout-grid", __iconNode13);
3018
3583
 
3019
3584
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/link-2.mjs
3020
- var __iconNode10 = [
3585
+ var __iconNode14 = [
3021
3586
  ["path", { d: "M9 17H7A5 5 0 0 1 7 7h2", key: "8i5ue5" }],
3022
3587
  ["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2", key: "1b9ql8" }],
3023
3588
  ["line", { x1: "8", x2: "16", y1: "12", y2: "12", key: "1jonct" }]
3024
3589
  ];
3025
- var Link2 = createLucideIcon("link-2", __iconNode10);
3590
+ var Link2 = createLucideIcon("link-2", __iconNode14);
3026
3591
 
3027
3592
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/list-filter.mjs
3028
- var __iconNode11 = [
3593
+ var __iconNode15 = [
3029
3594
  ["path", { d: "M2 5h20", key: "1fs1ex" }],
3030
3595
  ["path", { d: "M6 12h12", key: "8npq4p" }],
3031
3596
  ["path", { d: "M9 19h6", key: "456am0" }]
3032
3597
  ];
3033
- var ListFilter = createLucideIcon("list-filter", __iconNode11);
3598
+ var ListFilter = createLucideIcon("list-filter", __iconNode15);
3034
3599
 
3035
3600
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/map.mjs
3036
- var __iconNode12 = [
3601
+ var __iconNode16 = [
3037
3602
  [
3038
3603
  "path",
3039
3604
  {
@@ -3044,27 +3609,39 @@ var __iconNode12 = [
3044
3609
  ["path", { d: "M15 5.764v15", key: "1pn4in" }],
3045
3610
  ["path", { d: "M9 3.236v15", key: "1uimfh" }]
3046
3611
  ];
3047
- var Map2 = createLucideIcon("map", __iconNode12);
3612
+ var Map2 = createLucideIcon("map", __iconNode16);
3048
3613
 
3049
3614
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/maximize-2.mjs
3050
- var __iconNode13 = [
3615
+ var __iconNode17 = [
3051
3616
  ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
3052
3617
  ["path", { d: "m21 3-7 7", key: "1l2asr" }],
3053
3618
  ["path", { d: "m3 21 7-7", key: "tjx5ai" }],
3054
3619
  ["path", { d: "M9 21H3v-6", key: "wtvkvv" }]
3055
3620
  ];
3056
- var Maximize2 = createLucideIcon("maximize-2", __iconNode13);
3621
+ var Maximize2 = createLucideIcon("maximize-2", __iconNode17);
3057
3622
 
3058
3623
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/monitor.mjs
3059
- var __iconNode14 = [
3624
+ var __iconNode18 = [
3060
3625
  ["rect", { width: "20", height: "14", x: "2", y: "3", rx: "2", key: "48i651" }],
3061
3626
  ["line", { x1: "8", x2: "16", y1: "21", y2: "21", key: "1svkeh" }],
3062
3627
  ["line", { x1: "12", x2: "12", y1: "17", y2: "21", key: "vw1qmm" }]
3063
3628
  ];
3064
- var Monitor = createLucideIcon("monitor", __iconNode14);
3629
+ var Monitor = createLucideIcon("monitor", __iconNode18);
3630
+
3631
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/moon.mjs
3632
+ var __iconNode19 = [
3633
+ [
3634
+ "path",
3635
+ {
3636
+ 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",
3637
+ key: "kfwtm"
3638
+ }
3639
+ ]
3640
+ ];
3641
+ var Moon = createLucideIcon("moon", __iconNode19);
3065
3642
 
3066
3643
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/pencil.mjs
3067
- var __iconNode15 = [
3644
+ var __iconNode20 = [
3068
3645
  [
3069
3646
  "path",
3070
3647
  {
@@ -3074,25 +3651,25 @@ var __iconNode15 = [
3074
3651
  ],
3075
3652
  ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
3076
3653
  ];
3077
- var Pencil = createLucideIcon("pencil", __iconNode15);
3654
+ var Pencil = createLucideIcon("pencil", __iconNode20);
3078
3655
 
3079
3656
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/rectangle-horizontal.mjs
3080
- var __iconNode16 = [
3657
+ var __iconNode21 = [
3081
3658
  ["rect", { width: "20", height: "12", x: "2", y: "6", rx: "2", key: "9lu3g6" }]
3082
3659
  ];
3083
- var RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode16);
3660
+ var RectangleHorizontal = createLucideIcon("rectangle-horizontal", __iconNode21);
3084
3661
 
3085
3662
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/refresh-cw.mjs
3086
- var __iconNode17 = [
3663
+ var __iconNode22 = [
3087
3664
  ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
3088
3665
  ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
3089
3666
  ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
3090
3667
  ["path", { d: "M8 16H3v5", key: "1cv678" }]
3091
3668
  ];
3092
- var RefreshCw = createLucideIcon("refresh-cw", __iconNode17);
3669
+ var RefreshCw = createLucideIcon("refresh-cw", __iconNode22);
3093
3670
 
3094
3671
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/ruler.mjs
3095
- var __iconNode18 = [
3672
+ var __iconNode23 = [
3096
3673
  [
3097
3674
  "path",
3098
3675
  {
@@ -3105,19 +3682,26 @@ var __iconNode18 = [
3105
3682
  ["path", { d: "m8.5 6.5 2-2", key: "vc6u1g" }],
3106
3683
  ["path", { d: "m17.5 15.5 2-2", key: "wo5hmg" }]
3107
3684
  ];
3108
- var Ruler = createLucideIcon("ruler", __iconNode18);
3685
+ var Ruler = createLucideIcon("ruler", __iconNode23);
3109
3686
 
3110
3687
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/scan.mjs
3111
- var __iconNode19 = [
3688
+ var __iconNode24 = [
3112
3689
  ["path", { d: "M3 7V5a2 2 0 0 1 2-2h2", key: "aa7l1z" }],
3113
3690
  ["path", { d: "M17 3h2a2 2 0 0 1 2 2v2", key: "4qcy5o" }],
3114
3691
  ["path", { d: "M21 17v2a2 2 0 0 1-2 2h-2", key: "6vwrx8" }],
3115
3692
  ["path", { d: "M7 21H5a2 2 0 0 1-2-2v-2", key: "ioqczr" }]
3116
3693
  ];
3117
- var Scan = createLucideIcon("scan", __iconNode19);
3694
+ var Scan = createLucideIcon("scan", __iconNode24);
3695
+
3696
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/search.mjs
3697
+ var __iconNode25 = [
3698
+ ["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
3699
+ ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
3700
+ ];
3701
+ var Search = createLucideIcon("search", __iconNode25);
3118
3702
 
3119
3703
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/settings.mjs
3120
- var __iconNode20 = [
3704
+ var __iconNode26 = [
3121
3705
  [
3122
3706
  "path",
3123
3707
  {
@@ -3127,17 +3711,17 @@ var __iconNode20 = [
3127
3711
  ],
3128
3712
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
3129
3713
  ];
3130
- var Settings = createLucideIcon("settings", __iconNode20);
3714
+ var Settings = createLucideIcon("settings", __iconNode26);
3131
3715
 
3132
3716
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/smartphone.mjs
3133
- var __iconNode21 = [
3717
+ var __iconNode27 = [
3134
3718
  ["rect", { width: "14", height: "20", x: "5", y: "2", rx: "2", ry: "2", key: "1yt0o3" }],
3135
3719
  ["path", { d: "M12 18h.01", key: "mhygvu" }]
3136
3720
  ];
3137
- var Smartphone = createLucideIcon("smartphone", __iconNode21);
3721
+ var Smartphone = createLucideIcon("smartphone", __iconNode27);
3138
3722
 
3139
3723
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/square-mouse-pointer.mjs
3140
- var __iconNode22 = [
3724
+ var __iconNode28 = [
3141
3725
  [
3142
3726
  "path",
3143
3727
  {
@@ -3147,35 +3731,249 @@ var __iconNode22 = [
3147
3731
  ],
3148
3732
  ["path", { d: "M21 11V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h6", key: "14rsvq" }]
3149
3733
  ];
3150
- var SquareMousePointer = createLucideIcon("square-mouse-pointer", __iconNode22);
3734
+ var SquareMousePointer = createLucideIcon("square-mouse-pointer", __iconNode28);
3151
3735
 
3152
3736
  // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/sticky-note.mjs
3153
- var __iconNode23 = [
3737
+ var __iconNode29 = [
3154
3738
  [
3155
3739
  "path",
3156
3740
  {
3157
- d: "M21 9a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 15 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2z",
3158
- key: "1dfntj"
3159
- }
3160
- ],
3161
- ["path", { d: "M15 3v5a1 1 0 0 0 1 1h5", key: "6s6qgf" }]
3162
- ];
3163
- var StickyNote = createLucideIcon("sticky-note", __iconNode23);
3164
-
3165
- // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/upload.mjs
3166
- var __iconNode24 = [
3167
- ["path", { d: "M12 3v12", key: "1x0j5s" }],
3168
- ["path", { d: "m17 8-5-5-5 5", key: "7q97r8" }],
3169
- ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }]
3170
- ];
3171
- var Upload = createLucideIcon("upload", __iconNode24);
3741
+ d: "M21 9a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 15 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2z",
3742
+ key: "1dfntj"
3743
+ }
3744
+ ],
3745
+ ["path", { d: "M15 3v5a1 1 0 0 0 1 1h5", key: "6s6qgf" }]
3746
+ ];
3747
+ var StickyNote = createLucideIcon("sticky-note", __iconNode29);
3748
+
3749
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/sun.mjs
3750
+ var __iconNode30 = [
3751
+ ["circle", { cx: "12", cy: "12", r: "4", key: "4exip2" }],
3752
+ ["path", { d: "M12 2v2", key: "tus03m" }],
3753
+ ["path", { d: "M12 20v2", key: "1lh1kg" }],
3754
+ ["path", { d: "m4.93 4.93 1.41 1.41", key: "149t6j" }],
3755
+ ["path", { d: "m17.66 17.66 1.41 1.41", key: "ptbguv" }],
3756
+ ["path", { d: "M2 12h2", key: "1t8f8n" }],
3757
+ ["path", { d: "M20 12h2", key: "1q8mjw" }],
3758
+ ["path", { d: "m6.34 17.66-1.41 1.41", key: "1m8zz5" }],
3759
+ ["path", { d: "m19.07 4.93-1.41 1.41", key: "1shlcs" }]
3760
+ ];
3761
+ var Sun = createLucideIcon("sun", __iconNode30);
3762
+
3763
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/upload.mjs
3764
+ var __iconNode31 = [
3765
+ ["path", { d: "M12 3v12", key: "1x0j5s" }],
3766
+ ["path", { d: "m17 8-5-5-5 5", key: "7q97r8" }],
3767
+ ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }]
3768
+ ];
3769
+ var Upload = createLucideIcon("upload", __iconNode31);
3770
+
3771
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/user-round.mjs
3772
+ var __iconNode32 = [
3773
+ ["circle", { cx: "12", cy: "8", r: "5", key: "1hypcn" }],
3774
+ ["path", { d: "M20 21a8 8 0 0 0-16 0", key: "rfgkzh" }]
3775
+ ];
3776
+ var UserRound = createLucideIcon("user-round", __iconNode32);
3777
+
3778
+ // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/x.mjs
3779
+ var __iconNode33 = [
3780
+ ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
3781
+ ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
3782
+ ];
3783
+ var X = createLucideIcon("x", __iconNode33);
3784
+
3785
+ // src/core/geometry.ts
3786
+ function rectanglesIntersect(a, b) {
3787
+ return a.left < b.left + b.width && a.left + a.width > b.left && a.top < b.top + b.height && a.top + a.height > b.top;
3788
+ }
3789
+ function getPointSelection(point) {
3790
+ return {
3791
+ left: point.x,
3792
+ top: point.y,
3793
+ width: 1,
3794
+ height: 1
3795
+ };
3796
+ }
3797
+ function toViewportSelection(selection) {
3798
+ return {
3799
+ left: selection.x,
3800
+ top: selection.y,
3801
+ width: selection.width,
3802
+ height: selection.height
3803
+ };
3804
+ }
3805
+ function toPublicSelection(selection) {
3806
+ return {
3807
+ x: Math.round(selection.left),
3808
+ y: Math.round(selection.top),
3809
+ width: Math.round(selection.width),
3810
+ height: Math.round(selection.height)
3811
+ };
3812
+ }
3813
+ function getSelectionCenter(selection) {
3814
+ if ("left" in selection) {
3815
+ return {
3816
+ x: selection.left + selection.width / 2,
3817
+ y: selection.top + selection.height / 2
3818
+ };
3819
+ }
3820
+ return {
3821
+ x: selection.x + selection.width / 2,
3822
+ y: selection.y + selection.height / 2
3823
+ };
3824
+ }
3825
+ function isRelativeSelection(value) {
3826
+ if (!value || typeof value !== "object") return false;
3827
+ const selection = value;
3828
+ return typeof selection.x === "number" && typeof selection.y === "number" && typeof selection.width === "number" && typeof selection.height === "number";
3829
+ }
3830
+ function getViewportSize(environment) {
3831
+ const targetWindow = environment?.window ?? window;
3832
+ return {
3833
+ width: targetWindow.innerWidth,
3834
+ height: targetWindow.innerHeight
3835
+ };
3836
+ }
3837
+ function isPointInViewport(point, environment) {
3838
+ const viewport = getViewportSize(environment);
3839
+ return point.x >= 0 && point.y >= 0 && point.x <= viewport.width && point.y <= viewport.height;
3840
+ }
3841
+ function isSelectionInViewport(selection, environment) {
3842
+ const viewport = getViewportSize(environment);
3843
+ return rectanglesIntersect(selection, {
3844
+ left: 0,
3845
+ top: 0,
3846
+ width: viewport.width,
3847
+ height: viewport.height
3848
+ });
3849
+ }
3850
+ function clampPoint(point, environment) {
3851
+ const viewport = getViewportSize(environment);
3852
+ return {
3853
+ x: clamp(point.x, 0, viewport.width),
3854
+ y: clamp(point.y, 0, viewport.height)
3855
+ };
3856
+ }
3857
+ function getPopoverPosition(point, environment, options) {
3858
+ const bounds = getPopoverBounds(environment);
3859
+ const margin = 12;
3860
+ const width = Math.min(
3861
+ options?.width ?? 320,
3862
+ Math.max(240, bounds.width - margin * 2)
3863
+ );
3864
+ const estimatedHeight = options?.estimatedHeight ?? 178;
3865
+ const offset = options?.offset ?? 12;
3866
+ return {
3867
+ left: clamp(
3868
+ point.x + offset,
3869
+ bounds.left + margin,
3870
+ bounds.left + bounds.width - width - margin
3871
+ ),
3872
+ top: clamp(
3873
+ point.y + offset,
3874
+ bounds.top + margin,
3875
+ bounds.top + bounds.height - estimatedHeight - margin
3876
+ )
3877
+ };
3878
+ }
3879
+ function getPopoverBounds(environment) {
3880
+ if (!environment) {
3881
+ return {
3882
+ left: 0,
3883
+ top: 0,
3884
+ width: window.innerWidth,
3885
+ height: window.innerHeight
3886
+ };
3887
+ }
3888
+ return environment.overlayRect;
3889
+ }
3890
+ function toHostPoint(point, environment) {
3891
+ if (!environment) return point;
3892
+ return {
3893
+ x: point.x + environment.viewportRect.left,
3894
+ y: point.y + environment.viewportRect.top
3895
+ };
3896
+ }
3897
+ function toHostSelection(selection, environment) {
3898
+ return {
3899
+ left: selection.left + environment.viewportRect.left,
3900
+ top: selection.top + environment.viewportRect.top,
3901
+ width: selection.width,
3902
+ height: selection.height
3903
+ };
3904
+ }
3905
+ function toTargetPoint(point, environment) {
3906
+ if (!environment) return point;
3907
+ return {
3908
+ x: point.x - environment.viewportRect.left,
3909
+ y: point.y - environment.viewportRect.top
3910
+ };
3911
+ }
3912
+ function toTargetPointFromHostEvent(event, environment) {
3913
+ return toTargetPoint(
3914
+ {
3915
+ x: event.clientX,
3916
+ y: event.clientY
3917
+ },
3918
+ environment
3919
+ );
3920
+ }
3921
+ function placeLayerOverTarget(layer, environment) {
3922
+ layer.style.left = `${environment.viewportRect.left}px`;
3923
+ layer.style.top = `${environment.viewportRect.top}px`;
3924
+ layer.style.width = `${environment.viewportRect.width}px`;
3925
+ layer.style.height = `${environment.viewportRect.height}px`;
3926
+ layer.style.right = "auto";
3927
+ layer.style.bottom = "auto";
3928
+ }
3929
+ function clamp(value, min, max) {
3930
+ return Math.min(Math.max(value, min), Math.max(min, max));
3931
+ }
3932
+ function roundRatio(value) {
3933
+ return Math.round(value * 1e4) / 1e4;
3934
+ }
3935
+ function roundPoint(point) {
3936
+ return {
3937
+ x: Math.round(point.x),
3938
+ y: Math.round(point.y)
3939
+ };
3940
+ }
3172
3941
 
3173
- // node_modules/.pnpm/lucide-react@1.20.0_react@19.2.7/node_modules/lucide-react/dist/esm/icons/x.mjs
3174
- var __iconNode25 = [
3175
- ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
3176
- ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
3177
- ];
3178
- var X = createLucideIcon("x", __iconNode25);
3942
+ // src/core/scroll.ts
3943
+ function waitForNextFrame(environment) {
3944
+ return new Promise((resolve) => {
3945
+ (environment?.window ?? window).requestAnimationFrame(() => resolve());
3946
+ });
3947
+ }
3948
+ function runWithAutoScrollBehavior(targetDocument, callback) {
3949
+ const elements = [
3950
+ targetDocument.documentElement,
3951
+ targetDocument.body
3952
+ ].filter((element) => Boolean(element));
3953
+ const previousValues = elements.map((element) => element.style.scrollBehavior);
3954
+ elements.forEach((element) => {
3955
+ element.style.scrollBehavior = "auto";
3956
+ });
3957
+ try {
3958
+ callback();
3959
+ } finally {
3960
+ elements.forEach((element, index) => {
3961
+ element.style.scrollBehavior = previousValues[index] ?? "";
3962
+ });
3963
+ }
3964
+ }
3965
+ function setDocumentScrollInstantly(environment, position) {
3966
+ const scrollElement = environment.document.scrollingElement;
3967
+ if (scrollElement) {
3968
+ scrollElement.scrollLeft = Math.max(0, Math.round(position.x));
3969
+ scrollElement.scrollTop = Math.max(0, Math.round(position.y));
3970
+ return;
3971
+ }
3972
+ environment.window.scrollTo(
3973
+ Math.max(0, Math.round(position.x)),
3974
+ Math.max(0, Math.round(position.y))
3975
+ );
3976
+ }
3179
3977
 
3180
3978
  // src/react-shell/constants.ts
3181
3979
  var REVIEW_QA_FILTERS = [
@@ -3684,6 +4482,11 @@ var getSystemReviewTheme = () => {
3684
4482
 
3685
4483
  // src/react-shell/review/settings.modal.tsx
3686
4484
  var import_jsx_runtime2 = require("react/jsx-runtime");
4485
+ var getReviewThemeIcon = (theme) => {
4486
+ if (theme === "light") return Sun;
4487
+ if (theme === "system") return Monitor;
4488
+ return Moon;
4489
+ };
3687
4490
  var ReviewSettingsModal = ({
3688
4491
  figmaTokenDraft,
3689
4492
  reviewUserIdDraft,
@@ -3743,20 +4546,28 @@ var ReviewSettingsModal = ({
3743
4546
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "df-review-settings-body", children: [
3744
4547
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "df-review-settings-row", children: [
3745
4548
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Theme" }),
3746
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "df-review-settings-theme-options", children: REVIEW_THEME_OPTIONS.map((option) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
3747
- "button",
3748
- {
3749
- "aria-pressed": reviewThemeDraft === option.value,
3750
- className: `df-review-settings-theme-option${reviewThemeDraft === option.value ? " is-active" : ""}`,
3751
- type: "button",
3752
- onClick: () => {
3753
- onReviewThemeDraftChange(normalizeReviewTheme(option.value));
3754
- onClearStatus();
4549
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "df-review-settings-theme-options", children: REVIEW_THEME_OPTIONS.map((option) => {
4550
+ const ThemeIcon = getReviewThemeIcon(option.value);
4551
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
4552
+ "button",
4553
+ {
4554
+ "aria-pressed": reviewThemeDraft === option.value,
4555
+ className: `df-review-settings-theme-option${reviewThemeDraft === option.value ? " is-active" : ""}`,
4556
+ type: "button",
4557
+ onClick: () => {
4558
+ onReviewThemeDraftChange(
4559
+ normalizeReviewTheme(option.value)
4560
+ );
4561
+ onClearStatus();
4562
+ },
4563
+ children: [
4564
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ThemeIcon, { "aria-hidden": "true" }),
4565
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: option.label })
4566
+ ]
3755
4567
  },
3756
- children: option.label
3757
- },
3758
- option.value
3759
- )) })
4568
+ option.value
4569
+ );
4570
+ }) })
3760
4571
  ] }),
3761
4572
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "df-review-settings-field", children: [
3762
4573
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "df-review-settings-label-row", children: [
@@ -4607,7 +5418,7 @@ var getReviewItemRestoreScrollPosition = (targetWindow, targetDocument, item, an
4607
5418
  top: item.scroll?.y ?? 0
4608
5419
  });
4609
5420
  };
4610
- var setDocumentScrollInstantly = (targetWindow, targetDocument, position) => {
5421
+ var setDocumentScrollInstantly2 = (targetWindow, targetDocument, position) => {
4611
5422
  const scrollElement = targetDocument.scrollingElement;
4612
5423
  if (scrollElement) {
4613
5424
  scrollElement.scrollLeft = position.left;
@@ -4948,6 +5759,33 @@ var QaPanelHeader = ({
4948
5759
  }
4949
5760
  )
4950
5761
  ] }),
5762
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
5763
+ "select",
5764
+ {
5765
+ "aria-label": "QA status filter",
5766
+ className: "df-review-status-filter-select",
5767
+ value: qaStatusFilter,
5768
+ onChange: (event) => onQaStatusFilterChange(
5769
+ event.currentTarget.value
5770
+ ),
5771
+ children: [
5772
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "all", children: `All status (${qaStatusFilterCounts.get("all") ?? 0})` }),
5773
+ statusFilterOptions.map((statusOption) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: statusOption.value, children: `${statusOption.label} (${qaStatusFilterCounts.get(statusOption.value) ?? 0})` }, statusOption.value))
5774
+ ]
5775
+ }
5776
+ )
5777
+ ] }),
5778
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "df-review-list-title", children: [
5779
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "df-review-list-meta", children: [
5780
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: isAllQaVisible ? `${label} QA \xB7 All pages` : `${label} QA` }),
5781
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
5782
+ "strong",
5783
+ {
5784
+ title: `${activeRemainingItemCount} remaining of ${activeItemCount}`,
5785
+ children: !hasActiveFilter ? `${activeRemainingItemCount}/${activeItemCount}` : `${filteredItemCount}/${activeItemCount}`
5786
+ }
5787
+ )
5788
+ ] }),
4951
5789
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "df-review-filter-tabs", "aria-label": "QA filters", children: REVIEW_QA_FILTERS.map((filter) => {
4952
5790
  const count = qaFilterCounts.get(filter.key) ?? 0;
4953
5791
  const isActive = qaFilter === filter.key;
@@ -4964,25 +5802,6 @@ var QaPanelHeader = ({
4964
5802
  filter.key
4965
5803
  );
4966
5804
  }) })
4967
- ] }),
4968
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "df-review-list-title", children: [
4969
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: isAllQaVisible ? `${label} QA \xB7 All pages` : `${label} QA` }),
4970
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { title: `${activeRemainingItemCount} remaining of ${activeItemCount}`, children: !hasActiveFilter ? `${activeRemainingItemCount}/${activeItemCount}` : `${filteredItemCount}/${activeItemCount}` }),
4971
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
4972
- "select",
4973
- {
4974
- "aria-label": "QA status filter",
4975
- className: "df-review-status-filter-select",
4976
- value: qaStatusFilter,
4977
- onChange: (event) => onQaStatusFilterChange(
4978
- event.currentTarget.value
4979
- ),
4980
- children: [
4981
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: "all", children: `All status (${qaStatusFilterCounts.get("all") ?? 0})` }),
4982
- statusFilterOptions.map((statusOption) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: statusOption.value, children: `${statusOption.label} (${qaStatusFilterCounts.get(statusOption.value) ?? 0})` }, statusOption.value))
4983
- ]
4984
- }
4985
- )
4986
5805
  ] })
4987
5806
  ] });
4988
5807
  };
@@ -5108,7 +5927,6 @@ var ReviewQaPanel = ({
5108
5927
  // src/react-shell/presence/overlay.tsx
5109
5928
  var import_react6 = require("react");
5110
5929
  var import_jsx_runtime11 = require("react/jsx-runtime");
5111
- var COLLAPSED_USER_COUNT = 1;
5112
5930
  var getPresenceName = (user) => user.displayName || user.userId;
5113
5931
  var PresenceOverlay = ({
5114
5932
  presenceSessionId,
@@ -5116,18 +5934,31 @@ var PresenceOverlay = ({
5116
5934
  }) => {
5117
5935
  const [isExpanded, setIsExpanded] = (0, import_react6.useState)(false);
5118
5936
  if (users.length === 0) return null;
5119
- const visibleUsers = isExpanded ? users : users.slice(0, COLLAPSED_USER_COUNT);
5120
- const hiddenUserCount = users.length - visibleUsers.length;
5121
5937
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
5122
5938
  "div",
5123
5939
  {
5124
5940
  "aria-label": `Review presence, ${users.length} online`,
5125
5941
  className: `df-review-presence-overlay${isExpanded ? " is-expanded" : ""}`,
5126
5942
  children: [
5127
- visibleUsers.map((user) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5943
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
5944
+ "button",
5945
+ {
5946
+ "aria-label": `Show online reviewers, ${users.length} online`,
5947
+ "aria-expanded": isExpanded,
5948
+ className: "df-review-presence-button",
5949
+ type: "button",
5950
+ onClick: () => setIsExpanded((current) => !current),
5951
+ children: [
5952
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(UserRound, { "aria-hidden": "true" }),
5953
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "df-review-presence-badge", children: users.length })
5954
+ ]
5955
+ }
5956
+ ),
5957
+ isExpanded && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "df-review-presence-list", role: "list", children: users.map((user) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5128
5958
  "span",
5129
5959
  {
5130
5960
  className: `df-review-presence-chip${user.sessionId === presenceSessionId ? " is-self" : ""}`,
5961
+ role: "listitem",
5131
5962
  style: {
5132
5963
  "--df-review-presence-color": user.color
5133
5964
  },
@@ -5135,21 +5966,7 @@ var PresenceOverlay = ({
5135
5966
  children: getPresenceName(user)
5136
5967
  },
5137
5968
  user.sessionId
5138
- )),
5139
- hiddenUserCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
5140
- "button",
5141
- {
5142
- "aria-label": `Show ${hiddenUserCount} more online reviewers`,
5143
- "aria-expanded": isExpanded,
5144
- className: "df-review-presence-more",
5145
- type: "button",
5146
- onClick: () => setIsExpanded(true),
5147
- children: [
5148
- "+",
5149
- hiddenUserCount
5150
- ]
5151
- }
5152
- )
5969
+ )) })
5153
5970
  ]
5154
5971
  }
5155
5972
  );
@@ -5166,28 +5983,173 @@ var SOURCE_SELECTOR = [
5166
5983
  "[data-section-index]",
5167
5984
  "[data-section-id]"
5168
5985
  ].join(", ");
5169
- var getSourceCandidates = (target) => {
5986
+ var SECTION_OUTLINE_ROOT_SELECTOR = [
5987
+ "[data-wrk-source-component]",
5988
+ "header[data-wrk-source-file]",
5989
+ "footer[data-wrk-source-file]",
5990
+ '[role="banner"][data-wrk-source-file]',
5991
+ '[role="contentinfo"][data-wrk-source-file]'
5992
+ ].join(", ");
5993
+ var matchesIgnore = (file, patterns) => {
5994
+ const normalized = file.replace(/\\/g, "/");
5995
+ return patterns.some(
5996
+ (pattern) => typeof pattern === "string" ? normalized.includes(pattern) : pattern.test(normalized)
5997
+ );
5998
+ };
5999
+ var getSourceCandidates = (target, options) => {
5170
6000
  const startElement = getEventElement(target);
5171
6001
  if (!startElement) return [];
5172
6002
  const candidates = [];
5173
6003
  const seen = /* @__PURE__ */ new Set();
6004
+ const add = (element2, source, depth2, kind) => {
6005
+ if (!source?.file) return;
6006
+ const key = getSourceFileCompareKey(source.file);
6007
+ if (!addSourceFileCompareKey(seen, key)) return;
6008
+ candidates.push(createSourceCandidate(element2, source, depth2, kind));
6009
+ };
5174
6010
  let element = startElement;
5175
6011
  let depth = 0;
5176
6012
  while (element && element.nodeType === 1) {
5177
- const source = getSourceHintFromElement(element);
5178
- if (source?.file) {
5179
- const key = getSourceCandidateKey(source);
5180
- if (!seen.has(key)) {
5181
- seen.add(key);
5182
- candidates.push(createSourceCandidate(element, source, depth));
5183
- }
5184
- }
6013
+ add(element, getSourceHintFromElement(element), depth, "source");
6014
+ add(element, getDataHintFromElement(element), 0, "data");
5185
6015
  if (element === element.ownerDocument.documentElement) break;
5186
6016
  element = element.parentElement;
5187
6017
  depth += 1;
5188
6018
  }
5189
- return candidates.slice(0, 8);
6019
+ const ignore = options?.ignore;
6020
+ const visible = candidates.filter(
6021
+ (candidate) => !isCoreOutlineNode(candidate.label, candidate.source.file) && !(ignore?.length && matchesIgnore(candidate.source.file ?? "", ignore))
6022
+ );
6023
+ return visible.slice(0, 8);
6024
+ };
6025
+ var getSectionOutline = (root, options) => {
6026
+ const maxDepth = options?.maxDepth ?? 9;
6027
+ return getSectionOutlineRoots(root, options).map((element, index) => {
6028
+ const source = getSourceHintFromElement(element);
6029
+ const label = getOutlineLabel(element, source, "section");
6030
+ const seen = /* @__PURE__ */ new Set();
6031
+ if (source?.file) {
6032
+ addSourceFileCompareKey(seen, getOutlineSourceKey(source));
6033
+ }
6034
+ return {
6035
+ id: `${label}-${index}`,
6036
+ label,
6037
+ depth: 1,
6038
+ filePath: getDisplaySourcePath(source?.file) ?? label,
6039
+ element,
6040
+ source,
6041
+ data: getDataHintFromElement(element),
6042
+ children: getSectionOutlineChildren(
6043
+ element,
6044
+ 2,
6045
+ maxDepth,
6046
+ seen,
6047
+ options
6048
+ )
6049
+ };
6050
+ });
5190
6051
  };
6052
+ function getSectionOutlineRoots(root, options) {
6053
+ return Array.from(root.querySelectorAll(SECTION_OUTLINE_ROOT_SELECTOR)).filter(
6054
+ (element) => {
6055
+ const source = getSourceHintFromElement(element);
6056
+ const label = getOutlineLabel(element, source, "");
6057
+ return !isSkippedOutlineNode(label, source?.file, options);
6058
+ }
6059
+ );
6060
+ }
6061
+ function getSectionOutlineChildren(parent, depth, maxDepth, seen, options) {
6062
+ if (depth > maxDepth) return [];
6063
+ const entries = [];
6064
+ for (const child of Array.from(parent.children)) {
6065
+ const source = getSourceHintFromElement(child);
6066
+ const label = getOutlineLabel(child, source, child.tagName.toLowerCase());
6067
+ const sourceKey = source?.file ? getOutlineSourceKey(source) : "";
6068
+ const isNewSource = Boolean(sourceKey) && !hasEquivalentSourceFileKey(seen, sourceKey);
6069
+ if (shouldStopOutlineBranch(label, source?.file, options)) continue;
6070
+ if (isHiddenOutlineNode(label, source?.file, options)) {
6071
+ entries.push(
6072
+ ...getSectionOutlineChildren(child, depth, maxDepth, seen, options)
6073
+ );
6074
+ continue;
6075
+ }
6076
+ if (source?.file && isNewSource) {
6077
+ const childSeen = new Set(seen);
6078
+ addSourceFileCompareKey(childSeen, sourceKey);
6079
+ entries.push({
6080
+ id: `${sourceKey}-${getElementOutlinePath(child)}-${entries.length}`,
6081
+ label,
6082
+ depth,
6083
+ filePath: getDisplaySourcePath(source.file) ?? source.file,
6084
+ element: child,
6085
+ source,
6086
+ data: getDataHintFromElement(child),
6087
+ children: getSectionOutlineChildren(
6088
+ child,
6089
+ depth + 1,
6090
+ maxDepth,
6091
+ childSeen,
6092
+ options
6093
+ )
6094
+ });
6095
+ continue;
6096
+ }
6097
+ entries.push(
6098
+ ...getSectionOutlineChildren(child, depth, maxDepth, seen, options)
6099
+ );
6100
+ }
6101
+ return entries;
6102
+ }
6103
+ function getElementOutlinePath(element) {
6104
+ const indices = [];
6105
+ let current = element;
6106
+ while (current?.parentElement) {
6107
+ indices.unshift(Array.from(current.parentElement.children).indexOf(current));
6108
+ current = current.parentElement;
6109
+ }
6110
+ return indices.join("-");
6111
+ }
6112
+ function getOutlineSourceKey(source) {
6113
+ return getSourceFileCompareKey(source.file);
6114
+ }
6115
+ function getSourceFileCompareKey(file) {
6116
+ return file?.trim().replace(/\\/g, "/") ?? "";
6117
+ }
6118
+ function addSourceFileCompareKey(seen, key) {
6119
+ if (!key || hasEquivalentSourceFileKey(seen, key)) return false;
6120
+ seen.add(key);
6121
+ return true;
6122
+ }
6123
+ function hasEquivalentSourceFileKey(seen, key) {
6124
+ for (const seenKey of seen) {
6125
+ if (isEquivalentSourceFileKey(seenKey, key)) return true;
6126
+ }
6127
+ return false;
6128
+ }
6129
+ function isEquivalentSourceFileKey(a, b) {
6130
+ return a === b || a.endsWith(`/${b}`) || b.endsWith(`/${a}`);
6131
+ }
6132
+ function getOutlineLabel(element, source, fallback) {
6133
+ return source?.component?.trim() || getComponentNameFromSourceFile(source?.file) || element.id.trim() || fallback;
6134
+ }
6135
+ function isHiddenOutlineNode(label, file, options) {
6136
+ const ignore = options?.ignore;
6137
+ const isIgnoredSource = file && ignore?.length ? matchesIgnore(file, ignore) : false;
6138
+ return isCoreOutlineNode(label, file) || isIgnoredSource;
6139
+ }
6140
+ function shouldStopOutlineBranch(label, file, options) {
6141
+ return !options?.includePlacer && isPlacerOutlineNode(label, file);
6142
+ }
6143
+ function isSkippedOutlineNode(label, file, options) {
6144
+ return shouldStopOutlineBranch(label, file, options) || isHiddenOutlineNode(label, file, options);
6145
+ }
6146
+ function isCoreOutlineNode(label, file) {
6147
+ const text = `${label} ${file ?? ""}`.toLowerCase();
6148
+ return text.includes("core.section") || text.includes("core.content") || text.includes("core.column") || ["coresection", "corecontent", "corecolumn"].includes(label.toLowerCase());
6149
+ }
6150
+ function isPlacerOutlineNode(label, file) {
6151
+ return `${label} ${file ?? ""}`.toLowerCase().includes("placer");
6152
+ }
5191
6153
  var getSourceOpenUrl = (source, options) => {
5192
6154
  const normalizedOptions = normalizeSourceOpenOptions(options);
5193
6155
  const file = source?.file?.trim();
@@ -5226,6 +6188,18 @@ var openSourceInEditor = (source, options) => {
5226
6188
  window.open(url, "_blank", "noreferrer");
5227
6189
  return true;
5228
6190
  };
6191
+ function getDataHintFromElement(element) {
6192
+ const file = getSourceAttribute(element, "data-wrk-data-file");
6193
+ if (!file) return void 0;
6194
+ return {
6195
+ component: void 0,
6196
+ file,
6197
+ line: getSourceAttribute(element, "data-wrk-data-line"),
6198
+ column: void 0,
6199
+ sectionId: void 0,
6200
+ sectionIndex: void 0
6201
+ };
6202
+ }
5229
6203
  function getSourceHintFromElement(element) {
5230
6204
  const source = {
5231
6205
  component: getSourceAttribute(
@@ -5241,7 +6215,7 @@ function getSourceHintFromElement(element) {
5241
6215
  };
5242
6216
  return Object.values(source).some(Boolean) ? source : void 0;
5243
6217
  }
5244
- function createSourceCandidate(element, source, depth) {
6218
+ function createSourceCandidate(element, source, depth, kind) {
5245
6219
  const confidence = getSourceConfidence(source, depth);
5246
6220
  const fileName = source.file?.split(/[\\/]/).pop() ?? source.file ?? "source";
5247
6221
  const component = source.component?.trim();
@@ -5251,7 +6225,7 @@ function createSourceCandidate(element, source, depth) {
5251
6225
  const column = getSourcePosition(source.column);
5252
6226
  const position = line ? `:${line}${column ? `:${column}` : ""}` : "";
5253
6227
  return {
5254
- id: getSourceCandidateKey(source),
6228
+ id: `${kind}:${getSourceCandidateKey(source)}`,
5255
6229
  depth,
5256
6230
  element,
5257
6231
  filePath: getDisplaySourcePath(source.file) ?? fileName,
@@ -5260,6 +6234,7 @@ function createSourceCandidate(element, source, depth) {
5260
6234
  positionLabel: line ? `${line}:${column ?? 1}` : "",
5261
6235
  confidence,
5262
6236
  confidenceLabel: confidence >= 0.82 ? "high" : confidence >= 0.58 ? "medium" : "low",
6237
+ kind,
5263
6238
  usesPosition: confidence >= 0.72 && Boolean(line),
5264
6239
  source
5265
6240
  };
@@ -5283,7 +6258,7 @@ function getDisplaySourcePath(file) {
5283
6258
  const normalizedFile = file?.trim().replace(/\\/g, "/");
5284
6259
  if (!normalizedFile) return void 0;
5285
6260
  const sourceRootMatch = normalizedFile.match(
5286
- /(?:^|\/)((?:dev\/)?src\/.+|app\/.+|pages\/.+|components\/.+)$/
6261
+ /(?:^|\/)((?:dev\/)?src\/.+|app\/.+|pages?\/.+|components\/.+)$/
5287
6262
  );
5288
6263
  return sourceRootMatch?.[1] ?? normalizedFile;
5289
6264
  }
@@ -5774,6 +6749,7 @@ var ViewportPresetIcon = ({
5774
6749
  }) => {
5775
6750
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ReviewScopeIcon2, { scope: getViewportPresetKind(preset) });
5776
6751
  };
6752
+ var getPresetSelectValue = (preset) => `${preset.label}:${preset.width}x${preset.height}`;
5777
6753
  var ReviewTopbar = ({
5778
6754
  draftTarget,
5779
6755
  copyLabel,
@@ -5794,6 +6770,13 @@ var ReviewTopbar = ({
5794
6770
  onOpenInitialPrompt,
5795
6771
  onOpenSettings
5796
6772
  }) => {
6773
+ const selectedPresetValue = getPresetSelectValue(size);
6774
+ const handlePresetSelectChange = (event) => {
6775
+ const nextPreset = viewportPresets.find(
6776
+ (preset) => getPresetSelectValue(preset) === event.currentTarget.value
6777
+ );
6778
+ if (nextPreset) onSizeChange(nextPreset);
6779
+ };
5797
6780
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("header", { className: "df-review-topbar", children: [
5798
6781
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
5799
6782
  "form",
@@ -5843,6 +6826,27 @@ var ReviewTopbar = ({
5843
6826
  },
5844
6827
  preset.label
5845
6828
  )) }),
6829
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6830
+ "select",
6831
+ {
6832
+ "aria-label": "Viewport preset",
6833
+ className: "df-review-preset-select",
6834
+ value: selectedPresetValue,
6835
+ onChange: handlePresetSelectChange,
6836
+ children: viewportPresets.map((preset) => {
6837
+ const scope = getViewportPresetKind(preset);
6838
+ const count = presetScopeCounts.get(scope) ?? 0;
6839
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6840
+ "option",
6841
+ {
6842
+ value: getPresetSelectValue(preset),
6843
+ children: `${preset.label} (${count})`
6844
+ },
6845
+ getPresetSelectValue(preset)
6846
+ );
6847
+ })
6848
+ }
6849
+ ),
5846
6850
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "df-review-tool-divider", "aria-hidden": "true", children: "|" }),
5847
6851
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "df-review-active-size", children: [
5848
6852
  size.width,
@@ -5904,6 +6908,64 @@ var ReviewTopbar = ({
5904
6908
  children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Settings, { "aria-hidden": "true" })
5905
6909
  }
5906
6910
  )
6911
+ ] }),
6912
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("details", { className: "df-review-overlays-menu", children: [
6913
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("summary", { "aria-label": "Open target tools", title: "Tools", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Ellipsis, { "aria-hidden": "true" }) }),
6914
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "df-review-overlays-popover", "aria-label": "Target tools", children: [
6915
+ isRulerAvailable && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6916
+ "button",
6917
+ {
6918
+ "aria-label": "Toggle ruler",
6919
+ className: `df-review-overlay-button is-ruler${isRulerVisible ? " is-active" : ""}`,
6920
+ type: "button",
6921
+ onClick: onToggleRuler,
6922
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Ruler, { "aria-hidden": "true" })
6923
+ }
6924
+ ),
6925
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6926
+ "button",
6927
+ {
6928
+ "aria-label": "Toggle grid overlay",
6929
+ className: `df-review-overlay-button is-grid${targetOverlayState.grid ? " is-active" : ""}`,
6930
+ type: "button",
6931
+ onClick: () => onToggleTargetOverlay("grid"),
6932
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LayoutGrid, { "aria-hidden": "true" })
6933
+ }
6934
+ ),
6935
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6936
+ "button",
6937
+ {
6938
+ "aria-disabled": !isFigmaOverlayAvailable,
6939
+ "aria-label": isFigmaOverlayAvailable ? "Toggle Figma overlay" : FIGMA_OVERLAY_UNAVAILABLE_MESSAGE,
6940
+ className: `df-review-overlay-button is-figma${targetOverlayState.figma ? " is-active" : ""}${isFigmaOverlayAvailable ? "" : " is-disabled"}`,
6941
+ disabled: !isFigmaOverlayAvailable,
6942
+ type: "button",
6943
+ onClick: () => onToggleTargetOverlay("figma"),
6944
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Image, { "aria-hidden": "true" })
6945
+ }
6946
+ ),
6947
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "df-review-tool-divider", "aria-hidden": "true", children: "|" }),
6948
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6949
+ "button",
6950
+ {
6951
+ "aria-label": "Open initial prompt",
6952
+ className: "df-review-overlay-button is-prompt",
6953
+ type: "button",
6954
+ onClick: onOpenInitialPrompt,
6955
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CircleQuestionMark, { "aria-hidden": "true" })
6956
+ }
6957
+ ),
6958
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6959
+ "button",
6960
+ {
6961
+ "aria-label": "Open settings",
6962
+ className: "df-review-overlay-button is-settings",
6963
+ type: "button",
6964
+ onClick: onOpenSettings,
6965
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Settings, { "aria-hidden": "true" })
6966
+ }
6967
+ )
6968
+ ] })
5907
6969
  ] })
5908
6970
  ] })
5909
6971
  ] });
@@ -5914,7 +6976,7 @@ var import_react11 = require("react");
5914
6976
 
5915
6977
  // src/react-shell/hooks/use.review.item.restore.ts
5916
6978
  var import_react7 = require("react");
5917
- function runWithAutoScrollBehavior(targetDocument, callback) {
6979
+ function runWithAutoScrollBehavior2(targetDocument, callback) {
5918
6980
  const elements = [
5919
6981
  targetDocument?.documentElement,
5920
6982
  targetDocument?.body
@@ -6015,8 +7077,8 @@ var useReviewItemRestore = ({
6015
7077
  isCurrentRestore
6016
7078
  );
6017
7079
  if (!isCurrentRestore()) return false;
6018
- runWithAutoScrollBehavior(targetDocument, () => {
6019
- setDocumentScrollInstantly(
7080
+ runWithAutoScrollBehavior2(targetDocument, () => {
7081
+ setDocumentScrollInstantly2(
6020
7082
  targetWindow,
6021
7083
  targetDocument,
6022
7084
  getReviewItemRestoreScrollPosition(
@@ -6190,163 +7252,6 @@ function normalizeStoredReviewItem(value) {
6190
7252
  };
6191
7253
  }
6192
7254
 
6193
- // src/core/geometry.ts
6194
- function rectanglesIntersect(a, b) {
6195
- return a.left < b.left + b.width && a.left + a.width > b.left && a.top < b.top + b.height && a.top + a.height > b.top;
6196
- }
6197
- function getPointSelection(point) {
6198
- return {
6199
- left: point.x,
6200
- top: point.y,
6201
- width: 1,
6202
- height: 1
6203
- };
6204
- }
6205
- function toViewportSelection(selection) {
6206
- return {
6207
- left: selection.x,
6208
- top: selection.y,
6209
- width: selection.width,
6210
- height: selection.height
6211
- };
6212
- }
6213
- function toPublicSelection(selection) {
6214
- return {
6215
- x: Math.round(selection.left),
6216
- y: Math.round(selection.top),
6217
- width: Math.round(selection.width),
6218
- height: Math.round(selection.height)
6219
- };
6220
- }
6221
- function getSelectionCenter(selection) {
6222
- if ("left" in selection) {
6223
- return {
6224
- x: selection.left + selection.width / 2,
6225
- y: selection.top + selection.height / 2
6226
- };
6227
- }
6228
- return {
6229
- x: selection.x + selection.width / 2,
6230
- y: selection.y + selection.height / 2
6231
- };
6232
- }
6233
- function isRelativeSelection(value) {
6234
- if (!value || typeof value !== "object") return false;
6235
- const selection = value;
6236
- return typeof selection.x === "number" && typeof selection.y === "number" && typeof selection.width === "number" && typeof selection.height === "number";
6237
- }
6238
- function getViewportSize(environment) {
6239
- const targetWindow = environment?.window ?? window;
6240
- return {
6241
- width: targetWindow.innerWidth,
6242
- height: targetWindow.innerHeight
6243
- };
6244
- }
6245
- function isPointInViewport(point, environment) {
6246
- const viewport = getViewportSize(environment);
6247
- return point.x >= 0 && point.y >= 0 && point.x <= viewport.width && point.y <= viewport.height;
6248
- }
6249
- function isSelectionInViewport(selection, environment) {
6250
- const viewport = getViewportSize(environment);
6251
- return rectanglesIntersect(selection, {
6252
- left: 0,
6253
- top: 0,
6254
- width: viewport.width,
6255
- height: viewport.height
6256
- });
6257
- }
6258
- function clampPoint(point, environment) {
6259
- const viewport = getViewportSize(environment);
6260
- return {
6261
- x: clamp(point.x, 0, viewport.width),
6262
- y: clamp(point.y, 0, viewport.height)
6263
- };
6264
- }
6265
- function getPopoverPosition(point, environment, options) {
6266
- const bounds = getPopoverBounds(environment);
6267
- const margin = 12;
6268
- const width = Math.min(
6269
- options?.width ?? 320,
6270
- Math.max(240, bounds.width - margin * 2)
6271
- );
6272
- const estimatedHeight = options?.estimatedHeight ?? 178;
6273
- const offset = options?.offset ?? 12;
6274
- return {
6275
- left: clamp(
6276
- point.x + offset,
6277
- bounds.left + margin,
6278
- bounds.left + bounds.width - width - margin
6279
- ),
6280
- top: clamp(
6281
- point.y + offset,
6282
- bounds.top + margin,
6283
- bounds.top + bounds.height - estimatedHeight - margin
6284
- )
6285
- };
6286
- }
6287
- function getPopoverBounds(environment) {
6288
- if (!environment) {
6289
- return {
6290
- left: 0,
6291
- top: 0,
6292
- width: window.innerWidth,
6293
- height: window.innerHeight
6294
- };
6295
- }
6296
- return environment.overlayRect;
6297
- }
6298
- function toHostPoint(point, environment) {
6299
- if (!environment) return point;
6300
- return {
6301
- x: point.x + environment.viewportRect.left,
6302
- y: point.y + environment.viewportRect.top
6303
- };
6304
- }
6305
- function toHostSelection(selection, environment) {
6306
- return {
6307
- left: selection.left + environment.viewportRect.left,
6308
- top: selection.top + environment.viewportRect.top,
6309
- width: selection.width,
6310
- height: selection.height
6311
- };
6312
- }
6313
- function toTargetPoint(point, environment) {
6314
- if (!environment) return point;
6315
- return {
6316
- x: point.x - environment.viewportRect.left,
6317
- y: point.y - environment.viewportRect.top
6318
- };
6319
- }
6320
- function toTargetPointFromHostEvent(event, environment) {
6321
- return toTargetPoint(
6322
- {
6323
- x: event.clientX,
6324
- y: event.clientY
6325
- },
6326
- environment
6327
- );
6328
- }
6329
- function placeLayerOverTarget(layer, environment) {
6330
- layer.style.left = `${environment.viewportRect.left}px`;
6331
- layer.style.top = `${environment.viewportRect.top}px`;
6332
- layer.style.width = `${environment.viewportRect.width}px`;
6333
- layer.style.height = `${environment.viewportRect.height}px`;
6334
- layer.style.right = "auto";
6335
- layer.style.bottom = "auto";
6336
- }
6337
- function clamp(value, min, max) {
6338
- return Math.min(Math.max(value, min), Math.max(min, max));
6339
- }
6340
- function roundRatio(value) {
6341
- return Math.round(value * 1e4) / 1e4;
6342
- }
6343
- function roundPoint(point) {
6344
- return {
6345
- x: Math.round(point.x),
6346
- y: Math.round(point.y)
6347
- };
6348
- }
6349
-
6350
7255
  // src/core/dom.anchor.ts
6351
7256
  var COMMON_ANCHOR_ATTRIBUTES = [
6352
7257
  "data-testid",
@@ -6383,6 +7288,20 @@ function getDomAnchorFromPoint(point, configuredAttribute = "data-qa-id", enviro
6383
7288
  source: getDomSourceHint(target)
6384
7289
  };
6385
7290
  }
7291
+ function getDomAnchorFromElement(target, configuredAttribute = "data-qa-id", environment) {
7292
+ if (target.ownerDocument !== environment.document) return void 0;
7293
+ const candidates = createAnchorCandidates(target, configuredAttribute);
7294
+ const primary = candidates[0];
7295
+ if (!primary) return void 0;
7296
+ return {
7297
+ ...primary,
7298
+ candidates,
7299
+ htmlSnippet: getElementHtmlSnippet(
7300
+ getAnchorSourceElement(target, primary, configuredAttribute) ?? target
7301
+ ),
7302
+ source: getDomSourceHint(target)
7303
+ };
7304
+ }
6386
7305
  function getElementViewportSelection(anchor, environment, preferredSelection) {
6387
7306
  const element = getAnchorElement(anchor, environment, preferredSelection);
6388
7307
  if (!element) return void 0;
@@ -7201,59 +8120,23 @@ function getPointHighlightSelection(item, environment) {
7201
8120
  if (!point) return void 0;
7202
8121
  const size = 16;
7203
8122
  return {
7204
- viewport: {
7205
- left: point.viewport.x - size / 2,
7206
- top: point.viewport.y - size / 2,
7207
- width: size,
7208
- height: size
7209
- },
7210
- isBound: point.isBound
7211
- };
7212
- }
7213
- function getVisibleHighlightSelection(candidates, environment) {
7214
- return candidates.find(
7215
- (candidate) => Boolean(candidate && isSelectionInViewport(candidate.viewport, environment))
7216
- );
7217
- }
7218
- function isDomReviewItem(item) {
7219
- return item.scope === "dom" || item.kind === "note" && Boolean(item.anchor && getItemSelection(item));
7220
- }
7221
-
7222
- // src/core/scroll.ts
7223
- function waitForNextFrame(environment) {
7224
- return new Promise((resolve) => {
7225
- (environment?.window ?? window).requestAnimationFrame(() => resolve());
7226
- });
7227
- }
7228
- function runWithAutoScrollBehavior2(targetDocument, callback) {
7229
- const elements = [
7230
- targetDocument.documentElement,
7231
- targetDocument.body
7232
- ].filter((element) => Boolean(element));
7233
- const previousValues = elements.map((element) => element.style.scrollBehavior);
7234
- elements.forEach((element) => {
7235
- element.style.scrollBehavior = "auto";
7236
- });
7237
- try {
7238
- callback();
7239
- } finally {
7240
- elements.forEach((element, index) => {
7241
- element.style.scrollBehavior = previousValues[index] ?? "";
7242
- });
7243
- }
8123
+ viewport: {
8124
+ left: point.viewport.x - size / 2,
8125
+ top: point.viewport.y - size / 2,
8126
+ width: size,
8127
+ height: size
8128
+ },
8129
+ isBound: point.isBound
8130
+ };
7244
8131
  }
7245
- function setDocumentScrollInstantly2(environment, position) {
7246
- const scrollElement = environment.document.scrollingElement;
7247
- if (scrollElement) {
7248
- scrollElement.scrollLeft = Math.max(0, Math.round(position.x));
7249
- scrollElement.scrollTop = Math.max(0, Math.round(position.y));
7250
- return;
7251
- }
7252
- environment.window.scrollTo(
7253
- Math.max(0, Math.round(position.x)),
7254
- Math.max(0, Math.round(position.y))
8132
+ function getVisibleHighlightSelection(candidates, environment) {
8133
+ return candidates.find(
8134
+ (candidate) => Boolean(candidate && isSelectionInViewport(candidate.viewport, environment))
7255
8135
  );
7256
8136
  }
8137
+ function isDomReviewItem(item) {
8138
+ return item.scope === "dom" || item.kind === "note" && Boolean(item.anchor && getItemSelection(item));
8139
+ }
7257
8140
 
7258
8141
  // src/core/overlay.style.ts
7259
8142
  function createStyleElement() {
@@ -7915,6 +8798,12 @@ function createStyleElement() {
7915
8798
  outline-offset: 1px;
7916
8799
  }
7917
8800
 
8801
+ @media (hover: none) and (pointer: coarse) {
8802
+ .dfwr-textarea {
8803
+ font-size: 16px;
8804
+ }
8805
+ }
8806
+
7918
8807
  .dfwr-adjust-panel {
7919
8808
  display: grid;
7920
8809
  gap: 4px;
@@ -9621,6 +10510,7 @@ function createWebReviewKit(options) {
9621
10510
  close: () => app.close(),
9622
10511
  toggle: () => app.toggle(),
9623
10512
  setMode: (mode) => app.setMode(mode),
10513
+ startElementReview: (element, comment) => app.startElementReview(element, comment),
9624
10514
  getMode: () => app.getMode(),
9625
10515
  highlightItem: (itemId) => app.highlightItem(itemId),
9626
10516
  setHiddenItemIds: (itemIds) => app.setHiddenItemIds(itemIds),
@@ -9751,6 +10641,16 @@ var WebReviewKitApp = class {
9751
10641
  this.areaDraft = void 0;
9752
10642
  this.render();
9753
10643
  }
10644
+ async startElementReview(element, comment) {
10645
+ if (!this.isOpen) {
10646
+ this.isOpen = true;
10647
+ }
10648
+ this.setModeState("element");
10649
+ this.noteDraft = void 0;
10650
+ this.areaDraft = void 0;
10651
+ this.isSelectingArea = false;
10652
+ await this.bindElementDraftToElement(element, comment);
10653
+ }
9754
10654
  getMode() {
9755
10655
  return this.mode;
9756
10656
  }
@@ -9959,6 +10859,47 @@ var WebReviewKitApp = class {
9959
10859
  this.noteDraft = draft;
9960
10860
  this.render();
9961
10861
  }
10862
+ async bindElementDraftToElement(element, comment) {
10863
+ const environment = this.getEnvironment();
10864
+ if (!environment || element.ownerDocument !== environment.document) return;
10865
+ const viewport = getViewportSize(environment);
10866
+ const draft = await this.withOverlayHidden(() => {
10867
+ const rect = element.getBoundingClientRect();
10868
+ if (rect.width <= 0 || rect.height <= 0) return void 0;
10869
+ const selection = {
10870
+ left: rect.left,
10871
+ top: rect.top,
10872
+ width: rect.width,
10873
+ height: rect.height
10874
+ };
10875
+ const anchor = getDomAnchorFromElement(
10876
+ element,
10877
+ this.options.anchors?.attribute,
10878
+ environment
10879
+ );
10880
+ const markerPoint = { x: selection.left, y: selection.top };
10881
+ const marker = {
10882
+ viewport: roundPoint(markerPoint),
10883
+ relative: anchor ? getRelativePoint(markerPoint, anchor, environment) : void 0
10884
+ };
10885
+ const reviewSelection = {
10886
+ viewport: toPublicSelection(selection),
10887
+ relative: anchor ? getRelativeSelection(selection, anchor, environment) : void 0
10888
+ };
10889
+ const previewElement = "style" in element ? element : void 0;
10890
+ return {
10891
+ viewport,
10892
+ anchor,
10893
+ marker,
10894
+ selection: reviewSelection,
10895
+ comment,
10896
+ previewElement
10897
+ };
10898
+ });
10899
+ if (!draft) return;
10900
+ this.noteDraft = draft;
10901
+ this.render();
10902
+ }
9962
10903
  async createAreaDraft(selection) {
9963
10904
  const environment = this.getEnvironment();
9964
10905
  if (!environment) return;
@@ -10044,8 +10985,8 @@ var WebReviewKitApp = class {
10044
10985
  if (!environment) return;
10045
10986
  const scroll = item.scroll;
10046
10987
  if (scroll) {
10047
- runWithAutoScrollBehavior2(environment.document, () => {
10048
- setDocumentScrollInstantly2(environment, scroll);
10988
+ runWithAutoScrollBehavior(environment.document, () => {
10989
+ setDocumentScrollInstantly(environment, scroll);
10049
10990
  });
10050
10991
  await waitForNextFrame(environment);
10051
10992
  }
@@ -10063,6 +11004,8 @@ function createNoopController() {
10063
11004
  },
10064
11005
  setMode() {
10065
11006
  },
11007
+ async startElementReview() {
11008
+ },
10066
11009
  getMode() {
10067
11010
  return "idle";
10068
11011
  },
@@ -11466,8 +12409,18 @@ var useReviewShellData = ({
11466
12409
  [qaStatusFilter, scopeFilteredNumberedActiveItems]
11467
12410
  );
11468
12411
  const hiddenOverlayItemIdList = (0, import_react16.useMemo)(
11469
- () => Array.from(hiddenOverlayItemIds),
11470
- [hiddenOverlayItemIds]
12412
+ () => {
12413
+ const nextHiddenItemIds = new Set(hiddenOverlayItemIds);
12414
+ if (qaStatusFilter !== "all") {
12415
+ activeItems.forEach((item) => {
12416
+ if (normalizeReviewItemStatus(item.status) !== qaStatusFilter) {
12417
+ nextHiddenItemIds.add(item.id);
12418
+ }
12419
+ });
12420
+ }
12421
+ return Array.from(nextHiddenItemIds);
12422
+ },
12423
+ [activeItems, hiddenOverlayItemIds, qaStatusFilter]
11471
12424
  );
11472
12425
  const qaFilterCounts = (0, import_react16.useMemo)(() => {
11473
12426
  const counts = /* @__PURE__ */ new Map();
@@ -12201,6 +13154,112 @@ var getReviewModeWriteMode = (mode) => {
12201
13154
  var SOURCE_PANEL_MAX_WIDTH = 440;
12202
13155
  var SOURCE_PANEL_MIN_WIDTH = 240;
12203
13156
  var SOURCE_PANEL_MAX_HEIGHT = 260;
13157
+ var SOURCE_TREE_PANEL_CLOSE_DELAY_MS = 180;
13158
+ var waitForFrame = (targetWindow) => new Promise((resolve) => {
13159
+ (targetWindow ?? window).requestAnimationFrame(() => resolve());
13160
+ });
13161
+ var waitForMs = (ms) => new Promise((resolve) => {
13162
+ window.setTimeout(resolve, ms);
13163
+ });
13164
+ var getScrollElement = (targetDocument) => targetDocument.scrollingElement;
13165
+ var scrollElementInTarget = (element, block) => {
13166
+ const targetWindow = element.ownerDocument.defaultView;
13167
+ if (!targetWindow) return;
13168
+ const targetDocument = element.ownerDocument;
13169
+ const scrollElement = getScrollElement(targetDocument);
13170
+ const rect = element.getBoundingClientRect();
13171
+ const currentLeft = scrollElement?.scrollLeft ?? targetWindow.scrollX;
13172
+ const currentTop = scrollElement?.scrollTop ?? targetWindow.scrollY;
13173
+ const clientWidth = scrollElement?.clientWidth ?? targetWindow.innerWidth;
13174
+ const clientHeight = scrollElement?.clientHeight ?? targetWindow.innerHeight;
13175
+ const scrollWidth = scrollElement?.scrollWidth ?? targetDocument.documentElement.scrollWidth;
13176
+ const scrollHeight = scrollElement?.scrollHeight ?? targetDocument.documentElement.scrollHeight;
13177
+ const nextLeft = clamp(
13178
+ currentLeft + rect.left + rect.width / 2 - clientWidth / 2,
13179
+ 0,
13180
+ Math.max(0, scrollWidth - clientWidth)
13181
+ );
13182
+ const nextTop = block === "center" ? clamp(
13183
+ currentTop + rect.top + rect.height / 2 - clientHeight / 2,
13184
+ 0,
13185
+ Math.max(0, scrollHeight - clientHeight)
13186
+ ) : clamp(
13187
+ currentTop + rect.top,
13188
+ 0,
13189
+ Math.max(0, scrollHeight - clientHeight)
13190
+ );
13191
+ runWithAutoScrollBehavior(targetDocument, () => {
13192
+ if (scrollElement) {
13193
+ scrollElement.scrollLeft = Math.round(nextLeft);
13194
+ scrollElement.scrollTop = Math.round(nextTop);
13195
+ return;
13196
+ }
13197
+ targetWindow.scrollTo(Math.round(nextLeft), Math.round(nextTop));
13198
+ });
13199
+ };
13200
+ var centerFrameScrollOnElement = (frameScroll, frame, element) => {
13201
+ if (!frameScroll || !frame) return;
13202
+ const frameScrollRect = frameScroll.getBoundingClientRect();
13203
+ const frameRect = frame.getBoundingClientRect();
13204
+ const elementRect = element.getBoundingClientRect();
13205
+ const elementHostCenterX = frameRect.left + elementRect.left + elementRect.width / 2;
13206
+ const elementHostCenterY = frameRect.top + elementRect.top + elementRect.height / 2;
13207
+ const visibleCenterX = frameScrollRect.left + frameScrollRect.width / 2;
13208
+ const visibleCenterY = frameScrollRect.top + frameScrollRect.height / 2;
13209
+ const nextLeft = clamp(
13210
+ frameScroll.scrollLeft + elementHostCenterX - visibleCenterX,
13211
+ 0,
13212
+ Math.max(0, frameScroll.scrollWidth - frameScroll.clientWidth)
13213
+ );
13214
+ const nextTop = clamp(
13215
+ frameScroll.scrollTop + elementHostCenterY - visibleCenterY,
13216
+ 0,
13217
+ Math.max(0, frameScroll.scrollHeight - frameScroll.clientHeight)
13218
+ );
13219
+ const previousScrollBehavior = frameScroll.style.scrollBehavior;
13220
+ frameScroll.style.scrollBehavior = "auto";
13221
+ frameScroll.scrollLeft = Math.round(nextLeft);
13222
+ frameScroll.scrollTop = Math.round(nextTop);
13223
+ frameScroll.style.scrollBehavior = previousScrollBehavior;
13224
+ };
13225
+ var getSectionOutlineFilterTerms = (value) => value.trim().toLowerCase().split(/\s+/).filter(Boolean);
13226
+ var getSectionOutlineEntryCount = (entries) => entries.reduce(
13227
+ (count, entry) => count + 1 + getSectionOutlineEntryCount(entry.children),
13228
+ 0
13229
+ );
13230
+ var DEFAULT_COLLAPSED_ROOT_LABELS = /* @__PURE__ */ new Set(["FrameHeader", "FrameFooter"]);
13231
+ var getDefaultCollapsedSectionOutlineIds = (entries) => {
13232
+ const collapsedIds = /* @__PURE__ */ new Set();
13233
+ const visit = (entry) => {
13234
+ const shouldCollapseRoot = entry.depth === 1 && DEFAULT_COLLAPSED_ROOT_LABELS.has(entry.label);
13235
+ if ((entry.depth >= 2 || shouldCollapseRoot) && entry.children.length > 0) {
13236
+ collapsedIds.add(entry.id);
13237
+ }
13238
+ entry.children.forEach(visit);
13239
+ };
13240
+ entries.forEach(visit);
13241
+ return collapsedIds;
13242
+ };
13243
+ var matchesSectionOutlineFilter = (entry, terms) => {
13244
+ if (terms.length === 0) return true;
13245
+ const text = [
13246
+ entry.label,
13247
+ entry.filePath,
13248
+ entry.source?.file,
13249
+ entry.data?.file
13250
+ ].filter(Boolean).join(" ").toLowerCase();
13251
+ return terms.every((term) => text.includes(term));
13252
+ };
13253
+ var filterSectionOutlineEntries = (entries, terms) => {
13254
+ if (terms.length === 0) return entries;
13255
+ return entries.flatMap((entry) => {
13256
+ const children = filterSectionOutlineEntries(entry.children, terms);
13257
+ if (!matchesSectionOutlineFilter(entry, terms) && children.length === 0) {
13258
+ return [];
13259
+ }
13260
+ return [{ ...entry, children }];
13261
+ });
13262
+ };
12204
13263
  var ReviewShell = ({
12205
13264
  projectId,
12206
13265
  pages,
@@ -12272,7 +13331,11 @@ var ReviewShell = ({
12272
13331
  });
12273
13332
  const sourceShortcutCleanupRef = (0, import_react19.useRef)(null);
12274
13333
  const sourceInspectorInteractionRef = (0, import_react19.useRef)(false);
13334
+ const [sidePanel, setSidePanel] = (0, import_react19.useState)("qa");
12275
13335
  const [sourceInspectorState, setSourceInspectorState] = (0, import_react19.useState)(null);
13336
+ const [sectionOutline, setSectionOutline] = (0, import_react19.useState)(null);
13337
+ const [sectionOutlineFilter, setSectionOutlineFilter] = (0, import_react19.useState)("");
13338
+ const [collapsedSectionOutlineIds, setCollapsedSectionOutlineIds] = (0, import_react19.useState)(() => /* @__PURE__ */ new Set());
12276
13339
  const [isAllQaVisible, setIsAllQaVisible] = (0, import_react19.useState)(false);
12277
13340
  const sourceOpenOptions = (0, import_react19.useMemo)(
12278
13341
  () => ({
@@ -12281,7 +13344,42 @@ var ReviewShell = ({
12281
13344
  }),
12282
13345
  [sourceInspector, sourceRoot]
12283
13346
  );
13347
+ const sourceCandidateOptions = (0, import_react19.useMemo)(
13348
+ () => ({
13349
+ ignore: sourceInspector?.ignore,
13350
+ includePlacer: sourceInspector?.includePlacer
13351
+ }),
13352
+ [sourceInspector]
13353
+ );
13354
+ const sectionOutlineOptions = (0, import_react19.useMemo)(
13355
+ () => ({
13356
+ includePlacer: sourceInspector?.includePlacer,
13357
+ ignore: sourceInspector?.ignore,
13358
+ maxDepth: sourceInspector?.maxDepth
13359
+ }),
13360
+ [sourceInspector]
13361
+ );
12284
13362
  const isSourceInspectorEnabled = sourceInspector?.enabled !== false;
13363
+ const isSourceTreeHoverOutlineEnabled = sourceInspector?.hoverOutline !== false;
13364
+ const isQaPanelVisible = isListVisible && sidePanel === "qa";
13365
+ const isSourceTreePanelVisible = isSourceInspectorEnabled && isListVisible && sidePanel === "source";
13366
+ const sectionOutlineFilterTerms = (0, import_react19.useMemo)(
13367
+ () => getSectionOutlineFilterTerms(sectionOutlineFilter),
13368
+ [sectionOutlineFilter]
13369
+ );
13370
+ const filteredSectionOutline = (0, import_react19.useMemo)(
13371
+ () => sectionOutline ? filterSectionOutlineEntries(sectionOutline, sectionOutlineFilterTerms) : [],
13372
+ [sectionOutline, sectionOutlineFilterTerms]
13373
+ );
13374
+ const sectionOutlineTotalCount = (0, import_react19.useMemo)(
13375
+ () => getSectionOutlineEntryCount(sectionOutline ?? []),
13376
+ [sectionOutline]
13377
+ );
13378
+ const filteredSectionOutlineCount = (0, import_react19.useMemo)(
13379
+ () => getSectionOutlineEntryCount(filteredSectionOutline),
13380
+ [filteredSectionOutline]
13381
+ );
13382
+ const isSectionOutlineFiltering = sectionOutlineFilterTerms.length > 0;
12285
13383
  const {
12286
13384
  activeItems,
12287
13385
  activeRemainingItemCount,
@@ -12617,6 +13715,12 @@ var ReviewShell = ({
12617
13715
  sourceInspectorInteractionRef.current = false;
12618
13716
  setSourceInspectorState(null);
12619
13717
  }, []);
13718
+ (0, import_react19.useEffect)(() => {
13719
+ clearSourceInspector();
13720
+ setSectionOutlineFilter("");
13721
+ setCollapsedSectionOutlineIds(/* @__PURE__ */ new Set());
13722
+ setSectionOutline(null);
13723
+ }, [clearSourceInspector, targetSrc]);
12620
13724
  const getSourceInspectorRect = (0, import_react19.useCallback)(
12621
13725
  (element) => {
12622
13726
  const frame = iframeRef.current;
@@ -12670,13 +13774,15 @@ var ReviewShell = ({
12670
13774
  );
12671
13775
  const showSourceInspectorForTarget = (0, import_react19.useCallback)(
12672
13776
  (target2, isPinned = false) => {
12673
- const candidates = getSourceCandidates(target2).map((candidate) => ({
12674
- ...candidate,
12675
- openUrl: getSourceOpenUrl(candidate.source, {
12676
- ...sourceOpenOptions,
12677
- omitPosition: !candidate.usesPosition
13777
+ const candidates = getSourceCandidates(target2, sourceCandidateOptions).map(
13778
+ (candidate) => ({
13779
+ ...candidate,
13780
+ openUrl: getSourceOpenUrl(candidate.source, {
13781
+ ...sourceOpenOptions,
13782
+ omitPosition: !candidate.usesPosition
13783
+ })
12678
13784
  })
12679
- }));
13785
+ );
12680
13786
  const firstCandidate = candidates[0];
12681
13787
  const rect = firstCandidate ? getSourceInspectorRect(firstCandidate.element) : null;
12682
13788
  if (!firstCandidate || !rect) {
@@ -12698,12 +13804,16 @@ var ReviewShell = ({
12698
13804
  [
12699
13805
  getSourceInspectorPanelPosition,
12700
13806
  getSourceInspectorRect,
13807
+ sourceCandidateOptions,
12701
13808
  sourceOpenOptions
12702
13809
  ]
12703
13810
  );
12704
13811
  const showSourceOutlineForTarget = (0, import_react19.useCallback)(
12705
13812
  (target2) => {
12706
- const firstCandidate = getSourceCandidates(target2)[0];
13813
+ const firstCandidate = getSourceCandidates(
13814
+ target2,
13815
+ sourceCandidateOptions
13816
+ )[0];
12707
13817
  const rect = firstCandidate ? getSourceInspectorRect(firstCandidate.element) : null;
12708
13818
  if (!firstCandidate || !rect) {
12709
13819
  setSourceInspectorState(null);
@@ -12720,8 +13830,35 @@ var ReviewShell = ({
12720
13830
  });
12721
13831
  return firstCandidate;
12722
13832
  },
12723
- [getSourceInspectorRect]
13833
+ [getSourceInspectorRect, sourceCandidateOptions]
13834
+ );
13835
+ const showSourceOutlineForElement = (0, import_react19.useCallback)(
13836
+ (element) => {
13837
+ if (!isSourceTreeHoverOutlineEnabled) return;
13838
+ const rect = getSourceInspectorRect(element);
13839
+ if (!rect) {
13840
+ setSourceInspectorState(
13841
+ (current) => current?.isPinned ? current : null
13842
+ );
13843
+ return;
13844
+ }
13845
+ setSourceInspectorState(
13846
+ (current) => current?.isPinned ? current : {
13847
+ candidates: [],
13848
+ isPinned: false,
13849
+ panelLeft: 0,
13850
+ panelMaxWidth: SOURCE_PANEL_MAX_WIDTH,
13851
+ panelRight: null,
13852
+ panelTop: 0,
13853
+ rect
13854
+ }
13855
+ );
13856
+ },
13857
+ [getSourceInspectorRect, isSourceTreeHoverOutlineEnabled]
12724
13858
  );
13859
+ const clearSourceOutlineHover = (0, import_react19.useCallback)(() => {
13860
+ setSourceInspectorState((current) => current?.isPinned ? current : null);
13861
+ }, []);
12725
13862
  const openSourceCandidate = (0, import_react19.useCallback)(
12726
13863
  (candidate) => {
12727
13864
  const didOpen = openSourceInEditor(candidate.source, {
@@ -12733,6 +13870,153 @@ var ReviewShell = ({
12733
13870
  },
12734
13871
  [clearSourceInspector, showToast, sourceOpenOptions]
12735
13872
  );
13873
+ const getCurrentSectionOutline = (0, import_react19.useCallback)(
13874
+ () => {
13875
+ let frameDocument = null;
13876
+ try {
13877
+ frameDocument = iframeRef.current?.contentDocument ?? null;
13878
+ } catch {
13879
+ frameDocument = null;
13880
+ }
13881
+ return frameDocument ? getSectionOutline(frameDocument, sectionOutlineOptions) : [];
13882
+ },
13883
+ [iframeRef, sectionOutlineOptions]
13884
+ );
13885
+ const setSectionOutlineWithDefaultCollapse = (0, import_react19.useCallback)(
13886
+ (nextSectionOutline) => {
13887
+ setSectionOutline(nextSectionOutline);
13888
+ setCollapsedSectionOutlineIds(
13889
+ getDefaultCollapsedSectionOutlineIds(nextSectionOutline)
13890
+ );
13891
+ },
13892
+ []
13893
+ );
13894
+ (0, import_react19.useEffect)(() => {
13895
+ if (sidePanel !== "source" || !isListVisible) return void 0;
13896
+ const refreshSectionOutline = () => {
13897
+ setSectionOutlineWithDefaultCollapse(getCurrentSectionOutline());
13898
+ };
13899
+ const animationFrame = window.requestAnimationFrame(refreshSectionOutline);
13900
+ const firstTimeout = window.setTimeout(refreshSectionOutline, 120);
13901
+ const secondTimeout = window.setTimeout(refreshSectionOutline, 500);
13902
+ return () => {
13903
+ window.cancelAnimationFrame(animationFrame);
13904
+ window.clearTimeout(firstTimeout);
13905
+ window.clearTimeout(secondTimeout);
13906
+ };
13907
+ }, [
13908
+ getCurrentSectionOutline,
13909
+ isListVisible,
13910
+ setSectionOutlineWithDefaultCollapse,
13911
+ sidePanel,
13912
+ targetSrc
13913
+ ]);
13914
+ const toggleQaPanel = (0, import_react19.useCallback)(() => {
13915
+ setSidePanel("qa");
13916
+ setIsListVisible((current) => sidePanel === "qa" ? !current : true);
13917
+ }, [setIsListVisible, sidePanel]);
13918
+ const toggleSourceTreePanel = (0, import_react19.useCallback)(() => {
13919
+ if (!isSourceInspectorEnabled) return;
13920
+ if (sidePanel === "source" && isListVisible) {
13921
+ setIsListVisible(false);
13922
+ return;
13923
+ }
13924
+ setSidePanel("source");
13925
+ setSectionOutlineWithDefaultCollapse(getCurrentSectionOutline());
13926
+ setIsListVisible(true);
13927
+ }, [
13928
+ getCurrentSectionOutline,
13929
+ isListVisible,
13930
+ isSourceInspectorEnabled,
13931
+ setSectionOutlineWithDefaultCollapse,
13932
+ setIsListVisible,
13933
+ sidePanel
13934
+ ]);
13935
+ const toggleSectionOutlineEntry = (0, import_react19.useCallback)((entryId) => {
13936
+ setCollapsedSectionOutlineIds((current) => {
13937
+ const next = new Set(current);
13938
+ if (next.has(entryId)) {
13939
+ next.delete(entryId);
13940
+ } else {
13941
+ next.add(entryId);
13942
+ }
13943
+ return next;
13944
+ });
13945
+ }, []);
13946
+ const scrollToSection = (0, import_react19.useCallback)((entry) => {
13947
+ scrollElementInTarget(entry.element, "start");
13948
+ centerFrameScrollOnElement(
13949
+ frameScrollRef.current,
13950
+ iframeRef.current,
13951
+ entry.element
13952
+ );
13953
+ }, [frameScrollRef, iframeRef]);
13954
+ const openSectionSource = (0, import_react19.useCallback)(
13955
+ (entry) => {
13956
+ const didOpen = openSourceInEditor(entry.source, {
13957
+ ...sourceOpenOptions,
13958
+ omitPosition: true
13959
+ });
13960
+ showToast(didOpen ? "Source opened" : "Source root required");
13961
+ },
13962
+ [showToast, sourceOpenOptions]
13963
+ );
13964
+ const openSectionData = (0, import_react19.useCallback)(
13965
+ (entry) => {
13966
+ const didOpen = openSourceInEditor(entry.data, sourceOpenOptions);
13967
+ showToast(didOpen ? "Data opened" : "Data hint not found");
13968
+ },
13969
+ [showToast, sourceOpenOptions]
13970
+ );
13971
+ const startSectionDomReview = (0, import_react19.useCallback)(
13972
+ (entry) => {
13973
+ if (!canWriteDom) {
13974
+ showToast("DOM QA unavailable");
13975
+ return;
13976
+ }
13977
+ clearSourceInspector();
13978
+ setIsListVisible(false);
13979
+ let targetWindow = null;
13980
+ try {
13981
+ targetWindow = entry.element.ownerDocument.defaultView ?? iframeRef.current?.contentWindow ?? null;
13982
+ } catch {
13983
+ targetWindow = null;
13984
+ }
13985
+ void waitForMs(SOURCE_TREE_PANEL_CLOSE_DELAY_MS).then(async () => {
13986
+ initReviewKit();
13987
+ await waitForFrame(targetWindow);
13988
+ const controller = controllerRef.current;
13989
+ if (!controller) {
13990
+ showToast("DOM QA unavailable");
13991
+ return;
13992
+ }
13993
+ scrollElementInTarget(entry.element, "center");
13994
+ await waitForFrame(targetWindow);
13995
+ centerFrameScrollOnElement(
13996
+ frameScrollRef.current,
13997
+ iframeRef.current,
13998
+ entry.element
13999
+ );
14000
+ await waitForFrame(targetWindow);
14001
+ await controller.startElementReview(entry.element);
14002
+ await waitForFrame(targetWindow);
14003
+ setMode(controller.getMode());
14004
+ }).catch(() => {
14005
+ setMode(controllerRef.current?.getMode() ?? "idle");
14006
+ });
14007
+ },
14008
+ [
14009
+ canWriteDom,
14010
+ clearSourceInspector,
14011
+ controllerRef,
14012
+ frameScrollRef,
14013
+ iframeRef,
14014
+ initReviewKit,
14015
+ setIsListVisible,
14016
+ setMode,
14017
+ showToast
14018
+ ]
14019
+ );
12736
14020
  const cleanupSourceOpenShortcut = (0, import_react19.useCallback)(() => {
12737
14021
  sourceShortcutCleanupRef.current?.();
12738
14022
  sourceShortcutCleanupRef.current = null;
@@ -12780,7 +14064,7 @@ var ReviewShell = ({
12780
14064
  background: rgba(15, 23, 42, 0.86) !important;
12781
14065
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.24) !important;
12782
14066
  content: "Source select" !important;
12783
- font: 700 12px/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
14067
+ font: 500 12px/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
12784
14068
  pointer-events: none !important;
12785
14069
  }
12786
14070
 
@@ -12797,7 +14081,7 @@ var ReviewShell = ({
12797
14081
  color: #ffffff !important;
12798
14082
  background: rgba(15, 23, 42, 0.9) !important;
12799
14083
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.28) !important;
12800
- font: 800 11px/1.35 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace !important;
14084
+ font: 500 11px/1.35 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace !important;
12801
14085
  overflow-wrap: anywhere !important;
12802
14086
  pointer-events: none !important;
12803
14087
  white-space: normal !important;
@@ -12898,8 +14182,9 @@ var ReviewShell = ({
12898
14182
  }
12899
14183
  };
12900
14184
  const handleMouseMove = (event) => {
14185
+ if (isSourcePanelPinned) return;
12901
14186
  lastSourceTarget = event.target;
12902
- const candidates = getSourceCandidates(event.target);
14187
+ const candidates = getSourceCandidates(event.target, sourceCandidateOptions);
12903
14188
  const sourceElement = candidates[0]?.element ?? null;
12904
14189
  if (event.altKey && !isSourceSelecting) {
12905
14190
  setSourceSelecting(true);
@@ -12933,6 +14218,7 @@ var ReviewShell = ({
12933
14218
  return;
12934
14219
  }
12935
14220
  if (!isOptionKeyEvent(event)) return;
14221
+ if (isSourcePanelPinned) return;
12936
14222
  cancelReviewMode();
12937
14223
  setSourceSelecting(true);
12938
14224
  };
@@ -12983,6 +14269,7 @@ var ReviewShell = ({
12983
14269
  iframeRef,
12984
14270
  isSourceInspectorEnabled,
12985
14271
  showToast,
14272
+ sourceCandidateOptions,
12986
14273
  showSourceOutlineForTarget,
12987
14274
  showSourceInspectorForTarget
12988
14275
  ]);
@@ -12997,12 +14284,19 @@ var ReviewShell = ({
12997
14284
  mode === "element"
12998
14285
  );
12999
14286
  bindSourceOpenShortcut();
14287
+ if (sidePanel === "source" && isListVisible) {
14288
+ setSectionOutlineWithDefaultCollapse(getCurrentSectionOutline());
14289
+ }
13000
14290
  }, [
13001
14291
  bindSourceOpenShortcut,
14292
+ getCurrentSectionOutline,
13002
14293
  iframeRef,
13003
14294
  initReviewKit,
14295
+ isListVisible,
13004
14296
  mode,
13005
- refreshTargetFigmaConfig
14297
+ refreshTargetFigmaConfig,
14298
+ setSectionOutlineWithDefaultCollapse,
14299
+ sidePanel
13006
14300
  ]);
13007
14301
  (0, import_react19.useEffect)(() => {
13008
14302
  const frame = window.requestAnimationFrame(bindSourceOpenShortcut);
@@ -13083,6 +14377,112 @@ var ReviewShell = ({
13083
14377
  onRefreshReviewData: refreshReviewData2,
13084
14378
  onToast: showToast
13085
14379
  });
14380
+ const renderSectionOutlineEntry = (entry) => {
14381
+ const hasChildren = entry.children.length > 0;
14382
+ const isCollapsed = !isSectionOutlineFiltering && collapsedSectionOutlineIds.has(entry.id);
14383
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
14384
+ "div",
14385
+ {
14386
+ className: `df-review-section-outline-item is-depth-${entry.depth}`,
14387
+ children: [
14388
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
14389
+ "div",
14390
+ {
14391
+ className: "df-review-section-outline-row",
14392
+ style: { paddingLeft: `${Math.max(0, entry.depth - 1) * 12 + 6}px` },
14393
+ onMouseEnter: () => showSourceOutlineForElement(entry.element),
14394
+ onMouseLeave: clearSourceOutlineHover,
14395
+ onMouseOver: () => showSourceOutlineForElement(entry.element),
14396
+ onMouseOut: (event) => {
14397
+ if (event.relatedTarget instanceof Node && event.currentTarget.contains(event.relatedTarget)) {
14398
+ return;
14399
+ }
14400
+ clearSourceOutlineHover();
14401
+ },
14402
+ onPointerEnter: () => showSourceOutlineForElement(entry.element),
14403
+ onPointerLeave: clearSourceOutlineHover,
14404
+ children: [
14405
+ hasChildren ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14406
+ "button",
14407
+ {
14408
+ "aria-label": isCollapsed ? `Expand ${entry.label}` : `Collapse ${entry.label}`,
14409
+ "aria-expanded": !isCollapsed,
14410
+ className: `df-review-section-outline-toggle${isCollapsed ? " is-collapsed" : ""}`,
14411
+ type: "button",
14412
+ onClick: () => toggleSectionOutlineEntry(entry.id),
14413
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChevronDown, { "aria-hidden": "true" })
14414
+ }
14415
+ ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14416
+ "span",
14417
+ {
14418
+ "aria-hidden": "true",
14419
+ className: "df-review-section-outline-toggle is-placeholder"
14420
+ }
14421
+ ),
14422
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14423
+ "button",
14424
+ {
14425
+ className: "df-review-section-outline-name",
14426
+ type: "button",
14427
+ onClick: () => scrollToSection(entry),
14428
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: entry.label })
14429
+ }
14430
+ ),
14431
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "df-review-section-outline-links", children: [
14432
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14433
+ "button",
14434
+ {
14435
+ "aria-label": `Open ${entry.label} data`,
14436
+ className: "df-review-section-outline-link",
14437
+ title: "Open data",
14438
+ type: "button",
14439
+ disabled: !entry.data?.file,
14440
+ onClick: () => openSectionData(entry),
14441
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Database, { "aria-hidden": "true" })
14442
+ }
14443
+ ),
14444
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14445
+ "button",
14446
+ {
14447
+ "aria-label": `Open ${entry.label} source`,
14448
+ className: "df-review-section-outline-link",
14449
+ title: "Open source",
14450
+ type: "button",
14451
+ disabled: !entry.source?.file,
14452
+ onClick: () => openSectionSource(entry),
14453
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CodeXml, { "aria-hidden": "true" })
14454
+ }
14455
+ ),
14456
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14457
+ "span",
14458
+ {
14459
+ "aria-hidden": "true",
14460
+ className: "df-review-section-outline-divider",
14461
+ children: "|"
14462
+ }
14463
+ ),
14464
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14465
+ "button",
14466
+ {
14467
+ "aria-label": `Start DOM QA for ${entry.label}`,
14468
+ className: "df-review-section-outline-link is-dom-select",
14469
+ title: "DOM select",
14470
+ type: "button",
14471
+ disabled: !canWriteDom,
14472
+ onClick: () => startSectionDomReview(entry),
14473
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SquareMousePointer, { "aria-hidden": "true" })
14474
+ }
14475
+ )
14476
+ ] })
14477
+ ]
14478
+ }
14479
+ ),
14480
+ hasChildren && !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "df-review-section-outline-children", children: entry.children.map(renderSectionOutlineEntry) })
14481
+ ]
14482
+ },
14483
+ entry.id
14484
+ );
14485
+ };
13086
14486
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
13087
14487
  "div",
13088
14488
  {
@@ -13113,13 +14513,6 @@ var ReviewShell = ({
13113
14513
  onOpenSettings: openFigmaSettings
13114
14514
  }
13115
14515
  ),
13116
- currentPagePresenceUsers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "df-review-presence-row", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
13117
- PresenceOverlay,
13118
- {
13119
- presenceSessionId,
13120
- users: currentPagePresenceUsers
13121
- }
13122
- ) }),
13123
14516
  isSitemapOpen && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
13124
14517
  SitemapModal,
13125
14518
  {
@@ -13172,19 +14565,40 @@ var ReviewShell = ({
13172
14565
  }
13173
14566
  ),
13174
14567
  toastMessage && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "df-review-copy-toast", role: "status", children: toastMessage }),
13175
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "df-review-side-rail", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
13176
- "button",
13177
- {
13178
- "aria-label": isListVisible ? "Hide QA list" : "Show QA list",
13179
- className: "df-review-side-toggle",
13180
- type: "button",
13181
- onClick: () => setIsListVisible((current) => !current),
13182
- children: [
13183
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(GripVertical, {}) }),
13184
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: "QA" })
13185
- ]
13186
- }
13187
- ) }),
14568
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "df-review-side-rail", children: [
14569
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14570
+ "button",
14571
+ {
14572
+ "aria-label": isQaPanelVisible ? "Hide QA list" : "Show QA list",
14573
+ "aria-pressed": isQaPanelVisible,
14574
+ className: `df-review-side-toggle${isQaPanelVisible ? " is-active" : ""}`,
14575
+ type: "button",
14576
+ onClick: toggleQaPanel,
14577
+ title: "QA",
14578
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FileText, {}) })
14579
+ }
14580
+ ),
14581
+ isSourceInspectorEnabled && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14582
+ "button",
14583
+ {
14584
+ "aria-controls": "df-review-section-outline",
14585
+ "aria-label": isSourceTreePanelVisible ? "Hide source tree" : "Show source tree",
14586
+ "aria-pressed": isSourceTreePanelVisible,
14587
+ className: `df-review-side-toggle${isSourceTreePanelVisible ? " is-active" : ""}`,
14588
+ type: "button",
14589
+ onClick: toggleSourceTreePanel,
14590
+ title: "Source Tree",
14591
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Search, {}) })
14592
+ }
14593
+ ),
14594
+ currentPagePresenceUsers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14595
+ PresenceOverlay,
14596
+ {
14597
+ presenceSessionId,
14598
+ users: currentPagePresenceUsers
14599
+ }
14600
+ )
14601
+ ] }),
13188
14602
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
13189
14603
  ReviewQaPanel,
13190
14604
  {
@@ -13195,7 +14609,7 @@ var ReviewShell = ({
13195
14609
  filteredNumberedActiveItems,
13196
14610
  getItemPresetScope,
13197
14611
  hiddenOverlayItemIds,
13198
- isListVisible,
14612
+ isListVisible: isQaPanelVisible,
13199
14613
  isAllQaVisible,
13200
14614
  isRemoteSource,
13201
14615
  copiedPromptKey,
@@ -13223,6 +14637,49 @@ var ReviewShell = ({
13223
14637
  onToggleItemOverlayVisibility: toggleItemOverlayVisibility
13224
14638
  }
13225
14639
  ),
14640
+ isSourceInspectorEnabled && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14641
+ "aside",
14642
+ {
14643
+ className: "df-review-source-tree-panel",
14644
+ "aria-hidden": !isSourceTreePanelVisible,
14645
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { id: "df-review-section-outline", className: "df-review-section-outline", children: [
14646
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "df-review-section-outline-head", children: [
14647
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { children: [
14648
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: "Source Tree" }),
14649
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("small", { children: isSectionOutlineFiltering ? `${filteredSectionOutlineCount} / ${sectionOutlineTotalCount} results` : `${sectionOutline?.length ?? 0} roots` })
14650
+ ] }),
14651
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "df-review-section-outline-filter", children: [
14652
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Search, { "aria-hidden": "true" }),
14653
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14654
+ "input",
14655
+ {
14656
+ "aria-label": "Filter source tree",
14657
+ type: "text",
14658
+ value: sectionOutlineFilter,
14659
+ placeholder: "Filter",
14660
+ autoComplete: "off",
14661
+ enterKeyHint: "search",
14662
+ spellCheck: false,
14663
+ onChange: (event) => setSectionOutlineFilter(event.currentTarget.value)
14664
+ }
14665
+ ),
14666
+ sectionOutlineFilter && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
14667
+ "button",
14668
+ {
14669
+ "aria-label": "Clear source tree filter",
14670
+ className: "df-review-section-outline-filter-clear",
14671
+ type: "button",
14672
+ onMouseDown: (event) => event.preventDefault(),
14673
+ onClick: () => setSectionOutlineFilter(""),
14674
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(X, { "aria-hidden": "true" })
14675
+ }
14676
+ )
14677
+ ] })
14678
+ ] }),
14679
+ filteredSectionOutline.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "df-review-section-outline-list", children: filteredSectionOutline.map(renderSectionOutlineEntry) }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "df-review-section-outline-empty", children: isSectionOutlineFiltering ? "No source matches" : "No sections found" })
14680
+ ] })
14681
+ }
14682
+ ),
13226
14683
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
13227
14684
  ReviewTargetFrame,
13228
14685
  {
@@ -13294,7 +14751,7 @@ var ReviewShell = ({
13294
14751
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "df-review-source-candidate-list", children: sourceInspectorState.candidates.map((candidate) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
13295
14752
  "button",
13296
14753
  {
13297
- className: "df-review-source-candidate",
14754
+ className: `df-review-source-candidate is-${candidate.kind}`,
13298
14755
  type: "button",
13299
14756
  onClick: (event) => {
13300
14757
  event.preventDefault();
@@ -13304,7 +14761,7 @@ var ReviewShell = ({
13304
14761
  children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "df-review-source-candidate-main", children: [
13305
14762
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: candidate.label }),
13306
14763
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: candidate.filePath }),
13307
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("small", { children: candidate.positionLabel || (candidate.usesPosition ? "" : "file only") })
14764
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("small", { children: candidate.positionLabel || "-:-" })
13308
14765
  ] })
13309
14766
  },
13310
14767
  candidate.id
@@ -13528,12 +14985,16 @@ lucide-react/dist/esm/context.mjs:
13528
14985
  lucide-react/dist/esm/Icon.mjs:
13529
14986
  lucide-react/dist/esm/createLucideIcon.mjs:
13530
14987
  lucide-react/dist/esm/icons/bot.mjs:
14988
+ lucide-react/dist/esm/icons/chevron-down.mjs:
13531
14989
  lucide-react/dist/esm/icons/circle-question-mark.mjs:
14990
+ lucide-react/dist/esm/icons/code-xml.mjs:
13532
14991
  lucide-react/dist/esm/icons/copy.mjs:
14992
+ lucide-react/dist/esm/icons/database.mjs:
14993
+ lucide-react/dist/esm/icons/ellipsis.mjs:
13533
14994
  lucide-react/dist/esm/icons/external-link.mjs:
13534
14995
  lucide-react/dist/esm/icons/eye-off.mjs:
13535
14996
  lucide-react/dist/esm/icons/eye.mjs:
13536
- lucide-react/dist/esm/icons/grip-vertical.mjs:
14997
+ lucide-react/dist/esm/icons/file-text.mjs:
13537
14998
  lucide-react/dist/esm/icons/image.mjs:
13538
14999
  lucide-react/dist/esm/icons/layout-grid.mjs:
13539
15000
  lucide-react/dist/esm/icons/link-2.mjs:
@@ -13541,16 +15002,20 @@ lucide-react/dist/esm/icons/list-filter.mjs:
13541
15002
  lucide-react/dist/esm/icons/map.mjs:
13542
15003
  lucide-react/dist/esm/icons/maximize-2.mjs:
13543
15004
  lucide-react/dist/esm/icons/monitor.mjs:
15005
+ lucide-react/dist/esm/icons/moon.mjs:
13544
15006
  lucide-react/dist/esm/icons/pencil.mjs:
13545
15007
  lucide-react/dist/esm/icons/rectangle-horizontal.mjs:
13546
15008
  lucide-react/dist/esm/icons/refresh-cw.mjs:
13547
15009
  lucide-react/dist/esm/icons/ruler.mjs:
13548
15010
  lucide-react/dist/esm/icons/scan.mjs:
15011
+ lucide-react/dist/esm/icons/search.mjs:
13549
15012
  lucide-react/dist/esm/icons/settings.mjs:
13550
15013
  lucide-react/dist/esm/icons/smartphone.mjs:
13551
15014
  lucide-react/dist/esm/icons/square-mouse-pointer.mjs:
13552
15015
  lucide-react/dist/esm/icons/sticky-note.mjs:
15016
+ lucide-react/dist/esm/icons/sun.mjs:
13553
15017
  lucide-react/dist/esm/icons/upload.mjs:
15018
+ lucide-react/dist/esm/icons/user-round.mjs:
13554
15019
  lucide-react/dist/esm/icons/x.mjs:
13555
15020
  lucide-react/dist/esm/lucide-react.mjs:
13556
15021
  (**