@capillaryjs/capillary-ui 1.2.0 → 1.4.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 (92) hide show
  1. package/CHANGELOG.md +152 -16
  2. package/README.md +177 -35
  3. package/colors/README.md +53 -3
  4. package/colors/gray/colors.css +4 -2
  5. package/colors/green/colors.css +4 -2
  6. package/colors/iceblue/colors.css +4 -2
  7. package/colors/ocean/colors.css +4 -2
  8. package/colors/orange/colors.css +4 -2
  9. package/colors/purple/colors.css +4 -2
  10. package/colors/red/colors.css +7 -3
  11. package/colors/yellow/colors.css +8 -4
  12. package/dist/Components/app/app.d.ts +3 -3
  13. package/dist/Components/app/app.d.ts.map +1 -1
  14. package/dist/Components/component.d.ts +13 -2
  15. package/dist/Components/component.d.ts.map +1 -1
  16. package/dist/Components/data/descriptionList.d.ts.map +1 -1
  17. package/dist/Components/data/listview/listview.d.ts.map +1 -1
  18. package/dist/Components/data/table/DataTable.d.ts +8 -0
  19. package/dist/Components/data/table/DataTable.d.ts.map +1 -1
  20. package/dist/Components/data/table/FilterPanel.d.ts.map +1 -1
  21. package/dist/Components/data/table/TableHeader.d.ts +2 -0
  22. package/dist/Components/data/table/TableHeader.d.ts.map +1 -1
  23. package/dist/Components/data/table/TableHeaderCell.d.ts +17 -0
  24. package/dist/Components/data/table/TableHeaderCell.d.ts.map +1 -1
  25. package/dist/Components/data/table/tableDataSource.d.ts +6 -0
  26. package/dist/Components/data/table/tableDataSource.d.ts.map +1 -1
  27. package/dist/Components/data/treeview/treeview.d.ts.map +1 -1
  28. package/dist/Components/layout/groupBox.d.ts.map +1 -1
  29. package/dist/Components/layout/header.d.ts.map +1 -1
  30. package/dist/Components/layout/layout.d.ts +2 -2
  31. package/dist/Components/layout/layout.d.ts.map +1 -1
  32. package/dist/Components/layout/layoutTraits.d.ts +6 -0
  33. package/dist/Components/layout/layoutTraits.d.ts.map +1 -1
  34. package/dist/Components/layout/optionGroup.d.ts.map +1 -1
  35. package/dist/Components/layout/optionsBox.d.ts +2 -1
  36. package/dist/Components/layout/optionsBox.d.ts.map +1 -1
  37. package/dist/Components/layout/splitView.d.ts +2 -0
  38. package/dist/Components/layout/splitView.d.ts.map +1 -1
  39. package/dist/Components/lineinputs/CheckableControl.d.ts +2 -2
  40. package/dist/Components/lineinputs/CheckableControl.d.ts.map +1 -1
  41. package/dist/Components/lineinputs/LabeledInputControl.d.ts +2 -2
  42. package/dist/Components/lineinputs/LabeledInputControl.d.ts.map +1 -1
  43. package/dist/Components/lineinputs/LineControl.d.ts +7 -0
  44. package/dist/Components/lineinputs/LineControl.d.ts.map +1 -0
  45. package/dist/Components/lineinputs/SelectControl.d.ts.map +1 -1
  46. package/dist/Components/lineinputs/checkbox/Checkbox.d.ts +9 -3
  47. package/dist/Components/lineinputs/checkbox/Checkbox.d.ts.map +1 -1
  48. package/dist/Components/lineinputs/checkbox/QuadCheckbox.d.ts +1 -0
  49. package/dist/Components/lineinputs/checkbox/QuadCheckbox.d.ts.map +1 -1
  50. package/dist/Components/lineinputs/checkbox/TriCheckbox.d.ts +1 -0
  51. package/dist/Components/lineinputs/checkbox/TriCheckbox.d.ts.map +1 -1
  52. package/dist/Components/lineinputs/datetime/TemporalInput.d.ts.map +1 -1
  53. package/dist/Components/lineinputs/dropdown.d.ts +4 -2
  54. package/dist/Components/lineinputs/dropdown.d.ts.map +1 -1
  55. package/dist/Components/lineinputs/radio.d.ts +9 -4
  56. package/dist/Components/lineinputs/radio.d.ts.map +1 -1
  57. package/dist/Components/lineinputs/requiredPresentation.d.ts +21 -0
  58. package/dist/Components/lineinputs/requiredPresentation.d.ts.map +1 -0
  59. package/dist/Components/lineinputs/textbox.d.ts.map +1 -1
  60. package/dist/Components/lineinputs/toggle.d.ts +4 -2
  61. package/dist/Components/lineinputs/toggle.d.ts.map +1 -1
  62. package/dist/Components/menu/button.d.ts +2 -2
  63. package/dist/Components/menu/button.d.ts.map +1 -1
  64. package/dist/Components/status/progressBar.d.ts +2 -2
  65. package/dist/Components/status/progressBar.d.ts.map +1 -1
  66. package/dist/Components/status/statusPresentation.d.ts.map +1 -1
  67. package/dist/Components/theme/stylesheetPicker.d.ts +2 -1
  68. package/dist/Components/theme/stylesheetPicker.d.ts.map +1 -1
  69. package/dist/index.d.ts +1 -1
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +2750 -2084
  72. package/dist/index.js.map +1 -1
  73. package/dist/jsx-dev-runtime.js +1 -1
  74. package/dist/{jsx-runtime-BD_q3rPg.js → jsx-runtime-Ba-uafjl.js} +595 -475
  75. package/dist/jsx-runtime-Ba-uafjl.js.map +1 -0
  76. package/dist/jsx-runtime.js +1 -1
  77. package/dist/localization.d.ts +1 -1
  78. package/dist/localization.d.ts.map +1 -1
  79. package/dist/routing/RouteOutlet.d.ts.map +1 -1
  80. package/dist/styling/theme.d.ts +1 -1
  81. package/dist/styling/theme.d.ts.map +1 -1
  82. package/docs/application-composition-guide.md +22 -5
  83. package/package.json +3 -3
  84. package/styles/structural.css +756 -161
  85. package/themes/README.md +9 -2
  86. package/themes/base.css +114 -18
  87. package/themes/capillary/theme.css +300 -0
  88. package/themes/shiny/theme.css +35 -21
  89. package/themes/soft/theme.css +37 -0
  90. package/themes/white/theme.css +52 -0
  91. package/dist/jsx-runtime-BD_q3rPg.js.map +0 -1
  92. package/themes/java/theme.css +0 -21
@@ -30,6 +30,7 @@
30
30
  align-items: stretch;
31
31
  min-inline-size: 0;
32
32
  min-block-size: 0;
33
+ gap: calc(var(--_cap-island-flow, 0) * var(--island-gap, 0px));
33
34
  }
34
35
 
35
36
  .cap-layout-horizontal {
@@ -51,11 +52,55 @@
51
52
  }
52
53
 
53
54
  .cap-scroll {
55
+ /* Move the clip into the surrounding gutter without moving the
56
+ * content. The inherited allowance is owned by the parent layout,
57
+ * so local gaps and nested scrollports do not add extra spacing. */
58
+ --_cap-scroll-gutter: calc(var(--_cap-island-flow, 0) * var(--_cap-island-gutter, 0px));
59
+ margin: calc(-1 * var(--_cap-scroll-gutter));
60
+ padding: var(--_cap-scroll-gutter);
54
61
  overflow: auto;
55
62
  min-inline-size: 0;
56
63
  min-block-size: 0;
57
64
  }
58
65
 
66
+ /* The mode crosses wrappers; each layout resolves its own public gap.
67
+ * Only the first enabled scope contributes a perimeter inset. */
68
+ .cap-island-layout {
69
+ --_cap-island-flow: 1;
70
+ --_cap-island-margin: 0px;
71
+ --_cap-island-separator-background: transparent;
72
+ box-sizing: border-box;
73
+ padding: var(--_cap-island-outer-inset, var(--island-inset, 0px));
74
+ gap: calc(var(--_cap-island-flow, 0) * var(--island-gap, 0px));
75
+ }
76
+
77
+ .cap-island-layout > * {
78
+ --_cap-island-outer-inset: 0px;
79
+ }
80
+
81
+ .cap-layout-horizontal > *,
82
+ .cap-layout-vertical > *,
83
+ .cap-island-layout > * {
84
+ --_cap-island-gutter: calc(var(--_cap-island-flow, 0) * var(--island-gap, 0px) / 2);
85
+ }
86
+
87
+ .cap-island-layout.cap-scroll {
88
+ padding: calc(var(--_cap-island-outer-inset, var(--island-inset, 0px))
89
+ + var(--_cap-scroll-gutter));
90
+ }
91
+
92
+ .cap-island-layout-off {
93
+ --_cap-island-flow: 0;
94
+ --_cap-island-margin: initial;
95
+ --_cap-island-separator-background: initial;
96
+ }
97
+
98
+ .cap-island-layout-off > *,
99
+ .island > * {
100
+ --_cap-island-outer-inset: initial;
101
+ --_cap-island-gutter: 0px;
102
+ }
103
+
59
104
  .colored {
60
105
  --colored-base-bg:
61
106
  linear-gradient(
@@ -73,10 +118,12 @@
73
118
 
74
119
  .app-footer.island,
75
120
  .island {
121
+ --_cap-island-flow: 0;
122
+ --_cap-island-separator-background: initial;
76
123
  box-sizing: border-box;
77
124
  min-width: 0;
78
125
  min-height: 0;
79
- margin: var(--island-margin);
126
+ margin: var(--_cap-island-margin, var(--island-margin));
80
127
  padding: var(--island-padding);
81
128
  background: var(--island-background);
82
129
  border: var(--island-border);
@@ -86,13 +133,13 @@
86
133
 
87
134
  .cap-fill-horizontal.island,
88
135
  .cap-fill-horizontal .island {
89
- max-width: calc(100% - (2 * var(--island-margin)));
136
+ max-width: calc(100% - (2 * var(--_cap-island-margin, var(--island-margin))));
90
137
  overflow-x: auto;
91
138
  }
92
139
 
93
140
  .cap-fill-vertical.island,
94
141
  .cap-fill-vertical .island {
95
- max-height: calc(100% - (2 * var(--island-margin)));
142
+ max-height: calc(100% - (2 * var(--_cap-island-margin, var(--island-margin))));
96
143
  overflow-y: auto;
97
144
  }
98
145
 
@@ -144,17 +191,40 @@ cap-breadcrumb {
144
191
  font-weight: var(--breadcrumb-current-font-weight, 600);
145
192
  }
146
193
 
194
+ cap-button,
195
+ cap-checkbox,
196
+ cap-dropdown,
197
+ cap-datepicker,
198
+ cap-datetimepicker,
199
+ cap-progressbar,
200
+ cap-quadcheckbox,
201
+ cap-radiobutton,
202
+ cap-textbox,
203
+ cap-timepicker,
204
+ cap-toggle,
205
+ cap-tricheckbox {
206
+ --_cap-control-row-min: var(--_cap-control-compact-min,
207
+ max(var(--control-min-height, 2em), var(--control-row-min-height, 0px)));
208
+ min-height: calc(var(--_cap-control-row-min)
209
+ + 2 * var(--control-row-padding-block, .25em));
210
+ padding-block: var(--control-row-padding-block, .25em);
211
+ box-sizing: border-box;
212
+ font-family: inherit;
213
+ font-size: var(--ui-font-size);
214
+ line-height: 1.2;
215
+ }
216
+
147
217
  cap-button > button {
148
218
  display: inline-flex;
149
219
  align-items: center;
150
220
  justify-content: center;
151
221
  min-height: var(--control-min-height, 2em);
152
222
  margin: 0;
153
- padding: 0 5px;
223
+ padding: var(--ui-control-padding);
154
224
  color: var(--button-color);
155
225
  background: var(--button-background);
156
226
  border: var(--button-border);
157
- border-radius: var(--radius-md);
227
+ border-radius: var(--ui-border-radius);
158
228
  box-shadow: var(--button-shadow);
159
229
  box-sizing: border-box;
160
230
  cursor: default;
@@ -169,9 +239,6 @@ cap-button > button {
169
239
  flex-flow: row wrap;
170
240
  align-items: center;
171
241
  align-content: center;
172
- font-family: inherit;
173
- font-size: var(--ui-font-size);
174
- line-height: 1.2;
175
242
  }
176
243
 
177
244
  cap-button > button:hover:not(:disabled, [aria-disabled="true"]) {
@@ -190,8 +257,8 @@ cap-button > button {
190
257
  box-shadow: var(--focus-ring);
191
258
  }
192
259
 
193
- cap-button > button:disabled,
194
- cap-button > button[aria-disabled="true"] {
260
+ cap-button > button:disabled:not([aria-busy="true"]),
261
+ cap-button > button[aria-disabled="true"]:not([aria-busy="true"]) {
195
262
  color: var(--input-color-disabled);
196
263
  background: var(--button-background-disabled);
197
264
  border-color: var(--button-border-disabled);
@@ -200,14 +267,17 @@ cap-button > button {
200
267
  }
201
268
 
202
269
  cap-button > button[aria-busy="true"]:not([aria-invalid="true"]) {
203
- background: var(--working-background-image), var(--button-background-disabled);
270
+ /* Busy is unavailable for activation, but remains a normal button
271
+ * surface with the loading texture layered on top. */
272
+ background: var(--working-background-image), var(--button-background);
204
273
  background-repeat: repeat, no-repeat;
205
274
  background-size: 2rem 2rem, 100% 100%;
206
275
  animation: cap-working-progress .55s linear infinite;
207
276
  }
208
277
 
209
278
  cap-button > button[aria-invalid="true"] {
210
- border-color: var(--error-color);
279
+ border-color: var(--error-control-border);
280
+ box-shadow: var(--error-control-shadow);
211
281
  }
212
282
 
213
283
  @media (prefers-reduced-motion: reduce) {
@@ -226,8 +296,8 @@ cap-button > button {
226
296
  cap-error {
227
297
  position: absolute;
228
298
  z-index: 1200;
229
- inset-block-start: -.35em;
230
- inset-inline-end: -.35em;
299
+ inset-block-start: -.5rem;
300
+ inset-inline-end: -.5rem;
231
301
  display: block;
232
302
  width: 1.25em;
233
303
  height: 1.25em;
@@ -241,18 +311,20 @@ cap-error {
241
311
 
242
312
  cap-error > cap-erroricon {
243
313
  position: absolute;
244
- inset: 0;
245
- display: grid;
246
- width: 1.25em;
247
- height: 1.25em;
314
+ display: flex;
315
+ width: 1rem;
316
+ height: 1rem;
317
+ font-size: .9rem;
248
318
  color: var(--error-contrast);
249
319
  background: var(--error-color);
250
- border: 1px solid var(--error-color);
320
+ border: var(--error-icon-border);
251
321
  border-radius: 50%;
322
+ box-shadow: var(--error-icon-shadow);
252
323
  box-sizing: border-box;
253
- font-weight: 700;
254
- line-height: 1;
255
- place-items: center;
324
+ font-weight: bold;
325
+ justify-content: center;
326
+ align-items: center;
327
+
256
328
  }
257
329
 
258
330
  cap-error > cap-erroricon::before {
@@ -271,8 +343,8 @@ cap-error {
271
343
  padding: var(--space-xs) var(--space-sm);
272
344
  color: var(--ui-color);
273
345
  background: var(--error-bg-neutral, var(--application-background));
274
- border: 1px solid var(--error-color);
275
- border-radius: var(--radius-md);
346
+ border: 1px solid var(--error-control-border);
347
+ border-radius: var(--ui-border-radius);
276
348
  box-shadow: var(--ui-shadow);
277
349
  opacity: 0;
278
350
  overflow-wrap: anywhere;
@@ -319,9 +391,14 @@ cap-tricheckbox {
319
391
  flex-flow: row wrap;
320
392
  align-items: center;
321
393
  align-content: center;
322
- font-family: inherit;
323
- font-size: var(--ui-font-size);
324
- line-height: 1.2;
394
+ --_cap-checkable-label-color: var(--ui-text-color);
395
+ --_cap-checkable-cursor: pointer;
396
+ --_cap-checkable-box-background: var(--checkbox-box-background,
397
+ var(--ui-input-bg, transparent));
398
+ --_cap-checkable-box-border: var(--checkbox-box-border,
399
+ var(--cbx-o-border, 1px solid currentColor));
400
+ --_cap-checkable-box-shadow: var(--checkbox-box-shadow);
401
+ --_cap-checkable-box-filter: none;
325
402
  }
326
403
 
327
404
  cap-checkbox > label,
@@ -331,14 +408,14 @@ cap-tricheckbox {
331
408
  display: flex;
332
409
  flex-flow: row nowrap;
333
410
  position: relative;
334
- min-height: 1.2em;
411
+ min-height: var(--_cap-control-row-min);
335
412
  margin: 0;
336
- color: var(--ui-text-color);
413
+ color: var(--_cap-checkable-label-color);
337
414
  border-radius: var(--ui-border-radius);
338
415
  box-sizing: border-box;
339
416
  align-items: center;
340
417
  gap: .3em;
341
- cursor: pointer;
418
+ cursor: var(--_cap-checkable-cursor);
342
419
  user-select: none;
343
420
  }
344
421
 
@@ -350,6 +427,18 @@ cap-tricheckbox {
350
427
  cursor: not-allowed;
351
428
  }
352
429
 
430
+ cap-checkbox > label:has(> input[aria-readonly="true"]:not(:disabled)),
431
+ cap-quadcheckbox > label:has(> input[aria-readonly="true"]:not(:disabled)),
432
+ cap-radiobutton > label:has(> input[aria-readonly="true"]:not(:disabled)),
433
+ cap-tricheckbox > label:has(> input[aria-readonly="true"]:not(:disabled)) {
434
+ --_cap-checkable-label-color: var(--checkable-label-color-readonly);
435
+ --_cap-checkable-cursor: default;
436
+ --_cap-checkable-box-background: var(--checkbox-box-background-readonly);
437
+ --_cap-checkable-box-border: var(--checkbox-box-border-readonly);
438
+ --_cap-checkable-box-shadow: var(--checkbox-box-shadow-readonly);
439
+ --_cap-checkable-box-filter: saturate(.78);
440
+ }
441
+
353
442
  cap-checkbox > label > input,
354
443
  cap-quadcheckbox > label > input,
355
444
  cap-radiobutton > label > input,
@@ -372,22 +461,25 @@ cap-tricheckbox {
372
461
  cap-radiobutton > label > input + cap-checkshell,
373
462
  cap-tricheckbox > label > input + cap-checkshell {
374
463
  position: relative;
375
- display: grid;
376
- width: 1em;
377
- height: 1em;
378
- flex: 0 0 1em;
464
+ display: flex;
465
+ align-items: center;
466
+ justify-content: center;
467
+ width: var(--checkbox-box-size, 1em);
468
+ height: var(--checkbox-box-size, 1em);
469
+ flex: 0 0 var(--checkbox-box-size, 1em);
379
470
  box-sizing: border-box;
380
471
  text-align: center;
381
472
  line-height: 1;
382
473
  color: var(--input-color, var(--ui-text-color, currentColor));
383
- background: var(--checkbox-box-background, var(--ui-input-bg, transparent));
384
- border: var(--checkbox-box-border, var(--cbx-o-border, 1px solid currentColor));
385
- border-radius: var(--cbx-border-radius, var(--radius-sm, 0.2rem));
386
- box-shadow: var(--checkbox-box-shadow);
474
+ background: var(--_cap-checkable-box-background);
475
+ border: var(--_cap-checkable-box-border);
476
+ border-radius: var(--checkbox-box-radius,
477
+ var(--cbx-border-radius, var(--radius-sm, 0.2rem)));
478
+ box-shadow: var(--_cap-checkable-box-shadow);
479
+ filter: var(--_cap-checkable-box-filter);
387
480
  font-family: inherit;
388
481
  font-size: 1em;
389
482
  user-select: none;
390
- place-items: center;
391
483
  }
392
484
 
393
485
  cap-checkbox > label > input:checked + cap-checkshell,
@@ -397,9 +489,58 @@ cap-tricheckbox {
397
489
  color: var(--checkbox-symbol-color, var(--selection-color, currentColor));
398
490
  background: var(--checkbox-box-background-checked,
399
491
  var(--selection-background, var(--ui-accent-color, Highlight)));
492
+ border: var(--checkbox-box-border-checked, var(--checkbox-box-border,
493
+ var(--cbx-o-border, 1px solid currentColor)));
400
494
  box-shadow: var(--checkbox-box-shadow-checked);
401
495
  }
402
496
 
497
+
498
+
499
+ cap-checkbox > label:has(> input:required:invalid:not(:disabled):not([aria-invalid="true"]))::before,
500
+ cap-quadcheckbox > label:has(> input:required:invalid:not(:disabled):not([aria-invalid="true"]))::before,
501
+ cap-radiobutton > label:has(> input:required:invalid:not(:disabled):not([aria-invalid="true"]))::before,
502
+ cap-tricheckbox > label:has(> input:required:invalid:not(:disabled):not([aria-invalid="true"]))::before {
503
+ content: "";
504
+ position: absolute;
505
+ z-index: 0;
506
+ inset-block: -4px;
507
+ inset-inline-start: -4px;
508
+ inset-inline-end: calc(-4px - 1em);
509
+ border: 1px dashed var(--required-color);
510
+ border-radius: inherit;
511
+ pointer-events: none;
512
+ }
513
+
514
+
515
+ cap-checkbox > label:has(> input:required:invalid:not(:disabled):not([aria-invalid="true"]))::after,
516
+ cap-quadcheckbox > label:has(> input:required:invalid:not(:disabled):not([aria-invalid="true"]))::after,
517
+ cap-radiobutton > label:has(> input:required:invalid:not(:disabled):not([aria-invalid="true"]))::after,
518
+ cap-tricheckbox > label:has(> input:required:invalid:not(:disabled):not([aria-invalid="true"]))::after {
519
+ content: "✲";
520
+ position: absolute;
521
+ z-index: 1;
522
+ inset-block-start: -.5em;
523
+ inset-inline-end: -1em;
524
+ display: flex;
525
+ inline-size: 1rem;
526
+ block-size: 1rem;
527
+ align-items: center;
528
+ justify-content: center;
529
+ color: var(--required-indicator-color);
530
+ background: var(--required-indicator-background);
531
+ font-size: .75rem;
532
+ font-weight: 700;
533
+ line-height: 1;
534
+ pointer-events: none;
535
+ }
536
+
537
+ cap-checkbox > label:has(> input[aria-invalid="true"]),
538
+ cap-quadcheckbox > label:has(> input[aria-invalid="true"]),
539
+ cap-radiobutton > label:has(> input[aria-invalid="true"]),
540
+ cap-tricheckbox > label:has(> input[aria-invalid="true"]) {
541
+ box-shadow: var(--error-control-shadow);
542
+ }
543
+
403
544
  cap-checkbox > label > input:focus-visible + cap-checkshell,
404
545
  cap-quadcheckbox > label > input:focus-visible + cap-checkshell,
405
546
  cap-radiobutton > label > input:focus-visible + cap-checkshell,
@@ -427,18 +568,12 @@ cap-tricheckbox {
427
568
  animation: cap-working-progress .55s linear infinite;
428
569
  }
429
570
 
430
- cap-checkbox > label:has(> input[aria-invalid="true"]),
431
- cap-quadcheckbox > label:has(> input[aria-invalid="true"]),
432
- cap-radiobutton > label:has(> input[aria-invalid="true"]),
433
- cap-tricheckbox > label:has(> input[aria-invalid="true"]) {
434
- color: var(--error-color);
435
- }
436
-
437
571
  cap-checkbox > label > input[aria-invalid="true"] + cap-checkshell,
438
572
  cap-quadcheckbox > label > input[aria-invalid="true"] + cap-checkshell,
439
573
  cap-radiobutton > label > input[aria-invalid="true"] + cap-checkshell,
440
574
  cap-tricheckbox > label > input[aria-invalid="true"] + cap-checkshell {
441
- border-color: var(--error-color);
575
+ border-color: var(--error-control-border);
576
+ box-shadow: none;
442
577
  }
443
578
 
444
579
  @media (prefers-reduced-motion: reduce) {
@@ -451,31 +586,15 @@ cap-tricheckbox {
451
586
  }
452
587
 
453
588
  @media (forced-colors: active) {
454
- cap-checkbox > label > input[aria-invalid="true"] + cap-checkshell,
455
- cap-quadcheckbox > label > input[aria-invalid="true"] + cap-checkshell,
456
- cap-radiobutton > label > input[aria-invalid="true"] + cap-checkshell,
457
- cap-tricheckbox > label > input[aria-invalid="true"] + cap-checkshell {
589
+ cap-checkbox > label:has(> input[aria-invalid="true"]),
590
+ cap-quadcheckbox > label:has(> input[aria-invalid="true"]),
591
+ cap-radiobutton > label:has(> input[aria-invalid="true"]),
592
+ cap-tricheckbox > label:has(> input[aria-invalid="true"]) {
458
593
  outline: 2px solid Mark;
459
594
  outline-offset: 1px;
460
595
  }
461
596
  }
462
597
 
463
- cap-checkbox > label > input[value="require"] + cap-checkshell,
464
- cap-quadcheckbox > label > input[value="require"] + cap-checkshell,
465
- cap-tricheckbox > label > input[value="require"] + cap-checkshell {
466
- color: var(--palette-contrast-light);
467
- background: var(--palette-green);
468
- box-shadow: var(--checkbox-box-shadow-checked);
469
- }
470
-
471
- cap-checkbox > label > input[value="deny"] + cap-checkshell,
472
- cap-quadcheckbox > label > input[value="deny"] + cap-checkshell,
473
- cap-tricheckbox > label > input[value="deny"] + cap-checkshell {
474
- color: var(--palette-contrast-light);
475
- background: var(--palette-red);
476
- box-shadow: var(--checkbox-box-shadow-checked);
477
- }
478
-
479
598
  cap-dropdown,
480
599
  cap-datepicker,
481
600
  cap-datetimepicker,
@@ -487,15 +606,40 @@ cap-toggle {
487
606
  position: relative;
488
607
  align-items: center;
489
608
  gap: .5em;
490
- min-height: var(--control-min-height, 2em);
491
609
  color: var(--ui-text-color);
492
- font-family: inherit;
493
- font-size: var(--ui-font-size);
494
- line-height: 1.2;
495
- box-sizing: border-box;
496
610
  user-select: none;
497
611
  }
498
612
 
613
+ /* GroupBox owns the ordinary body layout. Labeled controls fill its
614
+ direct body so their label/control row keeps labels left and native
615
+ input surfaces right; an explicitly nested Layout remains supported
616
+ for non-standard arrangements. */
617
+ cap-groupbox > cap-content > cap-dropdown,
618
+ /* GroupBox owns the ordinary body layout. Labeled controls fill its
619
+ direct body so their label/control row keeps labels left and native
620
+ input surfaces right; an explicitly nested Layout remains supported
621
+ for non-standard arrangements. */
622
+ cap-groupbox > cap-content > cap-datepicker,
623
+ /* GroupBox owns the ordinary body layout. Labeled controls fill its
624
+ direct body so their label/control row keeps labels left and native
625
+ input surfaces right; an explicitly nested Layout remains supported
626
+ for non-standard arrangements. */
627
+ cap-groupbox > cap-content > cap-datetimepicker,
628
+ /* GroupBox owns the ordinary body layout. Labeled controls fill its
629
+ direct body so their label/control row keeps labels left and native
630
+ input surfaces right; an explicitly nested Layout remains supported
631
+ for non-standard arrangements. */
632
+ cap-groupbox > cap-content > cap-textbox,
633
+ /* GroupBox owns the ordinary body layout. Labeled controls fill its
634
+ direct body so their label/control row keeps labels left and native
635
+ input surfaces right; an explicitly nested Layout remains supported
636
+ for non-standard arrangements. */
637
+ cap-groupbox > cap-content > cap-timepicker,
638
+ /* GroupBox owns the ordinary body layout. Labeled controls fill its
639
+ direct body so their label/control row keeps labels left and native
640
+ input surfaces right; an explicitly nested Layout remains supported
641
+ for non-standard arrangements. */
642
+ cap-groupbox > cap-content > cap-toggle,
499
643
  cap-groupbox > cap-content > cap-layout > cap-dropdown,
500
644
  cap-groupbox > cap-content > cap-layout > cap-datepicker,
501
645
  cap-groupbox > cap-content > cap-layout > cap-datetimepicker,
@@ -547,12 +691,12 @@ cap-dropdown {
547
691
  max-width: 100%;
548
692
  min-width: var(--input-min-width, 6rem);
549
693
  margin: 0;
550
- padding: 0 5px;
694
+ padding: var(--ui-control-padding);
551
695
  padding-inline-end: var(--dropdown-padding-inline-end);
552
696
  color: var(--input-color);
553
697
  background: var(--dropdown-select-background);
554
698
  border: var(--dropdown-select-border);
555
- border-radius: var(--radius-md);
699
+ border-radius: var(--ui-border-radius);
556
700
  box-shadow: var(--dropdown-select-shadow);
557
701
  box-sizing: border-box;
558
702
  font: inherit;
@@ -562,6 +706,11 @@ cap-dropdown {
562
706
  white-space: nowrap;
563
707
  }
564
708
 
709
+ cap-dropdown > cap-selectshell > select[aria-readonly="true"]:not(:disabled) {
710
+ color: var(--input-color-readonly);
711
+ cursor: default;
712
+ }
713
+
565
714
  cap-dropdown > cap-selectshell::after {
566
715
  content: var(--dropdown-underlay-content);
567
716
  position: absolute;
@@ -583,9 +732,10 @@ cap-dropdown {
583
732
  z-index: 2;
584
733
  inset-block: 0;
585
734
  inset-inline-end: 0;
586
- display: grid;
735
+ display: flex;
736
+ align-items: center;
737
+ justify-content: center;
587
738
  inline-size: var(--dropdown-trigger-width);
588
- place-items: center;
589
739
  color: var(--dropdown-trigger-color);
590
740
  background: var(--dropdown-trigger-background);
591
741
  border: var(--dropdown-trigger-border);
@@ -597,7 +747,7 @@ cap-dropdown {
597
747
  pointer-events: none;
598
748
  }
599
749
 
600
- cap-dropdown > cap-selectshell:has(> select:hover:not(:disabled))::before {
750
+ cap-dropdown > cap-selectshell:has(> select:hover:not(:disabled):not([aria-readonly="true"]))::before {
601
751
  background: var(--dropdown-trigger-background-hover);
602
752
  box-shadow: var(--dropdown-trigger-shadow-hover);
603
753
  }
@@ -613,6 +763,46 @@ cap-dropdown {
613
763
  border: var(--dropdown-underlay-border-disabled);
614
764
  }
615
765
 
766
+ cap-dropdown > cap-selectshell:has(> select[aria-readonly="true"]:not(:disabled))::before {
767
+ color: var(--dropdown-trigger-color-readonly);
768
+ background: var(--dropdown-trigger-background-readonly);
769
+ border: var(--dropdown-trigger-border-readonly);
770
+ box-shadow: var(--dropdown-trigger-shadow-readonly);
771
+ }
772
+
773
+ cap-dropdown > cap-selectshell:has(> select[aria-readonly="true"]:not(:disabled))::after {
774
+ background: var(--dropdown-underlay-background-readonly);
775
+ border: var(--dropdown-underlay-border-readonly);
776
+ box-shadow: var(--dropdown-underlay-shadow-readonly);
777
+ }
778
+
779
+
780
+
781
+ cap-dropdown > cap-selectshell:has(> select:required:invalid:not(:disabled):not([aria-invalid="true"])) {
782
+ outline: 1px dashed var(--required-color);
783
+ outline-offset: 3px;
784
+ }
785
+
786
+
787
+ cap-dropdown:has(> cap-selectshell > select:required:invalid:not(:disabled):not([aria-invalid="true"]))::after {
788
+ content: "✲";
789
+ position: absolute;
790
+ z-index: 3;
791
+ inset-block-start: max(calc(var(--control-row-padding-block, .25em) + .15em), .3em);
792
+ inset-inline-end: calc(var(--dropdown-trigger-width) + .5em);
793
+ display: flex;
794
+ inline-size: 1rem;
795
+ block-size: 1rem;
796
+ align-items: center;
797
+ justify-content: center;
798
+ color: var(--required-indicator-color);
799
+ background: var(--required-indicator-background);
800
+ font-size: .75rem;
801
+ font-weight: 700;
802
+ line-height: 1;
803
+ pointer-events: none;
804
+ }
805
+
616
806
  cap-dropdown > cap-selectshell > select:focus-visible {
617
807
  outline: 2px solid transparent;
618
808
  outline-offset: 1px;
@@ -633,10 +823,21 @@ cap-dropdown {
633
823
  animation: cap-working-progress .55s linear infinite;
634
824
  }
635
825
 
826
+ cap-dropdown > cap-selectshell:has(> select[aria-readonly="true"][aria-busy="true"]:not([aria-invalid="true"]))::after {
827
+ background: var(--working-background-image), var(--dropdown-underlay-background-readonly);
828
+ background-repeat: repeat, no-repeat;
829
+ background-size: 2rem 2rem, 100% 100%;
830
+ }
831
+
636
832
  cap-dropdown > cap-selectshell:has(> select[aria-invalid="true"])::before,
637
833
  cap-dropdown > cap-selectshell:has(> select[aria-invalid="true"])::after,
638
834
  cap-dropdown > cap-selectshell > select[aria-invalid="true"] {
639
- border-color: var(--error-color);
835
+ border-color: var(--error-control-border);
836
+ }
837
+
838
+ cap-dropdown > cap-selectshell:has(> select[aria-invalid="true"]) {
839
+ border-radius: var(--ui-border-radius);
840
+ box-shadow: var(--error-control-shadow);
640
841
  }
641
842
 
642
843
  @media (prefers-reduced-motion: reduce) {
@@ -678,10 +879,28 @@ cap-datatable {
678
879
  }
679
880
 
680
881
  cap-datatable > table {
681
- border-collapse: collapse;
882
+ /* Collapsed borders belong to the table paint layer, so they can
883
+ * disappear behind scrolling rows even though the header cells are
884
+ * sticky. Keep zero visual spacing while letting each sticky cell
885
+ * retain its own header-edge and column-divider chrome. */
886
+ border-collapse: separate;
887
+ border-spacing: 0;
682
888
  width: 100%;
683
889
  }
684
890
 
891
+ cap-datatable[data-cap-retained-loading]::after {
892
+ content: "";
893
+ position: absolute;
894
+ z-index: 3;
895
+ inset: 0;
896
+ opacity: 0.33;
897
+ animation: cap-working-progress .55s linear infinite;
898
+ background-image: var(--working-background-image);
899
+ background-repeat: repeat;
900
+ background-size: 2rem 2rem;
901
+ pointer-events: none;
902
+ }
903
+
685
904
  cap-datatable thead:has([aria-expanded="true"]) {
686
905
  position: relative;
687
906
  z-index: 1100;
@@ -741,6 +960,16 @@ cap-datatable {
741
960
  cap-datatable:has(> cap-error) {
742
961
  outline: 2px solid Mark;
743
962
  }
963
+
964
+ cap-datatable[data-cap-retained-loading]::after {
965
+ display: none;
966
+ }
967
+ }
968
+
969
+ @media (prefers-reduced-motion: reduce) {
970
+ cap-datatable[data-cap-retained-loading]::after {
971
+ animation: none !important;
972
+ }
744
973
  }
745
974
 
746
975
  cap-placeholder {
@@ -788,14 +1017,15 @@ cap-placeholder {
788
1017
 
789
1018
  cap-datatable > table > thead {
790
1019
  color: var(--table-header-color);
791
- background: var(--ui-gradient);
1020
+ background: var(--table-header-background);
792
1021
  }
793
1022
 
794
1023
  cap-datatable > table > thead > tr > th {
795
1024
  position: sticky;
796
1025
  inset-block-start: 0;
797
1026
  z-index: 2;
798
- background: var(--ui-gradient);
1027
+ height: 1.5rem;
1028
+ background: var(--table-header-background);
799
1029
  border: 2px groove #fff7;
800
1030
  border-left: none;
801
1031
  }
@@ -834,9 +1064,37 @@ cap-datatable > table > thead > tr > th[aria-sort] {
834
1064
  top: 50%;
835
1065
  transform: translateY(-50%);
836
1066
  width: 1em;
1067
+ height: 1.25em;
837
1068
  text-align: center;
838
1069
  }
839
1070
 
1071
+ /* An unsorted column offers both directions at the same muted weight
1072
+ * as the filter funnel. A sorted column continues to render its one
1073
+ * active text arrow above. */
1074
+ cap-datatable > table > thead > tr > th[aria-sort="none"] > button.sort > span.sortindicator {
1075
+ opacity: 0.5;
1076
+ }
1077
+
1078
+ cap-datatable > table > thead > tr > th[aria-sort="none"] > button.sort > span.sortindicator::before,
1079
+ cap-datatable > table > thead > tr > th[aria-sort="none"] > button.sort > span.sortindicator::after {
1080
+ content: "";
1081
+ position: absolute;
1082
+ left: 50%;
1083
+ transform: translateX(-50%);
1084
+ border-left: .36em solid transparent;
1085
+ border-right: .36em solid transparent;
1086
+ }
1087
+
1088
+ cap-datatable > table > thead > tr > th[aria-sort="none"] > button.sort > span.sortindicator::before {
1089
+ top: .04em;
1090
+ border-bottom: .5em solid currentColor;
1091
+ }
1092
+
1093
+ cap-datatable > table > thead > tr > th[aria-sort="none"] > button.sort > span.sortindicator::after {
1094
+ bottom: .04em;
1095
+ border-top: .5em solid currentColor;
1096
+ }
1097
+
840
1098
  cap-datatable > table > thead > tr > th[aria-sort] > button.filter {
841
1099
  appearance: none;
842
1100
  position: absolute;
@@ -844,6 +1102,7 @@ cap-datatable > table > thead > tr > th[aria-sort] {
844
1102
  top: 50%;
845
1103
  transform: translateY(-50%);
846
1104
  width: 1em;
1105
+ height: 1em;
847
1106
  padding: 0;
848
1107
  color: inherit;
849
1108
  background: transparent;
@@ -856,17 +1115,33 @@ cap-datatable > table > thead > tr > th[aria-sort] {
856
1115
  opacity: 0.5;
857
1116
  }
858
1117
 
1118
+ /* A solid, font-independent funnel: the tapered bowl narrows into a
1119
+ * short stem, so the control stays legible at compact table-header
1120
+ * sizes in every theme and locale. */
1121
+ cap-datatable > table > thead > tr > th[aria-sort] > button.filter::before {
1122
+ content: "";
1123
+ position: absolute;
1124
+ inset: 50% auto auto 50%;
1125
+ width: .85em;
1126
+ height: .9em;
1127
+ background: currentColor;
1128
+ clip-path: polygon(0 0, 100% 0, 60% 58%, 60% 100%, 40% 100%, 40% 58%);
1129
+ transform: translate(-50%, -50%);
1130
+ }
1131
+
859
1132
  cap-datatable > table > thead > tr > th[aria-sort] > button.filter:hover {
860
1133
  opacity: 1;
861
1134
  }
862
1135
 
863
1136
  cap-filterpanel {
864
1137
  position: absolute;
865
- background: white;
866
- border: 1px solid #ccc;
867
- padding: 8px;
868
- min-width: 180px;
869
- box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
1138
+ color: var(--filter-panel-color);
1139
+ background: var(--filter-panel-background);
1140
+ border: var(--filter-panel-border);
1141
+ border-radius: var(--filter-panel-radius);
1142
+ padding: var(--filter-panel-padding);
1143
+ min-width: var(--filter-panel-min-width);
1144
+ box-shadow: var(--filter-panel-shadow);
870
1145
  z-index: 1000;
871
1146
  display: flex;
872
1147
  flex-flow: column nowrap;
@@ -926,11 +1201,11 @@ cap-timepicker {
926
1201
  min-width: var(--input-min-width, 6rem);
927
1202
  margin: 0;
928
1203
  margin-left: auto;
929
- padding: 0 5px;
1204
+ padding: var(--ui-control-padding);
930
1205
  color: var(--input-color);
931
1206
  background: var(--input-background);
932
1207
  border: var(--input-border);
933
- border-radius: var(--radius-md);
1208
+ border-radius: var(--ui-border-radius);
934
1209
  box-shadow: var(--input-shadow);
935
1210
  box-sizing: border-box;
936
1211
  font: inherit;
@@ -938,16 +1213,54 @@ cap-timepicker {
938
1213
 
939
1214
  cap-datepicker > input:disabled,
940
1215
  cap-datetimepicker > input:disabled,
941
- cap-timepicker > input:disabled,
942
- cap-datepicker > input[readonly],
943
- cap-datetimepicker > input[readonly],
944
- cap-timepicker > input[readonly] {
1216
+ cap-timepicker > input:disabled {
945
1217
  color: var(--input-color-disabled);
946
1218
  background: var(--input-background-disabled);
947
1219
  border-color: var(--ui-input-border-disabled);
948
1220
  cursor: not-allowed;
949
1221
  }
950
1222
 
1223
+ cap-datepicker > input[readonly]:not(:disabled),
1224
+ cap-datetimepicker > input[readonly]:not(:disabled),
1225
+ cap-timepicker > input[readonly]:not(:disabled) {
1226
+ color: var(--input-color-readonly);
1227
+ background: var(--input-background-readonly);
1228
+ border: var(--input-border-readonly);
1229
+ box-shadow: var(--input-shadow-readonly);
1230
+ cursor: default;
1231
+ }
1232
+
1233
+
1234
+
1235
+ cap-datepicker > input:required:invalid:not(:disabled):not([readonly]):not([aria-invalid="true"]),
1236
+ cap-datetimepicker > input:required:invalid:not(:disabled):not([readonly]):not([aria-invalid="true"]),
1237
+ cap-timepicker > input:required:invalid:not(:disabled):not([readonly]):not([aria-invalid="true"]) {
1238
+ outline: 1px dashed var(--required-color);
1239
+ outline-offset: 3px;
1240
+ }
1241
+
1242
+
1243
+ cap-datepicker:has(> input:required:invalid:not(:disabled):not([readonly]):not([aria-invalid="true"]))::after,
1244
+ cap-datetimepicker:has(> input:required:invalid:not(:disabled):not([readonly]):not([aria-invalid="true"]))::after,
1245
+ cap-timepicker:has(> input:required:invalid:not(:disabled):not([readonly]):not([aria-invalid="true"]))::after {
1246
+ content: "✲";
1247
+ position: absolute;
1248
+ z-index: 3;
1249
+ inset-block-start: max(calc(var(--control-row-padding-block, .25em) + .15em), .3em);
1250
+ inset-inline-end: .35em;
1251
+ display: flex;
1252
+ inline-size: 1rem;
1253
+ block-size: 1rem;
1254
+ align-items: center;
1255
+ justify-content: center;
1256
+ color: var(--required-indicator-color);
1257
+ background: var(--required-indicator-background);
1258
+ font-size: .75rem;
1259
+ font-weight: 700;
1260
+ line-height: 1;
1261
+ pointer-events: none;
1262
+ }
1263
+
951
1264
  cap-datepicker > input:focus-visible,
952
1265
  cap-datetimepicker > input:focus-visible,
953
1266
  cap-timepicker > input:focus-visible {
@@ -973,10 +1286,19 @@ cap-timepicker {
973
1286
  background-size: 2rem 2rem, 100% 100%;
974
1287
  }
975
1288
 
1289
+ cap-datepicker > input[readonly]:not(:disabled)[aria-busy="true"]:not([aria-invalid="true"]),
1290
+ cap-datetimepicker > input[readonly]:not(:disabled)[aria-busy="true"]:not([aria-invalid="true"]),
1291
+ cap-timepicker > input[readonly]:not(:disabled)[aria-busy="true"]:not([aria-invalid="true"]) {
1292
+ background: var(--working-background-image), var(--input-background-readonly);
1293
+ background-repeat: repeat, no-repeat;
1294
+ background-size: 2rem 2rem, 100% 100%;
1295
+ }
1296
+
976
1297
  cap-datepicker > input[aria-invalid="true"],
977
1298
  cap-datetimepicker > input[aria-invalid="true"],
978
1299
  cap-timepicker > input[aria-invalid="true"] {
979
- border-color: var(--error-color);
1300
+ border-color: var(--error-control-border);
1301
+ box-shadow: var(--error-control-shadow);
980
1302
  }
981
1303
 
982
1304
  @media (prefers-reduced-motion: reduce) {
@@ -1002,7 +1324,8 @@ cap-descriptionlist {
1002
1324
  }
1003
1325
 
1004
1326
  cap-descriptionlist > dl {
1005
- display: grid;
1327
+ display: flex;
1328
+ flex-flow: column nowrap;
1006
1329
  margin: 0;
1007
1330
  }
1008
1331
 
@@ -1090,6 +1413,13 @@ cap-app {
1090
1413
  line-height: var(--line-height);
1091
1414
  }
1092
1415
 
1416
+ /* A direct shell header delegates content spacing to its navbar,
1417
+ * toolbar, and branding rows. Keep the inherited island token intact. */
1418
+ cap-app > header.island,
1419
+ cap-app > cap-header.island {
1420
+ padding: 0;
1421
+ }
1422
+
1093
1423
  cap-groupbox,
1094
1424
  cap-optionsbox {
1095
1425
  display: flex;
@@ -1131,22 +1461,18 @@ cap-optionsbox {
1131
1461
 
1132
1462
  cap-groupbox > cap-content,
1133
1463
  cap-optionsbox > cap-content {
1134
- display: block;
1464
+ display: flex;
1465
+ flex-flow: column nowrap;
1466
+ justify-content: flex-start;
1467
+ align-content: flex-start;
1468
+ align-items: flex-start;
1469
+ gap: var(--groupbox-content-gap, .5rem);
1135
1470
  min-width: 0;
1136
1471
  min-height: 0;
1137
1472
  margin-left: var(--cap-groupbox-content-margin, .25em);
1138
1473
  flex: 1 1 auto;
1139
1474
  }
1140
1475
 
1141
- cap-groupbox > cap-content > cap-layout,
1142
- cap-optionsbox > cap-content > cap-layout {
1143
- gap: .5rem;
1144
- justify-content: flex-start;
1145
- align-content: flex-start;
1146
- justify-items: flex-start;
1147
- align-items: flex-start;
1148
- }
1149
-
1150
1476
  /* Presentation contexts: each marker sets the complete context-sensitive
1151
1477
  property set, so the nearest marked ancestor wins through ordinary
1152
1478
  custom-property inheritance. Unmarked containers keep the control
@@ -1220,7 +1546,7 @@ cap-optionsbox {
1220
1546
  grid-column: 2;
1221
1547
  grid-row: 1;
1222
1548
  align-self: center;
1223
- border-block-start: 1px solid var(--ui-border-color);
1549
+ border-block-start: var(--groupbox-section-separator);
1224
1550
  }
1225
1551
 
1226
1552
  cap-groupbox.cap-groupbox-section > cap-header,
@@ -1234,7 +1560,7 @@ cap-optionsbox {
1234
1560
  min-height: 0;
1235
1561
  padding: 0 0.5rem 0 0;
1236
1562
  border-radius: 0;
1237
- color: var(--text-color);
1563
+ color: var(--groupbox-section-header-color);
1238
1564
  background: transparent;
1239
1565
  box-shadow: none;
1240
1566
  writing-mode: horizontal-tb;
@@ -1247,6 +1573,7 @@ cap-optionsbox {
1247
1573
  cap-optionsbox.cap-groupbox-section > cap-content {
1248
1574
  grid-column: 1 / -1;
1249
1575
  grid-row: 2;
1576
+ flex-flow: row nowrap;
1250
1577
  margin-left: 0;
1251
1578
  padding-block: 0.75rem;
1252
1579
  min-width: 0;
@@ -1265,7 +1592,7 @@ cap-optionsbox {
1265
1592
  justify-self: stretch;
1266
1593
  align-self: stretch;
1267
1594
  border-block-start: 0;
1268
- border-inline-end: 1px solid var(--ui-border-color);
1595
+ border-inline-end: var(--groupbox-section-separator);
1269
1596
  }
1270
1597
 
1271
1598
  .cap-layout-horizontal > cap-groupbox.cap-groupbox-section > cap-header,
@@ -1302,7 +1629,7 @@ cap-optionsbox {
1302
1629
  padding: 0;
1303
1630
  margin-block-end: 0.75rem;
1304
1631
  border-radius: 0;
1305
- color: var(--text-color);
1632
+ color: var(--groupbox-column-header-color);
1306
1633
  background: transparent;
1307
1634
  box-shadow: none;
1308
1635
  writing-mode: horizontal-tb;
@@ -1316,6 +1643,34 @@ cap-optionsbox {
1316
1643
  margin-left: 0;
1317
1644
  }
1318
1645
 
1646
+ /* A section's own content body is the ordinary horizontal column row.
1647
+ Preserve the same stretch, edge padding, and separators formerly
1648
+ provided when an application inserted a Layout just for that row. */
1649
+ cap-groupbox.cap-groupbox-section > cap-content > cap-groupbox.cap-groupbox-column,
1650
+ /* A section's own content body is the ordinary horizontal column row.
1651
+ Preserve the same stretch, edge padding, and separators formerly
1652
+ provided when an application inserted a Layout just for that row. */
1653
+ cap-optionsbox.cap-groupbox-section > cap-content > cap-groupbox.cap-groupbox-column {
1654
+ align-self: stretch;
1655
+ }
1656
+
1657
+ cap-groupbox.cap-groupbox-section > cap-content > cap-groupbox.cap-groupbox-column
1658
+ + cap-groupbox.cap-groupbox-column,
1659
+ cap-optionsbox.cap-groupbox-section > cap-content > cap-groupbox.cap-groupbox-column
1660
+ + cap-groupbox.cap-groupbox-column {
1661
+ border-inline-start: var(--groupbox-column-separator);
1662
+ }
1663
+
1664
+ cap-groupbox.cap-groupbox-section > cap-content > cap-groupbox.cap-groupbox-column:first-child,
1665
+ cap-optionsbox.cap-groupbox-section > cap-content > cap-groupbox.cap-groupbox-column:first-child {
1666
+ padding-inline-start: 0;
1667
+ }
1668
+
1669
+ cap-groupbox.cap-groupbox-section > cap-content > cap-groupbox.cap-groupbox-column:last-child,
1670
+ cap-optionsbox.cap-groupbox-section > cap-content > cap-groupbox.cap-groupbox-column:last-child {
1671
+ padding-inline-end: 0;
1672
+ }
1673
+
1319
1674
  .cap-layout-horizontal > cap-groupbox.cap-groupbox-column,
1320
1675
  .cap-layout-horizontal > cap-optionsbox.cap-groupbox-column,
1321
1676
  .cap-layout-vertical > cap-groupbox.cap-groupbox-column,
@@ -1325,7 +1680,7 @@ cap-optionsbox {
1325
1680
 
1326
1681
  .cap-layout-horizontal > cap-groupbox.cap-groupbox-column + cap-groupbox.cap-groupbox-column,
1327
1682
  .cap-layout-horizontal > cap-optionsbox.cap-groupbox-column + cap-optionsbox.cap-groupbox-column {
1328
- border-inline-start: 1px solid var(--ui-border-color);
1683
+ border-inline-start: var(--groupbox-column-separator);
1329
1684
  }
1330
1685
 
1331
1686
  .cap-layout-horizontal > cap-groupbox.cap-groupbox-column:first-child,
@@ -1346,7 +1701,7 @@ cap-optionsbox {
1346
1701
 
1347
1702
  .cap-layout-vertical > cap-groupbox.cap-groupbox-column + cap-groupbox.cap-groupbox-column,
1348
1703
  .cap-layout-vertical > cap-optionsbox.cap-groupbox-column + cap-optionsbox.cap-groupbox-column {
1349
- border-block-start: 1px solid var(--ui-border-color);
1704
+ border-block-start: var(--groupbox-column-separator);
1350
1705
  }
1351
1706
 
1352
1707
  .cap-layout-vertical > cap-groupbox.cap-groupbox-column:first-child,
@@ -1363,6 +1718,7 @@ cap-header {
1363
1718
  display: block;
1364
1719
  color: var(--section-header-color);
1365
1720
  font-size: var(--section-header-font-size);
1721
+ font-weight: var(--section-header-font-weight);
1366
1722
  border-radius: var(--ui-border-radius) var(--ui-border-radius) 0 0;
1367
1723
  padding: .25em;
1368
1724
  background: var(--section-header-background);
@@ -1440,6 +1796,19 @@ cap-listview {
1440
1796
  list-style: none;
1441
1797
  }
1442
1798
 
1799
+ cap-listview[data-cap-retained-loading]::after {
1800
+ content: "";
1801
+ position: absolute;
1802
+ z-index: 1;
1803
+ inset: 0;
1804
+ opacity: 0.33;
1805
+ animation: cap-working-progress .55s linear infinite;
1806
+ background-image: var(--working-background-image);
1807
+ background-repeat: repeat;
1808
+ background-size: 2rem 2rem;
1809
+ pointer-events: none;
1810
+ }
1811
+
1443
1812
  cap-listview > [role="listbox"] > [role="option"],
1444
1813
  cap-listview > ul[aria-hidden="true"] > li {
1445
1814
  display: flex;
@@ -1481,6 +1850,16 @@ cap-listview {
1481
1850
  outline: 2px solid Mark;
1482
1851
  outline-offset: -2px;
1483
1852
  }
1853
+
1854
+ cap-listview[data-cap-retained-loading]::after {
1855
+ display: none;
1856
+ }
1857
+ }
1858
+
1859
+ @media (prefers-reduced-motion: reduce) {
1860
+ cap-listview[data-cap-retained-loading]::after {
1861
+ animation: none !important;
1862
+ }
1484
1863
  }
1485
1864
 
1486
1865
  cap-navigationbar {
@@ -1606,8 +1985,9 @@ cap-optiongroup {
1606
1985
  }
1607
1986
 
1608
1987
  cap-optiongroup > fieldset[aria-invalid="true"] {
1609
- border: 1px solid var(--error-color);
1610
- border-radius: var(--radius-md);
1988
+ border: 1px solid var(--error-control-border);
1989
+ border-radius: var(--ui-border-radius);
1990
+ box-shadow: var(--error-control-shadow);
1611
1991
  }
1612
1992
 
1613
1993
  @media (prefers-reduced-motion: reduce) {
@@ -1623,15 +2003,20 @@ cap-optiongroup {
1623
2003
  }
1624
2004
  }
1625
2005
 
1626
- cap-optionsbox > cap-content {
2006
+ cap-optionsbox {
2007
+ --_cap-control-compact-min: 0px;
2008
+ --control-row-padding-block: 0px;
2009
+ }
2010
+
2011
+ cap-optionsbox > cap-content {
1627
2012
  display: flex;
1628
2013
  flex-direction: column;
1629
2014
  align-self: stretch;
1630
2015
  flex: 1 1 0;
1631
- gap: 1rem;
2016
+ gap: 2px;
1632
2017
  }
1633
2018
 
1634
- cap-optionsbox > cap-content * > fieldset > legend {
2019
+ cap-optionsbox > cap-content cap-optiongroup > fieldset > legend {
1635
2020
  display: flex;
1636
2021
  justify-content: space-between;
1637
2022
  align-items: center;
@@ -1640,23 +2025,30 @@ cap-optionsbox > cap-content {
1640
2025
  color: var(--palette-neutral-950);
1641
2026
  gap: 0.5rem;
1642
2027
  width: 100%;
1643
- padding: 0 0 0.25rem;
1644
- margin-bottom: 0.25rem;
2028
+ padding: 0 0 1px;
2029
+ margin-bottom: 1px;
1645
2030
  border-bottom: 1px solid var(--ui-border-color);
1646
2031
  user-select: none;
1647
2032
  }
1648
2033
 
1649
- cap-optionsbox > cap-content * > fieldset {
2034
+ cap-optionsbox > cap-content cap-optiongroup > fieldset {
1650
2035
  display: flex;
1651
- flex-flow: column;
2036
+ flex-flow: column nowrap;
1652
2037
  justify-content: stretch;
1653
2038
  justify-items: stretch;
1654
2039
  align-items: stretch;
1655
2040
  align-content: stretch;
1656
2041
  box-sizing: border-box;
1657
2042
  width: 100%;
1658
- gap: .33rem;
1659
- padding: .25em 0 .5em 0;
2043
+ gap: 2px;
2044
+ padding: 1px 0 2px;
2045
+ }
2046
+
2047
+ /* OptionsBox is deliberately a dense, vertical filter surface. Keep
2048
+ RadioGroup in the same rhythm as checkbox options, regardless of
2049
+ theme-level RadioGroup spacing. */
2050
+ cap-optionsbox > cap-content cap-radiogroup > fieldset {
2051
+ gap: 2px;
1660
2052
  }
1661
2053
 
1662
2054
  cap-panel {
@@ -1690,7 +2082,10 @@ cap-panel {
1690
2082
  }
1691
2083
 
1692
2084
  cap-progressbar {
1693
- display: block;
2085
+ display: flex;
2086
+ align-items: center;
2087
+ width: 100%;
2088
+ min-width: 0;
1694
2089
  }
1695
2090
 
1696
2091
  cap-progressbar > label,
@@ -1756,17 +2151,17 @@ cap-progressbar {
1756
2151
  white-space: nowrap;
1757
2152
  }
1758
2153
 
1759
- cap-progressbar:has(> progress:indeterminate) > cap-content > cap-progress {
2154
+ cap-progressbar:has(> progress:indeterminate[aria-busy="true"]) > cap-content > cap-progress {
1760
2155
  display: none;
1761
2156
  }
1762
2157
 
1763
- cap-progressbar:has(> progress:indeterminate) > cap-content > cap-label {
2158
+ cap-progressbar:has(> progress:indeterminate[aria-busy="true"]) > cap-content > cap-label {
1764
2159
  z-index: 2;
1765
2160
  }
1766
2161
 
1767
- cap-progressbar:has(> progress:indeterminate) > cap-content::after {
2162
+ cap-progressbar:has(> progress[aria-busy="true"]) > cap-content::after {
1768
2163
  position: absolute;
1769
- z-index: 1;
2164
+ z-index: 2;
1770
2165
  inset: 1px;
1771
2166
  content: "";
1772
2167
  border-radius: inherit;
@@ -1775,10 +2170,15 @@ cap-progressbar {
1775
2170
  background-size: 2rem 2rem;
1776
2171
  animation: cap-working-progress .55s linear infinite;
1777
2172
  opacity: .5;
2173
+ pointer-events: none;
2174
+ }
2175
+
2176
+ cap-progressbar:has(> progress[aria-busy="true"]) > cap-content > cap-label {
2177
+ z-index: 3;
1778
2178
  }
1779
2179
 
1780
2180
  @media (prefers-reduced-motion: reduce) {
1781
- cap-progressbar:has(> progress:indeterminate) > cap-content::after {
2181
+ cap-progressbar:has(> progress[aria-busy="true"]) > cap-content::after {
1782
2182
  animation: none !important;
1783
2183
  }
1784
2184
  }
@@ -1801,10 +2201,37 @@ cap-progressbar {
1801
2201
  }
1802
2202
  }
1803
2203
 
2204
+ cap-quadcheckbox > label > input[value="require"] + cap-checkshell,
2205
+ cap-tricheckbox > label > input[value="require"] + cap-checkshell {
2206
+ color: var(--checkbox-positive-color);
2207
+ background: var(--checkbox-positive-background);
2208
+ background-color: var(--palette-status-positive);
2209
+ border: var(--checkbox-positive-border);
2210
+ box-shadow: var(--checkbox-positive-shadow);
2211
+ }
2212
+
2213
+ cap-quadcheckbox > label > input[value="deny"] + cap-checkshell,
2214
+ cap-tricheckbox > label > input[value="deny"] + cap-checkshell {
2215
+ color: var(--checkbox-negative-color);
2216
+ background: var(--checkbox-negative-background);
2217
+ background-color: var(--palette-status-negative);
2218
+ border: var(--checkbox-negative-border);
2219
+ box-shadow: var(--checkbox-negative-shadow);
2220
+ }
2221
+
2222
+ cap-quadcheckbox > label > input[value="prefer"] + cap-checkshell,
2223
+ cap-tricheckbox > label > input[value="prefer"] + cap-checkshell {
2224
+ color: var(--checkbox-neutral-color);
2225
+ background: var(--checkbox-neutral-background);
2226
+ background-color: var(--palette-status-neutral);
2227
+ border: var(--checkbox-neutral-border);
2228
+ box-shadow: var(--checkbox-neutral-shadow);
2229
+ }
2230
+
1804
2231
  cap-radiogroup > fieldset {
1805
2232
  display: flex;
1806
2233
  flex-flow: column wrap;
1807
- gap: 0;
2234
+ gap: var(--radio-group-gap, 0px);
1808
2235
  margin: 0;
1809
2236
  padding: 0;
1810
2237
  min-inline-size: 0;
@@ -1824,11 +2251,19 @@ cap-radiogroup > fieldset {
1824
2251
  }
1825
2252
 
1826
2253
  cap-radiogroup > fieldset[aria-invalid="true"] cap-checkshell {
1827
- border-color: var(--error-color);
2254
+ border-color: var(--error-control-border);
2255
+ box-shadow: var(--error-control-shadow);
1828
2256
  }
1829
2257
 
1830
- cap-radiogroup > fieldset[aria-invalid="true"] cap-radiobutton > label {
1831
- color: var(--error-color);
2258
+ /* RadioGroup owns changes for its child buttons, so the readonly
2259
+ presentation is applied here rather than to each child input. */
2260
+ cap-radiogroup > fieldset[aria-readonly="true"] > cap-radiobutton {
2261
+ --_cap-checkable-label-color: var(--checkable-label-color-readonly);
2262
+ --_cap-checkable-cursor: default;
2263
+ --_cap-checkable-box-background: var(--checkbox-box-background-readonly);
2264
+ --_cap-checkable-box-border: var(--checkbox-box-border-readonly);
2265
+ --_cap-checkable-box-shadow: var(--checkbox-box-shadow-readonly);
2266
+ --_cap-checkable-box-filter: saturate(.78);
1832
2267
  }
1833
2268
 
1834
2269
  @media (forced-colors: active) {
@@ -1840,14 +2275,26 @@ cap-radiogroup > fieldset {
1840
2275
 
1841
2276
  cap-radiobutton > label > input[type="radio"] + cap-checkshell {
1842
2277
  border-radius: 50%;
2278
+ height: var(--checkbox-box-size, 1em);
2279
+ }
2280
+
2281
+ /* Radios may keep their neutral ring when selected and paint only the
2282
+ center dot; the generic checked checkbox treatment is the fallback. */
2283
+ cap-radiobutton > label > input[type="radio"]:checked + cap-checkshell {
2284
+ background: var(--radio-box-background-checked,
2285
+ var(--checkbox-box-background-checked));
2286
+ border: var(--radio-box-border-checked,
2287
+ var(--checkbox-box-border-checked));
2288
+ box-shadow: var(--radio-box-shadow-checked,
2289
+ var(--checkbox-box-shadow-checked));
1843
2290
  }
1844
2291
 
1845
2292
  cap-radiobutton > label > input[type="radio"]:checked + cap-checkshell::after {
1846
- width: .4em;
1847
- height: .4em;
2293
+ width: var(--radio-symbol-size, .4em);
2294
+ height: var(--radio-symbol-size, .4em);
1848
2295
  content: "";
1849
2296
  border-radius: 50%;
1850
- background: var(--checkbox-symbol-color);
2297
+ background: var(--radio-symbol-color, var(--checkbox-symbol-color));
1851
2298
  }
1852
2299
 
1853
2300
  cap-routeoutlet {
@@ -1856,16 +2303,10 @@ cap-routeoutlet {
1856
2303
  flex-direction: column;
1857
2304
  min-width: 0;
1858
2305
  min-height: 0;
1859
- overflow: hidden;
1860
2306
  }
1861
2307
 
1862
2308
  cap-routeoutlet > div {
1863
- display: flex;
1864
2309
  flex: 1 1 auto;
1865
- flex-direction: column;
1866
- min-width: 0;
1867
- min-height: 0;
1868
- overflow: auto;
1869
2310
  }
1870
2311
 
1871
2312
  cap-routeoutlet > div[hidden] {
@@ -1902,7 +2343,10 @@ cap-splitview {
1902
2343
  flex: 1 1 auto;
1903
2344
  min-width: 0;
1904
2345
  min-height: 0;
1905
- overflow: hidden;
2346
+ }
2347
+
2348
+ cap-splitview > * {
2349
+ --_cap-island-gutter: calc(var(--_cap-island-flow, 0) * var(--island-gap, 0px) / 2);
1906
2350
  }
1907
2351
 
1908
2352
  cap-splitview.horizontal {
@@ -1921,6 +2365,13 @@ cap-splitview {
1921
2365
  flex: 1 1 0;
1922
2366
  }
1923
2367
 
2368
+ /* Pane sizes describe content allocation. The compensated scrollport
2369
+ * padding must stay outside that size, even on an explicit islands scope. */
2370
+ cap-splitview > cap-primary.cap-scroll:not(.island),
2371
+ cap-splitview > cap-secondary.cap-scroll:not(.island) {
2372
+ box-sizing: content-box;
2373
+ }
2374
+
1924
2375
  cap-splitview.horizontal > cap-primary {
1925
2376
  min-inline-size: var(--split-primary-min-size, 96px);
1926
2377
  }
@@ -1941,9 +2392,17 @@ cap-splitview {
1941
2392
  position: relative;
1942
2393
  flex: none;
1943
2394
  box-sizing: border-box;
1944
- background: var(--ui-border-color);
2395
+ background: var(--_cap-island-separator-background, var(--ui-border-color));
1945
2396
  touch-action: none;
1946
2397
  user-select: none;
2398
+ z-index: 1;
2399
+ }
2400
+
2401
+ /* Keep a pointer target even when a flush theme gives the track zero
2402
+ * size. This area overlaps pane edges and never changes allocation. */
2403
+ cap-splitview > cap-separator::before {
2404
+ content: '';
2405
+ position: absolute;
1947
2406
  }
1948
2407
 
1949
2408
  cap-splitview > cap-separator::after {
@@ -1960,23 +2419,43 @@ cap-splitview {
1960
2419
  }
1961
2420
 
1962
2421
  cap-splitview.horizontal > cap-separator {
1963
- inline-size: .45rem;
2422
+ inline-size: calc((1 - var(--_cap-island-flow, 0)) * .45rem
2423
+ + var(--_cap-island-flow, 0) * var(--island-gap, 0px));
1964
2424
  cursor: col-resize;
1965
2425
  }
1966
2426
 
2427
+ cap-splitview.horizontal > cap-separator::before {
2428
+ inset-block: 0;
2429
+ left: 50%;
2430
+ width: max(100%, .45rem);
2431
+ transform: translateX(-50%);
2432
+ }
2433
+
1967
2434
  cap-splitview.horizontal > cap-separator::after {
1968
2435
  inset-block: 35%;
1969
- inset-inline: 1px;
2436
+ left: 50%;
2437
+ width: 3px;
2438
+ transform: translateX(-50%);
1970
2439
  }
1971
2440
 
1972
2441
  cap-splitview.vertical > cap-separator {
1973
- block-size: .45rem;
2442
+ block-size: calc((1 - var(--_cap-island-flow, 0)) * .45rem
2443
+ + var(--_cap-island-flow, 0) * var(--island-gap, 0px));
1974
2444
  cursor: row-resize;
1975
2445
  }
1976
2446
 
2447
+ cap-splitview.vertical > cap-separator::before {
2448
+ inset-inline: 0;
2449
+ top: 50%;
2450
+ height: max(100%, .45rem);
2451
+ transform: translateY(-50%);
2452
+ }
2453
+
1977
2454
  cap-splitview.vertical > cap-separator::after {
1978
2455
  inset-inline: 35%;
1979
- inset-block: 1px;
2456
+ top: 50%;
2457
+ height: 3px;
2458
+ transform: translateY(-50%);
1980
2459
  }
1981
2460
 
1982
2461
  cap-splitview[data-resizable="false"] > cap-separator {
@@ -2002,7 +2481,7 @@ cap-tabline {
2002
2481
  color: var(--button-color);
2003
2482
  background: var(--tab-button-background);
2004
2483
  border: none;
2005
- border-radius: var(--radius-md) var(--radius-md) 0 0;
2484
+ border-radius: var(--ui-border-radius) var(--ui-border-radius) 0 0;
2006
2485
  box-shadow: var(--tab-button-shadow);
2007
2486
  box-sizing: border-box;
2008
2487
  align-self: flex-end;
@@ -2092,11 +2571,11 @@ cap-textbox {
2092
2571
  max-width: 100%;
2093
2572
  min-width: var(--input-min-width, 6rem);
2094
2573
  margin: 0;
2095
- padding: 0 5px;
2574
+ padding: var(--ui-control-padding);
2096
2575
  color: var(--input-color);
2097
2576
  background: var(--input-background);
2098
2577
  border: var(--input-border);
2099
- border-radius: var(--radius-md);
2578
+ border-radius: var(--ui-border-radius);
2100
2579
  box-shadow: var(--input-shadow);
2101
2580
  box-sizing: border-box;
2102
2581
  font: inherit;
@@ -2115,6 +2594,41 @@ cap-textbox {
2115
2594
  cursor: not-allowed;
2116
2595
  }
2117
2596
 
2597
+ cap-textbox > input[readonly]:not(:disabled) {
2598
+ color: var(--input-color-readonly);
2599
+ background: var(--input-background-readonly);
2600
+ border: var(--input-border-readonly);
2601
+ box-shadow: var(--input-shadow-readonly);
2602
+ cursor: text;
2603
+ }
2604
+
2605
+
2606
+
2607
+ cap-textbox > input:required:invalid:not(:disabled):not([readonly]):not([aria-invalid="true"]) {
2608
+ outline: 1px dashed var(--required-color);
2609
+ outline-offset: 3px;
2610
+ }
2611
+
2612
+
2613
+ cap-textbox:has(> input:required:invalid:not(:disabled):not([readonly]):not([aria-invalid="true"]))::after {
2614
+ content: "✲";
2615
+ position: absolute;
2616
+ z-index: 3;
2617
+ inset-block-start: max(calc(var(--control-row-padding-block, .25em) + .15em), .3em);
2618
+ inset-inline-end: .35em;
2619
+ display: flex;
2620
+ inline-size: 1rem;
2621
+ block-size: 1rem;
2622
+ align-items: center;
2623
+ justify-content: center;
2624
+ color: var(--required-indicator-color);
2625
+ background: var(--required-indicator-background);
2626
+ font-size: .75rem;
2627
+ font-weight: 700;
2628
+ line-height: 1;
2629
+ pointer-events: none;
2630
+ }
2631
+
2118
2632
  cap-textbox > input:focus-visible {
2119
2633
  outline: 2px solid transparent;
2120
2634
  outline-offset: 1px;
@@ -2134,8 +2648,15 @@ cap-textbox {
2134
2648
  background-size: 2rem 2rem, 100% 100%;
2135
2649
  }
2136
2650
 
2651
+ cap-textbox > input[readonly]:not(:disabled)[aria-busy="true"]:not([aria-invalid="true"]) {
2652
+ background: var(--working-background-image), var(--input-background-readonly);
2653
+ background-repeat: repeat, no-repeat;
2654
+ background-size: 2rem 2rem, 100% 100%;
2655
+ }
2656
+
2137
2657
  cap-textbox > input[aria-invalid="true"] {
2138
- border-color: var(--error-color);
2658
+ border-color: var(--error-control-border);
2659
+ box-shadow: var(--error-control-shadow);
2139
2660
  }
2140
2661
 
2141
2662
  @media (prefers-reduced-motion: reduce) {
@@ -2152,7 +2673,6 @@ cap-textbox {
2152
2673
  }
2153
2674
 
2154
2675
  cap-toggle {
2155
- min-height: var(--control-min-height, 2em);
2156
2676
  display: flex;
2157
2677
  position: relative;
2158
2678
  flex-flow: row nowrap;
@@ -2171,7 +2691,7 @@ cap-toggle {
2171
2691
  cap-toggle > cap-options {
2172
2692
  display: flex;
2173
2693
  min-height: var(--control-min-height, 2em);
2174
- border-radius: var(--radius-md);
2694
+ border-radius: var(--ui-border-radius);
2175
2695
  box-shadow: var(--toggle-group-shadow);
2176
2696
  box-sizing: border-box;
2177
2697
  cursor: pointer;
@@ -2186,7 +2706,7 @@ cap-toggle {
2186
2706
  min-height: var(--control-min-height, 2em);
2187
2707
  min-width: 2em;
2188
2708
  margin: 0;
2189
- padding: 0 6px;
2709
+ padding: var(--ui-control-padding);
2190
2710
  position: relative;
2191
2711
  isolation: isolate;
2192
2712
  font: inherit;
@@ -2216,12 +2736,13 @@ cap-toggle {
2216
2736
  box-shadow: var(--toggle-button-shadow);
2217
2737
  }
2218
2738
 
2219
- cap-toggle > cap-options > button[role="radio"]:hover:not(:disabled)[aria-checked="false"]::before {
2739
+ cap-toggle > cap-options:not([aria-readonly="true"])
2740
+ > button[role="radio"]:hover:not(:disabled)[aria-checked="false"]::before {
2220
2741
  background: var(--button-background-hover);
2221
2742
  }
2222
2743
 
2223
2744
  cap-toggle > cap-options > button[role="radio"]:first-of-type {
2224
- border-radius: var(--radius-md) 0 0 var(--radius-md);
2745
+ border-radius: var(--ui-border-radius) 0 0 var(--ui-border-radius);
2225
2746
  }
2226
2747
 
2227
2748
  cap-toggle > cap-options > button[role="radio"]:first-of-type::before {
@@ -2230,11 +2751,11 @@ cap-toggle {
2230
2751
  }
2231
2752
 
2232
2753
  cap-toggle > cap-options > button[role="radio"]:last-of-type {
2233
- border-radius: 0 var(--radius-md) var(--radius-md) 0;
2754
+ border-radius: 0 var(--ui-border-radius) var(--ui-border-radius) 0;
2234
2755
  }
2235
2756
 
2236
2757
  cap-toggle > cap-options > button[role="radio"]:only-of-type {
2237
- border-radius: var(--radius-md);
2758
+ border-radius: var(--ui-border-radius);
2238
2759
  }
2239
2760
 
2240
2761
  cap-toggle > cap-options > button[role="radio"]:last-of-type::before {
@@ -2256,7 +2777,7 @@ cap-toggle {
2256
2777
  cap-toggle > cap-options > button[role="radio"][aria-checked="true"]::before {
2257
2778
  background: var(--toggle-button-background-checked);
2258
2779
  border: var(--toggle-button-border-checked);
2259
- box-shadow: none;
2780
+ box-shadow: var(--toggle-button-shadow-checked);
2260
2781
  inset-inline: var(--toggle-button-selected-inline-overlap);
2261
2782
  }
2262
2783
 
@@ -2270,6 +2791,51 @@ cap-toggle {
2270
2791
  border: var(--button-border-disabled);
2271
2792
  }
2272
2793
 
2794
+ cap-toggle > cap-options[aria-readonly="true"] > button[role="radio"]:not(:disabled) {
2795
+ cursor: default;
2796
+ }
2797
+
2798
+ cap-toggle > cap-options[aria-readonly="true"] > button[role="radio"]:not(:disabled)::before {
2799
+ filter: saturate(.78);
2800
+ }
2801
+
2802
+ cap-toggle > cap-options[aria-readonly="true"]
2803
+ > button[role="radio"][aria-checked="false"]
2804
+ + [role="radio"][aria-checked="false"]::before {
2805
+ border-inline-start: none;
2806
+ }
2807
+
2808
+ cap-toggle > cap-options[aria-readonly="true"]
2809
+ > button[role="radio"][aria-checked="false"]
2810
+ + [role="radio"][aria-checked="false"]::after {
2811
+ display: none;
2812
+ }
2813
+
2814
+ cap-toggle > cap-options[aria-readonly="true"]
2815
+ > button[role="radio"]:not(:disabled)[aria-checked="false"]::before {
2816
+ background: var(--toggle-button-background-readonly);
2817
+ border: var(--toggle-button-border-readonly);
2818
+ box-shadow: var(--toggle-button-shadow-readonly);
2819
+ }
2820
+
2821
+ /* A fixed choice is one contiguous surface. Retain the outer outline,
2822
+ but do not draw segment seams. This follows the inactive border
2823
+ rule so it also clears that rule's inline borders. */
2824
+ cap-toggle > cap-options[aria-readonly="true"]
2825
+ > button[role="radio"]:not(:disabled)[aria-checked]::before {
2826
+ border-inline: none;
2827
+ }
2828
+
2829
+ cap-toggle > cap-options[aria-readonly="true"]
2830
+ > button[role="radio"][aria-checked]:first-of-type::before {
2831
+ border-inline-start: var(--toggle-button-border-readonly);
2832
+ }
2833
+
2834
+ cap-toggle > cap-options[aria-readonly="true"]
2835
+ > button[role="radio"][aria-checked]:last-of-type::before {
2836
+ border-inline-end: var(--toggle-button-border-readonly);
2837
+ }
2838
+
2273
2839
  cap-toggle > cap-options[aria-busy="true"]:not([aria-invalid="true"])
2274
2840
  > button[role="radio"]::before {
2275
2841
  background: var(--working-background-image), var(--toggle-button-background);
@@ -2286,7 +2852,12 @@ cap-toggle {
2286
2852
  }
2287
2853
 
2288
2854
  cap-toggle > cap-options[aria-invalid="true"] > button[role="radio"]::before {
2289
- border-color: var(--error-color);
2855
+ border-color: var(--error-control-border);
2856
+ }
2857
+
2858
+ cap-toggle > cap-options[aria-invalid="true"] {
2859
+ border-radius: var(--ui-border-radius);
2860
+ box-shadow: var(--error-control-shadow);
2290
2861
  }
2291
2862
 
2292
2863
  cap-toggle > cap-options > button[role="radio"][aria-checked="false"]
@@ -2347,13 +2918,27 @@ cap-treeview {
2347
2918
 
2348
2919
  cap-treeview > [role="tree"],
2349
2920
  cap-treeview > ul[aria-hidden="true"] {
2350
- display: grid;
2351
- align-content: start;
2921
+ display: flex;
2922
+ flex-flow: column nowrap;
2923
+ align-items: stretch;
2352
2924
  margin: 0;
2353
2925
  padding: 0;
2354
2926
  list-style: none;
2355
2927
  }
2356
2928
 
2929
+ cap-treeview[data-cap-retained-loading]::after {
2930
+ content: "";
2931
+ position: absolute;
2932
+ z-index: 1;
2933
+ inset: 0;
2934
+ opacity: 0.33;
2935
+ animation: cap-working-progress .55s linear infinite;
2936
+ background-image: var(--working-background-image);
2937
+ background-repeat: repeat;
2938
+ background-size: 2rem 2rem;
2939
+ pointer-events: none;
2940
+ }
2941
+
2357
2942
  cap-treeview [role="treeitem"],
2358
2943
  cap-treeview > ul[aria-hidden="true"] > li {
2359
2944
  display: flex;
@@ -2422,4 +3007,14 @@ cap-treeview {
2422
3007
  cap-treeview:has(> cap-error) {
2423
3008
  outline: 2px solid Mark;
2424
3009
  }
3010
+
3011
+ cap-treeview[data-cap-retained-loading]::after {
3012
+ display: none;
3013
+ }
3014
+ }
3015
+
3016
+ @media (prefers-reduced-motion: reduce) {
3017
+ cap-treeview[data-cap-retained-loading]::after {
3018
+ animation: none !important;
3019
+ }
2425
3020
  }