@webority/theme 0.30.0 → 0.32.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/theme",
3
- "version": "0.30.0",
3
+ "version": "0.32.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": {
package/scss/_tokens.scss CHANGED
@@ -331,6 +331,7 @@
331
331
  --wui-z-shell-drawer: 1045; // mobile sidebar drawer
332
332
  --wui-z-modal-backdrop: 1500;
333
333
  --wui-z-modal: 1505;
334
+ --wui-z-tour: 1550; // product tour: above a modal, below menus and popovers
334
335
  --wui-z-menu: 1600; // portalled select/date/phone menus + infotip
335
336
  --wui-z-popover: 1600; // same rung as --wui-z-menu (above modal)
336
337
  --wui-z-tooltip: 1650;
@@ -236,6 +236,7 @@ $focus-ring-width: 3px; // BS 0.25rem (4px)
236
236
  //
237
237
  // SCSS variables are compile-time and can't reference the runtime custom
238
238
  // properties above — keep these numbers in sync with _tokens.scss by hand.
239
+ $zindex-tour: 1550;
239
240
  $zindex-popover: 1600;
240
241
  $zindex-tooltip: 1650;
241
242
  $zindex-toast: 1700;
@@ -64,8 +64,11 @@
64
64
  @import "wui/toolbar";
65
65
  @import "wui/theme-toggle";
66
66
  @import "wui/tree";
67
+ @import "wui/floating";
68
+ @import "wui/chat";
67
69
  // After `overlays`: anchors the shared modal shell to the top when it holds the palette card.
68
70
  @import "wui/command-palette";
69
71
  @import "wui/context-menu";
72
+ @import "wui/tour";
70
73
  // Last: restates the settled state of menus other partials style, so it must win.
71
74
  @import "wui/menu-motion";
@@ -1,315 +1,14 @@
1
- // Charts: AppLineChart and AppBarChart, and the <wui-chart> element behind AppChart.
1
+ // Charts: the <wui-chart> element behind AppChart.
2
2
  //
3
- // Part of the wui-components layer; see _wui-components.scss for the load order. The line and
4
- // bar charts use one accent (--color-primary), muted grid and labels, and direct labels instead of
5
- // a legend; the element draws series in the --wui-chart-* colours. Every colour is a token the
6
- // dark remap in _wui-aliases.scss flips with the rest of the portal.
7
-
8
- .wui-chart {
9
- margin: 0;
10
- min-width: 0;
11
- color: var(--color-text-muted);
12
- font-size: 12px;
13
- font-variant-numeric: tabular-nums;
14
- }
15
- .wui-chart-title {
16
- margin-bottom: 12px;
17
- font-size: 14px;
18
- font-weight: 600;
19
- color: var(--color-text);
20
- }
21
-
22
- // ============================================================================
23
- // Line chart
24
- // ============================================================================
25
- // The top tick label sits above the top gridline, so the plot leaves room for it.
26
- .wui-chart-plot {
27
- position: relative;
28
- margin-top: 8px;
29
- }
30
- // Strokes overhang the plot by half their width at the top and bottom gridlines.
31
- .wui-chart-svg {
32
- display: block;
33
- overflow: visible;
34
- }
35
- .wui-chart-grid {
36
- stroke: var(--color-border);
37
- stroke-width: 1;
38
- }
39
- .wui-chart-reference {
40
- stroke: var(--color-border-strong);
41
- stroke-width: 1;
42
- stroke-dasharray: 4 4;
43
- }
44
- .wui-chart-line {
45
- stroke: var(--color-primary);
46
- stroke-width: 2;
47
- stroke-linecap: round;
48
- }
49
- // Bands are a quiet wash behind the series; the tone tints, it does not shout.
50
- .wui-chart-band {
51
- fill: var(--color-bg-muted);
52
- opacity: 0.6;
53
- }
54
- .wui-chart-band-info {
55
- fill: var(--color-info-soft);
56
- }
57
- .wui-chart-band-success {
58
- fill: var(--color-success-soft);
59
- }
60
- .wui-chart-band-warning {
61
- fill: var(--color-warning-soft);
62
- }
63
- .wui-chart-band-danger {
64
- fill: var(--color-danger-soft);
65
- }
66
-
67
- // Y tick values sit just above their gridline at the left edge, inside the plot, so the chart
68
- // spends no width on a label gutter at 320px.
69
- .wui-chart-tick,
70
- .wui-chart-band-label,
71
- .wui-chart-reference-label {
72
- position: absolute;
73
- font-size: 11px;
74
- line-height: 1;
75
- white-space: nowrap;
76
- color: var(--color-text-muted);
77
- pointer-events: none;
78
- }
79
- .wui-chart-tick {
80
- left: 0;
81
- padding-bottom: 3px;
82
- transform: translateY(-100%);
83
- }
84
- .wui-chart-band-label {
85
- right: 0;
86
- padding-top: 3px;
87
- }
88
- .wui-chart-reference-label {
89
- right: 0;
90
- padding-bottom: 3px;
91
- transform: translateY(-100%);
92
- }
93
-
94
- // A 24px hit area per point (WCAG 2.2 target size), drawn as an 8px ring.
95
- .wui-chart-point {
96
- position: absolute;
97
- width: 24px;
98
- height: 24px;
99
- margin: -12px 0 0 -12px;
100
- padding: 0;
101
- display: grid;
102
- place-items: center;
103
- border: 0;
104
- border-radius: 50%;
105
- background: transparent;
106
- cursor: default;
107
- }
108
- .wui-chart-point:focus-visible {
109
- outline: 2px solid var(--color-primary);
110
- outline-offset: 0;
111
- }
112
- .wui-chart-dot {
113
- width: 8px;
114
- height: 8px;
115
- border-radius: 50%;
116
- border: 2px solid var(--color-primary);
117
- background: var(--color-surface);
118
- transition: transform 120ms var(--wui-ease-out-quart);
119
- }
120
- .wui-chart-point:hover .wui-chart-dot,
121
- .wui-chart-point:focus-visible .wui-chart-dot {
122
- transform: scale(1.35);
123
- background: var(--color-primary);
124
- }
125
-
126
- // CSS-only tooltip above the point; the first and last points anchor it to their own edge so
127
- // it never runs off a narrow chart.
128
- .wui-chart-tip {
129
- position: absolute;
130
- bottom: calc(100% + 4px);
131
- left: 50%;
132
- z-index: 1;
133
- display: flex;
134
- flex-direction: column;
135
- align-items: flex-start;
136
- gap: 2px;
137
- padding: 6px 10px;
138
- border: 1px solid var(--color-border-light);
139
- border-radius: var(--radius);
140
- background: var(--color-surface);
141
- box-shadow: var(--wui-shadow-overlay);
142
- white-space: nowrap;
143
- text-align: left;
144
- pointer-events: none;
145
- visibility: hidden;
146
- opacity: 0;
147
- transform: translateX(-50%);
148
- transition:
149
- opacity 120ms var(--wui-ease-out-quart),
150
- visibility 120ms;
151
- }
152
- .wui-chart-point-start .wui-chart-tip {
153
- left: 0;
154
- transform: none;
155
- }
156
- .wui-chart-point-end .wui-chart-tip {
157
- left: auto;
158
- right: 0;
159
- transform: none;
160
- }
161
- .wui-chart-point:hover .wui-chart-tip,
162
- .wui-chart-point:focus-visible .wui-chart-tip {
163
- visibility: visible;
164
- opacity: 1;
165
- }
166
- .wui-chart-tip-label {
167
- font-size: 11px;
168
- color: var(--color-text-muted);
169
- }
170
- .wui-chart-tip-value {
171
- font-size: 13px;
172
- font-weight: 600;
173
- color: var(--color-text);
174
- }
175
-
176
- .wui-chart-xaxis {
177
- position: relative;
178
- height: 16px;
179
- margin-top: 6px;
180
- }
181
- .wui-chart-xlabel {
182
- position: absolute;
183
- top: 0;
184
- font-size: 11px;
185
- line-height: 16px;
186
- white-space: nowrap;
187
- transform: translateX(-50%);
188
- }
189
- // Below md only every Nth label shows (the component marks the rest minor); a 12-month axis
190
- // would otherwise overlap on a phone.
191
- .wui-chart-xlabel-minor {
192
- display: none;
193
- }
194
- @media (min-width: 768px) {
195
- .wui-chart-xlabel-minor {
196
- display: block;
197
- }
198
- }
199
-
200
- // ============================================================================
201
- // Bar chart
202
- // ============================================================================
203
- .wui-bar-chart-list {
204
- margin: 0;
205
- padding: 0;
206
- list-style: none;
207
- }
208
- .wui-bar-chart-label {
209
- min-width: 0;
210
- color: var(--color-text-body);
211
- overflow-wrap: anywhere;
212
- }
213
- .wui-bar-chart-value {
214
- font-weight: 600;
215
- white-space: nowrap;
216
- color: var(--color-text);
217
- }
218
- .wui-bar-chart-track {
219
- position: relative;
220
- overflow: hidden;
221
- border-radius: 999px;
222
- background: var(--color-progress-track);
223
- }
224
- .wui-bar-chart-fill {
225
- border-radius: inherit;
226
- background: var(--color-primary);
227
- }
228
- // Each track is a focus stop; the ring sits outside the track's own clipped content.
229
- .wui-bar-chart-track:focus-visible {
230
- outline: 2px solid var(--color-primary);
231
- outline-offset: 2px;
232
- }
233
-
234
- // Horizontal: a label/value line over each bar, so a long label wraps instead of squeezing
235
- // the bar at 320px.
236
- .wui-bar-chart-horizontal .wui-bar-chart-list {
237
- display: flex;
238
- flex-direction: column;
239
- gap: 14px;
240
- }
241
- .wui-bar-chart-horizontal .wui-bar-chart-item {
242
- display: grid;
243
- grid-template-columns: minmax(0, 1fr) auto;
244
- grid-template-areas:
245
- "label value"
246
- "track track";
247
- column-gap: 12px;
248
- row-gap: 6px;
249
- align-items: baseline;
250
- }
251
- .wui-bar-chart-horizontal .wui-bar-chart-label {
252
- grid-area: label;
253
- }
254
- .wui-bar-chart-horizontal .wui-bar-chart-value {
255
- grid-area: value;
256
- }
257
- .wui-bar-chart-horizontal .wui-bar-chart-track {
258
- grid-area: track;
259
- height: 8px;
260
- }
261
- .wui-bar-chart-horizontal .wui-bar-chart-fill {
262
- height: 100%;
263
- transition: width 300ms var(--wui-ease-out-quart);
264
- }
265
-
266
- // Vertical: bars side by side, value above and label below each. The plot height is one var a
267
- // caller can set from its own class.
268
- .wui-bar-chart-vertical .wui-bar-chart-list {
269
- display: flex;
270
- gap: 8px;
271
- }
272
- .wui-bar-chart-vertical .wui-bar-chart-item {
273
- flex: 1 1 0;
274
- min-width: 0;
275
- display: grid;
276
- grid-template-areas:
277
- "value"
278
- "track"
279
- "label";
280
- justify-items: center;
281
- row-gap: 6px;
282
- text-align: center;
283
- }
284
- // Seven bars on a 320px phone leave about 40px a column, so "18 of 25" may wrap here.
285
- .wui-bar-chart-vertical .wui-bar-chart-value {
286
- grid-area: value;
287
- white-space: normal;
288
- }
289
- .wui-bar-chart-vertical .wui-bar-chart-track {
290
- grid-area: track;
291
- display: flex;
292
- align-items: flex-end;
293
- width: 100%;
294
- max-width: 32px;
295
- height: var(--wui-bar-chart-height, 180px);
296
- border-radius: var(--radius-sm);
297
- }
298
- .wui-bar-chart-vertical .wui-bar-chart-fill {
299
- width: 100%;
300
- transition: height 300ms var(--wui-ease-out-quart);
301
- }
302
- .wui-bar-chart-vertical .wui-bar-chart-label {
303
- grid-area: label;
304
- font-size: 11px;
305
- }
3
+ // Part of the wui-components layer; see _wui-components.scss for the load order. The element draws
4
+ // series in the --wui-chart-* colours. Every colour is a token the dark remap in _wui-aliases.scss
5
+ // flips with the rest of the portal.
306
6
 
307
7
  // ============================================================================
308
8
  // Chart element: <wui-chart> (AppChart, <app-chart>)
309
9
  // ============================================================================
310
10
  // The element builds the legend, the drawing surface, the state box and the data table; the
311
- // engine draws inside .wui-chart-canvas with colours the element reads from --wui-chart-*. The
312
- // names here stay clear of the line and bar chart classes above.
11
+ // engine draws inside .wui-chart-canvas with colours the element reads from --wui-chart-*.
313
12
  wui-chart {
314
13
  position: relative;
315
14
  display: block;
@@ -513,9 +212,6 @@ wui-chart[aria-busy="true"] .wui-chart-surface {
513
212
  }
514
213
 
515
214
  @media (prefers-reduced-motion: reduce) {
516
- .wui-chart-dot,
517
- .wui-chart-tip,
518
- .wui-bar-chart-fill,
519
215
  .wui-chart-legend-item,
520
216
  .wui-chart-legend-swatch,
521
217
  .wui-chart-surface {
@@ -0,0 +1,82 @@
1
+ // ── Assistant chat ──
2
+ // <wui-chat> / <app-chat>: a launcher pinned to a bottom corner and a side panel holding the
3
+ // conversation and the question box. The header, buttons, form field and alerts inside are the
4
+ // theme's own (.drawer-header, .btn, .form-control, .alert); only the placement and the two chat
5
+ // shapes live here. A compact launcher is the shared .wui-floating-btn circle (_floating.scss).
6
+ //
7
+ // Part of the wui-components layer — see _wui-components.scss for load order.
8
+
9
+ // The element is a plain host: its two parts are fixed to the viewport.
10
+ wui-chat {
11
+ display: contents;
12
+ }
13
+
14
+ .wui-chat-launcher {
15
+ position: fixed;
16
+ bottom: 0;
17
+ inset-inline-end: 0;
18
+ z-index: var(--wui-z-fixed);
19
+ margin: 1rem;
20
+ }
21
+ wui-chat[position="start"] .wui-chat-launcher {
22
+ inset-inline-end: auto;
23
+ inset-inline-start: 0;
24
+ }
25
+
26
+ // Above the shell chrome and below modals, like the drawer it stands in for.
27
+ .wui-chat-panel {
28
+ position: fixed;
29
+ top: 0;
30
+ bottom: 0;
31
+ inset-inline-end: 0;
32
+ z-index: var(--wui-z-shell-drawer);
33
+ display: flex;
34
+ flex-direction: column;
35
+ width: min(440px, 100%);
36
+ background: var(--color-surface);
37
+ border-inline-start: 1px solid var(--color-border);
38
+ box-shadow: var(--wui-shadow-overlay-lg);
39
+ }
40
+ wui-chat[position="start"] .wui-chat-panel {
41
+ inset-inline-end: auto;
42
+ inset-inline-start: 0;
43
+ border-inline-start: 0;
44
+ border-inline-end: 1px solid var(--color-border);
45
+ }
46
+ // `hidden` is how the element closes the panel; display: flex above would otherwise win over it.
47
+ .wui-chat-panel[hidden] {
48
+ display: none;
49
+ }
50
+
51
+ .wui-chat-body {
52
+ flex: 1 1 auto;
53
+ min-height: 0;
54
+ padding: 20px;
55
+ overflow-y: auto;
56
+ }
57
+ .wui-chat-empty {
58
+ padding-block: 2rem;
59
+ }
60
+ .wui-chat-foot {
61
+ flex: none;
62
+ padding: 16px 20px;
63
+ border-top: 1px solid var(--color-border);
64
+ }
65
+
66
+ // The person's question, on the right; the answer is plain text on the panel.
67
+ .wui-chat-question {
68
+ max-width: 85%;
69
+ }
70
+ .wui-chat-bubble {
71
+ padding: 10px 14px;
72
+ background: var(--color-bg-muted);
73
+ border-radius: var(--wui-radius-lg);
74
+ white-space: pre-wrap;
75
+ overflow-wrap: anywhere;
76
+ }
77
+
78
+ // The question box grows with its text, up to a few lines.
79
+ .wui-chat-foot .form-control {
80
+ max-height: 9rem;
81
+ resize: none;
82
+ }
@@ -0,0 +1,64 @@
1
+ // ── Floating stack ──
2
+ // The one fixed corner container the compact floating buttons (the chat launcher, the report-an-issue
3
+ // button) portal into, so they stack with a gap and never overlap or need a hand-set offset. React's
4
+ // useFloatingStack creates it; the items inside are not fixed themselves.
5
+ //
6
+ // Part of the wui-components layer — see _wui-components.scss for load order.
7
+
8
+ .wui-floating-stack {
9
+ position: fixed;
10
+ bottom: 0;
11
+ z-index: var(--wui-z-fixed);
12
+ display: flex;
13
+ // The primary item sits in the corner and the secondary one stacks above it.
14
+ flex-direction: column-reverse;
15
+ gap: 12px;
16
+ margin: 1rem;
17
+ // The container spans only its items, but a gap between them must not swallow clicks on the page.
18
+ pointer-events: none;
19
+ }
20
+ .wui-floating-stack[data-position="end"] {
21
+ inset-inline-end: 0;
22
+ align-items: flex-end;
23
+ }
24
+ .wui-floating-stack[data-position="start"] {
25
+ inset-inline-start: 0;
26
+ align-items: flex-start;
27
+ }
28
+ .wui-floating-stack-item {
29
+ display: inline-flex;
30
+ pointer-events: auto;
31
+ }
32
+ .wui-floating-stack-item--primary {
33
+ order: 0;
34
+ }
35
+ .wui-floating-stack-item--secondary {
36
+ order: 1;
37
+ }
38
+
39
+ // ── Compact floating button ──
40
+ // An icon-only circle. The label lives in the tooltip and the aria-label, never on the button.
41
+ .wui-floating-btn {
42
+ --wui-floating-size: 48px;
43
+
44
+ display: inline-flex;
45
+ align-items: center;
46
+ justify-content: center;
47
+ width: var(--wui-floating-size);
48
+ height: var(--wui-floating-size);
49
+ padding: 0;
50
+ border-radius: 50%;
51
+ box-shadow: var(--wui-shadow-overlay);
52
+ }
53
+ // Quieter than the primary circle: a light brand tint, the brand icon and a thin brand border.
54
+ .wui-floating-btn--secondary {
55
+ --wui-floating-size: 40px;
56
+ --bs-btn-border-color: var(--wui-primary-30);
57
+ --bs-btn-hover-border-color: var(--wui-primary-30);
58
+ --bs-btn-active-border-color: var(--wui-primary-30);
59
+ }
60
+ @media (prefers-reduced-motion: reduce) {
61
+ .wui-floating-btn {
62
+ transition: none;
63
+ }
64
+ }
@@ -5,7 +5,8 @@
5
5
  // classes, so a React re-render never wipes it.
6
6
  //
7
7
  // Below md the board is one column per screen: a scroll-snapped strip with a column switcher
8
- // above it. The board scrolls inside itself, so the page never scrolls sideways.
8
+ // above it that stays at the top of the viewport while the page scrolls. The board scrolls inside
9
+ // itself, so the page never scrolls sideways.
9
10
  //
10
11
  // Sizing variables, set on .wui-kanban (or any ancestor) to override:
11
12
  // --wui-kanban-column-width basis width of an open column (288px)
@@ -13,6 +14,8 @@
13
14
  // --wui-kanban-gap space between columns (16px)
14
15
  // --wui-kanban-column-min-height least height of a column, so short columns still read as
15
16
  // lanes (560px; not applied in the phone one-column mode)
17
+ // --wui-kanban-sticky-top where the phone switcher sticks (0, or under the app shell's
18
+ // topbar inside .app-shell)
16
19
  //
17
20
  // Part of the wui-components layer, see _wui-components.scss for load order.
18
21
 
@@ -21,11 +24,18 @@
21
24
  --wui-kanban-collapsed-width: 56px;
22
25
  --wui-kanban-gap: 16px;
23
26
  --wui-kanban-column-min-height: 560px;
27
+ --wui-kanban-sticky-top: 0px;
24
28
  display: block;
25
29
  position: relative;
26
30
  min-width: 0;
27
31
  max-width: 100%;
28
32
  }
33
+ // The shell's topbar is sticky too, so the switcher stops below it. 72px is .app-topbar's
34
+ // min-height in _shell.scss; change both together. :where() keeps this at .wui-kanban's own
35
+ // weight, so a page's `.wui-kanban { --wui-kanban-sticky-top: … }` still wins inside the shell.
36
+ :where(.app-shell) .wui-kanban {
37
+ --wui-kanban-sticky-top: 72px;
38
+ }
29
39
 
30
40
  .wui-kanban-board {
31
41
  display: flex;
@@ -210,9 +220,42 @@
210
220
  outline: 2px solid var(--color-primary);
211
221
  outline-offset: 2px;
212
222
  }
213
- .wui-kanban-card[hidden] {
223
+ .wui-kanban-card[hidden],
224
+ .wui-kanban-card[data-wui-overflow] {
225
+ display: none;
226
+ }
227
+
228
+ // "Show N more" under a capped column's cards; "Show fewer" once it is open.
229
+ .wui-kanban-more {
230
+ display: block;
231
+ width: calc(100% - 16px);
232
+ min-height: 36px;
233
+ margin: 0 8px 8px;
234
+ padding: 6px 10px;
235
+ border: 0;
236
+ border-radius: var(--wui-radius);
237
+ background: transparent;
238
+ color: var(--color-text-muted);
239
+ font-size: 0.8125rem;
240
+ font-weight: 600;
241
+ cursor: pointer;
242
+ }
243
+ .wui-kanban-more[hidden] {
214
244
  display: none;
215
245
  }
246
+ .wui-kanban-more:hover {
247
+ background: var(--color-surface);
248
+ color: var(--color-text);
249
+ }
250
+ .wui-kanban-more:focus-visible {
251
+ outline: 2px solid var(--color-primary);
252
+ outline-offset: 2px;
253
+ }
254
+ @media (pointer: coarse) {
255
+ .wui-kanban-more {
256
+ min-height: 44px;
257
+ }
258
+ }
216
259
  .wui-kanban[readonly] .wui-kanban-card,
217
260
  .wui-kanban-card[data-wui-locked] {
218
261
  cursor: default;
@@ -354,6 +397,7 @@
354
397
  }
355
398
  .wui-kanban-summary,
356
399
  .wui-kanban-body,
400
+ .wui-kanban-more,
357
401
  .wui-kanban-empty {
358
402
  display: none;
359
403
  }
@@ -365,18 +409,34 @@
365
409
  }
366
410
  }
367
411
 
368
- // ── Phone column switcher (hidden from md up) ──
369
- .wui-kanban-switcher {
412
+ // ── Phone column switcher and swipe hint (hidden from md up) ──
413
+ .wui-kanban-switcher,
414
+ .wui-kanban-hint {
370
415
  display: none;
371
416
  }
372
417
 
373
418
  @media (max-width: 767.98px) {
419
+ // Sticky over the page's own background, under the shell topbar (z-index 10).
374
420
  .wui-kanban-switcher {
421
+ position: sticky;
422
+ top: var(--wui-kanban-sticky-top);
423
+ z-index: 5;
375
424
  display: flex;
376
425
  gap: 6px;
377
426
  margin-bottom: 12px;
427
+ padding-block: 6px;
378
428
  overflow-x: auto;
379
429
  scrollbar-width: none;
430
+ background: var(--color-bg);
431
+ }
432
+ .wui-kanban-hint {
433
+ display: flex;
434
+ align-items: center;
435
+ justify-content: center;
436
+ gap: 6px;
437
+ margin: -6px 0 12px;
438
+ color: var(--color-text-muted);
439
+ font-size: 0.75rem;
380
440
  }
381
441
  .wui-kanban-switch {
382
442
  display: inline-flex;
@@ -443,6 +503,9 @@
443
503
  .wui-kanban-body {
444
504
  display: flex;
445
505
  }
506
+ .wui-kanban-more:not([hidden]) {
507
+ display: block;
508
+ }
446
509
  .wui-kanban-empty:not([hidden]) {
447
510
  display: block;
448
511
  }
@@ -867,6 +867,18 @@
867
867
  .file-preview[aria-busy="true"] {
868
868
  cursor: progress;
869
869
  }
870
+ // A disabled drop zone (AppDropZone `disabled`): dimmed, no pointer affordance, and no hover lift.
871
+ .file-input[aria-disabled="true"] {
872
+ opacity: 0.6;
873
+ cursor: not-allowed;
874
+ }
875
+ .file-input[aria-disabled="true"] > .file-input-zone-label {
876
+ cursor: not-allowed;
877
+ }
878
+ .file-input.file-input-tall[aria-disabled="true"]:hover:not(:focus-within):not(.dragging) {
879
+ background: var(--color-bg-muted);
880
+ border-color: var(--color-border);
881
+ }
870
882
  .wui-file-busy {
871
883
  position: absolute;
872
884
  inset: 0;
@@ -351,6 +351,12 @@
351
351
  padding-top: 12px;
352
352
  border-top: 1px solid var(--color-border);
353
353
  }
354
+ // A node the author places right after a group's links (`groups[].after` /
355
+ // `<app-nav-group-after>`). Like sidebarStart it has no place on the 88px rail.
356
+ .wui-nav-group-after {
357
+ flex: none;
358
+ margin-top: 4px;
359
+ }
354
360
  .app-nav-group-label {
355
361
  padding: 6px 14px;
356
362
  font-size: 12px;
@@ -439,6 +445,7 @@
439
445
  }
440
446
  .app-shell.collapsed .app-nav-badge,
441
447
  .app-shell.collapsed .app-nav-group-label,
448
+ .app-shell.collapsed .wui-nav-group-after,
442
449
  .app-shell.collapsed .app-sidebar-brand-text,
443
450
  .app-shell.collapsed .app-sidebar-start {
444
451
  display: none;
@@ -756,6 +763,7 @@
756
763
  .app-shell.app-shell.collapsed .app-nav-text,
757
764
  .app-shell.app-shell.collapsed .app-nav-badge,
758
765
  .app-shell.app-shell.collapsed .app-nav-group-label,
766
+ .app-shell.app-shell.collapsed .wui-nav-group-after,
759
767
  .app-shell.app-shell.collapsed .app-sidebar-start {
760
768
  display: revert;
761
769
  }