nexus-shared 3.2.0 → 4.1.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 (271) hide show
  1. package/CHANGELOG.md +2359 -0
  2. package/README.md +1911 -1123
  3. package/dist/Client.Index.d.ts +27 -0
  4. package/dist/Client.Index.js +27 -0
  5. package/dist/Components/Chats/ChatComposer.d.ts +7 -1
  6. package/dist/Components/Chats/ChatComposer.js +9 -6
  7. package/dist/Components/Chats/ChatParts.d.ts +15 -2
  8. package/dist/Components/Chats/ChatParts.js +15 -4
  9. package/dist/Components/Chats/ChatPopup.d.ts +46 -0
  10. package/dist/Components/Chats/ChatPopup.js +34 -0
  11. package/dist/Components/Chats/ChatThread.d.ts +9 -1
  12. package/dist/Components/Chats/ChatThread.js +54 -6
  13. package/dist/Components/Dashboards/DashboardBoard.d.ts +62 -0
  14. package/dist/Components/Dashboards/DashboardBoard.js +594 -0
  15. package/dist/Components/Dashboards/DashboardWidgets.d.ts +155 -0
  16. package/dist/Components/Dashboards/DashboardWidgets.js +159 -0
  17. package/dist/Components/Dashboards/WidgetFrame.d.ts +51 -0
  18. package/dist/Components/Dashboards/WidgetFrame.js +45 -0
  19. package/dist/Components/Documents/Button.d.ts +6 -1
  20. package/dist/Components/Documents/Button.js +2 -2
  21. package/dist/Components/Documents/DocumentFrame.d.ts +50 -0
  22. package/dist/Components/Documents/DocumentFrame.js +83 -0
  23. package/dist/Components/Documents/Menu.d.ts +4 -0
  24. package/dist/Components/Documents/Menu.js +40 -24
  25. package/dist/Components/Documents/PrintDocument.d.ts +95 -0
  26. package/dist/Components/Documents/PrintDocument.js +62 -0
  27. package/dist/Components/Documents/TabButtons.d.ts +6 -0
  28. package/dist/Components/Documents/TabButtons.js +5 -4
  29. package/dist/Components/Documents/Tabs.d.ts +59 -0
  30. package/dist/Components/Documents/Tabs.js +70 -0
  31. package/dist/Components/Domains/DomainCard.d.ts +98 -0
  32. package/dist/Components/Domains/DomainCard.js +182 -0
  33. package/dist/Components/Forms/ApiForm.js +24 -3
  34. package/dist/Components/Forms/Crud.d.ts +2 -2
  35. package/dist/Components/Forms/Crud.js +628 -247
  36. package/dist/Components/Forms/CrudActions.d.ts +137 -0
  37. package/dist/Components/Forms/CrudActions.js +214 -0
  38. package/dist/Components/Forms/CrudHistory.d.ts +6 -1
  39. package/dist/Components/Forms/CrudHistory.js +14 -6
  40. package/dist/Components/Forms/CrudNarrowPicker.d.ts +31 -0
  41. package/dist/Components/Forms/CrudNarrowPicker.js +180 -0
  42. package/dist/Components/Forms/CrudParts.d.ts +37 -2
  43. package/dist/Components/Forms/CrudParts.js +123 -7
  44. package/dist/Components/Forms/CrudRowForms.d.ts +26 -0
  45. package/dist/Components/Forms/CrudRowForms.js +174 -0
  46. package/dist/Components/Forms/CrudScopes.d.ts +28 -0
  47. package/dist/Components/Forms/CrudScopes.js +76 -0
  48. package/dist/Components/Forms/CrudTree.d.ts +90 -0
  49. package/dist/Components/Forms/CrudTree.js +363 -0
  50. package/dist/Components/Forms/CrudWorkspace.d.ts +73 -0
  51. package/dist/Components/Forms/CrudWorkspace.js +177 -0
  52. package/dist/Components/Forms/ExcelImport.js +3 -3
  53. package/dist/Components/Forms/Form.d.ts +6 -5
  54. package/dist/Components/Forms/Form.js +134 -21
  55. package/dist/Components/Forms/FormLeaveGuard.d.ts +44 -0
  56. package/dist/Components/Forms/FormLeaveGuard.js +65 -0
  57. package/dist/Components/Forms/FormQuestion.d.ts +6 -0
  58. package/dist/Components/Forms/FormQuestion.js +28 -0
  59. package/dist/Components/Forms/RecordFlows.d.ts +50 -0
  60. package/dist/Components/Forms/RecordFlows.js +282 -0
  61. package/dist/Components/Forms/SubmitForm.d.ts +37 -2
  62. package/dist/Components/Forms/SubmitForm.js +182 -10
  63. package/dist/Components/Inputs/CheckBox.js +1 -1
  64. package/dist/Components/Inputs/ChoiceField.d.ts +21 -1
  65. package/dist/Components/Inputs/ChoiceField.js +28 -2
  66. package/dist/Components/Inputs/ComputedInput.d.ts +51 -0
  67. package/dist/Components/Inputs/ComputedInput.js +179 -0
  68. package/dist/Components/Inputs/Dropdown.d.ts +13 -0
  69. package/dist/Components/Inputs/Dropdown.js +8 -6
  70. package/dist/Components/Inputs/DropdownParts.d.ts +3 -1
  71. package/dist/Components/Inputs/DropdownParts.js +16 -4
  72. package/dist/Components/Inputs/Field.d.ts +7 -1
  73. package/dist/Components/Inputs/Field.js +2 -2
  74. package/dist/Components/Inputs/GroupForm.d.ts +6 -6
  75. package/dist/Components/Inputs/GroupForm.js +12 -12
  76. package/dist/Components/Inputs/InputRenderer.d.ts +13 -6
  77. package/dist/Components/Inputs/InputRenderer.js +37 -32
  78. package/dist/Components/Inputs/MarkdownEditor.d.ts +6 -0
  79. package/dist/Components/Inputs/MarkdownEditor.js +32 -6
  80. package/dist/Components/Inputs/PictureInput.d.ts +41 -0
  81. package/dist/Components/Inputs/PictureInput.js +75 -0
  82. package/dist/Components/Inputs/RadioGroup.d.ts +16 -3
  83. package/dist/Components/Inputs/RadioGroup.js +8 -3
  84. package/dist/Components/Inputs/RowsInput.d.ts +15 -2
  85. package/dist/Components/Inputs/RowsInput.js +96 -8
  86. package/dist/Components/Inputs/TabularForm.d.ts +5 -5
  87. package/dist/Components/Inputs/TabularForm.js +45 -32
  88. package/dist/Components/Inputs/TextArea.d.ts +6 -0
  89. package/dist/Components/Inputs/TextArea.js +11 -2
  90. package/dist/Components/Inputs/TextBoxTypes.d.ts +6 -0
  91. package/dist/Components/Inputs/TextBoxTypes.js +17 -0
  92. package/dist/Components/Inputs/TreeView.d.ts +76 -2
  93. package/dist/Components/Inputs/TreeView.js +227 -16
  94. package/dist/Components/Layouts/MessageBox.d.ts +15 -2
  95. package/dist/Components/Layouts/MessageBox.js +56 -7
  96. package/dist/Components/Layouts/Popup.d.ts +34 -7
  97. package/dist/Components/Layouts/Popup.js +143 -13
  98. package/dist/Components/Layouts/PopupDock.d.ts +3 -1
  99. package/dist/Components/Layouts/PopupDock.js +2 -1
  100. package/dist/Components/Layouts/PopupHost.js +5 -4
  101. package/dist/Components/Messages/MailClient.d.ts +50 -0
  102. package/dist/Components/Messages/MailClient.js +410 -0
  103. package/dist/Components/Messages/MailColumns.d.ts +21 -0
  104. package/dist/Components/Messages/MailColumns.js +92 -0
  105. package/dist/Components/Messages/MailCompose.d.ts +46 -0
  106. package/dist/Components/Messages/MailCompose.js +154 -0
  107. package/dist/Components/Messages/MailReader.d.ts +43 -0
  108. package/dist/Components/Messages/MailReader.js +207 -0
  109. package/dist/Components/Messages/MailThread.d.ts +71 -0
  110. package/dist/Components/Messages/MailThread.js +185 -0
  111. package/dist/Components/Messages/MessageBell.d.ts +41 -0
  112. package/dist/Components/Messages/MessageBell.js +76 -0
  113. package/dist/Components/Viewers/DataTable.js +153 -49
  114. package/dist/Components/Viewers/DataTableColumns.d.ts +2 -2
  115. package/dist/Components/Viewers/DataTableColumns.js +2 -1
  116. package/dist/Components/Viewers/DataTableFilters.d.ts +1 -1
  117. package/dist/Components/Viewers/DataTableFilters.js +17 -2
  118. package/dist/Components/Viewers/DataTableParts.d.ts +23 -5
  119. package/dist/Components/Viewers/DataTableParts.js +26 -14
  120. package/dist/Components/Viewers/OwnerFiles.d.ts +227 -0
  121. package/dist/Components/Viewers/OwnerFiles.js +700 -0
  122. package/dist/Components/Viewers/QrCodeImage.d.ts +22 -0
  123. package/dist/Components/Viewers/QrCodeImage.js +15 -0
  124. package/dist/Components/Viewers/RecordCards.d.ts +16 -0
  125. package/dist/Components/Viewers/RecordCards.js +509 -0
  126. package/dist/Helpers/ApiModules.js +4 -0
  127. package/dist/Helpers/AuditEntries.d.ts +50 -0
  128. package/dist/Helpers/AuditEntries.js +96 -0
  129. package/dist/Helpers/BusyHooks.d.ts +6 -0
  130. package/dist/Helpers/BusyHooks.js +39 -0
  131. package/dist/Helpers/ChatBackend.d.ts +8 -1
  132. package/dist/Helpers/ChatBackend.js +18 -0
  133. package/dist/Helpers/ChatHelpers.d.ts +2 -0
  134. package/dist/Helpers/ChatHelpers.js +4 -1
  135. package/dist/Helpers/CrudBackend.d.ts +20 -2
  136. package/dist/Helpers/CrudBackend.js +46 -2
  137. package/dist/Helpers/CrudColumns.d.ts +91 -6
  138. package/dist/Helpers/CrudColumns.js +148 -7
  139. package/dist/Helpers/CrudDetailsTabs.d.ts +58 -0
  140. package/dist/Helpers/CrudDetailsTabs.js +126 -0
  141. package/dist/Helpers/CrudHelpers.d.ts +116 -2
  142. package/dist/Helpers/CrudHelpers.js +256 -0
  143. package/dist/Helpers/CrudNarrowPick.d.ts +83 -0
  144. package/dist/Helpers/CrudNarrowPick.js +157 -0
  145. package/dist/Helpers/CrudPickerPlan.d.ts +58 -0
  146. package/dist/Helpers/CrudPickerPlan.js +46 -0
  147. package/dist/Helpers/CrudRowForms.d.ts +32 -0
  148. package/dist/Helpers/CrudRowForms.js +76 -0
  149. package/dist/Helpers/CrudScopes.d.ts +32 -0
  150. package/dist/Helpers/CrudScopes.js +79 -0
  151. package/dist/Helpers/DashboardHelpers.d.ts +115 -0
  152. package/dist/Helpers/DashboardHelpers.js +305 -0
  153. package/dist/Helpers/DomainCards.d.ts +140 -0
  154. package/dist/Helpers/DomainCards.js +370 -0
  155. package/dist/Helpers/DropdownHelpers.d.ts +3 -1
  156. package/dist/Helpers/DropdownHelpers.js +6 -2
  157. package/dist/Helpers/ExcelHelpers.d.ts +1 -1
  158. package/dist/Helpers/ExcelHelpers.js +12 -11
  159. package/dist/Helpers/FileAdapter.d.ts +158 -0
  160. package/dist/Helpers/FileAdapter.js +173 -0
  161. package/dist/Helpers/FilePrimaries.d.ts +48 -0
  162. package/dist/Helpers/FilePrimaries.js +138 -0
  163. package/dist/Helpers/FormConfirm.d.ts +32 -0
  164. package/dist/Helpers/FormConfirm.js +40 -0
  165. package/dist/Helpers/FormStore.d.ts +100 -5
  166. package/dist/Helpers/FormStore.js +368 -25
  167. package/dist/Helpers/InputConditions.d.ts +56 -0
  168. package/dist/Helpers/InputConditions.js +192 -0
  169. package/dist/Helpers/InputMemory.d.ts +106 -0
  170. package/dist/Helpers/InputMemory.js +395 -0
  171. package/dist/Helpers/InputNarrowing.d.ts +50 -0
  172. package/dist/Helpers/InputNarrowing.js +148 -0
  173. package/dist/Helpers/InputParamsHelpers.d.ts +44 -1
  174. package/dist/Helpers/InputParamsHelpers.js +157 -74
  175. package/dist/Helpers/MailClientHelpers.d.ts +96 -0
  176. package/dist/Helpers/MailClientHelpers.js +211 -0
  177. package/dist/Helpers/MessageBackend.d.ts +152 -0
  178. package/dist/Helpers/MessageBackend.js +329 -0
  179. package/dist/Helpers/MessageHelpers.d.ts +160 -0
  180. package/dist/Helpers/MessageHelpers.js +573 -0
  181. package/dist/Helpers/MessageUnread.d.ts +95 -0
  182. package/dist/Helpers/MessageUnread.js +245 -0
  183. package/dist/Helpers/NexusDriveAdapter.d.ts +71 -0
  184. package/dist/Helpers/NexusDriveAdapter.js +236 -0
  185. package/dist/Helpers/NumberHelpers.d.ts +156 -0
  186. package/dist/Helpers/NumberHelpers.js +242 -0
  187. package/dist/Helpers/PagedPicker.d.ts +42 -0
  188. package/dist/Helpers/PagedPicker.js +85 -0
  189. package/dist/Helpers/Permissions.js +2 -1
  190. package/dist/Helpers/QrCode.d.ts +26 -0
  191. package/dist/Helpers/QrCode.js +463 -0
  192. package/dist/Helpers/RecordCards.d.ts +205 -0
  193. package/dist/Helpers/RecordCards.js +378 -0
  194. package/dist/Helpers/RequestCache.d.ts +14 -2
  195. package/dist/Helpers/RequestCache.js +22 -3
  196. package/dist/Helpers/RowsStore.d.ts +61 -2
  197. package/dist/Helpers/RowsStore.js +203 -16
  198. package/dist/Helpers/ServerPreview.d.ts +69 -0
  199. package/dist/Helpers/ServerPreview.js +99 -0
  200. package/dist/Helpers/TableColumns.js +4 -3
  201. package/dist/Helpers/TableExport.d.ts +7 -1
  202. package/dist/Helpers/TableExport.js +9 -3
  203. package/dist/Helpers/TableFilters.d.ts +1 -1
  204. package/dist/Helpers/TableFilters.js +24 -23
  205. package/dist/Helpers/TableHelpers.d.ts +38 -4
  206. package/dist/Helpers/TableHelpers.js +78 -10
  207. package/dist/Helpers/TableJoins.d.ts +13 -0
  208. package/dist/Helpers/TableJoins.js +34 -0
  209. package/dist/Helpers/TableStore.d.ts +28 -4
  210. package/dist/Helpers/TableStore.js +73 -11
  211. package/dist/Helpers/ToolbarFit.d.ts +23 -0
  212. package/dist/Helpers/ToolbarFit.js +30 -0
  213. package/dist/Helpers/TreeStore.d.ts +156 -6
  214. package/dist/Helpers/TreeStore.js +547 -18
  215. package/dist/Interfaces/ApiInterfaces.d.ts +10 -1
  216. package/dist/Interfaces/ApiInterfaces.js +10 -1
  217. package/dist/Interfaces/ChatInterfaces.d.ts +22 -0
  218. package/dist/Interfaces/CrudInterfaces.d.ts +539 -6
  219. package/dist/Interfaces/DashboardInterfaces.d.ts +123 -0
  220. package/dist/Interfaces/DashboardInterfaces.js +1 -0
  221. package/dist/Interfaces/DomainInterfaces.d.ts +145 -0
  222. package/dist/Interfaces/DomainInterfaces.js +1 -0
  223. package/dist/Interfaces/FileInterfaces.d.ts +183 -0
  224. package/dist/Interfaces/FileInterfaces.js +6 -0
  225. package/dist/Interfaces/FormInterfaces.d.ts +460 -32
  226. package/dist/Interfaces/FormInterfaces.js +79 -1
  227. package/dist/Interfaces/InputInterfaces.d.ts +22 -3
  228. package/dist/Interfaces/MailInterfaces.d.ts +192 -0
  229. package/dist/Interfaces/MailInterfaces.js +1 -0
  230. package/dist/Interfaces/RecordInterfaces.d.ts +367 -0
  231. package/dist/Interfaces/RecordInterfaces.js +1 -0
  232. package/dist/Interfaces/TableInterfaces.d.ts +102 -3
  233. package/dist/Services/ExcelApi.js +5 -0
  234. package/dist/Services/FileApi.d.ts +13 -0
  235. package/dist/Services/FileApi.js +29 -0
  236. package/dist/Services/ImageEditorLoader.d.ts +14 -0
  237. package/dist/Services/ImageEditorLoader.js +51 -0
  238. package/dist/Services/JoinSources.d.ts +79 -6
  239. package/dist/Services/JoinSources.js +132 -21
  240. package/dist/Services/MessageApi.d.ts +18 -0
  241. package/dist/Services/MessageApi.js +64 -0
  242. package/dist/Services/ModuleImport.d.ts +7 -0
  243. package/dist/Services/ModuleImport.js +22 -0
  244. package/dist/Shared.Index.d.ts +28 -0
  245. package/dist/Shared.Index.js +28 -0
  246. package/package.json +13 -2
  247. package/src/Styles/Nexus.Avatar.css +6 -5
  248. package/src/Styles/Nexus.Button.css +39 -4
  249. package/src/Styles/Nexus.Chat.css +114 -22
  250. package/src/Styles/Nexus.Choice.css +16 -0
  251. package/src/Styles/Nexus.Crud.css +486 -21
  252. package/src/Styles/Nexus.Dashboard.css +763 -0
  253. package/src/Styles/Nexus.Domain.css +384 -0
  254. package/src/Styles/Nexus.Dropdown.css +8 -0
  255. package/src/Styles/Nexus.Editor.css +20 -0
  256. package/src/Styles/Nexus.Files.css +437 -0
  257. package/src/Styles/Nexus.Form.css +5 -2
  258. package/src/Styles/Nexus.Index.css +7 -0
  259. package/src/Styles/Nexus.Input.css +73 -0
  260. package/src/Styles/Nexus.Mail.css +1062 -0
  261. package/src/Styles/Nexus.Menu.css +10 -1
  262. package/src/Styles/Nexus.Popup.css +135 -1
  263. package/src/Styles/Nexus.Print.css +288 -0
  264. package/src/Styles/Nexus.QrCode.css +12 -0
  265. package/src/Styles/Nexus.Record.css +430 -0
  266. package/src/Styles/Nexus.Tab.Buttons.css +87 -22
  267. package/src/Styles/Nexus.Table.css +1458 -1387
  268. package/src/Styles/Nexus.Theme.Picker.css +1 -0
  269. package/src/Styles/Nexus.Themes.css +12 -6
  270. package/src/Styles/Nexus.Tokens.css +8 -3
  271. package/src/Styles/Nexus.Tree.css +41 -1
@@ -0,0 +1,430 @@
1
+ @layer nexus.components {
2
+ /*
3
+ * A record's page of cards (`RecordCards`): the hero across the top, then the cards, as many to a row as have 26rem
4
+ * each (one on a phone), each as tall as what it holds. A card is a panel - the admin panel's edge, corner and surface -
5
+ * with its heading (an icon, the title and its count, a sentence, its buttons) over its body. Nothing inside a card is
6
+ * boxed: fields are label over value, items are rows between hairlines that reach the card's edges.
7
+ */
8
+ .nx-record {
9
+ display: grid;
10
+ gap: var(--nx-space-4);
11
+ min-width: 0;
12
+ container-type: inline-size;
13
+ }
14
+
15
+ .nx-record__cards {
16
+ display: grid;
17
+ grid-template-columns: repeat(auto-fill, minmax(min(100%, 26rem), 1fr));
18
+ gap: var(--nx-space-4);
19
+ align-items: start;
20
+ }
21
+
22
+ .nx-record-card,
23
+ .nx-record-hero {
24
+ min-width: 0;
25
+ border: 1px solid var(--nx-border);
26
+ border-radius: var(--nx-radius-lg);
27
+ background: var(--nx-surface);
28
+ /* A link to a card (`#emails`) leaves a little room above it. */
29
+ scroll-margin-block: var(--nx-space-4);
30
+ }
31
+
32
+ .nx-record-card--wide {
33
+ grid-column: 1 / -1;
34
+ }
35
+
36
+ .nx-record-card__head {
37
+ display: flex;
38
+ align-items: flex-start;
39
+ gap: var(--nx-space-3);
40
+ padding: var(--nx-space-4) var(--nx-space-4) 0;
41
+ }
42
+
43
+ /* The card's icon on a soft tint of the theme's colour: an icon, so 3:1 is its floor. */
44
+ .nx-record-card__icon {
45
+ display: grid;
46
+ flex: none;
47
+ place-items: center;
48
+ width: var(--nx-control-sm);
49
+ height: var(--nx-control-sm);
50
+ border-radius: var(--nx-radius);
51
+ background: color-mix(in oklab, var(--nx-primary) 12%, var(--nx-surface));
52
+ color: var(--nx-primary);
53
+ }
54
+
55
+ .nx-record-card__text {
56
+ display: grid;
57
+ flex: 1 1 auto;
58
+ align-content: center;
59
+ min-width: 0;
60
+ /* The title's line is a button's height, so a heading with buttons and one without line up. */
61
+ min-height: var(--nx-control-sm);
62
+ }
63
+
64
+ /*
65
+ * The title and its sentence, then the buttons. The text keeps at least 12rem beside them; a narrow card (a phone, two
66
+ * buttons, a long label) puts the buttons on a line of their own under the text, at its start, never squeezing the
67
+ * title to a few words a line.
68
+ */
69
+ .nx-record-card__main {
70
+ display: flex;
71
+ flex: 1 1 auto;
72
+ flex-wrap: wrap;
73
+ align-items: flex-start;
74
+ gap: var(--nx-space-2) var(--nx-space-3);
75
+ min-width: 0;
76
+ }
77
+
78
+ .nx-record-card__main > .nx-record-card__text {
79
+ flex: 1 1 12rem;
80
+ }
81
+
82
+ /* A title alone needs less: its buttons stay beside it down to 8rem. */
83
+ .nx-record-card__main > .nx-record-card__text:not(:has(> .nx-record-card__lead)) {
84
+ flex-basis: 8rem;
85
+ }
86
+
87
+ .nx-record-card__main > .nx-record-card__actions {
88
+ justify-content: flex-start;
89
+ }
90
+
91
+ .nx-record-card__title {
92
+ display: flex;
93
+ flex-wrap: wrap;
94
+ align-items: baseline;
95
+ gap: 0 var(--nx-space-2);
96
+ margin: 0;
97
+ font-size: var(--nx-text-lg);
98
+ font-weight: 600;
99
+ line-height: var(--nx-control-sm);
100
+ overflow-wrap: anywhere;
101
+ }
102
+
103
+ /* Focused from code only (the focus coming home after a popup), never by Tab: no ring of its own. */
104
+ .nx-record-card__title:focus {
105
+ outline: none;
106
+ }
107
+
108
+ /* Its own line height, so the title's line is the same with a count and without one (while the list is read). */
109
+ .nx-record-card__count {
110
+ color: var(--nx-text-muted);
111
+ line-height: 1;
112
+ font-size: var(--nx-text-sm);
113
+ font-weight: 500;
114
+ font-variant-numeric: tabular-nums;
115
+ }
116
+
117
+ .nx-record-card__lead {
118
+ margin: 0 0 var(--nx-space-1);
119
+ color: var(--nx-text-muted);
120
+ font-size: var(--nx-text-sm);
121
+ line-height: 1.45;
122
+ }
123
+
124
+ .nx-record-card__actions {
125
+ display: flex;
126
+ flex: none;
127
+ flex-wrap: wrap;
128
+ justify-content: flex-end;
129
+ gap: var(--nx-space-2);
130
+ }
131
+
132
+ .nx-record-card__body {
133
+ min-width: 0;
134
+ padding: var(--nx-space-3) var(--nx-space-4) var(--nx-space-4);
135
+ }
136
+
137
+ .nx-record-card__empty {
138
+ margin: 0;
139
+ color: var(--nx-text-muted);
140
+ font-size: var(--nx-text-sm);
141
+ }
142
+
143
+ .nx-record-card__message {
144
+ margin: 0 0 var(--nx-space-3);
145
+ font-size: var(--nx-text-md);
146
+ }
147
+
148
+ /* A list reaches the card's edges, its last row as close to the foot as the heading is to the first. */
149
+ .nx-record-card--items > .nx-record-card__body {
150
+ padding: var(--nx-space-2) 0 var(--nx-space-1);
151
+ }
152
+
153
+ .nx-record-card--items > .nx-record-card__body > :is(.nx-record-card__empty, .nx-record__failed) {
154
+ margin: var(--nx-space-1) var(--nx-space-4) var(--nx-space-3);
155
+ }
156
+
157
+ /* A card of the page's own stacks what it is given at the cards' own gap, a paragraph's margins dropped. */
158
+ .nx-record-card--content > .nx-record-card__body {
159
+ display: grid;
160
+ gap: var(--nx-space-3);
161
+ align-content: start;
162
+ }
163
+
164
+ .nx-record-card--content > .nx-record-card__body > * {
165
+ margin-block: 0;
166
+ }
167
+
168
+ /* While a source loads: the table's bone, on the line it holds (the table draws it as a block, so two classes). */
169
+ .nx-table__bone.nx-record__bone {
170
+ display: inline-block;
171
+ max-width: 100%;
172
+ vertical-align: baseline;
173
+ }
174
+
175
+ /* A mark held while it is read: a tag's size, the bone's tint. */
176
+ .nx-record__bone-tag {
177
+ width: 7rem;
178
+ background: color-mix(in oklab, var(--nx-text) 9%, transparent);
179
+ }
180
+
181
+ .nx-record__held {
182
+ display: grid;
183
+ }
184
+
185
+ /* A held line is a line box of the text it stands for (its font and line height), its bone on the baseline. */
186
+ .nx-record__held-line,
187
+ .nx-record-item__text > .nx-record__held-line {
188
+ display: block;
189
+ }
190
+
191
+ /* The hero */
192
+
193
+ .nx-record-hero {
194
+ --nx-record-hero-picture: 5.5rem;
195
+
196
+ display: flex;
197
+ align-items: center;
198
+ gap: var(--nx-space-4);
199
+ padding: var(--nx-space-4) var(--nx-space-5);
200
+ }
201
+
202
+ .nx-record-hero__picture {
203
+ display: flex;
204
+ flex: none;
205
+ }
206
+
207
+ .nx-record-hero__text {
208
+ display: grid;
209
+ flex: 1 1 auto;
210
+ gap: 2px;
211
+ min-width: 0;
212
+ }
213
+
214
+ .nx-record-hero__title {
215
+ margin: 0;
216
+ font-size: var(--nx-text-xl);
217
+ font-weight: 650;
218
+ letter-spacing: -0.01em;
219
+ line-height: 1.3;
220
+ overflow-wrap: anywhere;
221
+ }
222
+
223
+ .nx-record-hero__line {
224
+ margin: 0;
225
+ color: var(--nx-text-muted);
226
+ font-size: var(--nx-text-sm);
227
+ line-height: 1.45;
228
+ overflow-wrap: anywhere;
229
+ }
230
+
231
+ .nx-record-hero__marks {
232
+ display: flex;
233
+ flex-wrap: wrap;
234
+ gap: 4px;
235
+ margin-top: var(--nx-space-1);
236
+ }
237
+
238
+ .nx-record-hero > .nx-record-card__actions {
239
+ align-self: flex-start;
240
+ }
241
+
242
+ /* Fields: label over value, as many to a row as have 11rem; long text and chips across. */
243
+
244
+ .nx-record-fields {
245
+ display: grid;
246
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
247
+ gap: var(--nx-space-3) var(--nx-space-4);
248
+ margin: 0;
249
+ }
250
+
251
+ .nx-record-field {
252
+ min-width: 0;
253
+ }
254
+
255
+ .nx-record-field--wide {
256
+ grid-column: 1 / -1;
257
+ }
258
+
259
+ .nx-record-field__label {
260
+ color: var(--nx-text-muted);
261
+ font-size: var(--nx-text-xs);
262
+ font-weight: 500;
263
+ line-height: 1.5;
264
+ }
265
+
266
+ /* One line's height while it loads too, so nothing moves when the values come. */
267
+ .nx-record-field__value {
268
+ min-height: 1.45em;
269
+ margin: 0;
270
+ font-size: var(--nx-text-md);
271
+ line-height: 1.45;
272
+ overflow-wrap: anywhere;
273
+ }
274
+
275
+ .nx-record-field__empty {
276
+ color: var(--nx-text-muted);
277
+ }
278
+
279
+ .nx-record-field__lines {
280
+ white-space: pre-line;
281
+ }
282
+
283
+ .nx-record-chips {
284
+ display: flex;
285
+ flex-wrap: wrap;
286
+ gap: 4px;
287
+ margin: 2px 0 0;
288
+ padding: 0;
289
+ list-style: none;
290
+ }
291
+
292
+ /* Items: rows between hairlines, a picture or an icon, the name and its marks, lines, and icon buttons on the right. */
293
+
294
+ .nx-record-items {
295
+ display: grid;
296
+ margin: 0;
297
+ padding: 0;
298
+ list-style: none;
299
+ }
300
+
301
+ .nx-record-item {
302
+ display: flex;
303
+ align-items: center;
304
+ gap: var(--nx-space-3);
305
+ min-width: 0;
306
+ padding: var(--nx-space-2) var(--nx-space-4);
307
+ }
308
+
309
+ .nx-record-item + .nx-record-item {
310
+ border-top: 1px solid var(--nx-border);
311
+ }
312
+
313
+ .nx-record-item__media {
314
+ display: grid;
315
+ flex: none;
316
+ place-items: center;
317
+ width: var(--nx-control-md);
318
+ height: var(--nx-control-md);
319
+ overflow: hidden;
320
+ border-radius: 50%;
321
+ }
322
+
323
+ .nx-record-item__media--icon {
324
+ border-radius: var(--nx-radius);
325
+ background: color-mix(in oklab, var(--nx-text) 6%, var(--nx-surface));
326
+ color: var(--nx-text-muted);
327
+ }
328
+
329
+ .nx-record-item__media--held {
330
+ background: color-mix(in oklab, var(--nx-text) 9%, transparent);
331
+ }
332
+
333
+ .nx-record-item__text {
334
+ display: grid;
335
+ flex: 1 1 auto;
336
+ gap: 2px;
337
+ min-width: 0;
338
+ }
339
+
340
+ /* At least a mark's height, so a row is as tall with marks as without, and as its held row. */
341
+ .nx-record-item__title {
342
+ display: flex;
343
+ flex-wrap: wrap;
344
+ align-items: center;
345
+ gap: 2px var(--nx-space-2);
346
+ min-height: calc(var(--nx-text-xs) * 1.6 + 2px);
347
+ margin: 0;
348
+ font-size: var(--nx-text-md);
349
+ font-weight: 500;
350
+ line-height: 1.45;
351
+ }
352
+
353
+ .nx-record-item__name {
354
+ min-width: 0;
355
+ overflow-wrap: anywhere;
356
+ }
357
+
358
+ .nx-record-item__marks {
359
+ display: inline-flex;
360
+ flex-wrap: wrap;
361
+ gap: 4px;
362
+ }
363
+
364
+ .nx-record-item__line {
365
+ margin: 0;
366
+ color: var(--nx-text-muted);
367
+ font-size: var(--nx-text-sm);
368
+ line-height: 1.45;
369
+ overflow-wrap: anywhere;
370
+ }
371
+
372
+ .nx-record-item__actions {
373
+ display: flex;
374
+ flex: none;
375
+ align-items: center;
376
+ gap: 2px;
377
+ }
378
+
379
+ /* A popup's step: its sentence over the form, and the button that stays on it under. */
380
+
381
+ .nx-record-step {
382
+ display: grid;
383
+ gap: var(--nx-space-3);
384
+ }
385
+
386
+ .nx-record-step__lead {
387
+ font-size: var(--nx-text-md);
388
+ line-height: 1.5;
389
+ }
390
+
391
+ .nx-record-step__lead > p {
392
+ margin: 0;
393
+ }
394
+
395
+ .nx-record-step__also {
396
+ margin: 0;
397
+ }
398
+
399
+ /* A narrow page (a phone, a popup): the hero's picture smaller, its padding the cards'. */
400
+ @container (max-width: 34rem) {
401
+ .nx-record-hero {
402
+ --nx-record-hero-picture: 4rem;
403
+
404
+ gap: var(--nx-space-3);
405
+ padding: var(--nx-space-4);
406
+ }
407
+
408
+ .nx-record-hero__title {
409
+ font-size: var(--nx-text-lg);
410
+ }
411
+
412
+ .nx-record-card__head {
413
+ padding: var(--nx-space-3) var(--nx-space-3) 0;
414
+ }
415
+
416
+ .nx-record-card__body {
417
+ padding: var(--nx-space-3);
418
+ }
419
+
420
+ .nx-record-item {
421
+ gap: var(--nx-space-2);
422
+ padding-inline: var(--nx-space-3);
423
+ }
424
+
425
+ .nx-record-item__media {
426
+ width: var(--nx-control-sm);
427
+ height: var(--nx-control-sm);
428
+ }
429
+ }
430
+ }
@@ -105,25 +105,25 @@
105
105
  transition: color var(--nx-duration);
106
106
  }
107
107
 
108
- .nx-tabs__option:hover:not(:has(:checked, :disabled)) {
108
+ .nx-tabs__option:hover:not(:has(:checked, :disabled), [aria-selected="true"], :disabled) {
109
109
  background: var(--nx-tabs-hover);
110
110
  color: var(--nx-text);
111
111
  }
112
112
 
113
- .nx-tabs__option:has(:checked) {
113
+ .nx-tabs__option:is(:has(:checked), [aria-selected="true"]) {
114
114
  color: var(--nx-tabs-active-color);
115
115
  cursor: default;
116
116
  }
117
117
 
118
- .nx-tabs__option:has(:checked) .nx-icon {
118
+ .nx-tabs__option:is(:has(:checked), [aria-selected="true"]) .nx-icon {
119
119
  color: var(--nx-tabs-active-icon);
120
120
  }
121
121
 
122
- .nx-tabs__option:has(:focus-visible) {
122
+ .nx-tabs__option:is(:has(:focus-visible), :focus-visible) {
123
123
  box-shadow: var(--nx-focus-ring);
124
124
  }
125
125
 
126
- .nx-tabs__option:has(:disabled) {
126
+ .nx-tabs__option:is(:has(:disabled), :disabled) {
127
127
  cursor: not-allowed;
128
128
  opacity: 0.45;
129
129
  }
@@ -178,7 +178,7 @@
178
178
  padding 240ms cubic-bezier(0.2, 0, 0, 1);
179
179
  }
180
180
 
181
- .nx-tabs--labels-selected .nx-tabs__option:has(:checked) {
181
+ .nx-tabs--labels-selected .nx-tabs__option:is(:has(:checked), [aria-selected="true"]) {
182
182
  padding: 0 var(--nx-space-3);
183
183
  background: var(--nx-tabs-indicator);
184
184
  box-shadow:
@@ -187,7 +187,7 @@
187
187
  }
188
188
 
189
189
  /* In a full-width group, the selected option takes the free space. */
190
- .nx-tabs--labels-selected.nx-tabs--block .nx-tabs__option:has(:checked) {
190
+ .nx-tabs--labels-selected.nx-tabs--block .nx-tabs__option:is(:has(:checked), [aria-selected="true"]) {
191
191
  flex: 1 1 auto;
192
192
  }
193
193
 
@@ -202,7 +202,7 @@
202
202
  margin 240ms cubic-bezier(0.2, 0, 0, 1);
203
203
  }
204
204
 
205
- .nx-tabs--labels-selected .nx-tabs__option:has(:checked) .nx-tabs__label {
205
+ .nx-tabs--labels-selected .nx-tabs__option:is(:has(:checked), [aria-selected="true"]) .nx-tabs__label {
206
206
  grid-template-columns: 1fr;
207
207
  margin-inline-start: 6px;
208
208
  }
@@ -239,9 +239,10 @@
239
239
  * its own, exactly as the one choice's indicator is, and an option that is not chosen sits flat on the track. The
240
240
  * options wrap onto more rows when they do not fit, each row as tall as a one-row track's options, so a picker of
241
241
  * 26 letters is one track of several rows rather than a line that runs off a phone. A one-character option is
242
- * square, so a row of letters lines up.
242
+ * square, so a row of letters lines up. A choice group drawn as tabs (`RadioGroup design="tabs"`, `nx-tabs--wrap`)
243
+ * is drawn the same way: its choice lives in the inputs, not in a value the track could slide an indicator to.
243
244
  */
244
- .nx-tabs--multiple {
245
+ :is(.nx-tabs--multiple, .nx-tabs--wrap) {
245
246
  --nx-tabs-option-height: calc(var(--nx-tabs-height) - 2 * var(--nx-tabs-pad) - 2px);
246
247
 
247
248
  display: inline-flex;
@@ -251,26 +252,30 @@
251
252
  height: auto;
252
253
  }
253
254
 
254
- .nx-tabs--multiple.nx-tabs--block {
255
+ :is(.nx-tabs--multiple, .nx-tabs--wrap).nx-tabs--block {
255
256
  display: flex;
256
257
  }
257
258
 
258
- .nx-tabs--multiple .nx-tabs__option {
259
+ :is(.nx-tabs--multiple, .nx-tabs--wrap) .nx-tabs__option {
259
260
  flex: 0 0 auto;
260
261
  min-width: var(--nx-tabs-option-height);
261
262
  height: var(--nx-tabs-option-height);
262
263
  }
263
264
 
264
- /* A chosen option can be unchosen, so it keeps the pointer, and it keeps its raised look under the pointer too. */
265
- .nx-tabs--multiple .nx-tabs__option:has(:checked) {
265
+ /* A chosen option keeps its raised look under the pointer too. */
266
+ :is(.nx-tabs--multiple, .nx-tabs--wrap) .nx-tabs__option:has(:checked) {
266
267
  background: var(--nx-tabs-indicator);
267
268
  box-shadow:
268
269
  inset 0 0 0 1px var(--nx-tabs-indicator-border),
269
270
  var(--nx-tabs-indicator-shadow);
271
+ }
272
+
273
+ /* One of several can be unchosen, so it keeps the pointer. */
274
+ .nx-tabs--multiple .nx-tabs__option:has(:checked) {
270
275
  cursor: pointer;
271
276
  }
272
277
 
273
- .nx-tabs--multiple .nx-tabs__option:has(:checked):has(:focus-visible) {
278
+ :is(.nx-tabs--multiple, .nx-tabs--wrap) .nx-tabs__option:has(:checked):has(:focus-visible) {
274
279
  box-shadow:
275
280
  inset 0 0 0 1px var(--nx-tabs-indicator-border),
276
281
  var(--nx-focus-ring);
@@ -278,7 +283,7 @@
278
283
 
279
284
  /* A finger needs more than a small button's 22px: on a touch screen every option is a medium control's height, square at the least. */
280
285
  @media (pointer: coarse) {
281
- .nx-tabs--multiple {
286
+ :is(.nx-tabs--multiple, .nx-tabs--wrap) {
282
287
  --nx-tabs-option-height: var(--nx-control-md);
283
288
  }
284
289
  }
@@ -340,21 +345,21 @@
340
345
  transform 200ms cubic-bezier(0.2, 0, 0, 1);
341
346
  }
342
347
 
343
- .nx-tabs--list .nx-tabs__option:has(:checked) {
348
+ .nx-tabs--list .nx-tabs__option:is(:has(:checked), [aria-selected="true"]) {
344
349
  background: var(--nx-tabs-list-selected);
345
350
  }
346
351
 
347
352
  /* A list of several choices: a chosen row can be unchosen, so it keeps the pointer. */
348
- .nx-tabs--list:not([role="radiogroup"]) .nx-tabs__option:has(:checked) {
353
+ .nx-tabs--list:not([role="radiogroup"], [role="tablist"]) .nx-tabs__option:is(:has(:checked), [aria-selected="true"]) {
349
354
  cursor: pointer;
350
355
  }
351
356
 
352
- .nx-tabs--list .nx-tabs__option:has(:checked)::before {
357
+ .nx-tabs--list .nx-tabs__option:is(:has(:checked), [aria-selected="true"])::before {
353
358
  opacity: 1;
354
359
  transform: none;
355
360
  }
356
361
 
357
- .nx-tabs--list .nx-tabs__option:has(:checked) .nx-tabs__text {
362
+ .nx-tabs--list .nx-tabs__option:is(:has(:checked), [aria-selected="true"]) .nx-tabs__text {
358
363
  font-weight: 600;
359
364
  }
360
365
 
@@ -404,7 +409,7 @@
404
409
  --nx-tabs-active-icon: var(--nx-primary);
405
410
  }
406
411
 
407
- .nx-tabs--list.nx-tabs--primary .nx-tabs__option:has(:checked) .nx-tabs__badge {
412
+ .nx-tabs--list.nx-tabs--primary .nx-tabs__option:is(:has(:checked), [aria-selected="true"]) .nx-tabs__badge {
408
413
  background: var(--nx-primary-solid);
409
414
  color: var(--nx-primary-text);
410
415
  }
@@ -423,8 +428,68 @@
423
428
  --nx-tabs-list-gap: 12px;
424
429
  }
425
430
 
431
+ /*
432
+ * Tabs (`Tabs`): the same options as buttons with role="tab", marked by aria-selected rather than a checked radio.
433
+ * Only what a button brings of its own is taken away; the ring is the options' own box-shadow.
434
+ */
435
+ button.nx-tabs__option {
436
+ margin: 0;
437
+ border: 0;
438
+ background: none;
439
+ font-family: inherit;
440
+ outline: none;
441
+ }
442
+
443
+ [role="tablist"] .nx-tabs__option[aria-selected="true"] {
444
+ cursor: default;
445
+ }
446
+
447
+ /*
448
+ * design="auto": the list, until its container (a popup's workspace) is narrower than 720px; there the same rows lie
449
+ * in one strip that scrolls sideways, the bar under the chosen one. The strip keeps room for the focus ring, which a
450
+ * scrolling box would cut off.
451
+ */
452
+ @container (max-width: 719.98px) {
453
+ .nx-tabs--auto {
454
+ grid-auto-columns: max-content;
455
+ grid-auto-flow: column;
456
+ padding: 3px;
457
+ overflow-x: auto;
458
+ overscroll-behavior-x: contain;
459
+ scrollbar-width: none;
460
+ }
461
+
462
+ .nx-tabs--auto .nx-tabs__option {
463
+ white-space: nowrap;
464
+ }
465
+
466
+ .nx-tabs--auto .nx-tabs__option::before {
467
+ top: auto;
468
+ right: 10px;
469
+ bottom: 0;
470
+ left: 10px;
471
+ width: auto;
472
+ height: 3px;
473
+ transform: scaleX(0.3);
474
+ }
475
+
476
+ .nx-tabs--auto .nx-tabs__description {
477
+ display: none;
478
+ }
479
+ }
480
+
481
+ /* A tab's panel: it takes the focus when it holds nothing that does, so its ring is drawn inside it. */
482
+ .nx-tab-panel {
483
+ min-width: 0;
484
+ }
485
+
486
+ .nx-tab-panel:focus-visible {
487
+ outline: 2px solid var(--nx-primary);
488
+ outline-offset: -2px;
489
+ }
490
+
426
491
  [data-nx-motion="reduce"] .nx-tabs__indicator,
427
- [data-nx-motion="reduce"] .nx-tabs--multiple .nx-tabs__option,
492
+ [data-nx-motion="reduce"] :is(.nx-tabs--multiple, .nx-tabs--wrap) .nx-tabs__option,
428
493
  [data-nx-motion="reduce"] .nx-tabs--labels-selected :is(.nx-tabs__option, .nx-tabs__label),
429
494
  [data-nx-motion="reduce"] .nx-tabs--list .nx-tabs__option::before {
430
495
  transition: none;