@webority/theme 0.53.1 → 0.54.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 (62) hide show
  1. package/dist/purge-safelist.json +339 -3
  2. package/dist/webority-theme.css +1 -1
  3. package/package.json +1 -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 +2 -2
  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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/theme",
3
- "version": "0.53.1",
3
+ "version": "0.54.0",
4
4
  "description": "Webority shared design system — Bootstrap 5.3 SCSS overrides, --wui-* tokens, and shared component CSS. The single source of brand chrome for React portals and Razor sites.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "publishConfig": {
@@ -549,8 +549,8 @@
549
549
  }
550
550
  // No box to light up, so keyboard focus gets the outline ring instead.
551
551
  .btn.btn-ghost:focus-visible {
552
- outline: 2px solid var(--color-primary-ink);
553
- outline-offset: 2px;
552
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
553
+ outline-offset: var(--wui-focus-ring-offset);
554
554
  box-shadow: none;
555
555
  }
556
556
  .btn.btn-ghost.btn-ghost:disabled,
@@ -702,8 +702,8 @@ button.wui-input-leading:hover {
702
702
  }
703
703
  button.wui-input-trailing:focus-visible,
704
704
  button.wui-input-leading:focus-visible {
705
- outline: 2px solid var(--color-primary);
706
- outline-offset: 2px;
705
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
706
+ outline-offset: var(--wui-focus-ring-offset);
707
707
  color: var(--color-primary-ink);
708
708
  border-radius: 9999px;
709
709
  }
@@ -829,6 +829,9 @@ html.is-scrolling body::-webkit-scrollbar-thumb {
829
829
  .press-feedback {
830
830
  transition: none;
831
831
  }
832
+ .press-feedback:active:not(:disabled) {
833
+ transform: none;
834
+ }
832
835
  // Hover animation options: hide the moving layer and drop lift/glow so no
833
836
  // option animates, regardless of which .btn-anim-* is applied.
834
837
  .btn:not(.btn-icon):not(.u-action)::before {
@@ -854,6 +857,26 @@ html.is-scrolling body::-webkit-scrollbar-thumb {
854
857
  color: var(--color-text) !important;
855
858
  }
856
859
 
860
+ // Bootstrap paints `.text-danger/-success/-warning/-info` and `.link-*` with the
861
+ // brand FILL hue (2.29:1 to 4.38:1 on white). Text takes the AA text token, which
862
+ // the alias layer also lifts for dark mode.
863
+ @each $family in (danger, success, warning, info) {
864
+ .text-#{$family},
865
+ .link-#{$family},
866
+ .link-#{$family}:hover,
867
+ .link-#{$family}:focus {
868
+ color: var(--color-#{$family}-text) !important;
869
+ }
870
+ .link-#{$family} {
871
+ text-decoration-color: var(--color-#{$family}-text) !important;
872
+ }
873
+ }
874
+
875
+ // Lets a flex child shrink below its content so `.text-truncate` can work.
876
+ .min-w-0 {
877
+ min-width: 0 !important;
878
+ }
879
+
857
880
  // Font-family utilities Bootstrap has no equivalent for. Products were declaring
858
881
  // these locally, which is how a font choice drifts between surfaces.
859
882
  .font-mono {
@@ -62,6 +62,11 @@
62
62
  // ---- Gradient backgrounds -------------------------------------------
63
63
  .bg-hero-gradient { background: var(--wui-hero-gradient); }
64
64
  .bg-cta-gradient { background: var(--wui-cta-gradient); }
65
+ // The brand ring sinks into these deep brand fills; white keeps the focus ring at 3:1 on them.
66
+ .bg-hero-gradient,
67
+ .bg-cta-gradient {
68
+ --color-focus-ring: var(--color-on-scrim);
69
+ }
65
70
 
66
71
  // ---- Marketing pill buttons (locked design parity) -------------------
67
72
  // Pixel-locked to the standalone reference's `btn-squircle inline-flex
@@ -336,11 +336,12 @@ $link-hover-decoration: underline;
336
336
 
337
337
 
338
338
  // ---- Focus ring -----------------------------------------------------
339
- // $focus-ring-color is intentionally NOT overridden. rgba($primary, …) here captures the
340
- // LIBRARY's $primary (this file compiles before a product's brand override), so the ring
341
- // leaked indigo into every product. Bootstrap's !default `rgba($primary, $focus-ring-opacity)`
342
- // is evaluated after the brand override, so it tracks the brand correctly.
339
+ // Bootstrap's own ring is the primary at 25% opacity, under 3:1 on white (WCAG 1.4.11). It
340
+ // points at the runtime ring token instead, so every Bootstrap control that keeps a box-shadow
341
+ // ring (close button, nav link, pagination, accordion, .focus-ring) draws the solid, brand-tracking
342
+ // colour. A runtime var also avoids capturing the library's compile-time $primary.
343
343
  // $focus-ring-blur matches BS (0) — not restated.
344
+ $focus-ring-color: var(--color-focus-ring);
344
345
  $focus-ring-width: 3px; // BS 0.25rem (4px)
345
346
 
346
347
 
@@ -43,6 +43,20 @@
43
43
  // It is the only focus cue on a field, so it must clear 3:1 against the field and surface
44
44
  // (WCAG 1.4.11): the full primary, not a tint.
45
45
  --color-focus-border: var(--wui-primary);
46
+ // The keyboard focus ring every control draws on :focus-visible: an outline of this colour,
47
+ // width and offset. The primary ink clears 4.5:1 on every light surface and the dark primary
48
+ // on every dark one, so the ring keeps 3:1 whatever the brand. A coloured surface (a scrim, a
49
+ // brand hero) resets --color-focus-ring for its subtree. Inside a scroller that would clip an
50
+ // outer ring, the ring is drawn inset with --wui-focus-ring-inset.
51
+ --color-focus-ring: var(--color-primary-ink);
52
+ --wui-focus-ring-width: 2px;
53
+ --wui-focus-ring-offset: 2px;
54
+ --wui-focus-ring-inset: calc(-1 * var(--wui-focus-ring-width));
55
+ // Pressed: a translucent wash of the control's own ink laid over whatever fill it has, so it
56
+ // reads one step deeper than hover on any surface and in either theme, with no motion.
57
+ --color-pressed-overlay: color-mix(in srgb, currentColor 12%, transparent);
58
+ --wui-press-scale: 0.96;
59
+ --wui-press-duration: 80ms;
46
60
  --color-text-muted: var(--wui-text-2);
47
61
  --color-text-subtle: var(--wui-text-3);
48
62
 
@@ -34,21 +34,41 @@
34
34
  @import "wui/navigation";
35
35
  @import "wui/card";
36
36
  @import "wui/data";
37
+ @import "wui/illustration";
37
38
  @import "wui/table-server";
38
39
  @import "wui/kanban";
40
+ @import "wui/inline-edit";
41
+ @import "wui/mention-input";
42
+ @import "wui/comment-thread";
39
43
  @import "wui/overlays";
44
+ @import "wui/drawer";
40
45
  @import "wui/modal-remote";
41
46
  @import "wui/utilities";
42
47
  @import "wui/typography";
43
48
  @import "wui/disclosure";
44
49
  @import "wui/display";
45
50
  @import "wui/flow";
51
+ // After `flow`: the pricing section extends its `.plan-grid` rules.
52
+ @import "wui/sections";
46
53
  @import "wui/chart";
47
54
  @import "wui/chart-card";
48
55
  @import "wui/calendar";
49
56
  @import "wui/rich-text";
50
57
  @import "wui/scrollbar";
51
58
  @import "wui/sortable";
59
+ // Before `split-view`, which places the legend sheet inside the list column.
60
+ @import "wui/record-pager";
61
+ @import "wui/shortcuts";
62
+ @import "wui/split-view";
63
+ @import "wui/groups";
64
+ @import "wui/carousel";
65
+ @import "wui/onboarding-checklist";
66
+ @import "wui/rating";
67
+ @import "wui/relative-time";
68
+ @import "wui/resizable";
69
+ @import "wui/rolling-number";
70
+ @import "wui/show-more";
71
+ @import "wui/truncate";
52
72
  // After `navigation`/`overlays`: the switcher restates dropdown-item chrome those partials
53
73
  // set, so it has to win on equal specificity.
54
74
  @import "wui/workspace";
@@ -62,14 +82,23 @@
62
82
  @import "wui/dock";
63
83
  @import "wui/consent-banner";
64
84
  @import "wui/file-viewer";
85
+ @import "wui/lightbox";
65
86
  @import "wui/toolbar";
66
87
  @import "wui/theme-toggle";
67
88
  @import "wui/tree";
68
89
  @import "wui/floating";
69
90
  @import "wui/chat";
91
+ @import "wui/code-block";
70
92
  // After `overlays`: anchors the shared modal shell to the top when it holds the palette card.
71
93
  @import "wui/command-palette";
72
94
  @import "wui/context-menu";
95
+ @import "wui/menubar";
96
+ @import "wui/navigation-menu";
73
97
  @import "wui/tour";
98
+ @import "wui/hover-card";
99
+ @import "wui/notification-center";
100
+ @import "wui/whats-new";
101
+ // After every component partial: the shared focus ring and pressed wash settle ties with their hover rules.
102
+ @import "wui/interaction";
74
103
  // Last: restates the settled state of menus other partials style, so it must win.
75
104
  @import "wui/menu-motion";
@@ -37,7 +37,7 @@
37
37
  cursor: progress;
38
38
  }
39
39
  .wui-avatar-picker-face:focus-visible {
40
- outline: 2px solid var(--color-primary);
40
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
41
41
  outline-offset: 3px;
42
42
  }
43
43
  // A file held over the photo: the ring says it can be dropped there.
@@ -75,8 +75,8 @@ wui-calendar {
75
75
  .wui-calendar-today-btn:focus-visible,
76
76
  .wui-calendar-nav-btn:focus-visible,
77
77
  .wui-calendar-view-btn:focus-visible {
78
- outline: 2px solid var(--color-primary);
79
- outline-offset: 2px;
78
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
79
+ outline-offset: var(--wui-focus-ring-offset);
80
80
  }
81
81
  .wui-calendar-title {
82
82
  flex: 1 1 auto;
@@ -180,11 +180,11 @@ wui-calendar {
180
180
  // A day cell, a week or day heading and an event are reached by keyboard; the ring is the same
181
181
  // primary outline every other control in the library draws. The engine marks days with data-date.
182
182
  wui-calendar [data-date]:focus-visible {
183
- outline: 2px solid var(--color-primary);
184
- outline-offset: -2px;
183
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
184
+ outline-offset: var(--wui-focus-ring-inset);
185
185
  }
186
186
  wui-calendar a:focus-visible {
187
- outline: 2px solid var(--color-primary);
187
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
188
188
  outline-offset: 1px;
189
189
  }
190
190
  // The engine draws day numbers, headings and event titles as bare anchors, which the page's link
@@ -190,6 +190,6 @@ button.card-clickable {
190
190
  transform: translateY(-1px);
191
191
  }
192
192
  .card-clickable:focus-visible {
193
- outline: 2px solid var(--color-primary);
194
- outline-offset: 2px;
193
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
194
+ outline-offset: var(--wui-focus-ring-offset);
195
195
  }
@@ -0,0 +1,182 @@
1
+ // ── Carousel ──
2
+ // AppCarousel / <app-carousel> (a <wui-carousel> element): slides in a scroll-snap track with previous
3
+ // and next buttons, a dot per page and an optional visible pause button. The track scrolls on its own
4
+ // (swipe, trackpad, keys); the element adds the buttons, dots and autoplay. Slides in view come from
5
+ // --wui-carousel-per-view, -md and -lg set on the element; --wui-carousel-view is what applies at the
6
+ // current width and is what the element reads to group the dots into pages.
7
+ //
8
+ // Part of the wui-components layer, see _wui-components.scss for load order.
9
+
10
+ .wui-carousel {
11
+ --wui-carousel-gap: 20px;
12
+ --wui-carousel-view: var(--wui-carousel-per-view, 1);
13
+
14
+ display: block;
15
+ min-width: 0;
16
+ }
17
+ @include media-breakpoint-up(md) {
18
+ .wui-carousel {
19
+ --wui-carousel-view: var(--wui-carousel-per-view-md, var(--wui-carousel-per-view, 1));
20
+ }
21
+ }
22
+ @include media-breakpoint-up(lg) {
23
+ .wui-carousel {
24
+ --wui-carousel-view: var(--wui-carousel-per-view-lg, var(--wui-carousel-per-view-md, var(--wui-carousel-per-view, 1)));
25
+ }
26
+ }
27
+
28
+ .wui-carousel-stage {
29
+ display: flex;
30
+ align-items: center;
31
+ gap: 8px;
32
+ }
33
+
34
+ .wui-carousel-track {
35
+ position: relative; // slides measure their offset from the track
36
+ display: flex;
37
+ flex: 1 1 0;
38
+ min-width: 0;
39
+ gap: var(--wui-carousel-gap);
40
+ overflow-x: auto;
41
+ overscroll-behavior-x: contain;
42
+ scroll-snap-type: x mandatory;
43
+ scrollbar-width: none;
44
+ &::-webkit-scrollbar {
45
+ display: none;
46
+ }
47
+ &:focus-visible {
48
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
49
+ outline-offset: var(--wui-focus-ring-offset);
50
+ border-radius: var(--wui-radius-sm);
51
+ }
52
+ }
53
+ @media (prefers-reduced-motion: no-preference) {
54
+ .wui-carousel-track {
55
+ scroll-behavior: smooth;
56
+ }
57
+ }
58
+
59
+ .wui-carousel-slide {
60
+ flex: 0 0 calc((100% - (var(--wui-carousel-view) - 1) * var(--wui-carousel-gap)) / var(--wui-carousel-view));
61
+ min-width: 0;
62
+ scroll-snap-align: start;
63
+ }
64
+
65
+ .wui-carousel-arrow {
66
+ display: grid;
67
+ flex: none;
68
+ place-items: center;
69
+ width: 44px;
70
+ height: 44px;
71
+ padding: 0;
72
+ border: 1px solid var(--color-border);
73
+ border-radius: 50%;
74
+ background: var(--color-surface);
75
+ color: var(--color-text);
76
+ cursor: pointer;
77
+ transition:
78
+ background-color 160ms var(--wui-ease-ui),
79
+ color 160ms var(--wui-ease-ui);
80
+ &:hover {
81
+ background: var(--color-primary-soft);
82
+ color: var(--color-primary-ink);
83
+ }
84
+ &:focus-visible {
85
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
86
+ outline-offset: var(--wui-focus-ring-offset);
87
+ }
88
+ // Disabled by aria so a focused button at the end of the row keeps focus.
89
+ &[aria-disabled="true"] {
90
+ opacity: 0.4;
91
+ cursor: default;
92
+ background: var(--color-surface);
93
+ color: var(--color-text);
94
+ }
95
+ }
96
+
97
+ .wui-carousel-dots {
98
+ display: flex;
99
+ flex-wrap: wrap;
100
+ justify-content: center;
101
+ margin-top: 8px;
102
+ }
103
+ // A 24px target around a 10px dot (WCAG 2.5.8).
104
+ .wui-carousel-dot {
105
+ position: relative;
106
+ width: 24px;
107
+ height: 24px;
108
+ padding: 0;
109
+ border: 0;
110
+ background: transparent;
111
+ cursor: pointer;
112
+ &::before {
113
+ content: "";
114
+ position: absolute;
115
+ inset: 7px;
116
+ border-radius: 50%;
117
+ background: var(--color-border-strong);
118
+ transition: background-color 160ms var(--wui-ease-ui);
119
+ }
120
+ &:hover::before {
121
+ background: var(--color-text-muted);
122
+ }
123
+ &[aria-current="true"]::before {
124
+ background: var(--color-primary);
125
+ }
126
+ &:focus-visible {
127
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
128
+ outline-offset: 0;
129
+ border-radius: 50%;
130
+ }
131
+ }
132
+
133
+ .wui-carousel-pause {
134
+ display: inline-flex;
135
+ align-items: center;
136
+ gap: 8px;
137
+ margin-bottom: 12px;
138
+ padding: 8px 16px;
139
+ border: 1px solid var(--color-primary);
140
+ border-radius: 999px;
141
+ background: var(--color-surface);
142
+ color: var(--color-primary-ink);
143
+ font: inherit;
144
+ font-weight: 600;
145
+ cursor: pointer;
146
+ &:hover {
147
+ background: var(--color-primary-soft);
148
+ }
149
+ &:focus-visible {
150
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
151
+ outline-offset: var(--wui-focus-ring-offset);
152
+ }
153
+ &[hidden] {
154
+ display: none;
155
+ }
156
+ }
157
+ // The glyph is two bars (pause) and, once paused, a triangle (play).
158
+ .wui-carousel-pause-icon {
159
+ width: 10px;
160
+ height: 12px;
161
+ border-right: 3px solid currentColor;
162
+ border-left: 3px solid currentColor;
163
+ }
164
+ // The word swaps between Pause and Play and stays on one line.
165
+ .wui-carousel-pause-text {
166
+ white-space: nowrap;
167
+ }
168
+ wui-carousel[data-paused] .wui-carousel-pause-icon {
169
+ width: 0;
170
+ height: 0;
171
+ border: 6px solid transparent;
172
+ border-right: 0;
173
+ border-left: 10px solid currentColor;
174
+ }
175
+
176
+ // One page of slides: nothing to step through.
177
+ wui-carousel[data-single] {
178
+ .wui-carousel-arrow,
179
+ .wui-carousel-dots {
180
+ display: none;
181
+ }
182
+ }
@@ -48,7 +48,7 @@ wui-chart {
48
48
  color: var(--color-text);
49
49
  }
50
50
  .wui-chart-legend-item:focus-visible {
51
- outline: 2px solid var(--color-primary);
51
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
52
52
  outline-offset: 1px;
53
53
  }
54
54
  .wui-chart-legend-swatch {
@@ -81,7 +81,7 @@ wui-chart {
81
81
  transition: opacity 200ms var(--wui-ease-out-quart);
82
82
  }
83
83
  .wui-chart-surface:focus-visible {
84
- outline: 2px solid var(--color-primary);
84
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
85
85
  outline-offset: 4px;
86
86
  }
87
87
  .wui-chart-canvas {
@@ -25,8 +25,8 @@
25
25
  border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
26
26
  }
27
27
  .struct-card:has(.struct-card-input:focus-visible) {
28
- outline: 2px solid var(--color-primary);
29
- outline-offset: 2px;
28
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
29
+ outline-offset: var(--wui-focus-ring-offset);
30
30
  }
31
31
  .struct-card.checked {
32
32
  border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
@@ -582,6 +582,7 @@ wui-datepicker:not([aria-invalid="true"]) .datepicker:not(.open) .datepicker-tri
582
582
  wui-date-range:not([aria-invalid="true"]) .daterange:not(.open) .daterange-trigger:focus:not(:focus-visible) {
583
583
  background-color: var(--color-field-bg);
584
584
  border-color: var(--color-field-border);
585
+ outline: none;
585
586
  }
586
587
  // Portalled to <body> and fixed-positioned from JS so a modal's
587
588
  // overflow:hidden can't clip it; top/left come from inline styles. z-index
@@ -831,8 +832,8 @@ button.datepicker-month:hover {
831
832
  .datepicker-cell:focus-visible {
832
833
  outline: none;
833
834
  box-shadow:
834
- 0 0 0 2px var(--color-surface),
835
- 0 0 0 4px var(--color-primary);
835
+ 0 0 0 var(--wui-focus-ring-offset) var(--color-surface),
836
+ 0 0 0 calc(var(--wui-focus-ring-offset) + var(--wui-focus-ring-width)) var(--color-focus-ring);
836
837
  }
837
838
 
838
839
  // The panel view fades+scales in on every drill; each month nav slides in from its direction.
@@ -974,6 +975,53 @@ button.datepicker-month:hover {
974
975
  font-size: 12px;
975
976
  color: var(--color-text-subtle);
976
977
  }
978
+ // Quick ranges: a list beside the calendars. [hidden] must stay display:none, so the flex row
979
+ // applies only while the popover is open.
980
+ .daterange-pop.wui-daterange-pop--presets {
981
+ width: 800px;
982
+ }
983
+ .daterange-pop.wui-daterange-pop--presets:not([hidden]) {
984
+ display: flex;
985
+ gap: 18px;
986
+ }
987
+ .wui-daterange-presets {
988
+ display: flex;
989
+ flex-direction: column;
990
+ flex: 0 0 148px;
991
+ gap: 2px;
992
+ padding-right: 18px;
993
+ border-right: 1px solid var(--color-border);
994
+ }
995
+ .wui-daterange-main {
996
+ flex: 1;
997
+ min-width: 0;
998
+ }
999
+ .wui-daterange-preset {
1000
+ border: none;
1001
+ background: transparent;
1002
+ padding: 7px 10px;
1003
+ border-radius: var(--radius);
1004
+ font-size: 13px;
1005
+ font-weight: 500;
1006
+ text-align: left;
1007
+ white-space: nowrap;
1008
+ color: var(--color-text);
1009
+ cursor: pointer;
1010
+ transition: background 0.12s;
1011
+ }
1012
+ .wui-daterange-preset:hover:not(:disabled) {
1013
+ background: var(--color-primary-soft, color-mix(in srgb, var(--color-primary) 8%, transparent));
1014
+ color: var(--color-primary-ink);
1015
+ }
1016
+ .wui-daterange-preset.is-active {
1017
+ background: var(--color-primary-soft, color-mix(in srgb, var(--color-primary) 12%, transparent));
1018
+ color: var(--color-primary-ink);
1019
+ font-weight: 600;
1020
+ }
1021
+ .wui-daterange-preset:disabled {
1022
+ color: var(--color-text-subtle);
1023
+ cursor: not-allowed;
1024
+ }
977
1025
  @media (max-width: 767.98px) {
978
1026
  // Below Bootstrap md tier: stack the calendars so the popover still fits the viewport.
979
1027
  .daterange-pop {
@@ -983,6 +1031,27 @@ button.datepicker-month:hover {
983
1031
  flex-direction: column;
984
1032
  gap: 16px;
985
1033
  }
1034
+ // On a phone the quick ranges sit above the calendars, wrapping as a row of buttons.
1035
+ .daterange-pop.wui-daterange-pop--presets {
1036
+ width: 320px;
1037
+ }
1038
+ .daterange-pop.wui-daterange-pop--presets:not([hidden]) {
1039
+ flex-direction: column;
1040
+ gap: 12px;
1041
+ }
1042
+ .wui-daterange-presets {
1043
+ flex: none;
1044
+ flex-direction: row;
1045
+ flex-wrap: wrap;
1046
+ gap: 4px;
1047
+ padding: 0 0 12px;
1048
+ border-right: none;
1049
+ border-bottom: 1px solid var(--color-border);
1050
+ }
1051
+ .wui-daterange-preset {
1052
+ min-height: 44px;
1053
+ border: 1px solid var(--color-border);
1054
+ }
986
1055
  }
987
1056
  @media (prefers-reduced-motion: reduce) {
988
1057
  .daterange-pop {
@@ -1137,8 +1206,8 @@ wui-timepicker[aria-invalid="true"] .timepicker.open .timepicker-trigger {
1137
1206
  outline: none;
1138
1207
  }
1139
1208
  .country-toggle:focus-visible {
1140
- outline: 2px solid var(--color-primary);
1141
- outline-offset: 2px;
1209
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
1210
+ outline-offset: var(--wui-focus-ring-offset);
1142
1211
  border-radius: var(--radius-sm);
1143
1212
  }
1144
1213
  .country-toggle:disabled {
@@ -1310,6 +1379,11 @@ wui-timepicker[aria-invalid="true"] .timepicker.open .timepicker-trigger {
1310
1379
  background: var(--color-primary-soft) !important;
1311
1380
  color: var(--color-primary-ink) !important;
1312
1381
  }
1382
+ // The tint alone is about 1.2:1; keyboard focus adds the ring, inset inside the scrolling list.
1383
+ .country-dropdown-item:focus-visible {
1384
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
1385
+ outline-offset: var(--wui-focus-ring-inset);
1386
+ }
1313
1387
  .country-dropdown-item.selected {
1314
1388
  background: var(--color-primary-soft) !important;
1315
1389
  color: var(--color-primary-ink) !important;
@@ -1392,7 +1466,7 @@ wui-timepicker[aria-invalid="true"] .timepicker.open .timepicker-trigger {
1392
1466
  color: var(--color-primary-ink);
1393
1467
  }
1394
1468
  .wui-timepicker-toggle:focus-visible {
1395
- outline: 2px solid var(--color-primary);
1469
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
1396
1470
  outline-offset: -4px;
1397
1471
  }
1398
1472
  .wui-timepicker-toggle:disabled {
@@ -1523,5 +1597,11 @@ wui-timepicker[aria-invalid="true"] .timepicker.open .timepicker-trigger {
1523
1597
  }
1524
1598
  .timepicker-option:focus-visible {
1525
1599
  outline: none;
1526
- box-shadow: inset 0 0 0 2px var(--color-primary);
1600
+ box-shadow: inset 0 0 0 var(--wui-focus-ring-width) var(--color-focus-ring);
1601
+ }
1602
+ // On the solid selected fill the ring would vanish into it; a surface line inside keeps it visible.
1603
+ .timepicker-option.is-selected:focus-visible {
1604
+ box-shadow:
1605
+ inset 0 0 0 var(--wui-focus-ring-width) var(--color-focus-ring),
1606
+ inset 0 0 0 calc(2 * var(--wui-focus-ring-width)) var(--color-surface);
1527
1607
  }