@micha.bigler/ui-core-micha 3.14.3 → 4.0.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 (367) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +7 -0
  3. package/dist/auth/UserMenu.js +1 -1
  4. package/dist/auth/apiClient.js +7 -6
  5. package/dist/chat/ChatList.js +1 -1
  6. package/dist/chat/ChatThread.js +2 -1
  7. package/dist/chat/ChatWorkspace.js +1 -1
  8. package/dist/chat/ModelPicker.js +2 -5
  9. package/dist/chat/kitSxRegistry.js +9 -0
  10. package/dist/chat/useChatSocket.js +1 -1
  11. package/dist/components/LoginForm.js +1 -1
  12. package/dist/components/SecurityComponent.js +1 -1
  13. package/dist/components/UserListComponent.js +2 -8
  14. package/dist/components/charts/ChartFrame.js +1 -1
  15. package/dist/components/charts/ScatterChart.js +2 -1
  16. package/dist/components/charts/kitSxRegistry.js +6 -0
  17. package/dist/entries/charts.js +6 -0
  18. package/dist/entries/chat.js +8 -0
  19. package/dist/entries/markdown.js +1 -0
  20. package/dist/index.js +0 -14
  21. package/dist/layout/SectionNav.js +1 -1
  22. package/dist/messaging/AttachmentList.js +2 -2
  23. package/dist/messaging/Composer.js +2 -1
  24. package/dist/messaging/ConversationLaunchers.js +1 -4
  25. package/dist/messaging/ConversationList.js +1 -1
  26. package/dist/messaging/DirectMessageLauncher.js +1 -1
  27. package/dist/messaging/MessagingProvider.js +0 -0
  28. package/dist/messaging/PollCard.js +7 -5
  29. package/dist/messaging/ReadTicks.js +2 -2
  30. package/dist/messaging/Thread.js +5 -3
  31. package/dist/notifications/NotificationBell.js +4 -7
  32. package/dist/notifications/NotificationSettings.js +1 -1
  33. package/dist/onboarding/OnboardingProvider.js +3 -6
  34. package/dist/pages/AccountPage.js +1 -2
  35. package/dist/pages/LoginPage.js +2 -3
  36. package/dist/pages/PasswordChangePage.js +2 -3
  37. package/dist/pages/PasswordInvitePage.js +2 -3
  38. package/dist/pages/PasswordResetRequestPage.js +2 -3
  39. package/dist/pages/SignUpPage.js +2 -3
  40. package/dist/pages/SignupConfirmPage.js +2 -3
  41. package/dist/theme/createAppTheme.js +5 -4
  42. package/dist/theme/kitSxEntry.js +11 -0
  43. package/dist/theme/kitSxRegistry.js +2 -15
  44. package/dist/theme/themeCompleteness.js +3 -12
  45. package/dist/utils/auth-errors.js +4 -3
  46. package/package.json +41 -16
  47. package/.github/workflows/publish.yml +0 -126
  48. package/DESIGN.md +0 -60
  49. package/WORK_ORDERS.md +0 -148
  50. package/dev/entries.jsx +0 -721
  51. package/dev/fixtures.js +0 -26
  52. package/dev/main.jsx +0 -75
  53. package/dev/mockTransport.jsx +0 -128
  54. package/docs/CHART-LAYOUT.md +0 -157
  55. package/docs/DARK-TOKENS.md +0 -140
  56. package/docs/TYPE-SCALE.md +0 -111
  57. package/docs/messaging-deviations.md +0 -118
  58. package/index.html +0 -12
  59. package/renovate.json +0 -10
  60. package/scripts/chart-api-census.mjs +0 -415
  61. package/src/auth/AuthContext.jsx +0 -158
  62. package/src/auth/ReauthModal.jsx +0 -82
  63. package/src/auth/UserMenu.jsx +0 -121
  64. package/src/auth/apiClient.jsx +0 -232
  65. package/src/auth/authApi.jsx +0 -539
  66. package/src/auth/authConfig.jsx +0 -34
  67. package/src/auth/reauth.js +0 -47
  68. package/src/chat/ChatComposer.jsx +0 -36
  69. package/src/chat/ChatList.jsx +0 -87
  70. package/src/chat/ChatThread.jsx +0 -128
  71. package/src/chat/ChatWorkspace.jsx +0 -244
  72. package/src/chat/MarkdownReply.jsx +0 -22
  73. package/src/chat/ModelPicker.jsx +0 -85
  74. package/src/chat/api.js +0 -18
  75. package/src/chat/useChatSocket.js +0 -32
  76. package/src/chat/wire.js +0 -7
  77. package/src/components/AccessCodeManager.jsx +0 -288
  78. package/src/components/AccessCodeSingleUseToggle.jsx +0 -92
  79. package/src/components/AllowedEmailDomainsManager.jsx +0 -92
  80. package/src/components/AuthFactorRequirementCard.jsx +0 -95
  81. package/src/components/BulkInviteCsvTab.jsx +0 -198
  82. package/src/components/EmptyState.jsx +0 -38
  83. package/src/components/LoginForm.jsx +0 -159
  84. package/src/components/MFAComponent.jsx +0 -350
  85. package/src/components/MfaLoginComponent.jsx +0 -252
  86. package/src/components/MobileBottomNav.jsx +0 -82
  87. package/src/components/PasskeysComponent.jsx +0 -252
  88. package/src/components/PasswordChangeForm.jsx +0 -87
  89. package/src/components/PasswordResetRequestForm.jsx +0 -43
  90. package/src/components/PasswordSetForm.jsx +0 -97
  91. package/src/components/ProfileComponent.jsx +0 -348
  92. package/src/components/QrSignupManager.jsx +0 -404
  93. package/src/components/QrSignupValidityManager.jsx +0 -106
  94. package/src/components/RegistrationMethodsManager.jsx +0 -150
  95. package/src/components/SecurityComponent.jsx +0 -141
  96. package/src/components/SocialLoginButtons.jsx +0 -83
  97. package/src/components/SoftChip.jsx +0 -93
  98. package/src/components/StatTile.jsx +0 -39
  99. package/src/components/SupportRecoveryRequestsTab.jsx +0 -482
  100. package/src/components/TurnstileWidget.jsx +0 -99
  101. package/src/components/UserInviteComponent.jsx +0 -76
  102. package/src/components/UserListComponent.jsx +0 -618
  103. package/src/components/charts/BarChart.jsx +0 -102
  104. package/src/components/charts/ChartFrame.jsx +0 -214
  105. package/src/components/charts/LineChart.jsx +0 -126
  106. package/src/components/charts/ScatterChart.jsx +0 -299
  107. package/src/components/charts/TimeSeriesChart.jsx +0 -300
  108. package/src/components/charts/chartDefaults.js +0 -644
  109. package/src/components/charts/chartLabels.js +0 -36
  110. package/src/components/charts/exportChart.js +0 -258
  111. package/src/components/charts/formatters.js +0 -39
  112. package/src/components/charts/palette.js +0 -33
  113. package/src/components/charts/yearTickInterval.js +0 -7
  114. package/src/i18n/authTranslations.ts +0 -2651
  115. package/src/i18n/chartsTranslations.ts +0 -91
  116. package/src/i18n/chatTranslations.ts +0 -55
  117. package/src/i18n/messagingTranslations.ts +0 -120
  118. package/src/i18n/notificationsTranslations.ts +0 -32
  119. package/src/i18n/onboardingTranslations.ts +0 -29
  120. package/src/i18n/sectionNavTranslations.ts +0 -20
  121. package/src/i18n/uiCoreTranslations.js +0 -29
  122. package/src/i18n/userMenuTranslations.ts +0 -5
  123. package/src/index.js +0 -158
  124. package/src/layout/PageLayout.jsx +0 -36
  125. package/src/layout/SectionNav.jsx +0 -320
  126. package/src/messaging/AttachmentList.jsx +0 -145
  127. package/src/messaging/Composer.jsx +0 -197
  128. package/src/messaging/ConversationLaunchers.jsx +0 -51
  129. package/src/messaging/ConversationList.jsx +0 -109
  130. package/src/messaging/DirectMessageLauncher.jsx +0 -112
  131. package/src/messaging/MessageBubble.jsx +0 -183
  132. package/src/messaging/MessagingProvider.jsx +0 -0
  133. package/src/messaging/MessagingScopeConfig.jsx +0 -24
  134. package/src/messaging/PollCard.jsx +0 -163
  135. package/src/messaging/ReactionBar.jsx +0 -43
  136. package/src/messaging/ReadTicks.jsx +0 -82
  137. package/src/messaging/Thread.jsx +0 -195
  138. package/src/messaging/api.js +0 -48
  139. package/src/messaging/composerImageCompression.js +0 -35
  140. package/src/messaging/linkifyText.jsx +0 -37
  141. package/src/notifications/NotificationBell.jsx +0 -84
  142. package/src/notifications/NotificationSettings.jsx +0 -330
  143. package/src/notifications/NotificationsProvider.jsx +0 -224
  144. package/src/notifications/PopupSurface.jsx +0 -105
  145. package/src/notifications/api.js +0 -55
  146. package/src/notifications/feedApi.js +0 -18
  147. package/src/notifications/realtime.jsx +0 -138
  148. package/src/notifications/serviceWorker/sw.js +0 -50
  149. package/src/onboarding/OnboardingProvider.jsx +0 -326
  150. package/src/onboarding/OnboardingWizard.jsx +0 -61
  151. package/src/onboarding/WizardDialogShell.jsx +0 -51
  152. package/src/onboarding/api.js +0 -13
  153. package/src/onboarding/stepSelection.js +0 -16
  154. package/src/onboarding/steps/BrowserPushStep.jsx +0 -121
  155. package/src/onboarding/steps/CompleteNameStep.jsx +0 -46
  156. package/src/onboarding/steps/CookieConsentStep.jsx +0 -133
  157. package/src/onboarding/steps/PwaInstallStep.jsx +0 -47
  158. package/src/pages/AccountPage.jsx +0 -394
  159. package/src/pages/LoginPage.jsx +0 -343
  160. package/src/pages/PasswordChangePage.jsx +0 -62
  161. package/src/pages/PasswordInvitePage.jsx +0 -177
  162. package/src/pages/PasswordResetRequestPage.jsx +0 -68
  163. package/src/pages/SignUpPage.jsx +0 -268
  164. package/src/pages/SignupConfirmPage.jsx +0 -155
  165. package/src/testing/checkKitIntegration.js +0 -233
  166. package/src/theme/createAppTheme.js +0 -423
  167. package/src/theme/fonts.js +0 -3
  168. package/src/theme/index.js +0 -21
  169. package/src/theme/kitSxRegistry.js +0 -285
  170. package/src/theme/themeCompleteness.js +0 -1045
  171. package/src/theme/tokens.js +0 -478
  172. package/src/utils/auth-errors.js +0 -76
  173. package/src/utils/authService.js +0 -223
  174. package/src/utils/resolveErrorText.js +0 -28
  175. package/src/utils/webauthn.js +0 -51
  176. package/tests/AccountPage.profileStatements.test.jsx +0 -162
  177. package/tests/AccountPage.test.jsx +0 -200
  178. package/tests/AuthContext.test.jsx +0 -129
  179. package/tests/BarChart.test.jsx +0 -112
  180. package/tests/BrowserPushStep.test.jsx +0 -110
  181. package/tests/ChartFrame.test.jsx +0 -336
  182. package/tests/ConversationList.test.jsx +0 -144
  183. package/tests/CookieConsentStep.test.jsx +0 -69
  184. package/tests/EmptyState.test.jsx +0 -62
  185. package/tests/LineChart.test.jsx +0 -80
  186. package/tests/MessagingProvider.test.jsx +0 -50
  187. package/tests/MobileBottomNav.test.jsx +0 -319
  188. package/tests/NotificationBell.test.jsx +0 -60
  189. package/tests/NotificationSettings.test.jsx +0 -276
  190. package/tests/NotificationsProvider.test.jsx +0 -240
  191. package/tests/OnboardingProvider.test.jsx +0 -294
  192. package/tests/OnboardingWizard.test.jsx +0 -143
  193. package/tests/PasswordChangeForm.test.jsx +0 -70
  194. package/tests/PasswordInvitePage.test.jsx +0 -142
  195. package/tests/PasswordSetForm.test.jsx +0 -70
  196. package/tests/PopupSurface.test.jsx +0 -142
  197. package/tests/ProfileComponent.refresh.test.jsx +0 -194
  198. package/tests/QrSignupManager.registrationContext.test.jsx +0 -106
  199. package/tests/QrSignupManagerInfoBox.test.jsx +0 -49
  200. package/tests/ScatterChart.test.jsx +0 -270
  201. package/tests/SectionNav.test.jsx +0 -363
  202. package/tests/SignUpPage.test.jsx +0 -208
  203. package/tests/SoftChip.test.jsx +0 -105
  204. package/tests/StatTile.test.jsx +0 -57
  205. package/tests/Thread.test.jsx +0 -151
  206. package/tests/TimeSeriesChart.test.jsx +0 -367
  207. package/tests/UserListComponent.test.jsx +0 -192
  208. package/tests/UserMenu.test.jsx +0 -171
  209. package/tests/apiClientLanguage.test.js +0 -33
  210. package/tests/apiClientPublicPaths.test.js +0 -178
  211. package/tests/authApiLogin.test.js +0 -42
  212. package/tests/authApiRegistration.test.js +0 -31
  213. package/tests/authErrorCodeRendering.test.jsx +0 -77
  214. package/tests/authErrors.test.js +0 -74
  215. package/tests/authTranslations.test.js +0 -74
  216. package/tests/chart-api-census.test.js +0 -366
  217. package/tests/chartAxisTickBand.test.jsx +0 -95
  218. package/tests/chartDefaults.test.js +0 -902
  219. package/tests/chartLabels.test.js +0 -50
  220. package/tests/chartsPalette.test.js +0 -99
  221. package/tests/chatApi.test.js +0 -48
  222. package/tests/chatDriverNames.test.jsx +0 -71
  223. package/tests/chatExports.test.js +0 -3
  224. package/tests/chatList.test.jsx +0 -84
  225. package/tests/chatPicker.test.jsx +0 -82
  226. package/tests/chatSocket.test.jsx +0 -26
  227. package/tests/chatThread.test.jsx +0 -116
  228. package/tests/chatTranslations.test.js +0 -47
  229. package/tests/chatWorkspace.test.jsx +0 -234
  230. package/tests/checkKitIntegration.test.jsx +0 -219
  231. package/tests/createAppTheme.test.js +0 -132
  232. package/tests/createAppThemeDark.test.js +0 -127
  233. package/tests/createAppThemeLightGuard.test.js +0 -40
  234. package/tests/createAppThemePageContrast.test.js +0 -108
  235. package/tests/createAppThemeTypography.test.js +0 -53
  236. package/tests/errorCallSiteGuard.test.js +0 -32
  237. package/tests/exportChart.test.js +0 -313
  238. package/tests/feedApi.test.js +0 -46
  239. package/tests/fixtures/light-theme-baseline.json +0 -2234
  240. package/tests/i18nAggregate.test.js +0 -120
  241. package/tests/i18nGermanVariant.test.js +0 -65
  242. package/tests/loginPageErrorResolution.test.jsx +0 -102
  243. package/tests/messagingApi.test.js +0 -32
  244. package/tests/messagingChunk6.test.jsx +0 -116
  245. package/tests/messagingCompactBubble.test.jsx +0 -64
  246. package/tests/messagingComposer.test.jsx +0 -136
  247. package/tests/messagingComposerChunk5.test.jsx +0 -113
  248. package/tests/messagingContractConformance.test.js +0 -69
  249. package/tests/messagingDirectMessageLauncher.test.jsx +0 -151
  250. package/tests/messagingExports.test.js +0 -21
  251. package/tests/messagingInteractions.test.jsx +0 -136
  252. package/tests/messagingLastMessagePreview.test.jsx +0 -93
  253. package/tests/messagingLinkify.test.jsx +0 -51
  254. package/tests/messagingMessageActions.test.jsx +0 -163
  255. package/tests/messagingMsg6.test.jsx +0 -105
  256. package/tests/messagingMsg6f.test.jsx +0 -155
  257. package/tests/messagingMsg6g.test.jsx +0 -166
  258. package/tests/messagingMsg6h.test.jsx +0 -136
  259. package/tests/messagingMsg6i.test.jsx +0 -129
  260. package/tests/messagingPollRendering.test.jsx +0 -142
  261. package/tests/messagingReactionMerge.test.jsx +0 -77
  262. package/tests/messagingReadTicksTooltip.test.jsx +0 -36
  263. package/tests/messagingThreadReceipts.test.jsx +0 -178
  264. package/tests/messagingThreadingQuoting.test.jsx +0 -87
  265. package/tests/messagingUnreadLifecycle.test.jsx +0 -78
  266. package/tests/notificationsApi.test.js +0 -41
  267. package/tests/notificationsExports.test.js +0 -34
  268. package/tests/onboardingDescriptors.test.js +0 -132
  269. package/tests/packageTreeShaking.test.js +0 -126
  270. package/tests/realtime.test.jsx +0 -219
  271. package/tests/resolveErrorText.test.js +0 -72
  272. package/tests/stepSelection.test.js +0 -53
  273. package/tests/themeCompleteness.test.js +0 -626
  274. package/tests/timeSeriesLegend.test.js +0 -99
  275. package/tests/userScreenTranslations.test.jsx +0 -218
  276. package/tsconfig.build.json +0 -18
  277. package/vite.config.mjs +0 -6
  278. package/work-orders/AUTH-1.md +0 -74
  279. package/work-orders/AUTH-2.md +0 -74
  280. package/work-orders/AUTH-4.md +0 -183
  281. package/work-orders/AUTH-5.md +0 -154
  282. package/work-orders/AUTH-7.md +0 -181
  283. package/work-orders/AUTH-8.md +0 -184
  284. package/work-orders/CHART-1.md +0 -285
  285. package/work-orders/CHART-2.md +0 -222
  286. package/work-orders/CHART-3.md +0 -163
  287. package/work-orders/CHART-4.md +0 -203
  288. package/work-orders/CHART-5.md +0 -226
  289. package/work-orders/CHART-6.md +0 -428
  290. package/work-orders/CHART-7.md +0 -175
  291. package/work-orders/DX-1.md +0 -169
  292. package/work-orders/DX-2.md +0 -188
  293. package/work-orders/DX-3.md +0 -195
  294. package/work-orders/I18N-1.md +0 -254
  295. package/work-orders/I18N-3.md +0 -207
  296. package/work-orders/MSG-3.md +0 -375
  297. package/work-orders/MSG-3b.md +0 -1002
  298. package/work-orders/MSG-3c.md +0 -378
  299. package/work-orders/MSG-3d.md +0 -268
  300. package/work-orders/MSG-3e.md +0 -164
  301. package/work-orders/MSG-3f.md +0 -391
  302. package/work-orders/MSG-6e.md +0 -308
  303. package/work-orders/MSG-6f.md +0 -214
  304. package/work-orders/MSG-6g.md +0 -244
  305. package/work-orders/MSG-6h.md +0 -238
  306. package/work-orders/MSG-6i.md +0 -271
  307. package/work-orders/MSG-6j.md +0 -117
  308. package/work-orders/NOTIF-12.md +0 -214
  309. package/work-orders/NOTIF-13.md +0 -142
  310. package/work-orders/NOTIF-14.md +0 -151
  311. package/work-orders/PRIM-1.md +0 -177
  312. package/work-orders/SHELL-1.md +0 -255
  313. package/work-orders/SHELL-2.md +0 -197
  314. package/work-orders/SHELL-3.md +0 -359
  315. package/work-orders/SHELL-4.md +0 -351
  316. package/work-orders/SHELL-5.md +0 -345
  317. package/work-orders/SHELL-6.md +0 -210
  318. package/work-orders/THEME-1.md +0 -587
  319. package/work-orders/THEME-10.md +0 -303
  320. package/work-orders/THEME-11.md +0 -208
  321. package/work-orders/THEME-2.md +0 -339
  322. package/work-orders/THEME-3.md +0 -210
  323. package/work-orders/THEME-4.md +0 -271
  324. package/work-orders/THEME-5.md +0 -341
  325. package/work-orders/THEME-6.md +0 -247
  326. package/work-orders/THEME-7.md +0 -82
  327. package/work-orders/THEME-8.md +0 -211
  328. package/work-orders/THEME-9.md +0 -194
  329. package/work-orders/UCM-AUTH-10.md +0 -490
  330. package/work-orders/UCM-AUTH-11.md +0 -185
  331. package/work-orders/UCM-AUTH-12.md +0 -98
  332. package/work-orders/UCM-AUTH-13.md +0 -47
  333. package/work-orders/UCM-AUTH-9.md +0 -207
  334. package/work-orders/UCM-CHART-10.md +0 -150
  335. package/work-orders/UCM-CHART-11.md +0 -132
  336. package/work-orders/UCM-CHART-12.md +0 -348
  337. package/work-orders/UCM-CHART-13.md +0 -122
  338. package/work-orders/UCM-CHART-14.md +0 -198
  339. package/work-orders/UCM-CHART-15.md +0 -187
  340. package/work-orders/UCM-CHART-16.md +0 -169
  341. package/work-orders/UCM-CHART-17.md +0 -195
  342. package/work-orders/UCM-CHART-18.md +0 -200
  343. package/work-orders/UCM-CHART-8.md +0 -147
  344. package/work-orders/UCM-CHART-9.md +0 -265
  345. package/work-orders/UCM-CHAT-1.md +0 -190
  346. package/work-orders/UCM-CHAT-2.md +0 -75
  347. package/work-orders/UCM-DEP-1.md +0 -63
  348. package/work-orders/UCM-I18N-4.md +0 -226
  349. package/work-orders/UCM-I18N-5.md +0 -211
  350. package/work-orders/UCM-MSG-20.md +0 -192
  351. package/work-orders/UCM-PRIM-2.md +0 -114
  352. package/work-orders/UCM-SHELL-7.md +0 -134
  353. package/work-orders/UCM-SHELL-8.md +0 -125
  354. package/work-orders/UCM-TEST-1.md +0 -304
  355. package/work-orders/UCM-THEME-13.md +0 -69
  356. package/work-orders/UCM-THEME-14.md +0 -312
  357. package/work-orders/UCM-THEME-15.md +0 -356
  358. package/work-orders/UCM-THEME-16.md +0 -80
  359. package/work-orders/UCM-THEME-17.md +0 -111
  360. package/work-orders/UCM-THEME-18.md +0 -184
  361. package/work-orders/assets/AUTH-4-user-list-card.html +0 -407
  362. package/work-orders/assets/PRIM-1-dashboard-primitives.html +0 -624
  363. package/work-orders/assets/SHELL-2-account-navigation.html +0 -1159
  364. package/work-orders/assets/THEME-1-baseline-reference-sheet.html +0 -1352
  365. package/work-orders/assets/UCM-CHAT-1-ai-chat.html +0 -447
  366. package/work-orders/assets/UCM-THEME-13-dark-prototype.html +0 -390
  367. package/work-orders/assets/UCM-THEME-17-type-scale.html +0 -391
@@ -1,184 +0,0 @@
1
- # UCM-THEME-18: Ship the frozen baseline type scale
2
-
3
- # A. Envelope, authored by the Expertenchat
4
-
5
- ## Goal & expected outcome
6
-
7
- `createAppTheme` produces the type scale frozen in [`docs/TYPE-SCALE.md`](../docs/TYPE-SCALE.md) (`UCM-THEME-17`,
8
- frozen 2026-10-04), in light and dark. The screen title (h4) steps down one size below the baseline's `sm`
9
- breakpoint. Released as a **minor** version (`3.12.0`), because every adopted app looks different after the bump.
10
-
11
- ## Decided values (from `docs/TYPE-SCALE.md`, by variant)
12
-
13
- | Variant | Before | After |
14
- |---|---|---|
15
- | h1 / h2 / h3 | 32 / 28 / 24 | **36 / 32 / 28** |
16
- | h4 | 20 | **24**, and **23 below `sm`** |
17
- | h5 | 18 | **20** |
18
- | subtitle1 | 15 | **13** |
19
-
20
- Unchanged: h6, subtitle2, body1, body2, button, caption, overline; every weight (headings 600, subtitle1 600);
21
- every line height; `letterSpacing`. If this table and `docs/TYPE-SCALE.md` disagree, the sheet wins.
22
-
23
- ## Context the operator established
24
-
25
- - **Typography lives in one block**: `src/theme/tokens.js:223-241`, built with `typeVariant` (`tokens.js:45`).
26
- `createAppTheme` (`src/theme/createAppTheme.js:379-387`) spreads it unchanged and takes only `fontFamily`
27
- from the app, so light and dark get the same scale from the same place.
28
- - **Breakpoints**: `tokens.js:250-252`, `sm: 600`. The mobile step means "below `sm`", the same line MUI's
29
- `breakpoints.down('sm')` draws.
30
- - **`assertThemeComplete`** reads `fontSize`, `fontWeight`, `lineHeight` and `letterSpacing` per variant
31
- (`src/theme/themeCompleteness.js:38`). A nested media-query key inside h4 is new to it.
32
- - **The light regression fixture** `tests/fixtures/light-theme-baseline.json`, checked by
33
- `tests/createAppThemeLightGuard.test.js`, contains the typography and changes with this order.
34
- - **The kit's own screens use the variants too** (h6 about 24 times, h4 twice, h5 once in `src/`), so kit
35
- screens such as the account pages change with the scale. That is intended.
36
-
37
- ## Scope + non-goals
38
-
39
- In scope: the typography values above; the h4 step below `sm`; the fixture's typography entries;
40
- `CHANGELOG.md` naming the visible change for every adopted app; the minor release.
41
-
42
- Non-goals:
43
- - No app repo changes. The per-app follow-up (listed below) is written after the release, one order per app.
44
- - No font family, weight or line-height change; no new variant; no change to `breakpoints`.
45
- - No responsive step for any variant other than h4.
46
-
47
- ## Tier · precondition / gate
48
-
49
- - **Tier 3 · tests: the typography values per variant and the h4 step, in light and dark; the light
50
- regression fixture updated in its typography entries only; the existing `createAppTheme` and completeness
51
- tests.** A change inside shared-core (`AGENTS.md` -> Tiering).
52
- - Precondition: `UCM-THEME-17` `done` (frozen sheet committed).
53
- - No prototype gate: the instrument is a decision sheet, not a screen to match.
54
-
55
- ## Risks
56
-
57
- - **Every adopted app moves on its next bump.** Intended; the changelog says so in one line an app session can
58
- act on.
59
- - **An app that overrides h4's size keeps the baseline's 23 px below `sm`**, because a theme merge keeps the
60
- nested media key. survey_app sets h4 to `2.125rem` today; on mobile it would fall to 23. The per-app
61
- follow-up handles it; the changelog names it.
62
- - **`assertThemeComplete` may misread the nested key** (as a missing or extra surface). It must neither raise
63
- a finding for the baseline's own media key nor let an app's h4 override go unnoticed.
64
-
65
- ## Required tests to WRITE (you write them and run YOUR OWN new ones; the Orchestrator's run is the gate)
66
-
67
- 1. For a light and a dark theme from `createAppTheme`: each variant in the table resolves to its decided
68
- `fontSize`, read from the theme, compared with the value in the table.
69
- 2. h4 carries a media-query entry for "below `sm`" with `fontSize` 23px, and that query is derived from
70
- `breakpoints.values.sm`, not typed a second time. Show the test fails if `sm` changes and the query does not.
71
- 3. `assertThemeComplete` on the baseline returns no typography finding.
72
-
73
- Run, do not write: `tests/createAppTheme.test.js`, `tests/createAppThemeLightGuard.test.js` (with the fixture's
74
- typography entries updated, and only those), the completeness tests.
75
-
76
- ## Parity guardrail
77
-
78
- No behaviour change; type sizes only. Palette, spacing, components and exports unchanged.
79
-
80
- ## Downstream (not this order; one order per app after the release)
81
-
82
- Measured 2026-10-04 (see `docs/TYPE-SCALE.md` -> "Known consequences"):
83
-
84
- | App | What the follow-up does |
85
- |---|---|
86
- | hram | screen titles on 5 pages from h5 to h4; drop the per-level weight 500 |
87
- | jg-ferien | screen titles on 3 pages from h5 to h4 (`DashboardPage.jsx:187`) |
88
- | kerzenziehen | admin screen title from h5 to h4 |
89
- | spesix | 1 page title from h5 to h4; drop per-level weight overrides |
90
- | fitness-monitor | 1 page title from h5 to h4 |
91
- | survey_app | drop the 800/700 weights and the h4 `2.125rem`/400 override; decide the h3 page titles (24 -> 28); closes the held `SVA-THEME-1` typography revert |
92
- | all other adopted apps | bump only |
93
-
94
- webshop-guenter (own handoff scale), Kira, Cinevia and Gustav (no MUI heading variants) are unaffected.
95
-
96
- ---
97
-
98
- # B. Implementation map, filled by the Orchestrator and ADDRESSED TO THE IMPLEMENTER
99
-
100
- Work from this package; open only the named files. A value the sheet lacks is `RESULT: BLOCKED <value>`.
101
-
102
- ## Target working directory (absolute)
103
-
104
- `C:\Users\biglmi\Documents\webapps\ui-core-micha` (branch `main`). Never the workspace root.
105
-
106
- ## Context package
107
-
108
- - **`src/theme/tokens.js`**: `BASELINE_STATIC.typography` (l.~222-241) uses `typeVariant(size, weight, lineHeight, extra)`
109
- (l.45). Change h1/h2/h3/h4/h5/subtitle1 to the table in Part A; nothing else in that block moves.
110
- h4 gets the mobile step as a nested media-query key inside the variant (`extra`), `fontSize: '23px'`.
111
- The query must be **derived from the breakpoint value**, not typed a second time: introduce one
112
- constant for `sm` (600) in `tokens.js`, use it in `breakpoints.values.sm` (l.~251) and build the key
113
- from it, in the form MUI's `breakpoints.down('sm')` produces (`@media (max-width:599.95px)`, that is
114
- `sm - 0.05`). Export the constant or the key builder so the test can reference it.
115
- - **`src/theme/createAppTheme.js`** (l.~379-387) spreads `BASELINE_STATIC.typography` and takes only
116
- `fontFamily` from the app; no change expected. Verify the nested media key survives `createTheme`
117
- into `theme.typography.h4` in both light and dark (read the resolved theme, do not assume).
118
- - **`src/theme/themeCompleteness.js`** (`TYPOGRAPHY_SURFACES`, l.~38) reads fontSize/fontWeight/lineHeight/
119
- letterSpacing per variant. Verify the baseline h4 with its media key raises no finding; change this file
120
- only if it does.
121
- - **Light regression fixture** `tests/fixtures/light-theme-baseline.json` (checked by
122
- `tests/createAppThemeLightGuard.test.js`): update ONLY the typography entries that this order changes
123
- (h1-h5 and subtitle1 `fontSize`, and h4's new media key), in both of its snapshots (`baseline`, `override`).
124
- Regenerate carefully: the diff of the fixture must contain nothing but those typography lines. Do not
125
- re-capture the whole file blindly; check `git diff` of the fixture afterwards (use `git diff` to read it,
126
- do not stage).
127
- - **Docs / release**: `CHANGELOG.md` entry `3.12.0 - UCM-THEME-18` (newest first, same style as the
128
- existing entries): the new scale in one table-free sentence; the visible change for every adopted app;
129
- that an app overriding h4's `fontSize` keeps the baseline's 23px below `sm` (survey_app sets h4
130
- `2.125rem`); that headings are fixed at weight 600 and apps should not override per level.
131
- `package.json` version `3.11.2` -> `3.12.0` (no lockfile in this repo).
132
- - Kit components: no edit expected (they use the variants).
133
-
134
- **Existing tests to follow** (style): `tests/createAppTheme.test.js`, `tests/createAppThemeDark.test.js`.
135
- New tests go in `tests/createAppThemeTypography.test.js`.
136
-
137
- **Pitfalls**: weights, line heights, letterSpacing, h6, subtitle2, body1/2, button, caption, overline are
138
- unchanged and must stay byte-identical. Do not touch `breakpoints` values or add a second source for `sm`.
139
-
140
- ## Required tests, restated
141
-
142
- The three tests of Part A. Test 2 must show it can fail: derive the expected query from
143
- `breakpoints.values.sm` of the resolved theme (not a literal), and include an assertion that would break if
144
- the baseline's key were typed independently of that value (for example by building a theme with a different
145
- `sm` through the same constant, if the constant is the single source, or by asserting the key string equals
146
- the builder applied to the theme's own `sm`).
147
-
148
- ## Preamble
149
-
150
- The text above is the COMPLETE spec: the committed WO file's content, not a plan to refine; there is no
151
- separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`, and the app
152
- `MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/schema/CI unless the
153
- spec says so; do not update `MEMORY.md`. **Do NOT edit `WORK_ORDERS.md`: the register row and the review
154
- verdicts are the orchestrator's alone.** **Your tools are for editing source and test files and for running
155
- the tests you wrote, nothing else.** Do NOT install dependencies, touch a lockfile, run a package manager,
156
- or tidy up stray files; if something in the repo state blocks you, stop and report it as
157
- `RESULT: BLOCKED <reason>` instead of fixing it. Do NOT `git add`/`commit`/`push`: leave every change
158
- uncommitted in the working tree for the orchestrator's independent review. WRITE the tests the
159
- `Required tests` section calls for AND **RUN the tests you just wrote** to confirm they execute and pass:
160
- that is the ONLY test run you do (NOT the affected/full suite, NOT any review). Run them with
161
- `npx vitest run <your test files>`. The orchestrator re-runs the authoritative set and does the independent
162
- review after you finish; those are the gate.
163
-
164
- Narrate continuously: a `PLAN: <step1> | <step2> | ...` line up front, then a single-line
165
- `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `... done` on
166
- completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final
167
- `RESULT: DONE|BLOCKED <reason>`.
168
-
169
- ---
170
-
171
- # C. Orchestrator only, NOT ADDRESSED TO THE IMPLEMENTER
172
-
173
- > **If you are the implementer reading this work order as your own specification: STOP at this line.**
174
- > Everything below describes what the Orchestrator does AFTER you finish. You do none of it: no
175
- > reviewers, no verification run, no register edit, no `git add`/`commit`/`push`.
176
-
177
- - Check `.claude/codex-status.md` first (newest-first). Before `git push`, run `git log origin/main..HEAD` and
178
- push only if every listed commit is this order's.
179
- - Review: Tier 3, independent `reviewer` (all configured lenses) and `ui_reviewer`, one batch, before the commit.
180
- - Release `3.12.0`: verify the publish through the job log (`npm view` lags for provenance publishes). Row ->
181
- `done` with the review Notiz and the version. Then the Expertenchat writes the per-app orders above.
182
-
183
- Mini-handover: `Orchestrator: implement work-orders/UCM-THEME-18.md in ui-core-micha (main). git pull first,
184
- read the WO, then follow orchestrate-codex.`
@@ -1,407 +0,0 @@
1
- <!doctype html>
2
- <html lang="de">
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>AUTH-4 — the account user list on a phone (prototype)</title>
7
- <style>
8
- /* ------------------------------------------------------------------
9
- Values are ui-core-micha baseline tokens (src/theme/tokens.js).
10
- The accent is a NEUTRAL PLACEHOLDER: `palette.primary` is app
11
- identity and the baseline deliberately has none, so every app
12
- supplies its own. Judge composition here, not the accent hue.
13
- ------------------------------------------------------------------ */
14
- :root {
15
- --text-primary: #212529; /* palette.text.primary */
16
- --text-secondary: #5B6670; /* palette.text.secondary */
17
- --text-muted: #6A7178; /* palette.text.disabled */
18
- --bg-default: #FAFAFA; /* palette.background.default */
19
- --surface: #FFFFFF; /* palette.background.paper */
20
- --subtle: #F4F5F6; /* palette.background.subtle (THEME-3) */
21
- --divider: rgba(33,37,41,.10);
22
- --control-border: rgba(33,37,41,.50);
23
- --success-bg: #E5F4E9; --success-text: #35794A;
24
- --stale-bg: #EAEDF1; --stale-text: #5B6B7D;
25
- --error: #BF3227;
26
- --radius-control: 3px; /* shape.borderRadius */
27
- --radius-card: 8px; /* radius.card */
28
- --sp-1: 8px; --sp-2: 16px; --sp-3: 24px; --sp-4: 32px;
29
- --touch: 44px; /* density.touchTarget */
30
- --control-h: 40px; /* density.controlHeight */
31
- --cell-pad: 10px 16px; /* density.tableCellPadding */
32
- --accent: #3D5A99; /* PLACEHOLDER, see note above */
33
- }
34
- * { box-sizing: border-box; }
35
- body {
36
- margin: 0; padding: var(--sp-3); background: #EDEFF1; color: var(--text-primary);
37
- font-family: 'DM Sans', system-ui, -apple-system, sans-serif;
38
- font-size: 14px; line-height: 1.55;
39
- }
40
- .doc { max-width: 1400px; margin: 0 auto; }
41
- h1 { font-size: 28px; font-weight: 600; line-height: 1.22; margin: 0 0 var(--sp-1); }
42
- h2 { font-size: 20px; font-weight: 600; margin: var(--sp-4) 0 var(--sp-1); }
43
- p { margin: 0 0 var(--sp-1); max-width: 76ch; }
44
- .lede { color: var(--text-secondary); }
45
- code { font-family: ui-monospace, Menlo, monospace; font-size: 12.5px;
46
- background: var(--stale-bg); padding: 1px 5px; border-radius: var(--radius-control); }
47
- .note { border-left: 3px solid var(--accent); background: var(--surface);
48
- padding: var(--sp-1) var(--sp-2); margin: var(--sp-2) 0;
49
- border-radius: 0 var(--radius-card) var(--radius-card) 0; }
50
- .note.warn { border-left-color: var(--error); }
51
- .note.pick { border-left-color: var(--success-text); }
52
- .note p:last-child { margin-bottom: 0; }
53
-
54
- .frames { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: flex-start; }
55
- .frame { background: var(--surface); border: 1px solid var(--divider);
56
- border-radius: var(--radius-card); overflow: hidden; }
57
- .frame-label { font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
58
- color: var(--text-muted); padding: 6px var(--sp-1);
59
- border-bottom: 1px solid var(--divider); background: var(--bg-default); }
60
- .frame-label.bad { color: var(--error); background: #FBEAE8; }
61
- .w375 { width: 375px; flex: 0 0 375px; }
62
- .w1280 { width: 1280px; max-width: 100%; }
63
- /* Wide content scrolls inside its own frame so the page body never scrolls sideways. */
64
- .scroll-x { overflow-x: auto; }
65
- .pane { background: var(--bg-default); padding: var(--sp-2); }
66
- .pane.mobile { padding: var(--sp-1); }
67
-
68
- /* --- shared controls (stay in both modes) ------------------------- */
69
- .toolbar { display: flex; gap: var(--sp-1); align-items: center; flex-wrap: wrap;
70
- margin-bottom: var(--sp-1); }
71
- .search { flex: 1 1 160px; min-width: 0; height: var(--control-h);
72
- border: 1px solid var(--control-border); border-radius: var(--radius-control);
73
- display: flex; align-items: center; gap: 6px; padding: 0 10px;
74
- background: var(--surface); color: var(--text-muted); font-size: 14px; }
75
- .search svg { width: 18px; height: 18px; flex: none; }
76
- .sortctl { height: var(--control-h); border: 1px solid var(--control-border);
77
- border-radius: var(--radius-control); display: flex; align-items: center; gap: 6px;
78
- padding: 0 10px; background: var(--surface); font-size: 13px; white-space: nowrap; }
79
- .sortctl svg { width: 16px; height: 16px; }
80
-
81
- /* --- the table (desktop, unchanged) ------------------------------- */
82
- table { border-collapse: collapse; width: 100%; font-size: 14px; background: var(--surface); }
83
- th, td { padding: var(--cell-pad); border-bottom: 1px solid var(--divider);
84
- text-align: left; vertical-align: middle; white-space: nowrap; }
85
- th { font-size: 13px; font-weight: 600; color: var(--text-secondary); }
86
- th .sortable { display: inline-flex; align-items: center; gap: 4px; }
87
- th svg { width: 14px; height: 14px; opacity: .5; }
88
- .selectbox { display: inline-flex; align-items: center; justify-content: space-between;
89
- gap: 6px; min-width: 120px; height: 36px; padding: 0 8px;
90
- border: 1px solid var(--control-border); border-radius: var(--radius-control);
91
- font-size: 14px; background: var(--surface); }
92
- .selectbox svg { width: 16px; height: 16px; opacity: .6; }
93
- .iconbtn { width: var(--touch); height: var(--touch); display: inline-grid; place-items: center;
94
- border-radius: 50%; color: var(--text-secondary); }
95
- .iconbtn svg { width: 20px; height: 20px; }
96
- .iconbtn.danger { color: var(--error); }
97
- .flag { display: inline-grid; place-items: center; width: 24px; height: 24px; }
98
- .flag svg { width: 18px; height: 18px; }
99
- .flag.yes { color: var(--success-text); }
100
- .flag.no { color: var(--text-muted); }
101
-
102
- /* the clipped "today" demo */
103
- .clip { overflow: hidden; position: relative; }
104
- .clip::after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; width: 28px;
105
- background: linear-gradient(to right, rgba(255,255,255,0), var(--error)); opacity: .18; }
106
- .clip table { width: 1053px; }
107
-
108
- /* --- the card list (mobile, the proposal) ------------------------- */
109
- .cardlist { display: flex; flex-direction: column; gap: var(--sp-1); }
110
- .ucard { background: var(--surface); border: 1px solid var(--divider);
111
- border-radius: var(--radius-card); padding: var(--sp-2); box-shadow: none; }
112
- .ucard-head { display: flex; align-items: flex-start; gap: var(--sp-1); }
113
- .ucard-id { min-width: 0; flex: 1 1 auto; }
114
- .ucard-email { font-size: 15px; font-weight: 600; overflow-wrap: anywhere; } /* subtitle1 */
115
- .ucard-name { font-size: 13px; color: var(--text-secondary); } /* body2 */
116
- .ucard-name.missing { color: var(--text-muted); font-style: italic; }
117
- .chips { display: flex; gap: 6px; flex-wrap: wrap; margin-top: var(--sp-1); }
118
- .chip { display: inline-flex; align-items: center; gap: 4px; height: 32px; padding: 0 10px;
119
- border-radius: 16px; font-size: 13px; font-weight: 500; }
120
- .chip svg { width: 15px; height: 15px; }
121
- .chip.new { background: var(--success-bg); color: var(--success-text); }
122
- .chip.never { background: var(--stale-bg); color: var(--stale-text); }
123
- .ucard-foot { display: flex; align-items: center; gap: var(--sp-1);
124
- margin-top: var(--sp-2); padding-top: var(--sp-1);
125
- border-top: 1px solid var(--divider); }
126
- .ucard-foot .selectbox { flex: 1 1 auto; min-width: 0; height: var(--control-h); }
127
- .rolelabel { font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
128
- color: var(--text-muted); display: block; margin-bottom: 2px; }
129
- .pagination { display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-1);
130
- padding: var(--sp-1) 0; font-size: 13px; color: var(--text-secondary); }
131
-
132
- .measure { font-variant-numeric: tabular-nums; }
133
- table.spec th, table.spec td { white-space: normal; }
134
- </style>
135
- </head>
136
- <body>
137
- <div class="doc">
138
-
139
- <h1>AUTH-4 — the account user list on a phone</h1>
140
- <p class="lede">Composition spec for <code>UserListComponent</code> below the <code>md</code>
141
- breakpoint. Drawn from <code>ui-core-micha</code>'s baseline tokens.</p>
142
-
143
- <div class="note">
144
- <p><strong>Declared coverage.</strong> One surface: the <strong>users</strong> section of
145
- <code>AccountPage</code> — its toolbar, its rows, its pagination. Nothing else.</p>
146
- <p><strong>Not covered, therefore unchanged:</strong> every other account section; the section
147
- navigation itself (that is <code>SHELL-5</code>); the delete confirmation dialog; the invite flow;
148
- the role list an app supplies; and the <strong>desktop table above <code>md</code></strong>, which
149
- this work order deliberately leaves exactly as it is.</p>
150
- </div>
151
-
152
- <div class="note warn">
153
- <p><strong>Authority.</strong> The Envelope wins on scope. The baseline wins on token values. This
154
- sheet wins on composition — what sits where, at which size, in which state. <strong>The accent is a
155
- neutral placeholder</strong>: <code>palette.primary</code> is app identity and the baseline has none,
156
- so each app supplies its own. Do not read the blue as a decision.</p>
157
- </div>
158
-
159
- <h2>1. The defect, measured</h2>
160
-
161
- <p>Measured 2026-08-11 in cockpit at <code>innerWidth</code> <strong>411</strong> CSS px — the mobile
162
- preset yields 411, not 375, so at the real target every figure is worse. The table renders
163
- <strong>1053&nbsp;px inside a 325&nbsp;px container</strong>. The container scrolls
164
- (<code>overflow-x: auto</code>) and the document does <em>not</em> overflow, so this is not a broken
165
- layout: it is a desktop table shown unchanged on a phone.</p>
166
-
167
- <div class="frame w375">
168
- <div class="frame-label bad">today — 411 px, 1053 px of table in a 325 px container</div>
169
- <div class="pane mobile">
170
- <div class="toolbar">
171
- <div class="search">
172
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.5 14h-.8l-.3-.3a6.5 6.5 0 1 0-.7.7l.3.3v.8l5 5 1.5-1.5-5-5Zm-6 0a4.5 4.5 0 1 1 0-9 4.5 4.5 0 0 1 0 9Z"/></svg>
173
- Suchen
174
- </div>
175
- </div>
176
- <div class="clip">
177
- <table>
178
- <thead><tr>
179
- <th style="width:220px">Email address</th><th style="width:180px">Name</th>
180
- <th style="width:90px">New</th><th style="width:163px">Successful Login</th>
181
- <th style="width:180px">Role</th><th style="width:220px">Actions</th>
182
- </tr></thead>
183
- <tbody>
184
- <tr>
185
- <td>anna.baumgartner@example.ch</td><td>Anna Baumgartner</td>
186
- <td><span class="flag yes"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4Z"/></svg></span></td>
187
- <td><span class="flag no"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M19 13H5v-2h14Z"/></svg></span></td>
188
- <td><span class="selectbox">admin <svg viewBox="0 0 24 24" fill="currentColor"><path d="M7 10l5 5 5-5Z"/></svg></span></td>
189
- <td><span class="iconbtn danger"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M6 19a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7H6Zm3-7h6v7H9ZM15.5 4l-1-1h-5l-1 1H5v2h14V4Z"/></svg></span></td>
190
- </tr>
191
- </tbody>
192
- </table>
193
- </div>
194
- <div class="pagination">Rows per page: 25 · 1–1 of 1</div>
195
- </div>
196
- </div>
197
-
198
- <div class="note">
199
- <p><strong>253&nbsp;px of that width is columns nobody chose.</strong> <code>New</code> (90) and
200
- <code>Successful Login</code> (163) are default-on props an app can switch off today —
201
- <code>AccountPage</code> forwards all of them — and cockpit simply left the defaults. But the four
202
- remaining columns are Email 220 + Name 180 + Role 180 + Actions 220 = <strong>800&nbsp;px</strong>
203
- against a 325&nbsp;px container. <strong>Configuration cannot fix this; only structure can.</strong>
204
- The defaults are deliberately left alone here — flipping them would be a silent estate-wide change.</p>
205
- </div>
206
-
207
- <h2>2. The proposal: a card per user below <code>md</code></h2>
208
-
209
- <p>The screen exists so an administrator can <strong>change a role</strong> or <strong>remove
210
- someone</strong>. Both are per-row controls, so any layout that puts them behind horizontal
211
- scrolling defeats the screen's purpose. A card brings them to thumb reach.</p>
212
-
213
- <div class="frames">
214
- <div class="frame w375">
215
- <div class="frame-label">proposed — 375 px</div>
216
- <div class="pane mobile">
217
- <div class="toolbar">
218
- <div class="search">
219
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.5 14h-.8l-.3-.3a6.5 6.5 0 1 0-.7.7l.3.3v.8l5 5 1.5-1.5-5-5Zm-6 0a4.5 4.5 0 1 1 0-9 4.5 4.5 0 0 1 0 9Z"/></svg>
220
- Suchen
221
- </div>
222
- <div class="sortctl">Email
223
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M7 10l5 5 5-5Z"/></svg>
224
- </div>
225
- </div>
226
-
227
- <div class="cardlist">
228
- <div class="ucard">
229
- <div class="ucard-head">
230
- <div class="ucard-id">
231
- <div class="ucard-email">anna.baumgartner@example.ch</div>
232
- <div class="ucard-name">Anna Baumgartner</div>
233
- </div>
234
- </div>
235
- <div class="chips">
236
- <span class="chip new">
237
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2 9.2 8.6 2 9.2l5.5 4.8L5.8 21 12 17.3 18.2 21l-1.7-7 5.5-4.8-7.2-.6Z"/></svg>
238
- Neu
239
- </span>
240
- <span class="chip never">
241
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 4a8 8 0 1 0 8 8h-2a6 6 0 1 1-6-6Zm1 3v5l4 2-.9 1.7L11 13V7Z"/></svg>
242
- Noch nie angemeldet
243
- </span>
244
- </div>
245
- <div class="ucard-foot">
246
- <div style="flex:1 1 auto; min-width:0">
247
- <span class="rolelabel">Rolle</span>
248
- <span class="selectbox" style="width:100%">admin
249
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M7 10l5 5 5-5Z"/></svg>
250
- </span>
251
- </div>
252
- <span class="iconbtn danger" title="Löschen">
253
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M6 19a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7H6Zm3-7h6v7H9ZM15.5 4l-1-1h-5l-1 1H5v2h14V4Z"/></svg>
254
- </span>
255
- </div>
256
- </div>
257
-
258
- <div class="ucard">
259
- <div class="ucard-head">
260
- <div class="ucard-id">
261
- <div class="ucard-email">t.k@example.ch</div>
262
- <div class="ucard-name missing">kein Name hinterlegt</div>
263
- </div>
264
- </div>
265
- <div class="chips">
266
- <span class="chip never" style="background:var(--success-bg); color:var(--success-text)">
267
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4Z"/></svg>
268
- Angemeldet
269
- </span>
270
- </div>
271
- <div class="ucard-foot">
272
- <div style="flex:1 1 auto; min-width:0">
273
- <span class="rolelabel">Rolle</span>
274
- <span class="selectbox" style="width:100%">none
275
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M7 10l5 5 5-5Z"/></svg>
276
- </span>
277
- </div>
278
- <span class="iconbtn danger" title="Löschen">
279
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M6 19a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7H6Zm3-7h6v7H9ZM15.5 4l-1-1h-5l-1 1H5v2h14V4Z"/></svg>
280
- </span>
281
- </div>
282
- </div>
283
-
284
- <div class="ucard">
285
- <div class="ucard-head">
286
- <div class="ucard-id">
287
- <div class="ucard-email">michael.hofstetter-brunner@verwaltung.example.ch</div>
288
- <div class="ucard-name">Michael Hofstetter-Brunner</div>
289
- </div>
290
- </div>
291
- <div class="chips">
292
- <span class="chip never" style="background:var(--success-bg); color:var(--success-text)">
293
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4Z"/></svg>
294
- Angemeldet
295
- </span>
296
- </div>
297
- <div class="ucard-foot">
298
- <div style="flex:1 1 auto; min-width:0">
299
- <span class="rolelabel">Rolle</span>
300
- <span class="selectbox" style="width:100%">sekretariat
301
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M7 10l5 5 5-5Z"/></svg>
302
- </span>
303
- </div>
304
- <span class="iconbtn danger" title="Löschen">
305
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M6 19a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7H6Zm3-7h6v7H9ZM15.5 4l-1-1h-5l-1 1H5v2h14V4Z"/></svg>
306
- </span>
307
- </div>
308
- </div>
309
- </div>
310
- <div class="pagination">25 pro Seite · 1–3 von 3</div>
311
- </div>
312
- </div>
313
- </div>
314
-
315
- <div class="note pick">
316
- <p><strong>Four composition decisions, each with its reason:</strong></p>
317
- <p><strong>The email is the card title, the name is secondary.</strong> The email is the identity an
318
- administrator searches by and the only guaranteed-present field — a user may have no name. A card
319
- with a missing name shows a muted placeholder rather than an empty line.</p>
320
- <p><strong>The two boolean columns become labelled chips.</strong> In the table they are icon-only
321
- with a tooltip, which a touch device cannot show at all. Chips carry the words. This is a small,
322
- deliberate improvement over parity, not drift — and it is why the flags cost vertical space rather
323
- than being dropped.</p>
324
- <p><strong>Role and delete sit together in a footer, separated by a divider.</strong> They are the
325
- two actions; grouping them keeps the card's top half purely identifying. The role select fills the
326
- remaining width so its label is never truncated; delete keeps the full 44&nbsp;px touch target.</p>
327
- <p><strong>Sorting needs its own control.</strong> A card list has no column headers to click, so the
328
- sortable-column affordance disappears with the table. A compact sort control sits beside the search
329
- field. <strong>Without it the mobile view silently loses a capability the desktop has</strong> — the
330
- kind of regression that is invisible in a diff.</p>
331
- </div>
332
-
333
- <h2>3. Above <code>md</code>: nothing changes</h2>
334
-
335
- <p>The table is right for a desktop — six columns are scannable at 1136&nbsp;px, and it was measured
336
- with 570&nbsp;px of headroom in the section strip beside it. Shown here only so "unchanged" is part
337
- of the spec rather than an omission.</p>
338
-
339
- <div class="frame w1280 scroll-x">
340
- <div class="frame-label">unchanged — 1280 px</div>
341
- <div class="pane">
342
- <div class="toolbar">
343
- <div class="search" style="max-width:320px">
344
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.5 14h-.8l-.3-.3a6.5 6.5 0 1 0-.7.7l.3.3v.8l5 5 1.5-1.5-5-5Zm-6 0a4.5 4.5 0 1 1 0-9 4.5 4.5 0 0 1 0 9Z"/></svg>
345
- Suchen
346
- </div>
347
- </div>
348
- <table>
349
- <thead><tr>
350
- <th><span class="sortable">Email address <svg viewBox="0 0 24 24" fill="currentColor"><path d="M7 14l5 5 5-5Z"/></svg></span></th>
351
- <th><span class="sortable">Name <svg viewBox="0 0 24 24" fill="currentColor"><path d="M7 14l5 5 5-5Z"/></svg></span></th>
352
- <th>New</th><th>Successful Login</th><th>Role</th><th>Actions</th>
353
- </tr></thead>
354
- <tbody>
355
- <tr>
356
- <td>anna.baumgartner@example.ch</td><td>Anna Baumgartner</td>
357
- <td><span class="flag yes"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4Z"/></svg></span></td>
358
- <td><span class="flag no"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M19 13H5v-2h14Z"/></svg></span></td>
359
- <td><span class="selectbox">admin <svg viewBox="0 0 24 24" fill="currentColor"><path d="M7 10l5 5 5-5Z"/></svg></span></td>
360
- <td><span class="iconbtn danger"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M6 19a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7H6Zm3-7h6v7H9ZM15.5 4l-1-1h-5l-1 1H5v2h14V4Z"/></svg></span></td>
361
- </tr>
362
- <tr>
363
- <td>t.k@example.ch</td><td style="color:var(--text-muted); font-style:italic">kein Name hinterlegt</td>
364
- <td><span class="flag no"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M19 13H5v-2h14Z"/></svg></span></td>
365
- <td><span class="flag yes"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4Z"/></svg></span></td>
366
- <td><span class="selectbox">none <svg viewBox="0 0 24 24" fill="currentColor"><path d="M7 10l5 5 5-5Z"/></svg></span></td>
367
- <td><span class="iconbtn danger"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M6 19a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7H6Zm3-7h6v7H9ZM15.5 4l-1-1h-5l-1 1H5v2h14V4Z"/></svg></span></td>
368
- </tr>
369
- </tbody>
370
- </table>
371
- <div class="pagination">Rows per page: 25 · 1–2 of 2</div>
372
- </div>
373
- </div>
374
-
375
- <h2>4. What the app supplies, and what that costs</h2>
376
-
377
- <p><code>UserListComponent</code> already takes <code>extraColumns</code> and
378
- <code>extraRowActions</code>, so the column set is app-configurable. The card must therefore render
379
- columns it has never seen.</p>
380
-
381
- <table class="spec">
382
- <thead><tr><th>Input</th><th>In the card</th></tr></thead>
383
- <tbody>
384
- <tr><td><code>extraColumns</code></td>
385
- <td>rendered as <strong>label: value</strong> rows below the chips, in the order given. No new
386
- required field on the column definition — an app that wants nothing else gets nothing else,
387
- and one that already passes columns keeps working unchanged.</td></tr>
388
- <tr><td><code>extraRowActions</code></td>
389
- <td>join delete in the footer. Beyond three actions total they must collapse into an overflow
390
- menu, or the footer wraps and the card loses its shape.</td></tr>
391
- <tr><td>the three toggleable columns</td>
392
- <td>as chips when on, absent when off. An app that switches both flags off gets a shorter card,
393
- not an empty chip row.</td></tr>
394
- </tbody>
395
- </table>
396
-
397
- <div class="note warn">
398
- <p><strong>What this sheet cannot show.</strong> No motion, no interaction states beyond the resting
399
- one — no hover, focus ring, pressed, or the open select menu. The delete confirmation dialog is
400
- untouched and undrawn. A long list is drawn as three cards; the real scroll behaviour and the
401
- pagination control at the bottom of a 25-card page are not represented. If DM Sans is not installed
402
- locally this page falls back to the system font — sizes and weights are still exact.</p>
403
- </div>
404
-
405
- </div>
406
- </body>
407
- </html>