@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,356 +0,0 @@
1
- # UCM-THEME-15: Derive status and control-border colours against the theme's own page
2
-
3
- # A. Envelope, authored by the Expertenchat
4
-
5
- ## Goal & expected outcome
6
-
7
- `createAppTheme` already derives one colour against the page it will sit on: `controlBorder.focus`
8
- (`deriveFocusColour`, `src/theme/createAppTheme.js`). Every other page-sensitive baseline colour is
9
- fixed. So an app or site whose `background.default` is not near-white gets baseline status and
10
- border colours that fail WCAG on its own page.
11
-
12
- After this order, the **baseline-supplied** status `main` colours and control-border colours are
13
- derived the same way, and only when they would otherwise fail. A theme on the baseline's own page
14
- resolves exactly as today. A theme on a tinted page gets colours that pass on that page.
15
- `assertThemeComplete` then returns zero contrast findings for every baseline-supplied colour on the
16
- estate's real site backgrounds.
17
-
18
- **Operator decision (2026-09-29):** option (a) of three. The factory derives the colours. Contrast
19
- findings do **not** become exemptible (option b, which would hide real accessibility failures on
20
- customer sites), and sites do not get their own status colours (option c, new per-customer design
21
- decisions).
22
-
23
- ## Context the operator established
24
-
25
- - **What the check measures** (`src/theme/themeCompleteness.js`, `contrastFindings`): for each status
26
- key, `main` against `#FFFFFF` **and** `background.default` at **4.5:1**; `controlBorder.main/hover/
27
- focus/error` against the same two surfaces at **3:1**. The pairs `text`-on-`bg` and
28
- `fillText`-on-`fill` are self-contained and do not depend on the page. Contrast findings are appended
29
- after exemption filtering (`themeCompleteness.js:371`), so no exemption can cover them. That stays.
30
- - **The baseline values** (`src/theme/tokens.js`, `BASELINE_PALETTE`): `success.main` `#1B8038`,
31
- `warning.main` `#976100`, `error.main` `#BF3227`, `info.main` `#01579B` (`stale` has no `main`), each
32
- built by `withMainShades`. `controlBorder.main` `rgba(33,37,41,.50)`, `.hover` `rgba(33,37,41,.65)`,
33
- `.error` `#BF3227`. `focus` is derived.
34
- - **Measured on the estate's real site backgrounds (2026-09-29),** baseline colours only:
35
-
36
- | Page `background.default` | Fails | Darkening needed (MUI `darken`) |
37
- |---|---|---|
38
- | baseline `#FAFAFA` | nothing | none |
39
- | `hafen` `#D8E4E1` | success 3.84, warning 4.00, error 4.35; border.main 2.91 | 0.10 / 0.08 / 0.03; border alpha 0.52 |
40
- | `jg-fegbern` `#eceae2` | success 4.16, warning 4.33; border.main 2.98 | 0.05 / 0.03; alpha 0.51 |
41
- | `routing` `#E8EAF6` | success 4.18, warning 4.35; border.main 2.98 | 0.05 / 0.03; alpha 0.51 |
42
- | `uph` `#E6EAF0` | success 4.15, warning 4.32; border.main 2.97 | 0.05 / 0.03; alpha 0.51 |
43
- | `ygbs` `#E398C7` | success 2.29, warning 2.38, error 2.59, info 3.38; border.main 2.50, border.error 2.59 | 0.40 / 0.38 / 0.34 / 0.21; alpha 0.59 |
44
-
45
- Sites are `survey_app/frontend/src/sites/*/theme.js`; `ygbs` also lives in `survey_contact_app`.
46
- - **Every adopted app already passes.** All ten apps on `createAppTheme` assert
47
- `assertThemeComplete(theme).findings` equals `[]`, so none of them has a contrast finding today.
48
-
49
- ## The rule (decided)
50
-
51
- 1. **Scope of derivation:** `success/warning/error/info.main`, and `controlBorder.main/hover/error`.
52
- The derived `main` also re-derives its `light`/`dark`/`contrastText` through `withMainShades`, so a
53
- status entry stays internally consistent. `text`, `fill`, `fillText`, `bg` are untouched.
54
- 2. **Only when it fails.** A value that already clears its threshold against both `#FFFFFF` and
55
- `background.default` is returned **unchanged, byte for byte**. So no theme that passes today moves.
56
- 3. **Only baseline-supplied values.** If the app's own config sets a status `main` or a
57
- `controlBorder` state, that value is the app's decision. It is never altered, and its finding
58
- stays.
59
- 4. **Direction and method:** status `main` and `controlBorder.error` are darkened with MUI `darken` in
60
- the smallest steps that clear the threshold, as `deriveFocusColour` does. `controlBorder.main/hover`
61
- keep their ink hue and raise their alpha instead, so they stay a translucent ink.
62
- 5. **Same surfaces as the check:** `#FFFFFF` and `background.default`, exactly the two that
63
- `contrastFindings` uses, just as the existing comment at `deriveFocusColour` insists.
64
- 6. **Unreachable stays visible:** if the maximum step does not clear the threshold, the loop stops,
65
- returns the last value and the finding remains. It never throws and always terminates. Dark pages
66
- are `UCM-THEME-14`'s subject, not this order's.
67
-
68
- ## Scope + non-goals
69
-
70
- In scope: the derivation in `createAppTheme` (next to `deriveFocusColour`, which may be generalised
71
- into one helper); `DESIGN.md` (one paragraph: which baseline colours are page-derived, and why);
72
- `CHANGELOG.md`; a **minor** release. It is a changed default, but only for themes that currently fail,
73
- and none of the adopted apps does.
74
-
75
- Non-goals:
76
- - No change to any baseline token value in `tokens.js`.
77
- - No exemption path for contrast findings.
78
- - No change to `text`/`fill`/`fillText`/`bg`, to `dataSeries`, or to anything the app sets itself.
79
- - No dark-mode handling (`UCM-THEME-14`).
80
- - No consumer change. `survey_app` and `survey_contact_app` adopt it through their own pin bump.
81
-
82
- ## Tier · precondition / gate
83
-
84
- - **Tier 3 · tests: derivation on the six measured pages, byte-identical output on the baseline page,
85
- app-supplied values untouched, termination; the kit's existing theme tests.** A change inside
86
- shared-core.
87
- - Precondition: none.
88
- - **Order with `UCM-THEME-14`:** this lands first. Both touch the focus derivation and the surface
89
- pair, and 14 is waiting on a design round (`UCM-THEME-13`) anyway.
90
- - Downstream: `survey_app`/`SVA-THEME-1` and `survey_contact_app`/`SCA-THEME-1` (site half) wait for
91
- this release **and** for their own pin bump.
92
-
93
- ## Risks
94
-
95
- - **`ygbs` will look different.** Its status colours darken by up to 40 % (success `#1B8038` becomes
96
- roughly `#104D22`). That is the price of legibility on a mid-pink page. It is visible on the customer
97
- site, and the operator sees it in `SVA-THEME-1`'s acceptance.
98
- - **Silent change for a future app on a tinted page.** Expected and intended: the baseline promises a
99
- passing colour, not a fixed hex. `DESIGN.md` has to say so, or someone will read the hex in
100
- `tokens.js` and expect it on screen.
101
- - **Rule 3 needs to know what the app set.** The merged palette alone cannot tell baseline from app
102
- values. Read the app's config (`appConfig.palette`) before deciding, not the resolved theme.
103
- - **`light`/`dark` shades shift with a derived `main`.** Components using `error.dark` for hover move
104
- with it. Correct, but name it in the changelog.
105
-
106
- ## Required tests to WRITE (you write them and run YOUR OWN new ones; the Orchestrator's run is the gate)
107
-
108
- Kit test suite, next to the existing theme tests:
109
-
110
- 1. **Six measured pages.** For each `background.default` in the table, with only `palette.primary`
111
- given, `assertThemeComplete` has no `contrast.*.main-on-*` and no `contrast.controlBorder.*`
112
- finding.
113
- 2. **No movement where nothing fails.** On the baseline page, the resolved status entries and
114
- `controlBorder` equal today's values exactly. Show that the test fails when one baseline hex is
115
- altered by hand.
116
- 3. **App values are untouched.** A config that sets `success.main` to a failing colour on a tinted
117
- page keeps exactly that colour, and the finding remains.
118
- 4. **Termination.** A page on which the maximum step cannot reach the threshold (a mid-grey such as
119
- `#767676`) returns without throwing and keeps the finding.
120
-
121
- Run, do not write: the kit's existing theme and `kitSxRegistry` tests.
122
-
123
- ## Parity guardrail
124
-
125
- No change for any theme that passes today. No API change, no new option.
126
-
127
- ---
128
-
129
- # B. Implementation map, filled by the Orchestrator and ADDRESSED TO THE IMPLEMENTER
130
-
131
- ## Context package
132
-
133
- ### Current shape (`src/theme/createAppTheme.js`, read in full before editing)
134
-
135
- - `clearsContrast(colour, surfaces)` (line ~39): `surfaces.every((s) => getContrastRatio(colour, s) >= 3)`
136
- — hardcoded to 3:1 and to MUI's own `getContrastRatio`. Used ONLY by `deriveFocusColour`.
137
- - `deriveFocusColour(primary, surfaces)` (line ~47): darkens in `0.05` steps (MUI `darken`), capped at
138
- coefficient `0.9`, stops and returns the last value if unreached (never throws).
139
- - `createAppTheme(appConfig)` (line ~170): throws if `!appConfig?.palette?.primary`. Builds
140
- `paletteTheme = createTheme({palette: appConfig.palette}, {palette: BASELINE_PALETTE}, {palette:
141
- appConfig.palette})` (app layered, then baseline, then app again — this is why an app-set value
142
- always wins in `finalPalette`, and why a value present in `BASELINE_PALETTE` but absent from
143
- `appConfig.palette` is a baseline value). `finalPalette = paletteTheme.palette`. Then:
144
- ```js
145
- const computedPalette = {
146
- controlBorder: {
147
- ...finalPalette.controlBorder,
148
- focus: deriveFocusColour(finalPalette.primary.main, ['#FFFFFF', finalPalette.background.default]),
149
- },
150
- };
151
- const resolvedPalette = { ...finalPalette, ...computedPalette };
152
- ```
153
- This is the exact seam this WO extends — do not restructure the surrounding merge order,
154
- `validateStyleOverrides`, or the final `createTheme(...)` call's argument layering.
155
-
156
- ### Do NOT touch `clearsContrast`/`deriveFocusColour` — add parallel, separate logic instead
157
-
158
- - The byte-identical-on-baseline-page requirement (test #2) and "no change to anything not
159
- described here" mean the existing focus derivation must keep behaving exactly as it does today.
160
- Do not generalise `clearsContrast` into a shared threshold-aware helper by EDITING it in place —
161
- add new, separate functions for this WO's derivations. (You may factor out a shared shape later if
162
- you can prove byte-for-byte equivalence, but the safe, required path is: leave the existing two
163
- functions untouched, add new ones alongside.)
164
- - **Use `calculateContrastRatio` from `./themeCompleteness`** (already exported, already used by
165
- `contrastFindings` — the same function the check itself uses) for every NEW contrast test in this
166
- WO, not MUI's `getContrastRatio`. This matters concretely for `controlBorder.main`/`.hover`: their
167
- baseline values are translucent (`rgba(33,37,41,.50)`), and `calculateContrastRatio` alpha-composites
168
- over the background before computing luminance (see its own docstring) — `getContrastRatio` is not
169
- documented to do this. Using the wrong function here would silently pick the wrong alpha.
170
-
171
- ### The two derivation shapes (rule 4)
172
-
173
- 1. **Darken-based** (status `main` for success/warning/error/info; `controlBorder.error`): same
174
- step/cap shape as `deriveFocusColour` (start `coefficient = 0.05`, `darken(original, min(coefficient,
175
- 0.9))`, step `+0.05`, stop and return the last value if `coefficient >= 0.9` without clearing) but
176
- parameterised by threshold (`4.5` for status `main`, `3` for `controlBorder.error`) and using
177
- `calculateContrastRatio`.
178
- 2. **Alpha-raising** (`controlBorder.main`, `.hover`): the baseline values are the fixed shape
179
- `rgba(33, 37, 41, <alpha>)` (`.50` and `.65`). Parse `r`,`g`,`b`,`a` (a small regex is enough — this
180
- path is NEVER invoked on an app-supplied value, see rule 3 below, so it never needs to handle an
181
- arbitrary CSS colour format). Step `alpha` up by `0.05`, capped at `1`, producing
182
- `rgba(${r}, ${g}, ${b}, ${alpha})` each step, stopping when `calculateContrastRatio` clears `3`
183
- against both surfaces or `alpha` reaches `1` (never throws; if unreached at `alpha = 1`, return that
184
- last candidate and the finding remains — same "give up, stay visible" contract as the darken path).
185
-
186
- ### Rule 3 — baseline vs app-supplied, decided from `appConfig.palette`, not the resolved theme
187
-
188
- Before deriving anything, for each of the 6 targets check the RAW input, not `finalPalette`:
189
- - Status keys: `appConfig.palette?.[statusKey]?.main !== undefined` → app-supplied, skip entirely
190
- (leave `finalPalette[statusKey]` exactly as merged, findings stay if any).
191
- - `controlBorder.main`/`.hover`/`.error`: `appConfig.palette?.controlBorder?.[state] !== undefined` →
192
- app-supplied, skip.
193
- - Only when NOT app-supplied: read the value off `finalPalette` (the merged/baseline value), check it
194
- against `['#FFFFFF', finalPalette.background.default]` at the relevant threshold, and derive only if
195
- it fails. **A value that already clears both thresholds is returned unchanged, byte for byte** — do
196
- not run it through `darken`/alpha-step at all if it already passes (this is what keeps the baseline
197
- page byte-identical: on `#FAFAFA`, everything already clears, so nothing here ever fires).
198
-
199
- ### Re-deriving a status entry consistently (rule 1)
200
-
201
- When a status `main` is derived, rebuild that status's `main`/`light`/`dark`/`contrastText` via the
202
- existing `withMainShades` (`src/theme/tokens.js`, already exported — import it, or re-derive the same
203
- shades inline using `lighten`/`darken` exactly as `withMainShades` does; prefer importing the real
204
- function over duplicating its formula) called as `withMainShades(derivedMain, existingContrastText)`
205
- — `existingContrastText` is `finalPalette[statusKey].contrastText`, unchanged (every baseline status
206
- already carries `'#FFFFFF'`; do not hardcode `'#FFFFFF'` here, read it off the entry so an
207
- app-overridden `contrastText` on an otherwise-baseline `main` is respected). `text`/`fill`/`fillText`/
208
- `bg` on that same status object are spread through unchanged — merge shape:
209
- `{ ...finalPalette[statusKey], ...withMainShades(derivedMain, finalPalette[statusKey].contrastText) }`.
210
-
211
- ### Wiring it into `createAppTheme`
212
-
213
- Extend the existing `computedPalette` object (do not add a second, separate merge step) so
214
- `resolvedPalette` picks up both the existing `controlBorder.focus` line and the new derivations, e.g.
215
- (shape, not literal code to paste — adapt to how you factor the helper functions):
216
- ```js
217
- const computedPalette = {
218
- ...derivedStatusEntries, // { success?, warning?, error?, info? } — only keys that were derived
219
- controlBorder: {
220
- ...finalPalette.controlBorder,
221
- ...derivedControlBorderEntries, // { main?, hover?, error? } — only keys that were derived
222
- focus: deriveFocusColour(finalPalette.primary.main, ['#FFFFFF', finalPalette.background.default]),
223
- },
224
- };
225
- ```
226
- `stale` has no `main` (`tokens.js`) — `contrastFindings` already skips it via `if (!main) continue;`;
227
- do not add derivation logic for `stale`.
228
-
229
- ### Test file
230
-
231
- New file next to the existing theme tests (`tests/createAppTheme.test.js` already exists — read it
232
- first; extend it if its structure fits, or add `tests/createAppThemePageContrast.test.js`).
233
- Use the six real background values from the Envelope's table directly (already verified against
234
- `survey_app/frontend/src/sites/*/theme.js` — `hafen` `#D8E4E1`, `jg-fegbern` `#eceae2`, `routing`
235
- `#E8EAF6`, `uph` `#E6EAF0`, `ygbs` `#E398C7`, plus the baseline `#FAFAFA`). Any valid `primary.main`
236
- works for these (the check is independent of primary) — reuse the kit's own test convention, e.g.
237
- `'#0F62FE'` (see `tests/StatTile.test.jsx`).
238
-
239
- 1. For each of the 6 pages: `createAppTheme({ palette: { primary: { main: '#0F62FE' }, background: {
240
- default: <page hex> } } })`, then `assertThemeComplete(theme).findings` has no entry whose
241
- `surface` starts with `contrast.` for any status `main-on-*` or any `contrast.controlBorder.*`
242
- (other, unrelated findings — e.g. undeclared surfaces this WO doesn't touch — are not this test's
243
- concern; assert on the specific surface-name prefixes, not on the whole array being empty, unless
244
- this repo's fixture already guarantees a clean baseline call is fully empty — check
245
- `tests/createAppTheme.test.js`/`tests/themeCompleteness.test.js` for the existing convention here).
246
- 2. On the baseline page (`background.default` left at its `BASELINE_STATIC`/`BASELINE_PALETTE`
247
- default, i.e. no override given), `theme.palette.success.main` (and `.light`/`.dark`/
248
- `.contrastText`), `.warning.main`, `.error.main`, `.info.main`, `.controlBorder.main`, `.hover`,
249
- `.error` all equal today's exact `BASELINE_PALETTE`/derived values (read them from `tokens.js`,
250
- do not hand-copy hexes into the test — import `BASELINE_PALETTE` and compare against it directly
251
- so the test can't drift from the source of truth). Then, per the Envelope's own instruction, show
252
- this test actually pins something: temporarily hand-edit one baseline hex in a throwaway local copy
253
- (or otherwise demonstrate) that the assertion fails if the value moved — narrate how you did this
254
- in your `PROGRESS` line rather than leaving a permanently-broken toggle in the committed test.
255
- 3. A config that sets e.g. `palette.success.main` to a colour that fails on a tinted page (construct
256
- one deliberately, e.g. a light green on `ygbs`'s pink) keeps EXACTLY that colour after
257
- `createAppTheme` (`theme.palette.success.main === appConfig.palette.success.main`), and
258
- `assertThemeComplete` still reports that specific `contrast.success.main-on-*` finding (proving
259
- rule 3's app-supplied values are never touched AND their findings are never silently hidden).
260
- 4. `createAppTheme({ palette: { primary: { main: '#0F62FE' }, background: { default: '#767676' } } })`
261
- does not throw, returns a defined `theme.palette.success.main` (etc.), and
262
- `assertThemeComplete(theme).findings` still contains the relevant `contrast.*` entries (mid-grey
263
- `#767676` is deliberately unreachable within the darken cap — confirm this numerically before
264
- relying on it: `calculateContrastRatio('#FFFFFF', '#767676')` and the darkened-`main` variants
265
- should stay below `4.5` even at the `0.9` darken cap; if your arithmetic says otherwise, pick
266
- another representative unreachable grey and say which and why in `PROGRESS`).
267
-
268
- Run, do not write: `tests/createAppTheme.test.js` (existing) and `tests/themeCompleteness.test.js`
269
- (existing) as the directly-dependent regression set — your own focused run only, the Orchestrator
270
- re-runs both as the gate.
271
-
272
- ### `DESIGN.md` and `CHANGELOG.md`
273
-
274
- - `DESIGN.md`: one paragraph — which baseline colours are page-derived (`success`/`warning`/`error`/
275
- `info.main`, `controlBorder.main`/`.hover`/`.error`, alongside the existing `controlBorder.focus`)
276
- and why (a fixed hex cannot promise WCAG on every page background; the baseline promises a passing
277
- colour, not a fixed one — state this explicitly so a future reader doesn't expect the `tokens.js`
278
- hex to appear unmodified on every site). If `DESIGN.md` does not exist at the repo root, check for
279
- an equivalent doc (grep for "baseline" or "token" in root `*.md` files) before creating a new one.
280
- - `CHANGELOG.md`: entry naming the changed default (derived colours are possible now, "byte identical
281
- when passing today"), and explicitly naming that `light`/`dark` shades move WITH a derived `main`
282
- (Risk note: a component styled with `error.dark` for hover moves too).
283
-
284
- ## Do-not-touch / invariants
285
-
286
- - No change to any literal in `BASELINE_PALETTE`/`BASELINE_STATIC` (`tokens.js`).
287
- - No exemption path added anywhere in `themeCompleteness.js`.
288
- - `text`/`fill`/`fillText`/`bg` on every status object, `dataSeries`, and anything the app sets itself
289
- (beyond the 6 targets named here) are untouched.
290
- - No dark-mode handling (`UCM-THEME-14`'s subject).
291
- - Do not touch `survey_app`/`survey_contact_app` — this WO is entirely inside `ui-core-micha`.
292
-
293
- ## Target repo working directory (absolute)
294
-
295
- `C:\Users\biglmi\Documents\webapps\ui-core-micha` (branch `main`)
296
-
297
- ## Preamble — a REQUIRED block IN this file, not something appended at invocation
298
-
299
- > The text above is the COMPLETE spec — the committed WO file's content, not a plan to refine; there
300
- > is no separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`, and the
301
- > app `MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/schema/CI
302
- > unless the spec says so; do not update `MEMORY.md`. **Do NOT edit `WORK_ORDERS.md` — the register
303
- > row and the review verdicts are the orchestrator's alone.** **Your tools are for editing source
304
- > and test files (and `DESIGN.md`/`CHANGELOG.md` as named above) and for running the tests you wrote
305
- > — nothing else.** Do NOT install dependencies, touch a lockfile, run a package manager, or tidy up
306
- > stray files; if something in the repo state blocks you, stop and report it as
307
- > `RESULT: BLOCKED <reason>` instead of fixing it. Do NOT `git add`/`commit`/`push` — leave every
308
- > change uncommitted in the working tree for the orchestrator's independent review. WRITE the tests
309
- > the `Required tests` section calls for AND **RUN the tests you just wrote** to confirm they execute
310
- > and pass — that is the ONLY test run you do (NOT the app's affected/full suite, NOT any review).
311
- > The orchestrator re-runs the authoritative set + does the independent review after you finish —
312
- > those are the gate; your own run does not count as the gate.
313
- >
314
- > Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line
315
- > `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `… done` on
316
- > completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final
317
- > `RESULT: DONE|BLOCKED <reason>`.
318
-
319
- ---
320
-
321
- # C. Orchestrator only, NOT ADDRESSED TO THE IMPLEMENTER
322
-
323
- > **If you are the implementer reading this work order as your own specification: STOP at this line.**
324
- > Everything below describes what the Orchestrator does AFTER you finish. You do none of it: no
325
- > reviewers, no verification run, no register edit, no `git add`/`commit`/`push`.
326
-
327
- ### Execution directive
328
-
329
- Check `.claude/codex-status.md` first (newest-first; read it with `head`). No line for today means use
330
- Codex. Before `git push`, run `git log origin/main..HEAD` and push only if every listed commit is this
331
- order's (parallel sessions share this checkout).
332
-
333
- ### Review routing
334
-
335
- Tier 3: independent `reviewer` (all configured lenses) and `ui_reviewer`, concurrent, one batch,
336
- before the commit. No `sec_reviewer`. Ask `ui_reviewer` specifically about rule 3: can a
337
- baseline-supplied value be told apart from an app-supplied one in every merge path?
338
-
339
- ### Verification
340
-
341
- The contrast values in the Envelope table are the acceptance data: re-derive them from the built
342
- themes and put the derived hex per site in the register Notiz. No prototype is in scope. The visual
343
- consequence is accepted per site in `SVA-THEME-1`, not here.
344
-
345
- ### Register + commit + release
346
-
347
- Row -> `done` with the review Notiz in the `AGENTS.md` shape and the published version. The publish
348
- runs on push to `main` when `package.json`/`src/**` change (`.github/workflows/publish.yml`). Then add
349
- `planned` pin-bump rows in `survey_app/WORK_ORDERS.md` and `survey_contact_app/WORK_ORDERS.md` (from
350
- `2.41.3`; classify each by the dependency-bump test in `AGENTS.md` -> Tiering, reading the changelog
351
- from `2.41.3` on) and unblock `SVA-THEME-1` / `SCA-THEME-1` against them.
352
-
353
- ### Mini-handover
354
-
355
- `Orchestrator: implement work-orders/UCM-THEME-15.md in ui-core-micha (main). git pull first, read the
356
- WO, then follow orchestrate-codex.`
@@ -1,80 +0,0 @@
1
- # UCM-THEME-16: Dark-safe info box in `QrSignupManager`
2
-
3
- # A. Envelope, authored by the Expertenchat
4
-
5
- ## Goal & expected outcome
6
-
7
- The "Signup Access / valid until" box under a generated signup QR code stays readable in dark mode. Today it
8
- paints a fixed light ground, `grey.50` (`#FAFAFA`), under the theme's secondary text; in dark that is
9
- `#AAB5BF` on `#FAFAFA`, **2.00:1**. After this order the box takes `background.subtle`, which resolves per
10
- mode: light `#F4F5F6` (5.37:1 for its text), dark `#20262C` (7.32:1).
11
-
12
- ## Decided (operator, 2026-10-02)
13
-
14
- - **`src/components/QrSignupManager.jsx:376`**: `bgcolor: 'grey.50'` -> `bgcolor: 'background.subtle'`.
15
- **The light change is accepted**: `#FAFAFA` -> `#F4F5F6`, a 1.05:1 step, barely visible.
16
- - **`src/components/QrSignupManager.jsx:361`** (`bgcolor: '#ffffff'` behind the QR code itself) **stays white
17
- on purpose**: a QR code needs a light quiet zone to scan. Recorded in `docs/DARK-TOKENS.md`.
18
- - **`src/messaging/ReadTicks.jsx:14`** (`DM_SENT_COLOR = 'grey.500'`) **stays unchanged.** It already clears
19
- contrast in dark (6.07:1 on the dark paper). The candidate `text.disabled` (`#6A7178`) is the value the file's
20
- own comment records as rejected, because it read too close to the "read" state. In light the tick sits at
21
- 2.68:1 on white. That is a pre-existing condition, softened by the icon shape (Done vs DoneAll), and not
22
- part of this order.
23
-
24
- These decisions replace the register row's original question ("accept the small light change, or add a
25
- token"), raised by the `UCM-THEME-14` review.
26
-
27
- ## Scope + non-goals
28
-
29
- In scope: the one property at `QrSignupManager.jsx:376`; `CHANGELOG.md`; a **patch** release.
30
-
31
- Non-goals: no change to `ReadTicks.jsx`, to the QR code's white ground, or to any token value.
32
-
33
- ## Tier · precondition / gate
34
-
35
- - **Tier 3 · tests: one rendered-style assertion per mode for the info box; the component's existing tests.**
36
- A change inside shared-core, even at one line (`AGENTS.md` -> Tiering).
37
- - Precondition: `UCM-THEME-14` landed (3.11.0, confirmed 2026-10-02).
38
-
39
- ## Risks
40
-
41
- - The light change is the only light-output change since `UCM-THEME-14`'s regression fixture. If that fixture
42
- covers this component, it needs this one entry updated, named, and nothing else.
43
-
44
- ## Required tests to WRITE (you write them and run YOUR OWN new ones; the Orchestrator's run is the gate)
45
-
46
- 1. In a light theme from `createAppTheme`, the info box's background resolves to `#F4F5F6`; in a dark theme to
47
- `#20262C`. Assert against the theme's own `background.subtle`, not a copied hex.
48
-
49
- Run, do not write: the existing `QrSignupManager` tests and the light regression fixture.
50
-
51
- ## Parity guardrail
52
-
53
- No behaviour change. One background, both modes.
54
-
55
- ---
56
-
57
- # B. Implementation map, filled by the Orchestrator and ADDRESSED TO THE IMPLEMENTER
58
-
59
- *Placeholder. The Orchestrator fills the context package, the absolute working directory, the
60
- progress contract and the preamble block on `git pull`, per `AGENTS.md` -> "Work Order". A one-line change
61
- may be implemented by the Orchestrator directly; authorship then sits with it and the independent review
62
- carries independence. Do not dispatch while this placeholder stands.*
63
-
64
- ---
65
-
66
- # C. Orchestrator only, NOT ADDRESSED TO THE IMPLEMENTER
67
-
68
- > **If you are the implementer reading this work order as your own specification: STOP at this line.**
69
- > Everything below describes what the Orchestrator does AFTER you finish. You do none of it: no
70
- > reviewers, no verification run, no register edit, no `git add`/`commit`/`push`.
71
-
72
- - Check `.claude/codex-status.md` first (newest-first). Before `git push`, run `git log origin/main..HEAD` and
73
- push only if every listed commit is this order's.
74
- - Review: Tier 3, independent `reviewer` (all configured lenses) and `ui_reviewer`, one batch, before the
75
- commit.
76
- - Release: verify the publish through the job log (`npm view` lags for provenance publishes). Row -> `done`
77
- with the review Notiz and the version.
78
-
79
- Mini-handover: `Orchestrator: implement work-orders/UCM-THEME-16.md in ui-core-micha (main). git pull first,
80
- read the WO, then follow orchestrate-codex.`
@@ -1,111 +0,0 @@
1
- # UCM-THEME-17: Decide a less compressed baseline type scale
2
-
3
- # A. Envelope, authored by the Expertenchat
4
-
5
- ## Goal & expected outcome
6
-
7
- The baseline's heading steps are too small to carry a hierarchy. Page title, card title and section label
8
- differ by 1 to 3 px, so screens rely on weight alone, and where every level is bold the levels merge. This
9
- order produces the **decided** type scale as a committed reference sheet that the operator freezes. A
10
- later implementation order puts it into `src/theme/tokens.js`. The output here is a document, no code.
11
-
12
- Operator decision (2026-10-04): treat this as a baseline finding, the way dark mode was treated
13
- (`UCM-THEME-13`), not as per-app overrides.
14
-
15
- ## Context the operator established
16
-
17
- - **The baseline scale today** (`src/theme/tokens.js:157-168`): h1 32, h2 28, h3 24, h4 20, h5 18, h6 16,
18
- subtitle1 15/600, subtitle2 13/500, body1 14, body2 13, button 14/500, caption 12, overline 11 (px).
19
- - **Measured on rendered screens, 2026-10-04** (computed styles in the browser):
20
-
21
- | Screen | Page title | Card title | Section | Text |
22
- |---|---|---|---|---|
23
- | hram, Research | h4 20/500 | h5 18/500 | subtitle1 15/600 | 14 |
24
- | jg-ferien, Dashboard | h5 18/600 | h6 16/600 | – | 14, partly 600 |
25
- | kerzenziehen, Admin | h5 18/600 | – | – | 14 |
26
- | survey_app site (operator screenshots) | h4 20/800 | h6 16/800 | – | – |
27
- | for comparison, the MUI scale (spesix, stale local build) | h4 34 | h5 24 | – | 16 |
28
-
29
- - **Operator feedback:** survey_app editor and sites read "more harmonious" at the old MUI sizes, and on the
30
- sites the section title and the question labels became indistinguishable. jg-ferien already restored its
31
- own sizes (`jg-ferien` `JG-DL-7`). Six other apps accepted the baseline scale without comment.
32
- - **The MUI scale is the other extreme**: 34/24 px titles read heavy in a dense tool.
33
-
34
- ## Inventory (stage 1, 2026-10-04)
35
-
36
- From 88 prototypes in `*/work-orders/assets/` (screen selectors hand-checked in nine: KZ-UI-1, RES-14,
37
- INNO-PLAN-1, JG-MEM-1, UX-10, PRIM-1, FM-8, OBS-10, KIRA-CRUD-6), the app theme overrides and the
38
- measurements above:
39
-
40
- | Role | Baseline today | Approved prototypes (typical) | MUI |
41
- |---|---|---|---|
42
- | Screen title | h4 20/600, fixed | 24 at 1280, 17-21 at 375 (KZ 24->17, jg 25.6->20, survey 24->21) | 34 |
43
- | Panel / dialog | h5 18 | 18-20 | 24 |
44
- | Card title | h6 16 | 15-18 | 20/500 |
45
- | Section label | subtitle1 15/600 | 12-13 at 600-700 | - |
46
- | Body | 14 | 14 (20 sheets), 15 (13 sheets) | 16 |
47
-
48
- - The approved designs had the larger title step (screen title about 1.7x body; baseline 1.43x), and step
49
- the title down on mobile. Both were lost between prototype and baseline.
50
- - The section label sits on the wrong side of body: 15 px, one pixel under the card title.
51
- - jg-ferien rejected larger **body** text (`JG-DL-7`); survey_app misses **heading** steps. The two are
52
- compatible.
53
- - Weight no longer carries hierarchy: every heading is 600 and apps override it per level (survey_app 800,
54
- hram 500).
55
-
56
- ## Structural decisions (operator, 2026-10-04)
57
-
58
- 1. **One scale** for every app and page type; no separate reading register. Body stays the tool density.
59
- 2. **The screen title steps down one size on narrow screens.**
60
- 3. **Size carries the hierarchy, weight is fixed**: headings share one weight; the section label is small
61
- and strong. App overrides are for font family, not for per-level weight.
62
- 4. **The section label (subtitle1) moves below body size**, set apart by weight.
63
-
64
- The role mapping of the `THEME-1` sheet stands: h4 screen title, h5 panel/dialog, h6 card title.
65
-
66
- ## Outcome
67
-
68
- **Frozen 2026-10-04** after two value rounds: candidate B, mobile screen title 23, h1 to h3 36 / 32 / 28. The
69
- frozen sheet is [`docs/TYPE-SCALE.md`](../docs/TYPE-SCALE.md); the implementation order is `UCM-THEME-18`.
70
-
71
- ## Scope + non-goals
72
-
73
- In scope: an inventory of the type sizes the estate actually uses (app overrides, prototypes, the
74
- `THEME-1` reference sheet's own reasoning); an instrument showing two to three candidate scales next to
75
- today's baseline and the MUI default, on real screens (hram Research, a survey site, the jg-ferien dashboard,
76
- a kerzenziehen admin view), at 375 px and 1280 px; value rounds; a frozen sheet with provenance and the
77
- rejected candidates.
78
-
79
- Non-goals:
80
- - No code, no tests (the implementation is a separate order).
81
- - No change to font families. Apps keep their identity fonts.
82
- - No per-app decisions. App overrides that exist only to escape the compressed scale (survey_app's planned
83
- revert, `JG-DL-7`) are reviewed after the freeze, not here.
84
-
85
- ## Tier · precondition / gate
86
-
87
- - **Tier 2 · tests: none (document only).** It decides future shared-core content but changes none.
88
- - Precondition: none.
89
- - Gate: **the operator freezes the sheet**, with a dated section in it.
90
-
91
- ## Risks
92
-
93
- - **Every adopted app moves with the baseline.** A new scale changes the look of ten-plus apps at once; the
94
- instrument has to show the dense tool screens, not only reading screens.
95
- - **Bigger steps cost vertical space** on dense screens (hram, cockpit). The candidates must be judged
96
- there, not only on the survey sites.
97
- - **Weight and size interact.** The fix may be partly a weight rule (fewer bold levels), not only sizes.
98
-
99
- ---
100
-
101
- # B. Implementation map
102
-
103
- *Not applicable. This is an Expertenchat document order, authored in-session with the operator.*
104
-
105
- ---
106
-
107
- # C. Orchestrator only, NOT ADDRESSED TO THE IMPLEMENTER
108
-
109
- > **If you are the implementer reading this: STOP.** There is no implementer for this order.
110
-
111
- Register: row -> `done` with the commit of the frozen sheet. Then the implementation order is written.