@threadlabs/looma 0.10.11 → 0.11.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 (128) hide show
  1. package/components/shared/editor.js +2 -26
  2. package/components/shared/icons.js +53 -0
  3. package/components/ui-avatar-group/ui-avatar-group.html +6 -6
  4. package/components/ui-avatar-group/ui-avatar-group.js +1 -1
  5. package/components/ui-breadcrumb-item/ui-breadcrumb-item.html +60 -0
  6. package/components/ui-breadcrumbs/ui-breadcrumbs.html +31 -0
  7. package/components/ui-card/ui-card.html +55 -0
  8. package/components/ui-combobox/ui-combobox.js +2 -2
  9. package/components/ui-context-menu/ui-context-menu.js +4 -4
  10. package/components/ui-cover/ui-cover.html +36 -0
  11. package/components/ui-description-item/ui-description-item.html +46 -0
  12. package/components/ui-description-list/ui-description-list.html +37 -0
  13. package/components/ui-icon/ui-icon.js +1 -1
  14. package/components/ui-list/ui-list.html +33 -0
  15. package/components/ui-list-item/ui-list-item.html +146 -0
  16. package/components/ui-menu/ui-menu.js +3 -3
  17. package/components/ui-page-header/ui-page-header.html +97 -0
  18. package/components/ui-radio/ui-radio.js +1 -1
  19. package/components/ui-radio-group/ui-radio-group.js +1 -1
  20. package/components/ui-section/ui-section.html +108 -0
  21. package/components/ui-spinner/ui-spinner.html +48 -0
  22. package/components/ui-status-message/ui-status-message.html +84 -0
  23. package/components/ui-text/ui-text.html +96 -0
  24. package/components/ui-tree/ui-tree.js +2 -2
  25. package/components/ui-tree-item/ui-tree-item.js +3 -3
  26. package/dist/index.js +1 -1
  27. package/editor/icons.d.ts +5 -0
  28. package/editor/index.js +6 -1
  29. package/package.json +1 -1
  30. package/styles/ui-avatar-group.css +6 -6
  31. package/styles/ui-breadcrumb-item.css +57 -0
  32. package/styles/ui-breadcrumbs.css +32 -0
  33. package/styles/ui-card.css +51 -0
  34. package/styles/ui-cover.css +35 -0
  35. package/styles/ui-description-item.css +43 -0
  36. package/styles/ui-description-list.css +38 -0
  37. package/styles/ui-list-item.css +146 -0
  38. package/styles/ui-list.css +33 -0
  39. package/styles/ui-page-header.css +89 -0
  40. package/styles/ui-section.css +94 -0
  41. package/styles/ui-spinner.css +42 -0
  42. package/styles/ui-status-message.css +72 -0
  43. package/styles/ui-text.css +85 -0
  44. package/vanilla/UiBreadcrumbItem.d.ts +14 -0
  45. package/vanilla/UiBreadcrumbItem.js +38 -0
  46. package/vanilla/UiBreadcrumbs.d.ts +14 -0
  47. package/vanilla/UiBreadcrumbs.js +39 -0
  48. package/vanilla/UiCard.d.ts +17 -0
  49. package/vanilla/UiCard.js +32 -0
  50. package/vanilla/UiCover.d.ts +14 -0
  51. package/vanilla/UiCover.js +28 -0
  52. package/vanilla/UiDescriptionItem.d.ts +14 -0
  53. package/vanilla/UiDescriptionItem.js +39 -0
  54. package/vanilla/UiDescriptionList.d.ts +14 -0
  55. package/vanilla/UiDescriptionList.js +28 -0
  56. package/vanilla/UiList.d.ts +14 -0
  57. package/vanilla/UiList.js +29 -0
  58. package/vanilla/UiListItem.d.ts +15 -0
  59. package/vanilla/UiListItem.js +77 -0
  60. package/vanilla/UiPageHeader.d.ts +14 -0
  61. package/vanilla/UiPageHeader.js +78 -0
  62. package/vanilla/UiSection.d.ts +16 -0
  63. package/vanilla/UiSection.js +64 -0
  64. package/vanilla/UiSpinner.d.ts +15 -0
  65. package/vanilla/UiSpinner.js +23 -0
  66. package/vanilla/UiStatusMessage.d.ts +16 -0
  67. package/vanilla/UiStatusMessage.js +53 -0
  68. package/vanilla/UiText.d.ts +20 -0
  69. package/vanilla/UiText.js +38 -0
  70. package/vanilla/index.js +13 -0
  71. package/vue/UiAvatarGroup.vue +6 -6
  72. package/vue/UiBreadcrumbItem.d.ts +18 -0
  73. package/vue/UiBreadcrumbItem.js +2 -0
  74. package/vue/UiBreadcrumbItem.vue +101 -0
  75. package/vue/UiBreadcrumbs.d.ts +18 -0
  76. package/vue/UiBreadcrumbs.js +2 -0
  77. package/vue/UiBreadcrumbs.vue +45 -0
  78. package/vue/UiCard.d.ts +24 -0
  79. package/vue/UiCard.js +2 -0
  80. package/vue/UiCard.vue +82 -0
  81. package/vue/UiCover.d.ts +18 -0
  82. package/vue/UiCover.js +2 -0
  83. package/vue/UiCover.vue +57 -0
  84. package/vue/UiDescriptionItem.d.ts +18 -0
  85. package/vue/UiDescriptionItem.js +2 -0
  86. package/vue/UiDescriptionItem.vue +58 -0
  87. package/vue/UiDescriptionList.d.ts +18 -0
  88. package/vue/UiDescriptionList.js +2 -0
  89. package/vue/UiDescriptionList.vue +62 -0
  90. package/vue/UiIconButton.d.ts +1 -1
  91. package/vue/UiList.d.ts +18 -0
  92. package/vue/UiList.js +2 -0
  93. package/vue/UiList.vue +60 -0
  94. package/vue/UiListItem.d.ts +26 -0
  95. package/vue/UiListItem.js +2 -0
  96. package/vue/UiListItem.vue +171 -0
  97. package/vue/UiPageHeader.d.ts +26 -0
  98. package/vue/UiPageHeader.js +2 -0
  99. package/vue/UiPageHeader.vue +118 -0
  100. package/vue/UiSection.d.ts +26 -0
  101. package/vue/UiSection.js +2 -0
  102. package/vue/UiSection.vue +128 -0
  103. package/vue/UiSpinner.d.ts +10 -0
  104. package/vue/UiSpinner.js +2 -0
  105. package/vue/UiSpinner.vue +87 -0
  106. package/vue/UiStatusMessage.d.ts +24 -0
  107. package/vue/UiStatusMessage.js +2 -0
  108. package/vue/UiStatusMessage.vue +121 -0
  109. package/vue/UiText.d.ts +30 -0
  110. package/vue/UiText.js +2 -0
  111. package/vue/UiText.vue +125 -0
  112. package/vue/chunks/UiAvatarGroup.js +1 -1
  113. package/vue/chunks/UiBreadcrumbItem.js +50 -0
  114. package/vue/chunks/UiBreadcrumbs.js +19 -0
  115. package/vue/chunks/UiCard.js +31 -0
  116. package/vue/chunks/UiCover.js +21 -0
  117. package/vue/chunks/UiDescriptionItem.js +16 -0
  118. package/vue/chunks/UiDescriptionList.js +21 -0
  119. package/vue/chunks/UiList.js +24 -0
  120. package/vue/chunks/UiListItem.js +39 -0
  121. package/vue/chunks/UiPageHeader.js +35 -0
  122. package/vue/chunks/UiSection.js +34 -0
  123. package/vue/chunks/UiSpinner.js +64 -0
  124. package/vue/chunks/UiStatusMessage.js +54 -0
  125. package/vue/chunks/UiText.js +40 -0
  126. package/vue/components.css +661 -29
  127. package/vue/index.d.ts +13 -0
  128. package/vue/index.js +15 -2
@@ -63,11 +63,11 @@
63
63
  display: none;
64
64
  }
65
65
 
66
- [data-component~="ui-avatar-group"][data-v-9d727004] {
67
- /* Avatars separate with a tight, crisp edge, matching Looma's 1px borders rather than the
68
- * diffuse elevation overlays use. */
69
- --_overlap-shadow: -2px 0 2px -1px rgba(0, 0, 0, 0.22);
70
- --_edge-ring: 0 0 0 1px rgba(0, 0, 0, 0.08);
66
+ [data-component~="ui-avatar-group"][data-v-6c48e0e3] {
67
+ /* Each avatar is ringed in the surface colour, so where one overlaps the next it reads as a
68
+ * whole circle set on top, not a shape cut into the one beneath. */
69
+ --_overlap-shadow: 0 0 0 0 transparent;
70
+ --_edge-ring: 0 0 0 2px var(--ui-surface);
71
71
 
72
72
  display: flex;
73
73
  align-items: center;
@@ -77,16 +77,16 @@
77
77
 
78
78
  /* Overlap and the separating shadow are applied by the controller: slotted avatars are nested
79
79
  * component roots outside this style scope. */
80
- [data-v-9d727004-s] {
81
- margin-inline-start: -0.625rem;
80
+ [data-v-6c48e0e3-s] {
81
+ margin-inline-start: -0.5rem;
82
82
  flex-shrink: 0;
83
83
  border-radius: 999px;
84
84
  }
85
- [data-v-9d727004-s]:first-child {
85
+ [data-v-6c48e0e3-s]:first-child {
86
86
  margin-inline-start: 0;
87
87
  }
88
- .overflow[data-v-9d727004] {
89
- margin-inline-start: -0.625rem;
88
+ .overflow[data-v-6c48e0e3] {
89
+ margin-inline-start: -0.5rem;
90
90
  display: inline-flex;
91
91
  align-items: center;
92
92
  justify-content: center;
@@ -104,12 +104,12 @@
104
104
  font-weight: 600;
105
105
  flex-shrink: 0;
106
106
  }
107
- .overflow[hidden][data-v-9d727004] {
107
+ .overflow[hidden][data-v-6c48e0e3] {
108
108
  display: none;
109
109
  }
110
110
 
111
111
  /* A component that sets its display still honours the hidden attribute on its root. */
112
- [data-component~="ui-avatar-group"][hidden][data-v-9d727004] {
112
+ [data-component~="ui-avatar-group"][hidden][data-v-6c48e0e3] {
113
113
  display: none;
114
114
  }
115
115
 
@@ -229,6 +229,89 @@
229
229
  display: none;
230
230
  }
231
231
 
232
+ [data-component~="ui-icon"][data-v-3d48bd86] {
233
+ display: inline-flex;
234
+ flex: none;
235
+ inline-size: var(--ui-icon-size, 1em);
236
+ block-size: var(--ui-icon-size, 1em);
237
+ }
238
+ svg[data-v-3d48bd86] {
239
+ inline-size: 100%;
240
+ block-size: 100%;
241
+ stroke-width: var(--ui-icon-stroke-width, 2);
242
+ }
243
+
244
+ /* A component that sets its display still honours the hidden attribute on its root. */
245
+ [data-component~="ui-icon"][hidden][data-v-3d48bd86] {
246
+ display: none;
247
+ }
248
+
249
+ /* One step in a ui-breadcrumbs trail: a link up to that place, or the current view. A chevron leads
250
+ every step but the first. An icon slotted before the name sits with it. */
251
+ [data-component~="ui-breadcrumb-item"][data-v-9de59def] {
252
+ display: inline-flex;
253
+ align-items: center;
254
+ gap: var(--ui-space-2);
255
+ min-inline-size: 0;
256
+ }
257
+ .separator[data-v-9de59def] {
258
+ display: inline-flex;
259
+ color: var(--ui-text-muted);
260
+ font-size: var(--ui-font-size-xs);
261
+ }
262
+ [data-component~="ui-breadcrumb-item"]:first-child .separator[data-v-9de59def] {
263
+ display: none;
264
+ }
265
+ .content[data-v-9de59def] {
266
+ display: inline-flex;
267
+ align-items: center;
268
+ gap: var(--ui-space-1);
269
+ min-inline-size: 0;
270
+ }
271
+ .content > a[data-v-9de59def-s] {
272
+ display: inline-flex;
273
+ align-items: center;
274
+ gap: var(--ui-space-1);
275
+ color: var(--ui-text-secondary);
276
+ text-decoration: none;
277
+ }
278
+ .content > a[data-v-9de59def-s]:hover {
279
+ color: var(--ui-text-primary);
280
+ text-decoration: underline;
281
+ }
282
+ [data-component~="ui-breadcrumb-item"][data-ui-breadcrumb-item-state~="current"] .content[data-v-9de59def] {
283
+ color: var(--ui-text-primary);
284
+ font-weight: var(--ui-font-medium);
285
+ }
286
+
287
+ /* A component that sets its display still honours the hidden attribute on its root. */
288
+ [data-component~="ui-breadcrumb-item"][hidden][data-v-9de59def] {
289
+ display: none;
290
+ }
291
+
292
+ /* Where a view sits: a trail of ui-breadcrumb-item, from the top down to the current view. It wraps
293
+ rather than scrolls, so every step stays reachable. */
294
+ [data-component~="ui-breadcrumbs"][data-v-0d86d58e] {
295
+ display: block;
296
+ min-inline-size: 0;
297
+ color: var(--ui-text-muted);
298
+ font-size: var(--ui-font-size-sm);
299
+ }
300
+ ol[data-v-0d86d58e] {
301
+ display: flex;
302
+ flex-wrap: wrap;
303
+ align-items: center;
304
+ gap: var(--ui-space-1) var(--ui-space-2);
305
+ margin: 0;
306
+ padding: 0;
307
+ list-style: none;
308
+ }
309
+
310
+ /* A component that sets its display still honours the hidden attribute on its root. */
311
+ [data-component~="ui-breadcrumbs"][hidden][data-v-0d86d58e] {
312
+ display: none;
313
+ }
314
+
232
315
  [data-component~="ui-button"][data-v-0c121308] {
233
316
  --_hue: var(--ui-accent);
234
317
  --_hue-hover: var(--ui-accent-hover);
@@ -549,6 +632,44 @@
549
632
  display: none;
550
633
  }
551
634
 
635
+ /* A surface that groups content. Its children stack with even space between them, so a card
636
+ needs no layout of its own. */
637
+ [data-component~="ui-card"][data-v-d00c53f0] {
638
+ display: flex;
639
+ flex-direction: column;
640
+ gap: var(--ui-space-4);
641
+ box-sizing: border-box;
642
+ min-inline-size: 0;
643
+ padding: var(--ui-space-5);
644
+ border: 1px solid var(--ui-border-default);
645
+ border-radius: var(--ui-radius-lg);
646
+ background: var(--ui-surface-raised);
647
+ color: var(--ui-text-primary);
648
+ }
649
+ [data-component~="ui-card"][data-ui-card-state~="padding=sm"][data-v-d00c53f0] {
650
+ gap: var(--ui-space-2);
651
+ padding: var(--ui-space-3);
652
+ }
653
+ [data-component~="ui-card"][data-ui-card-state~="padding=lg"][data-v-d00c53f0] {
654
+ padding: var(--ui-space-6);
655
+ }
656
+ [data-component~="ui-card"][data-ui-card-state~="variant=subtle"][data-v-d00c53f0] {
657
+ border-color: transparent;
658
+ background: var(--ui-surface-muted);
659
+ }
660
+ [data-component~="ui-card"][data-ui-card-state~="variant=elevated"][data-v-d00c53f0] {
661
+ border-color: var(--ui-border-subtle);
662
+ box-shadow: var(--ui-shadow-lg);
663
+ }
664
+ [data-component~="ui-card"][data-ui-card-state~="tone=danger"][data-v-d00c53f0] {
665
+ border-color: var(--ui-danger);
666
+ }
667
+
668
+ /* A component that sets its display still honours the hidden attribute on its root. */
669
+ [data-component~="ui-card"][hidden][data-v-d00c53f0] {
670
+ display: none;
671
+ }
672
+
552
673
  [data-component~="ui-checkbox"][data-v-9c9d1eaa] {
553
674
  display: inline-flex;
554
675
  align-items: flex-start;
@@ -1131,6 +1252,93 @@ button[data-v-0bd7ecc4] {
1131
1252
  display: none;
1132
1253
  }
1133
1254
 
1255
+ /* A layout primitive that centres its content in the space, both ways, with room around it: the
1256
+ frame for a view that is one card or one message. */
1257
+ [data-component~="ui-cover"][data-v-f341d85e] {
1258
+ display: flex;
1259
+ flex-direction: column;
1260
+ align-items: center;
1261
+ justify-content: center;
1262
+ gap: var(--ui-space-6);
1263
+ box-sizing: border-box;
1264
+ min-block-size: 100dvh;
1265
+ padding: var(--ui-space-6) var(--ui-space-4);
1266
+ }
1267
+ [data-component~="ui-cover"][data-ui-cover-state~="size=fill"][data-v-f341d85e] {
1268
+ flex: 1;
1269
+ min-block-size: 100%;
1270
+ }
1271
+ [data-component~="ui-cover"] > [data-v-f341d85e-s] {
1272
+ max-inline-size: 100%;
1273
+ }
1274
+
1275
+ /* A component that sets its display still honours the hidden attribute on its root. */
1276
+ [data-component~="ui-cover"][hidden][data-v-f341d85e] {
1277
+ display: none;
1278
+ }
1279
+
1280
+ /* One term and its value in a ui-description-list, laid out by the list's layout. */
1281
+ [data-component~="ui-description-item"][data-v-2d94bc9f] {
1282
+ display: var(--_ui-description-display, grid);
1283
+ grid-column: var(--_ui-description-column, 1 / -1);
1284
+ grid-template-columns: subgrid;
1285
+ flex-direction: column;
1286
+ align-items: var(--_ui-description-align, baseline);
1287
+ gap: var(--ui-space-1) var(--ui-space-6);
1288
+ min-inline-size: 0;
1289
+ padding: var(--_ui-description-padding, 0);
1290
+ border-width: var(--_ui-description-border-width, 0);
1291
+ border-style: solid;
1292
+ border-color: var(--ui-border-default);
1293
+ border-radius: var(--ui-radius-md);
1294
+ font-size: var(--ui-font-size-sm);
1295
+ }
1296
+ dt[data-v-2d94bc9f] {
1297
+ color: var(--ui-text-muted);
1298
+ }
1299
+ dd[data-v-2d94bc9f] {
1300
+ margin: 0;
1301
+ min-inline-size: 0;
1302
+ color: var(--ui-text-primary);
1303
+ font-weight: var(--ui-font-medium);
1304
+ font-size: var(--_ui-description-value-size, inherit);
1305
+ text-align: start;
1306
+ overflow-wrap: anywhere;
1307
+ }
1308
+
1309
+ /* A component that sets its display still honours the hidden attribute on its root. */
1310
+ [data-component~="ui-description-item"][hidden][data-v-2d94bc9f] {
1311
+ display: none;
1312
+ }
1313
+
1314
+ /* Named values: a term and what it is, for each item (ui-description-item). */
1315
+ /* Rows line every term up in one column and every value in the next, through subgrid. */
1316
+ [data-component~="ui-description-list"][data-v-0519dd0f] {
1317
+ display: grid;
1318
+ grid-template-columns: minmax(6rem, max-content) minmax(0, 1fr);
1319
+ gap: var(--ui-space-2) var(--ui-space-6);
1320
+ min-inline-size: 0;
1321
+ margin: 0;
1322
+ }
1323
+
1324
+ /* Tiles pass their shape to the items through private properties, which cross into each item. */
1325
+ [data-component~="ui-description-list"][data-ui-description-list-state~="layout=tiles"][data-v-0519dd0f] {
1326
+ --_ui-description-display: flex;
1327
+ --_ui-description-column: auto;
1328
+ --_ui-description-align: flex-start;
1329
+ --_ui-description-value-size: var(--ui-font-size-lg);
1330
+ --_ui-description-padding: var(--ui-space-3);
1331
+ --_ui-description-border-width: 1px;
1332
+ display: grid;
1333
+ grid-template-columns: repeat(auto-fill, minmax(min(100%, 10rem), 1fr));
1334
+ gap: var(--ui-space-3);
1335
+ }
1336
+
1337
+ /* A component that sets its display still honours the hidden attribute on its root. */
1338
+ [data-component~="ui-description-list"][hidden][data-v-0519dd0f] {
1339
+ display: none;
1340
+ }
1341
+
1134
1342
  [data-component~="ui-dialog"][data-v-0fd6654c] {
1135
1343
  position: fixed;
1136
1344
  inset: 0;
@@ -1691,23 +1899,6 @@ from {
1691
1899
  display: none;
1692
1900
  }
1693
1901
 
1694
- [data-component~="ui-icon"][data-v-3d48bd86] {
1695
- display: inline-flex;
1696
- flex: none;
1697
- inline-size: var(--ui-icon-size, 1em);
1698
- block-size: var(--ui-icon-size, 1em);
1699
- }
1700
- svg[data-v-3d48bd86] {
1701
- inline-size: 100%;
1702
- block-size: 100%;
1703
- stroke-width: var(--ui-icon-stroke-width, 2);
1704
- }
1705
-
1706
- /* A component that sets its display still honours the hidden attribute on its root. */
1707
- [data-component~="ui-icon"][hidden][data-v-3d48bd86] {
1708
- display: none;
1709
- }
1710
-
1711
1902
  [data-component~="ui-editor-slash-menu"][data-v-dcc1f07d] {
1712
1903
  user-select: none;
1713
1904
  }
@@ -2945,6 +3136,146 @@ svg[data-v-bcedd63e-s] {
2945
3136
  display: none;
2946
3137
  }
2947
3138
 
3139
+ /* A list of items (ui-list-item). It owns the spacing between them, so a view never sets it. The
3140
+ explicit list role keeps the list announced as one: some browsers drop it from a list with no
3141
+ markers. */
3142
+ [data-component~="ui-list"][data-v-935b1197] {
3143
+ display: flex;
3144
+ flex-direction: column;
3145
+ gap: var(--ui-list-gap, var(--ui-space-1));
3146
+ min-inline-size: 0;
3147
+ margin: 0;
3148
+ padding: 0;
3149
+ list-style: none;
3150
+ }
3151
+ [data-component~="ui-list"][data-ui-list-state~="layout=grid"][data-v-935b1197] {
3152
+ display: grid;
3153
+ grid-template-columns:
3154
+ repeat(auto-fill, minmax(min(100%, var(--ui-list-min-item-width, 14rem)), 1fr));
3155
+ gap: var(--ui-list-gap, var(--ui-space-3));
3156
+ }
3157
+
3158
+ /* A component that sets its display still honours the hidden attribute on its root. */
3159
+ [data-component~="ui-list"][hidden][data-v-935b1197] {
3160
+ display: none;
3161
+ }
3162
+
3163
+ /* One entry in a list: something to recognise (leading, usually an icon), its name (the default
3164
+ slot), one line about it (description), and what it offers (trailing, such as a button or a
3165
+ badge). The title and description are one line each and end in an ellipsis, so every item in a
3166
+ list has the same height.
3167
+
3168
+ A link in the title is the whole item: its hit area stretches over the item, so the icon and the
3169
+ padding follow it too, and the item takes the link's focus ring. The link stays a real link, so
3170
+ a router, a modified click, and "open in new tab" all work. Trailing controls sit above it and
3171
+ stay their own. */
3172
+ [data-component~="ui-list-item"][data-v-d61daf46] {
3173
+ position: relative;
3174
+ box-sizing: border-box;
3175
+ display: flex;
3176
+ align-items: center;
3177
+ gap: var(--ui-list-item-gap, var(--ui-space-3));
3178
+ min-inline-size: 0;
3179
+ min-block-size: var(--ui-control-size, 2.5rem);
3180
+ padding-block: var(--ui-list-item-padding-block, var(--ui-space-2));
3181
+ padding-inline: var(--ui-list-item-padding-inline, var(--ui-space-3));
3182
+ border-radius: var(--ui-radius-md);
3183
+ color: var(--ui-text-primary);
3184
+ transition:
3185
+ background-color var(--ui-motion-fast) var(--ui-motion-ease),
3186
+ border-color var(--ui-motion-fast) var(--ui-motion-ease);
3187
+ }
3188
+ [data-component~="ui-list-item"][data-ui-list-item-state~="variant=card"][data-v-d61daf46] {
3189
+ padding-block: var(--ui-list-item-padding-block, var(--ui-space-3));
3190
+ padding-inline: var(--ui-list-item-padding-inline, var(--ui-space-4));
3191
+ border: 1px solid var(--ui-border-default);
3192
+ border-radius: var(--ui-radius-lg);
3193
+ background: var(--ui-surface-raised);
3194
+ }
3195
+ [data-component~="ui-list-item"][data-v-d61daf46]:has(.title a[href]:hover) {
3196
+ background: var(--ui-surface-hover);
3197
+ }
3198
+ [data-component~="ui-list-item"][data-ui-list-item-state~="variant=card"][data-v-d61daf46]:has(.title
3199
+ a[href]:hover) {
3200
+ border-color: var(--ui-border-strong);
3201
+ }
3202
+ [data-component~="ui-list-item"][data-ui-list-item-state~="current"][data-v-d61daf46] {
3203
+ background: var(--ui-surface-hover);
3204
+ }
3205
+ [data-component~="ui-list-item"][data-v-d61daf46]:has(.title a[href]:focus-visible) {
3206
+ box-shadow: 0 0 0 2px var(--ui-focus-ring);
3207
+ }
3208
+ .leading[data-v-d61daf46],
3209
+ .trailing[data-v-d61daf46] {
3210
+ display: inline-flex;
3211
+ flex: none;
3212
+ align-items: center;
3213
+ gap: var(--ui-space-2);
3214
+ }
3215
+ .leading[data-v-d61daf46] {
3216
+ color: var(--ui-text-muted);
3217
+ font-size: var(--ui-list-item-icon-size, var(--ui-font-size-lg));
3218
+ }
3219
+
3220
+ /* Trailing controls take their own clicks, above the title link's stretched hit area. */
3221
+ .trailing[data-v-d61daf46] {
3222
+ position: relative;
3223
+ z-index: 1;
3224
+ color: var(--ui-text-muted);
3225
+ font-size: var(--ui-font-size-sm);
3226
+ }
3227
+ .content[data-v-d61daf46] {
3228
+ display: flex;
3229
+ flex: 1;
3230
+ flex-direction: column;
3231
+ gap: var(--ui-space-0-5, 2px);
3232
+ min-inline-size: 0;
3233
+ }
3234
+ .title[data-v-d61daf46],
3235
+ .description[data-v-d61daf46] {
3236
+ display: block;
3237
+ min-inline-size: 0;
3238
+ overflow: hidden;
3239
+ text-overflow: ellipsis;
3240
+ white-space: nowrap;
3241
+ }
3242
+ .title[data-v-d61daf46] {
3243
+ font-size: var(--ui-font-size-md);
3244
+ font-weight: var(--ui-font-medium);
3245
+ line-height: var(--ui-line-height-tight);
3246
+ }
3247
+ .description[data-v-d61daf46] {
3248
+ color: var(--ui-text-muted);
3249
+ font-size: var(--ui-font-size-sm);
3250
+ line-height: var(--ui-line-height-tight);
3251
+ }
3252
+ .title > a[data-v-d61daf46-s] {
3253
+ color: inherit;
3254
+ text-decoration: none;
3255
+ }
3256
+ .title > a[data-v-d61daf46-s]:focus-visible {
3257
+ outline: none;
3258
+ box-shadow: none;
3259
+ }
3260
+ .title > a[href][data-v-d61daf46-s]::after {
3261
+ position: absolute;
3262
+ inset: 0;
3263
+ border-radius: inherit;
3264
+ content: "";
3265
+ }
3266
+
3267
+ /* An unused region takes no space. */
3268
+ .leading[data-v-d61daf46]:empty,
3269
+ .description[data-v-d61daf46]:empty,
3270
+ .trailing[data-v-d61daf46]:empty {
3271
+ display: none;
3272
+ }
3273
+
3274
+ /* A component that sets its display still honours the hidden attribute on its root. */
3275
+ [data-component~="ui-list-item"][hidden][data-v-d61daf46] {
3276
+ display: none;
3277
+ }
3278
+
2948
3279
  /* Compact sets the part tokens its items read, so nothing has to rescale a global. */
2949
3280
  [data-component~="ui-menu"][data-ui-menu-state~="density=compact"][data-v-ad1dce95] {
2950
3281
  --ui-menu-item-padding-block: var(--ui-space-1);
@@ -3061,6 +3392,77 @@ svg[data-v-bcedd63e-s] {
3061
3392
  display: none;
3062
3393
  }
3063
3394
 
3395
+ /* The top of a view: its title (the page's one h1), with an optional icon or mark before it, a
3396
+ short eyebrow above it, a line or two of description under it, and the view's own actions at
3397
+ the end. Every view titles itself the same way, at the same size. */
3398
+ [data-component~="ui-page-header"][data-v-8dcefe30] {
3399
+ display: flex;
3400
+ flex-wrap: wrap;
3401
+ align-items: center;
3402
+ gap: var(--ui-space-3) var(--ui-space-4);
3403
+ min-inline-size: 0;
3404
+ }
3405
+ .leading[data-v-8dcefe30] {
3406
+ display: inline-flex;
3407
+ flex: none;
3408
+ align-self: center;
3409
+ color: var(--ui-text-muted);
3410
+ font-size: var(--ui-font-size-2xl);
3411
+ }
3412
+ .copy[data-v-8dcefe30] {
3413
+ display: flex;
3414
+ flex: 1 1 16rem;
3415
+ flex-direction: column;
3416
+ gap: var(--ui-space-1);
3417
+ min-inline-size: 0;
3418
+ }
3419
+ .eyebrow[data-v-8dcefe30] {
3420
+ color: var(--ui-text-muted);
3421
+ font-size: var(--ui-font-size-xs);
3422
+ font-weight: var(--ui-font-semibold);
3423
+ letter-spacing: 0.06em;
3424
+ text-transform: uppercase;
3425
+ }
3426
+ .title[data-v-8dcefe30] {
3427
+ margin: 0;
3428
+ color: var(--ui-text-primary);
3429
+ font-size: var(--ui-font-size-2xl);
3430
+ font-weight: var(--ui-font-bold, 700);
3431
+ line-height: var(--ui-line-height-tight);
3432
+ overflow-wrap: anywhere;
3433
+ }
3434
+ .description[data-v-8dcefe30] {
3435
+ color: var(--ui-text-secondary);
3436
+ font-size: var(--ui-font-size-md);
3437
+ line-height: var(--ui-line-height);
3438
+ }
3439
+ .actions[data-v-8dcefe30] {
3440
+ display: inline-flex;
3441
+ flex: none;
3442
+ flex-wrap: wrap;
3443
+ align-items: center;
3444
+ gap: var(--ui-space-2);
3445
+ }
3446
+ [data-component~="ui-page-header"][data-ui-page-header-state~="align=center"][data-v-8dcefe30] {
3447
+ flex-direction: column;
3448
+ text-align: center;
3449
+ }
3450
+ [data-component~="ui-page-header"][data-ui-page-header-state~="align=center"] .copy[data-v-8dcefe30] {
3451
+ align-items: center;
3452
+ flex-basis: auto;
3453
+ }
3454
+ .leading[data-v-8dcefe30]:empty,
3455
+ .eyebrow[data-v-8dcefe30]:empty,
3456
+ .description[data-v-8dcefe30]:empty,
3457
+ .actions[data-v-8dcefe30]:empty {
3458
+ display: none;
3459
+ }
3460
+
3461
+ /* A component that sets its display still honours the hidden attribute on its root. */
3462
+ [data-component~="ui-page-header"][hidden][data-v-8dcefe30] {
3463
+ display: none;
3464
+ }
3465
+
3064
3466
  [data-component~="ui-popover"][data-v-00194c85] {
3065
3467
  box-sizing: border-box;
3066
3468
  max-inline-size: min(
@@ -3534,6 +3936,80 @@ dialog[data-v-2ba71171] {
3534
3936
  display: none;
3535
3937
  }
3536
3938
 
3939
+ /* A part of a view: a heading, an optional line under it, actions for the whole section at its
3940
+ end, and the content. Sections space themselves out through the Stack around them. */
3941
+ [data-component~="ui-section"][data-v-4d1e5a3a] {
3942
+ display: flex;
3943
+ flex-direction: column;
3944
+ gap: var(--ui-space-4);
3945
+ min-inline-size: 0;
3946
+ }
3947
+ [data-component~="ui-section"][data-ui-section-state~="variant=card"][data-v-4d1e5a3a] {
3948
+ padding: var(--ui-space-5);
3949
+ border: 1px solid var(--ui-border-default);
3950
+ border-radius: var(--ui-radius-lg);
3951
+ background: var(--ui-surface-raised);
3952
+ }
3953
+ [data-component~="ui-section"][data-ui-section-state~="variant=divided"][data-v-4d1e5a3a] {
3954
+ padding-block-start: var(--ui-space-6);
3955
+ border-block-start: 1px solid var(--ui-border-default);
3956
+ }
3957
+ [data-component~="ui-section"][data-ui-section-state~="variant=card"][data-ui-section-state~="tone=danger"][data-v-4d1e5a3a] {
3958
+ border-color: var(--ui-danger);
3959
+ }
3960
+ .head[data-v-4d1e5a3a] {
3961
+ display: flex;
3962
+ flex-wrap: wrap;
3963
+ align-items: flex-start;
3964
+ justify-content: space-between;
3965
+ gap: var(--ui-space-2) var(--ui-space-4);
3966
+ }
3967
+ .copy[data-v-4d1e5a3a] {
3968
+ display: flex;
3969
+ flex: 1 1 16rem;
3970
+ flex-direction: column;
3971
+ gap: var(--ui-space-1);
3972
+ min-inline-size: 0;
3973
+ }
3974
+ .heading[data-v-4d1e5a3a] {
3975
+ margin: 0;
3976
+ color: var(--ui-text-primary);
3977
+ font-size: var(--ui-font-size-lg);
3978
+ font-weight: var(--ui-font-semibold);
3979
+ line-height: var(--ui-line-height-tight);
3980
+ }
3981
+ [data-component~="ui-section"][data-ui-section-state~="tone=danger"] .heading[data-v-4d1e5a3a] {
3982
+ color: var(--ui-danger);
3983
+ }
3984
+ .description[data-v-4d1e5a3a] {
3985
+ color: var(--ui-text-secondary);
3986
+ font-size: var(--ui-font-size-sm);
3987
+ line-height: var(--ui-line-height);
3988
+ }
3989
+ .actions[data-v-4d1e5a3a] {
3990
+ display: inline-flex;
3991
+ flex-wrap: wrap;
3992
+ gap: var(--ui-space-2);
3993
+ }
3994
+ .body[data-v-4d1e5a3a] {
3995
+ display: flex;
3996
+ flex-direction: column;
3997
+ gap: var(--ui-space-4);
3998
+ min-inline-size: 0;
3999
+ }
4000
+ .description[data-v-4d1e5a3a]:empty,
4001
+ .actions[data-v-4d1e5a3a]:empty {
4002
+ display: none;
4003
+ }
4004
+ .head[data-v-4d1e5a3a]:has(.heading[hidden]):has(.description:empty):has(.actions:empty) {
4005
+ display: none;
4006
+ }
4007
+
4008
+ /* A component that sets its display still honours the hidden attribute on its root. */
4009
+ [data-component~="ui-section"][hidden][data-v-4d1e5a3a] {
4010
+ display: none;
4011
+ }
4012
+
3537
4013
  [data-component~="ui-select"][data-v-f9be4ab9] {
3538
4014
  box-sizing: border-box;
3539
4015
  display: inline-block;
@@ -3783,6 +4259,35 @@ hr[aria-orientation="vertical"][data-v-357ad177] {
3783
4259
  display: none;
3784
4260
  }
3785
4261
 
4262
+ /* Something is on its way. It turns in the current text colour; with reduced motion it holds still,
4263
+ and the label (or the text beside it) still says what is happening. */
4264
+ [data-component~="ui-spinner"][data-v-3472d01c] {
4265
+ display: inline-flex;
4266
+ flex: none;
4267
+ color: currentColor;
4268
+ font-size: var(--ui-font-size-lg);
4269
+ line-height: 1;
4270
+ animation: ui-spinner-turn-3472d01c 0.8s linear infinite;
4271
+ }
4272
+ [data-component~="ui-spinner"][data-ui-spinner-state~="size=sm"][data-v-3472d01c] {
4273
+ font-size: var(--ui-font-size-md);
4274
+ }
4275
+ @keyframes ui-spinner-turn-3472d01c {
4276
+ to {
4277
+ transform: rotate(1turn);
4278
+ }
4279
+ }
4280
+ @media (prefers-reduced-motion: reduce) {
4281
+ [data-component~="ui-spinner"][data-v-3472d01c] {
4282
+ animation: none;
4283
+ }
4284
+ }
4285
+
4286
+ /* A component that sets its display still honours the hidden attribute on its root. */
4287
+ [data-component~="ui-spinner"][hidden][data-v-3472d01c] {
4288
+ display: none;
4289
+ }
4290
+
3786
4291
  [data-component~="ui-stack"][data-v-e8d52a11] {
3787
4292
  --_layout-gap: var(--ui-space-4);
3788
4293
  display: flex;
@@ -3832,6 +4337,62 @@ hr[aria-orientation="vertical"][data-v-357ad177] {
3832
4337
  display: none;
3833
4338
  }
3834
4339
 
4340
+ /* The one way a view says it is loading, has nothing yet, or failed, with an optional next step.
4341
+ Every view says it the same way, in the same place, at the same size. */
4342
+ [data-component~="ui-status-message"][data-v-a56387a4] {
4343
+ display: flex;
4344
+ flex-wrap: wrap;
4345
+ align-items: center;
4346
+ gap: var(--ui-space-2) var(--ui-space-4);
4347
+ padding-block: var(--ui-space-4);
4348
+ color: var(--ui-text-muted);
4349
+ font-size: var(--ui-font-size-md);
4350
+ line-height: var(--ui-line-height);
4351
+ }
4352
+ [data-component~="ui-status-message"][data-ui-status-message-state~="kind=error"][data-v-a56387a4] {
4353
+ color: var(--ui-danger);
4354
+ }
4355
+ [data-component~="ui-status-message"][data-ui-status-message-state~="layout=panel"][data-v-a56387a4] {
4356
+ padding: var(--ui-space-6);
4357
+ border: 1px dashed var(--ui-border-default);
4358
+ border-radius: var(--ui-radius-lg);
4359
+ }
4360
+ [data-component~="ui-status-message"][data-ui-status-message-state~="layout=fill"][data-v-a56387a4] {
4361
+ flex: 1;
4362
+ flex-direction: column;
4363
+ justify-content: center;
4364
+ min-block-size: 50vh;
4365
+ text-align: center;
4366
+ }
4367
+ .copy[data-v-a56387a4] {
4368
+ display: flex;
4369
+ flex: 1 1 12rem;
4370
+ flex-direction: column;
4371
+ gap: var(--ui-space-1);
4372
+ min-inline-size: 0;
4373
+ }
4374
+ [data-component~="ui-status-message"][data-ui-status-message-state~="layout=fill"] .copy[data-v-a56387a4] {
4375
+ flex: none;
4376
+ align-items: center;
4377
+ }
4378
+ .heading[data-v-a56387a4] {
4379
+ color: var(--ui-text-primary);
4380
+ font-weight: var(--ui-font-semibold);
4381
+ }
4382
+ .action[data-v-a56387a4] {
4383
+ display: inline-flex;
4384
+ flex-wrap: wrap;
4385
+ gap: var(--ui-space-2);
4386
+ }
4387
+ .action[data-v-a56387a4]:empty {
4388
+ display: none;
4389
+ }
4390
+
4391
+ /* A component that sets its display still honours the hidden attribute on its root. */
4392
+ [data-component~="ui-status-message"][hidden][data-v-a56387a4] {
4393
+ display: none;
4394
+ }
4395
+
3835
4396
  [data-component~="ui-switch"][data-v-26ab3add] {
3836
4397
  display: inline-flex;
3837
4398
  align-items: flex-start;
@@ -4081,6 +4642,77 @@ input[data-v-26ab3add], input[data-v-26ab3add]::after {
4081
4642
  display: none;
4082
4643
  }
4083
4644
 
4645
+ /* Running text, set on the type scale and in a tone that says what it is, so a view never styles
4646
+ text of its own. The root is a paragraph unless as= names a span, div, small, strong, or label. */
4647
+ [data-component~="ui-text"][data-v-70a75450] {
4648
+ margin: 0;
4649
+ min-inline-size: 0;
4650
+ color: var(--ui-text-primary);
4651
+ text-align: start;
4652
+ }
4653
+ [data-component~="ui-text"][data-ui-text-state~="size=xs"][data-v-70a75450] {
4654
+ font-size: var(--ui-font-size-xs);
4655
+ line-height: var(--ui-line-height);
4656
+ }
4657
+ [data-component~="ui-text"][data-ui-text-state~="size=sm"][data-v-70a75450] {
4658
+ font-size: var(--ui-font-size-sm);
4659
+ line-height: var(--ui-line-height);
4660
+ }
4661
+ [data-component~="ui-text"][data-ui-text-state~="size=md"][data-v-70a75450] {
4662
+ font-size: var(--ui-font-size-md);
4663
+ line-height: var(--ui-line-height);
4664
+ }
4665
+ [data-component~="ui-text"][data-ui-text-state~="size=lg"][data-v-70a75450] {
4666
+ font-size: var(--ui-font-size-lg);
4667
+ line-height: var(--ui-line-height-relaxed);
4668
+ }
4669
+ [data-component~="ui-text"][data-ui-text-state~="tone=secondary"][data-v-70a75450] {
4670
+ color: var(--ui-text-secondary);
4671
+ }
4672
+ [data-component~="ui-text"][data-ui-text-state~="tone=muted"][data-v-70a75450] {
4673
+ color: var(--ui-text-muted);
4674
+ }
4675
+ [data-component~="ui-text"][data-ui-text-state~="tone=accent"][data-v-70a75450] {
4676
+ color: var(--ui-accent-active);
4677
+ }
4678
+ [data-component~="ui-text"][data-ui-text-state~="tone=danger"][data-v-70a75450] {
4679
+ color: var(--ui-danger);
4680
+ }
4681
+ [data-component~="ui-text"][data-ui-text-state~="tone=success"][data-v-70a75450] {
4682
+ color: var(--ui-success);
4683
+ }
4684
+ [data-component~="ui-text"][data-ui-text-state~="weight=normal"][data-v-70a75450] {
4685
+ font-weight: var(--ui-font-normal);
4686
+ }
4687
+ [data-component~="ui-text"][data-ui-text-state~="weight=medium"][data-v-70a75450] {
4688
+ font-weight: var(--ui-font-medium);
4689
+ }
4690
+ [data-component~="ui-text"][data-ui-text-state~="weight=semibold"][data-v-70a75450] {
4691
+ font-weight: var(--ui-font-semibold);
4692
+ }
4693
+ [data-component~="ui-text"][data-ui-text-state~="variant=eyebrow"][data-v-70a75450] {
4694
+ font-size: var(--ui-font-size-xs);
4695
+ font-weight: var(--ui-font-semibold);
4696
+ letter-spacing: 0.06em;
4697
+ text-transform: uppercase;
4698
+ }
4699
+ [data-component~="ui-text"][data-ui-text-state~="variant=code"][data-v-70a75450] {
4700
+ font-family: var(--ui-font-family-mono);
4701
+ }
4702
+ [data-component~="ui-text"][data-ui-text-state~="truncate"][data-v-70a75450] {
4703
+ overflow: hidden;
4704
+ text-overflow: ellipsis;
4705
+ white-space: nowrap;
4706
+ }
4707
+ [data-component~="ui-text"][data-ui-text-state~="align=center"][data-v-70a75450] {
4708
+ text-align: center;
4709
+ }
4710
+
4711
+ /* A component that sets its display still honours the hidden attribute on its root. */
4712
+ [data-component~="ui-text"][hidden][data-v-70a75450] {
4713
+ display: none;
4714
+ }
4715
+
4084
4716
  [data-component~="ui-textarea"][data-v-0352d397] {
4085
4717
  box-sizing: border-box;
4086
4718
  display: inline-block;