@webority/theme 0.53.1 → 0.55.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.
Files changed (69) hide show
  1. package/dist/purge-safelist.json +354 -3
  2. package/dist/webority-theme.css +1 -1
  3. package/package.json +2 -1
  4. package/scss/_components.scss +27 -4
  5. package/scss/_marketing.scss +5 -0
  6. package/scss/_variables.scss +5 -4
  7. package/scss/_wui-aliases.scss +14 -0
  8. package/scss/_wui-components.scss +29 -0
  9. package/scss/wui/_avatar-picker.scss +1 -1
  10. package/scss/wui/_calendar.scss +5 -5
  11. package/scss/wui/_card.scss +2 -2
  12. package/scss/wui/_carousel.scss +182 -0
  13. package/scss/wui/_chart.scss +2 -2
  14. package/scss/wui/_choice.scss +88 -8
  15. package/scss/wui/_code-block.scss +138 -0
  16. package/scss/wui/_command-palette.scss +99 -1
  17. package/scss/wui/_comment-thread.scss +268 -0
  18. package/scss/wui/_context-menu.scss +2 -2
  19. package/scss/wui/_controls.scss +14 -12
  20. package/scss/wui/_data.scss +407 -14
  21. package/scss/wui/_disclosure.scss +2 -2
  22. package/scss/wui/_display.scss +13 -9
  23. package/scss/wui/_dock.scss +2 -2
  24. package/scss/wui/_drawer.scss +198 -0
  25. package/scss/wui/_file-viewer.scss +6 -6
  26. package/scss/wui/_groups.scss +111 -0
  27. package/scss/wui/_hover-card.scss +55 -0
  28. package/scss/wui/_illustration.scss +76 -0
  29. package/scss/wui/_image-crop.scss +6 -6
  30. package/scss/wui/_inline-edit.scss +131 -0
  31. package/scss/wui/_interaction.scss +286 -0
  32. package/scss/wui/_kanban.scss +6 -6
  33. package/scss/wui/_lightbox.scss +169 -0
  34. package/scss/wui/_media.scss +8 -5
  35. package/scss/wui/_mention-input.scss +88 -0
  36. package/scss/wui/_menubar.scss +110 -0
  37. package/scss/wui/_navigation-menu.scss +172 -0
  38. package/scss/wui/_navigation.scss +109 -6
  39. package/scss/wui/_notification-center.scss +251 -0
  40. package/scss/wui/_onboarding-checklist.scss +199 -0
  41. package/scss/wui/_overlays.scss +7 -11
  42. package/scss/wui/_rating.scss +87 -0
  43. package/scss/wui/_record-pager.scss +27 -0
  44. package/scss/wui/_relative-time.scss +10 -0
  45. package/scss/wui/_resizable.scss +98 -0
  46. package/scss/wui/_rich-text.scss +2 -2
  47. package/scss/wui/_rolling-number.scss +60 -0
  48. package/scss/wui/_sections.scss +315 -0
  49. package/scss/wui/_shell-parts.scss +12 -3
  50. package/scss/wui/_shell.scss +6 -6
  51. package/scss/wui/_shortcuts.scss +143 -0
  52. package/scss/wui/_show-more.scss +30 -0
  53. package/scss/wui/_sortable.scss +2 -2
  54. package/scss/wui/_split-view.scss +321 -0
  55. package/scss/wui/_toolbar.scss +4 -4
  56. package/scss/wui/_tour.scss +14 -93
  57. package/scss/wui/_tree.scss +2 -2
  58. package/scss/wui/_truncate.scss +32 -0
  59. package/scss/wui/_typography.scss +14 -0
  60. package/scss/wui/_utilities.scss +8 -8
  61. package/scss/wui/_whats-new.scss +147 -0
  62. package/scss/wui/_workspace.scss +2 -2
  63. package/scss/wui/tour/_advance.scss +67 -0
  64. package/scss/wui/tour/_base.scss +82 -0
  65. package/scss/wui/tour/_end.scss +82 -0
  66. package/scss/wui/tour/_media.scss +54 -0
  67. package/scss/wui/tour/_motion.scss +133 -0
  68. package/scss/wui/tour/_placement.scss +65 -0
  69. package/scss/wui/tour/_progress.scss +26 -0
@@ -262,8 +262,8 @@
262
262
  color: var(--color-text);
263
263
  }
264
264
  .wui-expand-toggle:focus-visible {
265
- outline: 2px solid var(--color-primary);
266
- outline-offset: 2px;
265
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
266
+ outline-offset: var(--wui-focus-ring-offset);
267
267
  }
268
268
  .wui-expand-toggle .wui-icon {
269
269
  transition: transform 0.18s var(--wui-ease-out-quart, ease);
@@ -498,6 +498,10 @@
498
498
  .wui-table-toolbar-clear {
499
499
  margin-left: auto;
500
500
  }
501
+ // "Select all 1,28,400 matching" stays one line when the bulk bar wraps.
502
+ .wui-table-toolbar-all {
503
+ white-space: nowrap;
504
+ }
501
505
  .wui-table-toolbar-main[hidden],
502
506
  .wui-table-toolbar-bulk[hidden] {
503
507
  display: none;
@@ -511,9 +515,11 @@
511
515
  }
512
516
  // Facets size themselves: a select, multi-select or date range takes about 180 to 240px and the
513
517
  // search box a wider 260 to 320px, so they wrap as a compact row instead of stacking at full
514
- // width. Segments keep their own width. A date range is the bare custom element, not a .field,
515
- // and on its own it fills its line.
518
+ // width. Segments keep their own width. A date range, and a select or multi-select without a
519
+ // label, are the bare custom element, not a .field, and on its own it fills its line.
516
520
  .wui-filter-bar > .field,
521
+ .wui-filter-bar > wui-select,
522
+ .wui-filter-bar > wui-multiselect,
517
523
  .wui-filter-bar > wui-date-range {
518
524
  flex: 1 1 180px;
519
525
  min-width: 0;
@@ -536,12 +542,109 @@
536
542
  // On a phone each facet takes its own line; segments and buttons keep their width.
537
543
  @media (max-width: 575.98px) {
538
544
  .wui-filter-bar > .field,
545
+ .wui-filter-bar > wui-select,
546
+ .wui-filter-bar > wui-multiselect,
539
547
  .wui-filter-bar > wui-date-range,
540
548
  .wui-filter-bar > .search-wrap {
541
549
  flex-basis: 100%;
542
550
  max-width: none;
543
551
  }
544
552
  }
553
+ // The Filters button and Clear all keep their label on one line, however full the row is.
554
+ .wui-filter-bar > .btn,
555
+ .wui-filter-more > summary {
556
+ white-space: nowrap;
557
+ flex: none;
558
+ }
559
+ // Facets folded behind the Filters button stack in one panel, each at the panel's width. Both surfaces
560
+ // draw it as the same <details>; in the Razor bar it sits inside the form, so the controls still submit.
561
+ .wui-filter-more-panel {
562
+ display: flex;
563
+ flex-direction: column;
564
+ align-items: stretch;
565
+ gap: 12px;
566
+ min-width: 240px;
567
+ }
568
+ .wui-filter-more-panel > .field,
569
+ .wui-filter-more-panel > wui-select,
570
+ .wui-filter-more-panel > wui-multiselect,
571
+ .wui-filter-more-panel > wui-date-range,
572
+ .wui-filter-more-panel > .search-wrap {
573
+ flex: none;
574
+ min-width: 0;
575
+ max-width: none;
576
+ }
577
+ .wui-filter-more-panel > wui-date-range .daterange {
578
+ width: 100%;
579
+ }
580
+ .wui-filter-more-head {
581
+ display: none;
582
+ }
583
+ .wui-filter-more {
584
+ position: relative;
585
+ }
586
+ .wui-filter-more > .wui-filter-more-trigger {
587
+ list-style: none;
588
+ cursor: pointer;
589
+ user-select: none;
590
+ }
591
+ .wui-filter-more > .wui-filter-more-trigger::-webkit-details-marker {
592
+ display: none;
593
+ }
594
+ .wui-filter-more > .wui-filter-more-panel {
595
+ position: absolute;
596
+ top: calc(100% + 4px);
597
+ left: 0;
598
+ z-index: var(--wui-z-popover);
599
+ width: 320px;
600
+ max-width: calc(100vw - 16px);
601
+ padding: 12px;
602
+ background: var(--color-surface);
603
+ border: 1px solid var(--color-border);
604
+ border-radius: var(--radius-xl);
605
+ box-shadow: var(--shadow-overlay);
606
+ }
607
+ .wui-filter-more:not([open]) > .wui-filter-more-panel {
608
+ display: none;
609
+ }
610
+ .wui-filter-count-phone {
611
+ display: none;
612
+ }
613
+ // `wui-filter-bar--folded` is set on a phone (by webority-ui.js in Razor, by AppFilterBar in React) once every facet
614
+ // is in the panel; the count then covers all of them and the panel gets its heading.
615
+ .wui-filter-bar--folded .wui-filter-count-desktop {
616
+ display: none;
617
+ }
618
+ .wui-filter-bar--folded .wui-filter-count-phone {
619
+ display: inline;
620
+ }
621
+ .wui-filter-bar--folded .wui-filter-more-head {
622
+ display: block;
623
+ font-weight: 600;
624
+ color: var(--color-text);
625
+ }
626
+ @media (max-width: 575.98px) {
627
+ // The panel becomes a sheet from the bottom edge; tapping the scrim (part of the summary) closes it.
628
+ .wui-filter-more > .wui-filter-more-panel {
629
+ position: fixed;
630
+ inset: auto 0 0 0;
631
+ z-index: var(--wui-z-shell-drawer);
632
+ width: auto;
633
+ max-width: none;
634
+ max-height: 85vh;
635
+ overflow-y: auto;
636
+ padding: 16px 20px 24px;
637
+ border-width: 1px 0 0;
638
+ border-radius: var(--radius-xl) var(--radius-xl) 0 0;
639
+ }
640
+ .wui-filter-more[open] > summary::before {
641
+ content: "";
642
+ position: fixed;
643
+ inset: 0;
644
+ z-index: var(--wui-z-shell-scrim);
645
+ background: var(--color-scrim);
646
+ }
647
+ }
545
648
 
546
649
  // Pagination footer: a "10 per page" menu beside the page buttons, flush under a table. No row
547
650
  // range and no total; the page buttons say where you are.
@@ -606,8 +709,8 @@
606
709
  color: var(--color-primary-ink);
607
710
  }
608
711
  .tpg-arrow:focus-visible {
609
- outline: 2px solid var(--color-primary);
610
- outline-offset: 2px;
712
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
713
+ outline-offset: var(--wui-focus-ring-offset);
611
714
  }
612
715
  // Text-5 already reads as "unavailable" — no opacity dimming on top of it.
613
716
  .tpg-arrow:disabled {
@@ -641,8 +744,8 @@
641
744
  color: var(--color-primary-ink);
642
745
  }
643
746
  .tpg-page:focus-visible {
644
- outline: 2px solid var(--color-primary);
645
- outline-offset: 2px;
747
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
748
+ outline-offset: var(--wui-focus-ring-offset);
646
749
  }
647
750
  .tpg-page.is-active {
648
751
  background: var(--color-primary);
@@ -804,6 +907,14 @@
804
907
  --bs-table-bg-state: color-mix(in srgb, var(--color-primary) 14%, transparent);
805
908
  }
806
909
 
910
+ // The open row (AppDataTable `activeRowKey`, or a Razor <tr> marked by `active-row-key`): the subtle
911
+ // primary background, no edge bar, so it reads apart from `data-status`'s bar and from a ticked row.
912
+ // Declared after is-selected so a row that is both shows the open-row tint; hover keeps it steady.
913
+ .table-ledger tbody tr.wui-row-active,
914
+ .table-ledger tbody tr.wui-row-active:hover {
915
+ --bs-table-bg-state: var(--bs-primary-bg-subtle);
916
+ }
917
+
807
918
  // Row status affordance (AppDataTable `rowStatus`, or `data-status` on a Razor <tr>): a colour bar
808
919
  // on the leading edge, so a row's state is legible without relying on a tint alone. Bootstrap paints
809
920
  // a cell's hover/selected tint with its own inset box-shadow, so the bar is LAYERED over that shadow
@@ -863,8 +974,8 @@
863
974
  cursor: pointer;
864
975
  }
865
976
  .table-ledger tbody tr.wui-row-link:focus-visible {
866
- outline: 2px solid var(--color-primary);
867
- outline-offset: -2px;
977
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
978
+ outline-offset: var(--wui-focus-ring-inset);
868
979
  }
869
980
 
870
981
  // Stacked on phones (AppDataTable `stackOnMobile`, Razor `stack-on-mobile`): below md (768px) each
@@ -1127,8 +1238,8 @@
1127
1238
  color: var(--color-primary-ink);
1128
1239
  }
1129
1240
  .u-action:focus-visible {
1130
- outline: 2px solid var(--color-primary);
1131
- outline-offset: 2px;
1241
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
1242
+ outline-offset: var(--wui-focus-ring-offset);
1132
1243
  }
1133
1244
  .u-action:disabled {
1134
1245
  opacity: 0.4;
@@ -1233,8 +1344,8 @@
1233
1344
  user-select: none;
1234
1345
  }
1235
1346
  .table th.sortable:focus-visible {
1236
- outline: 2px solid var(--color-primary);
1237
- outline-offset: -2px;
1347
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
1348
+ outline-offset: var(--wui-focus-ring-inset);
1238
1349
  }
1239
1350
  .table th.sortable .sort-icon {
1240
1351
  // Reserved space so the header does not jump width when the arrow appears.
@@ -1277,3 +1388,285 @@
1277
1388
  }
1278
1389
 
1279
1390
  // ============================================================================
1391
+
1392
+ // Resizable, pinned, grouped and virtual tables (AppDataTable `resizableColumns`, column `pin`,
1393
+ // `groupBy`, `virtual`; Razor `resizable-columns`, `th[data-pin]`, `group-by`, `virtual`).
1394
+ // <wui-data-table> is the table's scroller in place of the plain div, so it must be a block box.
1395
+ wui-data-table {
1396
+ display: block;
1397
+ min-width: 0;
1398
+ }
1399
+
1400
+ // The resize handle sits on the header cell's end edge. A pinned or sticky header cell is already a
1401
+ // containing block, so the relative position has no specificity of its own and never undoes theirs.
1402
+ :where(.table-ledger thead th.wui-col-resizable) {
1403
+ position: relative;
1404
+ }
1405
+ .wui-col-resize {
1406
+ position: absolute;
1407
+ top: 0;
1408
+ bottom: 0;
1409
+ inset-inline-end: 0;
1410
+ z-index: 1;
1411
+ width: 8px;
1412
+ cursor: col-resize;
1413
+ touch-action: none;
1414
+ user-select: none;
1415
+ }
1416
+ .wui-col-resize::after {
1417
+ content: "";
1418
+ position: absolute;
1419
+ top: 25%;
1420
+ bottom: 25%;
1421
+ inset-inline-end: 0;
1422
+ width: 2px;
1423
+ border-radius: 1px;
1424
+ background: var(--color-border-strong);
1425
+ opacity: 0;
1426
+ transition: opacity 0.12s ease;
1427
+ }
1428
+ .table-ledger thead th:hover > .wui-col-resize::after,
1429
+ .wui-col-resize:focus-visible::after,
1430
+ .wui-col-resize.is-dragging::after {
1431
+ opacity: 1;
1432
+ }
1433
+ .wui-col-resize:focus-visible::after,
1434
+ .wui-col-resize.is-dragging::after {
1435
+ background: var(--color-primary);
1436
+ }
1437
+ .wui-col-resize:focus-visible {
1438
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
1439
+ outline-offset: var(--wui-focus-ring-inset);
1440
+ border-radius: 2px;
1441
+ }
1442
+ // A fixed-layout table cuts a cell's overflow at the width the person chose. Not the last column (row
1443
+ // actions, whose tooltips and touch targets reach outside), the pinned edge cells (their shadow sits
1444
+ // outside) or the select and expand cells.
1445
+ .table-ledger[data-wui-fixed] > :is(tbody, tfoot) > tr > td:not(:last-child, .wui-pin-start-edge, .wui-pin-end-edge, .wui-select-cell, .wui-expand-cell) {
1446
+ overflow: hidden;
1447
+ text-overflow: ellipsis;
1448
+ }
1449
+ // A menu or picker inside a cell still has to float out of it.
1450
+ .table-ledger[data-wui-fixed] > tbody > tr > td:has([aria-expanded="true"], .dropdown-menu.show) {
1451
+ overflow: visible;
1452
+ }
1453
+
1454
+ // Pinned columns: each pinned cell reads its offset from --wui-pin-at, which points at the offset the
1455
+ // table holds (--wui-pin-start-<n> / --wui-pin-end-<n>, measured by <wui-data-table>). Surface colour
1456
+ // so scrolled cells do not show through; hover and selection still tint through Bootstrap's inset shadow.
1457
+ .table-ledger > * > tr:not(.wui-row-expanded, .wui-group-row) > .wui-pin-start {
1458
+ position: sticky;
1459
+ inset-inline-start: var(--wui-pin-at, 0px);
1460
+ z-index: 1;
1461
+ }
1462
+ .table-ledger > * > tr:not(.wui-row-expanded, .wui-group-row) > .wui-pin-end {
1463
+ position: sticky;
1464
+ inset-inline-end: var(--wui-pin-at, 0px);
1465
+ z-index: 1;
1466
+ }
1467
+ .table-ledger > :is(tbody, tfoot) > tr:not(.wui-row-expanded, .wui-group-row) > :is(.wui-pin-start, .wui-pin-end) {
1468
+ background-color: var(--color-surface);
1469
+ }
1470
+ .table-wrap.wui-table-scroll .table-ledger > thead > tr > :is(.wui-pin-start, .wui-pin-end) {
1471
+ z-index: 3;
1472
+ }
1473
+ // The shadow that shows a pinned column has content scrolled under it: drawn beside the edge column,
1474
+ // on a pseudo-element, because the cell's own box-shadow carries the hover, selected and status paint.
1475
+ .table-ledger :is(.wui-pin-start-edge, .wui-pin-end-edge)::after {
1476
+ content: "";
1477
+ position: absolute;
1478
+ top: 0;
1479
+ bottom: 0;
1480
+ width: 8px;
1481
+ pointer-events: none;
1482
+ opacity: 0;
1483
+ transition: opacity 0.15s ease;
1484
+ }
1485
+ .table-ledger .wui-pin-start-edge::after {
1486
+ inset-inline-start: 100%;
1487
+ background: linear-gradient(to right, color-mix(in srgb, var(--color-text) 10%, transparent), transparent);
1488
+ }
1489
+ .table-ledger .wui-pin-end-edge::after {
1490
+ inset-inline-end: 100%;
1491
+ background: linear-gradient(to left, color-mix(in srgb, var(--color-text) 10%, transparent), transparent);
1492
+ }
1493
+ .table-ledger:dir(rtl) .wui-pin-start-edge::after {
1494
+ background: linear-gradient(to left, color-mix(in srgb, var(--color-text) 10%, transparent), transparent);
1495
+ }
1496
+ .table-ledger:dir(rtl) .wui-pin-end-edge::after {
1497
+ background: linear-gradient(to right, color-mix(in srgb, var(--color-text) 10%, transparent), transparent);
1498
+ }
1499
+ .table-wrap[data-wui-overflow-start] > .table-ledger .wui-pin-start-edge::after,
1500
+ .table-wrap[data-wui-overflow-end] > .table-ledger .wui-pin-end-edge::after {
1501
+ opacity: 1;
1502
+ }
1503
+ // A pinned side stays put, so it never fades.
1504
+ .table-wrap[data-wui-overflow-start]:has(> .table-ledger .wui-pin-start) {
1505
+ --wui-overflow-fade-start: 0px;
1506
+ }
1507
+ .table-wrap[data-wui-overflow-end]:has(> .table-ledger .wui-pin-end) {
1508
+ --wui-overflow-fade-end: 0px;
1509
+ }
1510
+
1511
+ // Stacked cards (below md) have no columns to pin.
1512
+ @include media-breakpoint-down(md) {
1513
+ .table-ledger.wui-table-stack > * > tr > :is(.wui-pin-start, .wui-pin-end) {
1514
+ position: static;
1515
+ }
1516
+ .table-ledger.wui-table-stack :is(.wui-pin-start-edge, .wui-pin-end-edge)::after {
1517
+ content: none;
1518
+ }
1519
+ }
1520
+
1521
+ // Group header rows: a full-width band with a collapse toggle, the group's value and its row count.
1522
+ .table-ledger > tbody > tr.wui-group-row > th.wui-group-cell {
1523
+ padding: 8px 12px 8px 20px;
1524
+ border-bottom: 1px solid var(--color-border);
1525
+ background-color: var(--color-bg-muted);
1526
+ --bs-table-bg: var(--color-bg-muted);
1527
+ font-size: 13px;
1528
+ font-weight: 600;
1529
+ color: var(--color-text);
1530
+ text-align: start;
1531
+ }
1532
+ .table-ledger > tbody > tr.wui-group-row:hover {
1533
+ --bs-table-bg-state: transparent;
1534
+ }
1535
+ .wui-group-toggle {
1536
+ display: inline-flex;
1537
+ align-items: center;
1538
+ gap: 8px;
1539
+ max-width: 100%;
1540
+ padding: 4px 8px 4px 4px;
1541
+ border: none;
1542
+ border-radius: var(--radius-sm, 6px);
1543
+ background: transparent;
1544
+ color: inherit;
1545
+ font: inherit;
1546
+ cursor: pointer;
1547
+ }
1548
+ .wui-group-toggle:hover {
1549
+ background: color-mix(in srgb, var(--color-primary) 8%, transparent);
1550
+ }
1551
+ .wui-group-toggle:focus-visible {
1552
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
1553
+ outline-offset: var(--wui-focus-ring-offset);
1554
+ }
1555
+ .wui-group-toggle .wui-icon {
1556
+ flex: none;
1557
+ color: var(--color-text-subtle);
1558
+ transition: transform 0.15s ease;
1559
+ }
1560
+ .wui-group-toggle[aria-expanded="false"] .wui-icon {
1561
+ transform: rotate(-90deg);
1562
+ }
1563
+ .wui-group-toggle:dir(rtl)[aria-expanded="false"] .wui-icon {
1564
+ transform: rotate(90deg);
1565
+ }
1566
+ .wui-group-label {
1567
+ overflow: hidden;
1568
+ text-overflow: ellipsis;
1569
+ white-space: nowrap;
1570
+ }
1571
+ .wui-group-count {
1572
+ flex: none;
1573
+ min-width: 22px;
1574
+ padding: 1px 8px;
1575
+ border-radius: 999px;
1576
+ background: var(--color-surface);
1577
+ border: 1px solid var(--color-border);
1578
+ color: var(--color-text-muted);
1579
+ font-size: 12px;
1580
+ font-weight: 500;
1581
+ font-variant-numeric: tabular-nums;
1582
+ text-align: center;
1583
+ }
1584
+
1585
+ // Virtual rows: the spacers stand in for the rows outside the window, and on Razor those rows are
1586
+ // left out of layout.
1587
+ .table-ledger > tbody > tr.wui-virtual-spacer > td {
1588
+ padding: 0;
1589
+ border: 0;
1590
+ --bs-table-bg-state: transparent;
1591
+ }
1592
+ .table-ledger > tbody > tr.wui-virtual-off {
1593
+ display: none;
1594
+ }
1595
+
1596
+ @media (prefers-reduced-motion: reduce) {
1597
+ .wui-col-resize::after,
1598
+ .table-ledger :is(.wui-pin-start-edge, .wui-pin-end-edge)::after,
1599
+ .wui-group-toggle .wui-icon {
1600
+ transition: none;
1601
+ }
1602
+ }
1603
+
1604
+ // A pinned header (`maxHeight`) casts a shadow once rows have scrolled under it, so the cut-off row
1605
+ // reads as "more above". scrollEdges.js keeps data-wui-overflow-top on the scroller while it is
1606
+ // scrolled down, with or without <wui-data-table>. The shadow is layered over the cell's own inset
1607
+ // paint (hover, sort), like the status bar, and takes no room, so nothing shifts.
1608
+ .table-wrap.wui-table-scroll > .table-ledger > thead > tr > th {
1609
+ transition:
1610
+ background-color 0.12s ease,
1611
+ color 0.12s ease,
1612
+ box-shadow 0.15s ease;
1613
+ }
1614
+ .table-wrap.wui-table-scroll[data-wui-overflow-top] > .table-ledger > thead > tr > th {
1615
+ box-shadow:
1616
+ inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg))),
1617
+ 0 6px 8px -6px color-mix(in srgb, var(--color-text) 18%, transparent);
1618
+ }
1619
+
1620
+ // Saving rows (AppDataTable `rowSaving` / `rowSaveError`, or `data-wui-save-state` on a Razor <tr>). A
1621
+ // row whose add or change is on its way shows at once with a soft tint and a pulsing primary bar on its
1622
+ // leading edge; a failed save keeps a danger bar and tint, with the reason on a line under the identity
1623
+ // cell. Both bars are layered over the cell's inset paint, like the status bar, and replace it while shown.
1624
+ .table-ledger > tbody > tr[data-wui-save-state] {
1625
+ --bs-table-bg-state: var(--wui-row-save-tint);
1626
+ --wui-row-save-x: 3px;
1627
+ }
1628
+ .table-ledger:dir(rtl) > tbody > tr[data-wui-save-state] {
1629
+ --wui-row-save-x: -3px;
1630
+ }
1631
+ .table-ledger > tbody > tr[data-wui-save-state="saving"] {
1632
+ --wui-row-save-bar: var(--color-primary);
1633
+ --wui-row-save-tint: var(--color-bg-subtle);
1634
+ cursor: progress;
1635
+ }
1636
+ .table-ledger > tbody > tr[data-wui-save-state="error"] {
1637
+ --wui-row-save-bar: var(--color-danger);
1638
+ --wui-row-save-tint: color-mix(in srgb, var(--color-danger) 6%, transparent);
1639
+ }
1640
+ .table-ledger > tbody > tr[data-wui-save-state] > td:first-child {
1641
+ box-shadow:
1642
+ inset var(--wui-row-save-x) 0 0 0 var(--wui-row-save-bar),
1643
+ inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)));
1644
+ }
1645
+ .table-ledger > tbody > tr[data-wui-save-state="saving"] > td:first-child {
1646
+ animation: wui-row-saving 1.2s ease-in-out infinite;
1647
+ }
1648
+ @keyframes wui-row-saving {
1649
+ 50% {
1650
+ box-shadow:
1651
+ inset var(--wui-row-save-x) 0 0 0 color-mix(in srgb, var(--color-primary) 30%, transparent),
1652
+ inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)));
1653
+ }
1654
+ }
1655
+ .wui-row-save-error {
1656
+ display: block;
1657
+ margin-top: 2px;
1658
+ color: var(--color-danger-text);
1659
+ font-size: 12px;
1660
+ font-weight: 500;
1661
+ line-height: 1.35;
1662
+ white-space: normal;
1663
+ }
1664
+
1665
+ @media (prefers-reduced-motion: reduce) {
1666
+ .table-wrap.wui-table-scroll > .table-ledger > thead > tr > th {
1667
+ transition: none;
1668
+ }
1669
+ .table-ledger > tbody > tr[data-wui-save-state="saving"] > td:first-child {
1670
+ animation: none;
1671
+ }
1672
+ }
@@ -57,8 +57,8 @@
57
57
  color: var(--color-primary-ink);
58
58
  }
59
59
  .faq-q:focus-visible {
60
- outline: 2px solid var(--color-primary);
61
- outline-offset: -2px;
60
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
61
+ outline-offset: var(--wui-focus-ring-inset);
62
62
  }
63
63
  .faq-item.open .faq-q {
64
64
  color: var(--color-primary-ink);
@@ -238,8 +238,8 @@ a.kpi:hover {
238
238
  transform: translateY(-2px);
239
239
  }
240
240
  a.kpi:focus-visible {
241
- outline: 2px solid var(--color-primary);
242
- outline-offset: 2px;
241
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
242
+ outline-offset: var(--wui-focus-ring-offset);
243
243
  }
244
244
 
245
245
  // A row of tiles. Wraps rather than scrolls — a KPI strip that scrolls hides numbers.
@@ -514,8 +514,8 @@ a.info-row:hover .info-value {
514
514
  }
515
515
  // The ring is drawn on the label because the input it belongs to has no box.
516
516
  .segmented-option:has(.segmented-input:focus-visible) {
517
- outline: 2px solid var(--color-primary);
518
- outline-offset: 2px;
517
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
518
+ outline-offset: var(--wui-focus-ring-offset);
519
519
  }
520
520
  // Sliding thumb — one pill that glides to the selected segment. Positioned by JS (React in a
521
521
  // layout effect, Razor in webority-ui.js), which adds .is-animated once it has measured the
@@ -628,6 +628,10 @@ a.info-row:hover .info-value {
628
628
  .segmented-option:has(.segmented-input:checked) .wui-icon {
629
629
  transition: none;
630
630
  }
631
+ // The pressed wash (_interaction.scss) stands in for the press-in.
632
+ .segmented-option:active {
633
+ transform: none;
634
+ }
631
635
  }
632
636
 
633
637
  // ============================================================================
@@ -662,8 +666,8 @@ a.info-row:hover .info-value {
662
666
  border-radius: calc(var(--radius) - 3px);
663
667
  }
664
668
  .color-field-swatch:focus-visible {
665
- outline: 2px solid var(--color-primary);
666
- outline-offset: 2px;
669
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
670
+ outline-offset: var(--wui-focus-ring-offset);
667
671
  }
668
672
  .color-field-hex {
669
673
  flex: 1;
@@ -1063,8 +1067,8 @@ a.info-row:hover .info-value {
1063
1067
  background: var(--color-primary-soft);
1064
1068
  }
1065
1069
  .res-card:focus-visible {
1066
- outline: 2px solid var(--color-primary);
1067
- outline-offset: 2px;
1070
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
1071
+ outline-offset: var(--wui-focus-ring-offset);
1068
1072
  }
1069
1073
  .res-card-icon {
1070
1074
  flex: none;
@@ -1224,7 +1228,7 @@ a.info-row:hover .info-value {
1224
1228
  color: var(--color-primary-ink);
1225
1229
  }
1226
1230
  .wui-link:focus-visible {
1227
- outline: 2px solid var(--color-primary);
1231
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
1228
1232
  outline-offset: 3px;
1229
1233
  }
1230
1234
  .wui-link.is-disabled {
@@ -49,8 +49,8 @@ wui-dock {
49
49
  color: var(--color-primary-ink);
50
50
  }
51
51
  .dock-item:focus-visible {
52
- outline: 2px solid var(--color-primary);
53
- outline-offset: 2px;
52
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
53
+ outline-offset: var(--wui-focus-ring-offset);
54
54
  // Keyboard users get no pointer tracking — grow the focused item itself.
55
55
  --wui-dock-mag: 1.25;
56
56
  }