@micha.bigler/ui-core-micha 3.14.4 → 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.
- package/CHANGELOG.md +25 -0
- package/README.md +7 -0
- package/dist/chat/kitSxRegistry.js +9 -0
- package/dist/components/charts/kitSxRegistry.js +6 -0
- package/dist/entries/charts.js +6 -0
- package/dist/entries/chat.js +8 -0
- package/dist/entries/markdown.js +1 -0
- package/dist/index.js +0 -14
- package/dist/pages/AccountPage.js +1 -2
- package/dist/pages/LoginPage.js +1 -2
- package/dist/pages/PasswordChangePage.js +1 -2
- package/dist/pages/PasswordInvitePage.js +1 -2
- package/dist/pages/PasswordResetRequestPage.js +1 -2
- package/dist/pages/SignUpPage.js +1 -2
- package/dist/pages/SignupConfirmPage.js +1 -2
- package/dist/theme/kitSxEntry.js +11 -0
- package/dist/theme/kitSxRegistry.js +2 -15
- package/package.json +32 -7
- package/.github/workflows/ci.yml +0 -35
- package/.github/workflows/publish.yml +0 -126
- package/DESIGN.md +0 -60
- package/WORK_ORDERS.md +0 -150
- package/dev/entries.jsx +0 -721
- package/dev/fixtures.js +0 -26
- package/dev/main.jsx +0 -75
- package/dev/mockTransport.jsx +0 -128
- package/docs/CHART-LAYOUT.md +0 -157
- package/docs/DARK-TOKENS.md +0 -140
- package/docs/TYPE-SCALE.md +0 -111
- package/docs/messaging-deviations.md +0 -118
- package/index.html +0 -12
- package/renovate.json +0 -10
- package/scripts/chart-api-census.mjs +0 -415
- package/src/auth/AuthContext.jsx +0 -158
- package/src/auth/ReauthModal.jsx +0 -82
- package/src/auth/UserMenu.jsx +0 -121
- package/src/auth/apiClient.jsx +0 -232
- package/src/auth/authApi.jsx +0 -539
- package/src/auth/authConfig.jsx +0 -34
- package/src/auth/reauth.js +0 -47
- package/src/chat/ChatComposer.jsx +0 -36
- package/src/chat/ChatList.jsx +0 -87
- package/src/chat/ChatThread.jsx +0 -128
- package/src/chat/ChatWorkspace.jsx +0 -244
- package/src/chat/MarkdownReply.jsx +0 -22
- package/src/chat/ModelPicker.jsx +0 -85
- package/src/chat/api.js +0 -18
- package/src/chat/useChatSocket.js +0 -32
- package/src/chat/wire.js +0 -7
- package/src/components/AccessCodeManager.jsx +0 -288
- package/src/components/AccessCodeSingleUseToggle.jsx +0 -92
- package/src/components/AllowedEmailDomainsManager.jsx +0 -92
- package/src/components/AuthFactorRequirementCard.jsx +0 -95
- package/src/components/BulkInviteCsvTab.jsx +0 -198
- package/src/components/EmptyState.jsx +0 -38
- package/src/components/LoginForm.jsx +0 -159
- package/src/components/MFAComponent.jsx +0 -350
- package/src/components/MfaLoginComponent.jsx +0 -252
- package/src/components/MobileBottomNav.jsx +0 -82
- package/src/components/PasskeysComponent.jsx +0 -252
- package/src/components/PasswordChangeForm.jsx +0 -87
- package/src/components/PasswordResetRequestForm.jsx +0 -43
- package/src/components/PasswordSetForm.jsx +0 -97
- package/src/components/ProfileComponent.jsx +0 -348
- package/src/components/QrSignupManager.jsx +0 -404
- package/src/components/QrSignupValidityManager.jsx +0 -106
- package/src/components/RegistrationMethodsManager.jsx +0 -150
- package/src/components/SecurityComponent.jsx +0 -141
- package/src/components/SocialLoginButtons.jsx +0 -83
- package/src/components/SoftChip.jsx +0 -93
- package/src/components/StatTile.jsx +0 -39
- package/src/components/SupportRecoveryRequestsTab.jsx +0 -482
- package/src/components/TurnstileWidget.jsx +0 -99
- package/src/components/UserInviteComponent.jsx +0 -76
- package/src/components/UserListComponent.jsx +0 -618
- package/src/components/charts/BarChart.jsx +0 -102
- package/src/components/charts/ChartFrame.jsx +0 -214
- package/src/components/charts/LineChart.jsx +0 -126
- package/src/components/charts/ScatterChart.jsx +0 -299
- package/src/components/charts/TimeSeriesChart.jsx +0 -300
- package/src/components/charts/chartDefaults.js +0 -644
- package/src/components/charts/chartLabels.js +0 -36
- package/src/components/charts/exportChart.js +0 -258
- package/src/components/charts/formatters.js +0 -39
- package/src/components/charts/palette.js +0 -33
- package/src/components/charts/yearTickInterval.js +0 -7
- package/src/i18n/authTranslations.ts +0 -2651
- package/src/i18n/chartsTranslations.ts +0 -91
- package/src/i18n/chatTranslations.ts +0 -55
- package/src/i18n/messagingTranslations.ts +0 -120
- package/src/i18n/notificationsTranslations.ts +0 -32
- package/src/i18n/onboardingTranslations.ts +0 -29
- package/src/i18n/sectionNavTranslations.ts +0 -20
- package/src/i18n/uiCoreTranslations.js +0 -29
- package/src/i18n/userMenuTranslations.ts +0 -5
- package/src/index.js +0 -158
- package/src/layout/PageLayout.jsx +0 -36
- package/src/layout/SectionNav.jsx +0 -320
- package/src/messaging/AttachmentList.jsx +0 -145
- package/src/messaging/Composer.jsx +0 -197
- package/src/messaging/ConversationLaunchers.jsx +0 -51
- package/src/messaging/ConversationList.jsx +0 -109
- package/src/messaging/DirectMessageLauncher.jsx +0 -112
- package/src/messaging/MessageBubble.jsx +0 -183
- package/src/messaging/MessagingProvider.jsx +0 -0
- package/src/messaging/MessagingScopeConfig.jsx +0 -24
- package/src/messaging/PollCard.jsx +0 -163
- package/src/messaging/ReactionBar.jsx +0 -43
- package/src/messaging/ReadTicks.jsx +0 -82
- package/src/messaging/Thread.jsx +0 -195
- package/src/messaging/api.js +0 -48
- package/src/messaging/composerImageCompression.js +0 -35
- package/src/messaging/linkifyText.jsx +0 -37
- package/src/notifications/NotificationBell.jsx +0 -84
- package/src/notifications/NotificationSettings.jsx +0 -330
- package/src/notifications/NotificationsProvider.jsx +0 -224
- package/src/notifications/PopupSurface.jsx +0 -105
- package/src/notifications/api.js +0 -55
- package/src/notifications/feedApi.js +0 -18
- package/src/notifications/realtime.jsx +0 -138
- package/src/notifications/serviceWorker/sw.js +0 -50
- package/src/onboarding/OnboardingProvider.jsx +0 -326
- package/src/onboarding/OnboardingWizard.jsx +0 -61
- package/src/onboarding/WizardDialogShell.jsx +0 -51
- package/src/onboarding/api.js +0 -13
- package/src/onboarding/stepSelection.js +0 -16
- package/src/onboarding/steps/BrowserPushStep.jsx +0 -121
- package/src/onboarding/steps/CompleteNameStep.jsx +0 -46
- package/src/onboarding/steps/CookieConsentStep.jsx +0 -133
- package/src/onboarding/steps/PwaInstallStep.jsx +0 -47
- package/src/pages/AccountPage.jsx +0 -394
- package/src/pages/LoginPage.jsx +0 -343
- package/src/pages/PasswordChangePage.jsx +0 -62
- package/src/pages/PasswordInvitePage.jsx +0 -177
- package/src/pages/PasswordResetRequestPage.jsx +0 -68
- package/src/pages/SignUpPage.jsx +0 -268
- package/src/pages/SignupConfirmPage.jsx +0 -155
- package/src/testing/checkKitIntegration.js +0 -233
- package/src/theme/createAppTheme.js +0 -423
- package/src/theme/fonts.js +0 -3
- package/src/theme/index.js +0 -21
- package/src/theme/kitSxRegistry.js +0 -285
- package/src/theme/themeCompleteness.js +0 -1045
- package/src/theme/tokens.js +0 -478
- package/src/utils/auth-errors.js +0 -76
- package/src/utils/authService.js +0 -223
- package/src/utils/resolveErrorText.js +0 -28
- package/src/utils/webauthn.js +0 -51
- package/tests/AccountPage.profileStatements.test.jsx +0 -162
- package/tests/AccountPage.test.jsx +0 -200
- package/tests/AuthContext.test.jsx +0 -129
- package/tests/BarChart.test.jsx +0 -112
- package/tests/BrowserPushStep.test.jsx +0 -110
- package/tests/ChartFrame.test.jsx +0 -336
- package/tests/ConversationList.test.jsx +0 -144
- package/tests/CookieConsentStep.test.jsx +0 -69
- package/tests/EmptyState.test.jsx +0 -62
- package/tests/LineChart.test.jsx +0 -80
- package/tests/MessagingProvider.test.jsx +0 -50
- package/tests/MobileBottomNav.test.jsx +0 -319
- package/tests/NotificationBell.test.jsx +0 -60
- package/tests/NotificationSettings.test.jsx +0 -276
- package/tests/NotificationsProvider.test.jsx +0 -240
- package/tests/OnboardingProvider.test.jsx +0 -294
- package/tests/OnboardingWizard.test.jsx +0 -143
- package/tests/PasswordChangeForm.test.jsx +0 -70
- package/tests/PasswordInvitePage.test.jsx +0 -142
- package/tests/PasswordSetForm.test.jsx +0 -70
- package/tests/PopupSurface.test.jsx +0 -142
- package/tests/ProfileComponent.refresh.test.jsx +0 -194
- package/tests/QrSignupManager.registrationContext.test.jsx +0 -106
- package/tests/QrSignupManagerInfoBox.test.jsx +0 -49
- package/tests/ScatterChart.test.jsx +0 -270
- package/tests/SectionNav.test.jsx +0 -363
- package/tests/SignUpPage.test.jsx +0 -208
- package/tests/SoftChip.test.jsx +0 -105
- package/tests/StatTile.test.jsx +0 -57
- package/tests/Thread.test.jsx +0 -151
- package/tests/TimeSeriesChart.test.jsx +0 -367
- package/tests/UserListComponent.test.jsx +0 -192
- package/tests/UserMenu.test.jsx +0 -171
- package/tests/apiClientLanguage.test.js +0 -33
- package/tests/apiClientPublicPaths.test.js +0 -178
- package/tests/authApiLogin.test.js +0 -42
- package/tests/authApiRegistration.test.js +0 -31
- package/tests/authErrorCodeRendering.test.jsx +0 -77
- package/tests/authErrors.test.js +0 -74
- package/tests/authTranslations.test.js +0 -74
- package/tests/chart-api-census.test.js +0 -366
- package/tests/chartAxisTickBand.test.jsx +0 -95
- package/tests/chartDefaults.test.js +0 -902
- package/tests/chartLabels.test.js +0 -50
- package/tests/chartsPalette.test.js +0 -99
- package/tests/chatApi.test.js +0 -48
- package/tests/chatDriverNames.test.jsx +0 -71
- package/tests/chatExports.test.js +0 -3
- package/tests/chatList.test.jsx +0 -84
- package/tests/chatPicker.test.jsx +0 -82
- package/tests/chatSocket.test.jsx +0 -26
- package/tests/chatThread.test.jsx +0 -116
- package/tests/chatTranslations.test.js +0 -47
- package/tests/chatWorkspace.test.jsx +0 -234
- package/tests/checkKitIntegration.test.jsx +0 -219
- package/tests/createAppTheme.test.js +0 -132
- package/tests/createAppThemeDark.test.js +0 -127
- package/tests/createAppThemeLightGuard.test.js +0 -40
- package/tests/createAppThemePageContrast.test.js +0 -108
- package/tests/createAppThemeTypography.test.js +0 -53
- package/tests/errorCallSiteGuard.test.js +0 -32
- package/tests/exportChart.test.js +0 -313
- package/tests/feedApi.test.js +0 -46
- package/tests/fixtures/light-theme-baseline.json +0 -2234
- package/tests/i18nAggregate.test.js +0 -120
- package/tests/i18nGermanVariant.test.js +0 -65
- package/tests/loginPageErrorResolution.test.jsx +0 -102
- package/tests/messagingApi.test.js +0 -32
- package/tests/messagingChunk6.test.jsx +0 -116
- package/tests/messagingCompactBubble.test.jsx +0 -64
- package/tests/messagingComposer.test.jsx +0 -136
- package/tests/messagingComposerChunk5.test.jsx +0 -113
- package/tests/messagingContractConformance.test.js +0 -69
- package/tests/messagingDirectMessageLauncher.test.jsx +0 -151
- package/tests/messagingExports.test.js +0 -21
- package/tests/messagingInteractions.test.jsx +0 -136
- package/tests/messagingLastMessagePreview.test.jsx +0 -93
- package/tests/messagingLinkify.test.jsx +0 -51
- package/tests/messagingMessageActions.test.jsx +0 -163
- package/tests/messagingMsg6.test.jsx +0 -105
- package/tests/messagingMsg6f.test.jsx +0 -155
- package/tests/messagingMsg6g.test.jsx +0 -166
- package/tests/messagingMsg6h.test.jsx +0 -136
- package/tests/messagingMsg6i.test.jsx +0 -129
- package/tests/messagingPollRendering.test.jsx +0 -142
- package/tests/messagingReactionMerge.test.jsx +0 -77
- package/tests/messagingReadTicksTooltip.test.jsx +0 -36
- package/tests/messagingThreadReceipts.test.jsx +0 -178
- package/tests/messagingThreadingQuoting.test.jsx +0 -87
- package/tests/messagingUnreadLifecycle.test.jsx +0 -78
- package/tests/notificationsApi.test.js +0 -41
- package/tests/notificationsExports.test.js +0 -34
- package/tests/onboardingDescriptors.test.js +0 -132
- package/tests/packageTreeShaking.test.js +0 -126
- package/tests/realtime.test.jsx +0 -219
- package/tests/resolveErrorText.test.js +0 -72
- package/tests/stepSelection.test.js +0 -53
- package/tests/themeCompleteness.test.js +0 -626
- package/tests/timeSeriesLegend.test.js +0 -99
- package/tests/userScreenTranslations.test.jsx +0 -218
- package/tsconfig.build.json +0 -18
- package/vite.config.mjs +0 -6
- package/work-orders/AUTH-1.md +0 -74
- package/work-orders/AUTH-2.md +0 -74
- package/work-orders/AUTH-4.md +0 -183
- package/work-orders/AUTH-5.md +0 -154
- package/work-orders/AUTH-7.md +0 -181
- package/work-orders/AUTH-8.md +0 -184
- package/work-orders/CHART-1.md +0 -285
- package/work-orders/CHART-2.md +0 -222
- package/work-orders/CHART-3.md +0 -163
- package/work-orders/CHART-4.md +0 -203
- package/work-orders/CHART-5.md +0 -226
- package/work-orders/CHART-6.md +0 -428
- package/work-orders/CHART-7.md +0 -175
- package/work-orders/DX-1.md +0 -169
- package/work-orders/DX-2.md +0 -188
- package/work-orders/DX-3.md +0 -195
- package/work-orders/I18N-1.md +0 -254
- package/work-orders/I18N-3.md +0 -207
- package/work-orders/MSG-3.md +0 -375
- package/work-orders/MSG-3b.md +0 -1002
- package/work-orders/MSG-3c.md +0 -378
- package/work-orders/MSG-3d.md +0 -268
- package/work-orders/MSG-3e.md +0 -164
- package/work-orders/MSG-3f.md +0 -391
- package/work-orders/MSG-6e.md +0 -308
- package/work-orders/MSG-6f.md +0 -214
- package/work-orders/MSG-6g.md +0 -244
- package/work-orders/MSG-6h.md +0 -238
- package/work-orders/MSG-6i.md +0 -271
- package/work-orders/MSG-6j.md +0 -117
- package/work-orders/NOTIF-12.md +0 -214
- package/work-orders/NOTIF-13.md +0 -142
- package/work-orders/NOTIF-14.md +0 -151
- package/work-orders/PRIM-1.md +0 -177
- package/work-orders/SHELL-1.md +0 -255
- package/work-orders/SHELL-2.md +0 -197
- package/work-orders/SHELL-3.md +0 -359
- package/work-orders/SHELL-4.md +0 -351
- package/work-orders/SHELL-5.md +0 -345
- package/work-orders/SHELL-6.md +0 -210
- package/work-orders/THEME-1.md +0 -587
- package/work-orders/THEME-10.md +0 -303
- package/work-orders/THEME-11.md +0 -208
- package/work-orders/THEME-2.md +0 -339
- package/work-orders/THEME-3.md +0 -210
- package/work-orders/THEME-4.md +0 -271
- package/work-orders/THEME-5.md +0 -341
- package/work-orders/THEME-6.md +0 -247
- package/work-orders/THEME-7.md +0 -82
- package/work-orders/THEME-8.md +0 -211
- package/work-orders/THEME-9.md +0 -194
- package/work-orders/UCM-AUTH-10.md +0 -490
- package/work-orders/UCM-AUTH-11.md +0 -185
- package/work-orders/UCM-AUTH-12.md +0 -98
- package/work-orders/UCM-AUTH-13.md +0 -47
- package/work-orders/UCM-AUTH-9.md +0 -207
- package/work-orders/UCM-CHART-10.md +0 -150
- package/work-orders/UCM-CHART-11.md +0 -132
- package/work-orders/UCM-CHART-12.md +0 -348
- package/work-orders/UCM-CHART-13.md +0 -122
- package/work-orders/UCM-CHART-14.md +0 -198
- package/work-orders/UCM-CHART-15.md +0 -187
- package/work-orders/UCM-CHART-16.md +0 -169
- package/work-orders/UCM-CHART-17.md +0 -195
- package/work-orders/UCM-CHART-18.md +0 -200
- package/work-orders/UCM-CHART-8.md +0 -147
- package/work-orders/UCM-CHART-9.md +0 -265
- package/work-orders/UCM-CHAT-1.md +0 -190
- package/work-orders/UCM-CHAT-2.md +0 -75
- package/work-orders/UCM-CI-1.md +0 -65
- package/work-orders/UCM-DEP-1.md +0 -63
- package/work-orders/UCM-I18N-4.md +0 -226
- package/work-orders/UCM-I18N-5.md +0 -211
- package/work-orders/UCM-MSG-20.md +0 -192
- package/work-orders/UCM-PRIM-2.md +0 -114
- package/work-orders/UCM-SHELL-7.md +0 -134
- package/work-orders/UCM-SHELL-8.md +0 -125
- package/work-orders/UCM-TEST-1.md +0 -304
- package/work-orders/UCM-THEME-13.md +0 -69
- package/work-orders/UCM-THEME-14.md +0 -312
- package/work-orders/UCM-THEME-15.md +0 -356
- package/work-orders/UCM-THEME-16.md +0 -80
- package/work-orders/UCM-THEME-17.md +0 -111
- package/work-orders/UCM-THEME-18.md +0 -184
- package/work-orders/assets/AUTH-4-user-list-card.html +0 -407
- package/work-orders/assets/PRIM-1-dashboard-primitives.html +0 -624
- package/work-orders/assets/SHELL-2-account-navigation.html +0 -1159
- package/work-orders/assets/THEME-1-baseline-reference-sheet.html +0 -1352
- package/work-orders/assets/UCM-CHAT-1-ai-chat.html +0 -447
- package/work-orders/assets/UCM-THEME-13-dark-prototype.html +0 -390
- package/work-orders/assets/UCM-THEME-17-type-scale.html +0 -391
|
@@ -1,624 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
<title>DS-5 — Dashboard primitives: StatTile and SoftChip</title>
|
|
7
|
-
<style>
|
|
8
|
-
/* ------------------------------------------------------------------
|
|
9
|
-
Token values are read from ui-core-micha/src/theme/tokens.js, not
|
|
10
|
-
chosen here. Where a value is derived (SoftChip's tints and text),
|
|
11
|
-
the derivation is stated next to it.
|
|
12
|
-
------------------------------------------------------------------ */
|
|
13
|
-
:root {
|
|
14
|
-
/* text */
|
|
15
|
-
--text-primary: #212529;
|
|
16
|
-
--text-secondary: #5B6670;
|
|
17
|
-
--text-disabled: #6A7178;
|
|
18
|
-
/* surfaces */
|
|
19
|
-
--bg-default: #FAFAFA;
|
|
20
|
-
--bg-paper: #FFFFFF;
|
|
21
|
-
--bg-subtle: #F4F5F6;
|
|
22
|
-
--divider: rgba(33,37,41,.10);
|
|
23
|
-
/* shape */
|
|
24
|
-
--radius-base: 3px; /* shape.borderRadius */
|
|
25
|
-
--radius-card: 8px; /* radius.card */
|
|
26
|
-
/* the four semantic tones: main as authored, dark = darken(main, .3) */
|
|
27
|
-
--success-main: #1B8038; --success-dark: #135A27;
|
|
28
|
-
--warning-main: #976100; --warning-dark: #6A4400;
|
|
29
|
-
--error-main: #BF3227; --error-dark: #86231B;
|
|
30
|
-
--info-main: #01579B; --info-dark: #013D6D;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
* { box-sizing: border-box; }
|
|
34
|
-
body {
|
|
35
|
-
margin: 0;
|
|
36
|
-
padding: 32px 24px 64px;
|
|
37
|
-
background: var(--bg-default);
|
|
38
|
-
color: var(--text-primary);
|
|
39
|
-
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
40
|
-
font-size: 14px; line-height: 1.55; /* body1 */
|
|
41
|
-
}
|
|
42
|
-
.wrap { max-width: 1180px; margin: 0 auto; }
|
|
43
|
-
|
|
44
|
-
h1 { font-size: 32px; font-weight: 600; line-height: 1.2; margin: 0 0 8px; }
|
|
45
|
-
h2 { font-size: 20px; font-weight: 600; line-height: 1.3; margin: 44px 0 4px; }
|
|
46
|
-
h3 { font-size: 15px; font-weight: 600; line-height: 1.4; margin: 26px 0 10px; }
|
|
47
|
-
.lede { color: var(--text-secondary); max-width: 74ch; margin: 0 0 4px; }
|
|
48
|
-
.note {
|
|
49
|
-
color: var(--text-secondary); font-size: 13px; line-height: 1.55;
|
|
50
|
-
max-width: 78ch; margin: 8px 0 0;
|
|
51
|
-
}
|
|
52
|
-
code {
|
|
53
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
54
|
-
font-size: .92em; background: var(--bg-subtle);
|
|
55
|
-
padding: 1px 5px; border-radius: var(--radius-base);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.panel {
|
|
59
|
-
background: var(--bg-paper); border: 1px solid var(--divider);
|
|
60
|
-
border-radius: var(--radius-card); padding: 20px; margin-top: 14px;
|
|
61
|
-
}
|
|
62
|
-
.panel--flush { padding: 0; overflow: hidden; }
|
|
63
|
-
|
|
64
|
-
/* ============ StatTile — the actual component, faithfully ============
|
|
65
|
-
border 1px divider · radius 1 (=3px) · px 1.5 (12px) · py 1 (8px)
|
|
66
|
-
minWidth 120 · label caption 12/400 secondary · value h6 16/600
|
|
67
|
-
tabular-nums · caption 12/400 secondary */
|
|
68
|
-
.stat-row { display: flex; flex-wrap: wrap; gap: 12px; }
|
|
69
|
-
.stat-tile {
|
|
70
|
-
flex: 1 1 auto; /* decided: flex with a minWidth floor */
|
|
71
|
-
border: 1px solid var(--divider);
|
|
72
|
-
border-radius: var(--radius-base);
|
|
73
|
-
padding: 8px; /* decided: responsive, xs */
|
|
74
|
-
min-width: 120px;
|
|
75
|
-
background: var(--bg-paper);
|
|
76
|
-
}
|
|
77
|
-
@media (min-width: 600px) { .stat-tile { padding: 12px; } } /* sm and up */
|
|
78
|
-
.stat-tile--accent { border-width: 2px; border-color: #1F6FA8; } /* decided: accent kept */
|
|
79
|
-
.stat-tile__label,
|
|
80
|
-
.stat-tile__caption {
|
|
81
|
-
display: block;
|
|
82
|
-
font-size: 12px; font-weight: 400; line-height: 1.4;
|
|
83
|
-
color: var(--text-secondary);
|
|
84
|
-
}
|
|
85
|
-
.stat-tile__value { /* decided: h5 18/600, tabular-nums */
|
|
86
|
-
font-size: 18px; font-weight: 600; line-height: 1.3;
|
|
87
|
-
font-variant-numeric: tabular-nums;
|
|
88
|
-
color: var(--text-primary);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/* ============ SoftChip — as it exists today ============
|
|
92
|
-
dot 6px in tone.dark · bg alpha(main,.12) · border alpha(main,.30)
|
|
93
|
-
text tone.dark · caveat radius 3px 12/500 · status pill 11/600 */
|
|
94
|
-
.chip-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
|
|
95
|
-
.chip {
|
|
96
|
-
display: inline-flex; align-items: center; gap: 6px;
|
|
97
|
-
padding: 4px 8px;
|
|
98
|
-
border: 1px solid; border-radius: var(--radius-base);
|
|
99
|
-
font-size: 12px; font-weight: 500; line-height: 1.4;
|
|
100
|
-
white-space: nowrap;
|
|
101
|
-
}
|
|
102
|
-
/* decided: status uses the baseline's `overline` — 11/600, uppercase, .4px tracking */
|
|
103
|
-
.chip--status {
|
|
104
|
-
border-radius: 999px; font-size: 11px; font-weight: 600;
|
|
105
|
-
text-transform: uppercase; letter-spacing: .4px;
|
|
106
|
-
}
|
|
107
|
-
.chip--borderless { border-color: transparent; }
|
|
108
|
-
.chip__dot { width: 6px; height: 6px; border-radius: 50%; flex: none; }
|
|
109
|
-
|
|
110
|
-
.t-success { background: rgba(27,128,56,.12); border-color: rgba(27,128,56,.30); color: var(--success-dark); }
|
|
111
|
-
.t-warning { background: rgba(151,97,0,.12); border-color: rgba(151,97,0,.30); color: var(--warning-dark); }
|
|
112
|
-
.t-error { background: rgba(191,50,39,.12); border-color: rgba(191,50,39,.30); color: var(--error-dark); }
|
|
113
|
-
.t-info { background: rgba(1,87,155,.12); border-color: rgba(1,87,155,.30); color: var(--info-dark); }
|
|
114
|
-
.t-success .chip__dot { background: var(--success-dark); }
|
|
115
|
-
.t-warning .chip__dot { background: var(--warning-dark); }
|
|
116
|
-
.t-error .chip__dot { background: var(--error-dark); }
|
|
117
|
-
.t-info .chip__dot { background: var(--info-dark); }
|
|
118
|
-
|
|
119
|
-
/* measurement table */
|
|
120
|
-
table { border-collapse: collapse; width: 100%; font-size: 13px; }
|
|
121
|
-
th, td { padding: 10px 16px; text-align: left; border-bottom: 1px solid var(--divider); }
|
|
122
|
-
th {
|
|
123
|
-
font-size: 11px; font-weight: 600; line-height: 1.4;
|
|
124
|
-
text-transform: uppercase; letter-spacing: .4px;
|
|
125
|
-
color: var(--text-secondary); background: var(--bg-subtle);
|
|
126
|
-
}
|
|
127
|
-
tbody tr:last-child td { border-bottom: 0; }
|
|
128
|
-
td.num { font-variant-numeric: tabular-nums; }
|
|
129
|
-
.verdict { font-weight: 600; }
|
|
130
|
-
.pass { color: var(--success-dark); }
|
|
131
|
-
.fail { color: var(--error-dark); }
|
|
132
|
-
|
|
133
|
-
/* the two-width frames */
|
|
134
|
-
.frames { display: flex; gap: 24px; align-items: flex-start; flex-wrap: wrap; margin-top: 14px; }
|
|
135
|
-
.frame { border: 1px solid var(--divider); border-radius: var(--radius-card); background: var(--bg-paper); overflow: hidden; }
|
|
136
|
-
.frame__bar {
|
|
137
|
-
font-size: 11px; font-weight: 600; letter-spacing: .4px; text-transform: uppercase;
|
|
138
|
-
color: var(--text-secondary); background: var(--bg-subtle);
|
|
139
|
-
padding: 8px 12px; border-bottom: 1px solid var(--divider);
|
|
140
|
-
}
|
|
141
|
-
.frame__body { padding: 16px; }
|
|
142
|
-
.frame--mobile { width: 375px; }
|
|
143
|
-
.frame--mobile .frame__body { width: 375px; }
|
|
144
|
-
.frame--desktop { flex: 1 1 620px; min-width: 320px; }
|
|
145
|
-
|
|
146
|
-
/* the THEME-4 comparison */
|
|
147
|
-
.cmp { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; margin-top: 12px; }
|
|
148
|
-
.cmp__cell { border: 1px solid var(--divider); border-radius: var(--radius-base); padding: 14px; background: var(--bg-paper); }
|
|
149
|
-
.cmp__head { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .4px; color: var(--text-secondary); margin-bottom: 10px; }
|
|
150
|
-
.spec { font-size: 12px; color: var(--text-secondary); margin-top: 8px; font-variant-numeric: tabular-nums; }
|
|
151
|
-
|
|
152
|
-
.flag {
|
|
153
|
-
border-left: 3px solid var(--warning-main);
|
|
154
|
-
background: rgba(151,97,0,.06);
|
|
155
|
-
padding: 12px 16px; margin-top: 14px;
|
|
156
|
-
border-radius: 0 var(--radius-base) var(--radius-base) 0;
|
|
157
|
-
}
|
|
158
|
-
.flag strong { color: var(--warning-dark); }
|
|
159
|
-
</style>
|
|
160
|
-
</head>
|
|
161
|
-
<body>
|
|
162
|
-
<div class="wrap">
|
|
163
|
-
|
|
164
|
-
<h1>Dashboard primitives</h1>
|
|
165
|
-
<p class="lede">
|
|
166
|
-
<code>StatTile</code> and <code>SoftChip</code> drawn at the shared baseline's own token values.
|
|
167
|
-
A decision artifact for <code>DS-5</code> / <code>PRIM-1</code>, not an approved spec. <strong>Each component already
|
|
168
|
-
exists twice</strong> — hram as a file, and a second build inline inside a page in
|
|
169
|
-
<strong>fitness-monitor</strong> (<code>StatTile</code>) and <strong>cockpit</strong>
|
|
170
|
-
(<code>SoftChip</code>). The promotion trigger is met on evidence, and the
|
|
171
|
-
<a href="#divergences" style="color:var(--info-dark)">seven divergences between the two builds</a>
|
|
172
|
-
were <a href="#decided" style="color:var(--info-dark)">decided on 2026-08-12</a> — everything drawn
|
|
173
|
-
here is the promoted spec.
|
|
174
|
-
</p>
|
|
175
|
-
<p class="note">
|
|
176
|
-
Every colour, size and radius below is read from <code>ui-core-micha/src/theme/tokens.js</code>.
|
|
177
|
-
The chip tints are derived the way the component derives them — <code>alpha(main, .12)</code> fill,
|
|
178
|
-
<code>alpha(main, .30)</code> border, <code>darken(main, .3)</code> text and dot — so nothing here
|
|
179
|
-
is a hand-picked hex. Contrast ratios are computed in the page against the <em>blended</em>
|
|
180
|
-
background, because a ratio taken against the raw <code>rgba()</code> would be meaningless.
|
|
181
|
-
</p>
|
|
182
|
-
|
|
183
|
-
<!-- ================= StatTile ================= -->
|
|
184
|
-
<h2>StatTile — the KPI tile</h2>
|
|
185
|
-
<p class="lede">
|
|
186
|
-
A small bordered card: muted label, one bold tabular number, optional caption. Two call sites in
|
|
187
|
-
hram today — the Calibration KPI row and the Allocation rail.
|
|
188
|
-
</p>
|
|
189
|
-
|
|
190
|
-
<div class="frames">
|
|
191
|
-
<div class="frame frame--desktop">
|
|
192
|
-
<div class="frame__bar">1280 px — Calibration KPI row (three tiles)</div>
|
|
193
|
-
<div class="frame__body">
|
|
194
|
-
<div class="stat-row">
|
|
195
|
-
<div class="stat-tile">
|
|
196
|
-
<span class="stat-tile__label">theta*</span>
|
|
197
|
-
<div class="stat-tile__value">0.8421</div>
|
|
198
|
-
</div>
|
|
199
|
-
<div class="stat-tile">
|
|
200
|
-
<span class="stat-tile__label">Recovered</span>
|
|
201
|
-
<div class="stat-tile__value">0.8397</div>
|
|
202
|
-
<span class="stat-tile__caption">bias −0.0024</span>
|
|
203
|
-
</div>
|
|
204
|
-
<div class="stat-tile">
|
|
205
|
-
<span class="stat-tile__label">Interval covers theta*</span>
|
|
206
|
-
<div class="stat-tile__value">Yes</div>
|
|
207
|
-
<span class="stat-tile__caption">94.2 % of draws</span>
|
|
208
|
-
</div>
|
|
209
|
-
</div>
|
|
210
|
-
|
|
211
|
-
<h3>Allocation rail (two tiles, with a child slot)</h3>
|
|
212
|
-
<div class="stat-row">
|
|
213
|
-
<div class="stat-tile" style="min-width:180px">
|
|
214
|
-
<span class="stat-tile__label">Coverage at budget</span>
|
|
215
|
-
<div class="stat-tile__value">71.4 %</div>
|
|
216
|
-
<span class="stat-tile__caption">of maximum realizable</span>
|
|
217
|
-
</div>
|
|
218
|
-
<div class="stat-tile" style="min-width:180px">
|
|
219
|
-
<span class="stat-tile__label">Deaths averted</span>
|
|
220
|
-
<div class="stat-tile__value">63.8 %</div>
|
|
221
|
-
<div style="margin-top:6px">
|
|
222
|
-
<span class="chip chip--status t-info"><span class="chip__dot"></span>children slot</span>
|
|
223
|
-
</div>
|
|
224
|
-
</div>
|
|
225
|
-
</div>
|
|
226
|
-
</div>
|
|
227
|
-
</div>
|
|
228
|
-
|
|
229
|
-
<div class="frame frame--mobile">
|
|
230
|
-
<div class="frame__bar">375 px</div>
|
|
231
|
-
<div class="frame__body">
|
|
232
|
-
<div class="stat-row">
|
|
233
|
-
<div class="stat-tile">
|
|
234
|
-
<span class="stat-tile__label">theta*</span>
|
|
235
|
-
<div class="stat-tile__value">0.8421</div>
|
|
236
|
-
</div>
|
|
237
|
-
<div class="stat-tile">
|
|
238
|
-
<span class="stat-tile__label">Recovered</span>
|
|
239
|
-
<div class="stat-tile__value">0.8397</div>
|
|
240
|
-
<span class="stat-tile__caption">bias −0.0024</span>
|
|
241
|
-
</div>
|
|
242
|
-
<div class="stat-tile">
|
|
243
|
-
<span class="stat-tile__label">Interval covers theta*</span>
|
|
244
|
-
<div class="stat-tile__value">Yes</div>
|
|
245
|
-
<span class="stat-tile__caption">94.2 % of draws</span>
|
|
246
|
-
</div>
|
|
247
|
-
</div>
|
|
248
|
-
</div>
|
|
249
|
-
</div>
|
|
250
|
-
</div>
|
|
251
|
-
|
|
252
|
-
<p class="note">
|
|
253
|
-
At 375 px the tiles fill the width and wrap once they hit the 120 px floor — the decided
|
|
254
|
-
<code>flex: 1</code> plus <code>minWidth</code> rule, which is why two fit here where hram's
|
|
255
|
-
original <code>minWidth</code>-only version dropped to one per line.
|
|
256
|
-
</p>
|
|
257
|
-
|
|
258
|
-
<div class="flag">
|
|
259
|
-
<strong>StatTile passes <code>THEME-4</code> as written.</strong> It references tokens throughout —
|
|
260
|
-
<code>variant="caption"</code>, <code>variant="h5"</code>, <code>text.secondary</code>,
|
|
261
|
-
<code>divider</code> — and its only raw numbers are theme-relative multipliers
|
|
262
|
-
(<code>borderRadius: 1</code>, the spacing steps), not literals. What it lacks is a test:
|
|
263
|
-
<strong>neither build has one</strong>, in either app, and tests are part of promotion.
|
|
264
|
-
</div>
|
|
265
|
-
|
|
266
|
-
<!-- ================= SoftChip ================= -->
|
|
267
|
-
<h2>SoftChip — the annotation chip</h2>
|
|
268
|
-
<p class="lede">
|
|
269
|
-
Soft tinted chips that read as annotation rather than alarm. Two variants, four tones, a 6 px
|
|
270
|
-
leading dot. Replaced loud saturated fills — a bright-orange pill and a full-width green banner.
|
|
271
|
-
</p>
|
|
272
|
-
|
|
273
|
-
<div class="panel">
|
|
274
|
-
<h3 style="margin-top:0">caveat — radius 3 px, 12/500</h3>
|
|
275
|
-
<div class="chip-row">
|
|
276
|
-
<span class="chip t-warning"><span class="chip__dot"></span>Provisional ranges</span>
|
|
277
|
-
<span class="chip t-info"><span class="chip__dot"></span>Derived value</span>
|
|
278
|
-
<span class="chip t-error"><span class="chip__dot"></span>Outside calibrated range</span>
|
|
279
|
-
<span class="chip t-success"><span class="chip__dot"></span>Within tolerance</span>
|
|
280
|
-
</div>
|
|
281
|
-
|
|
282
|
-
<h3>status — pill radius, 11/600</h3>
|
|
283
|
-
<div class="chip-row">
|
|
284
|
-
<span class="chip chip--status t-success"><span class="chip__dot"></span>passed</span>
|
|
285
|
-
<span class="chip chip--status t-warning"><span class="chip__dot"></span>degraded</span>
|
|
286
|
-
<span class="chip chip--status t-error"><span class="chip__dot"></span>failed</span>
|
|
287
|
-
<span class="chip chip--status t-info"><span class="chip__dot"></span>queued</span>
|
|
288
|
-
</div>
|
|
289
|
-
|
|
290
|
-
<h3>In place — a card header, where the chip actually sits</h3>
|
|
291
|
-
<div style="border:1px solid var(--divider);border-radius:var(--radius-card);padding:16px;max-width:520px">
|
|
292
|
-
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:16px">
|
|
293
|
-
<div>
|
|
294
|
-
<div style="font-size:15px;font-weight:600;line-height:1.4">Sensitivity analysis</div>
|
|
295
|
-
<div style="font-size:12px;color:var(--text-secondary)">Tornado over 14 parameters</div>
|
|
296
|
-
</div>
|
|
297
|
-
<span class="chip t-warning"><span class="chip__dot"></span>Provisional ranges</span>
|
|
298
|
-
</div>
|
|
299
|
-
</div>
|
|
300
|
-
</div>
|
|
301
|
-
|
|
302
|
-
<h3>Computed contrast — text on the blended fill, not on the raw rgba</h3>
|
|
303
|
-
<div class="panel panel--flush">
|
|
304
|
-
<table id="contrast">
|
|
305
|
-
<thead>
|
|
306
|
-
<tr>
|
|
307
|
-
<th>Tone</th><th>main</th><th>text = darken(main,.3)</th>
|
|
308
|
-
<th>effective fill over paper</th><th>ratio</th><th>WCAG AA (4.5)</th>
|
|
309
|
-
</tr>
|
|
310
|
-
</thead>
|
|
311
|
-
<tbody></tbody>
|
|
312
|
-
</table>
|
|
313
|
-
</div>
|
|
314
|
-
<p class="note">
|
|
315
|
-
The fill is <code>alpha(main, .12)</code> over <code>background.paper</code>, so the real
|
|
316
|
-
background is a blend. <code>getContrastRatio</code> ignores alpha and would return the ratio
|
|
317
|
-
against white — which is close here but is the wrong number for the wrong reason. These are
|
|
318
|
-
computed from the blend.
|
|
319
|
-
</p>
|
|
320
|
-
|
|
321
|
-
<!-- ================= the THEME-4 problem ================= -->
|
|
322
|
-
<h2>The typography problem, and how it was resolved</h2>
|
|
323
|
-
<p class="lede">
|
|
324
|
-
SoftChip set typography as raw numbers, which is exactly what <code>THEME-4</code>'s shadowing check
|
|
325
|
-
forbids in a kit component. The four cells below are the options as they stood; the
|
|
326
|
-
<em>status</em> variant now uses <code>overline</code>, and <em>caveat</em> is deliberately left
|
|
327
|
-
unresolved (see the end of this page).
|
|
328
|
-
</p>
|
|
329
|
-
|
|
330
|
-
<div class="cmp">
|
|
331
|
-
<div class="cmp__cell">
|
|
332
|
-
<div class="cmp__head">status, as hram authored it</div>
|
|
333
|
-
<span class="chip chip--status t-success" style="text-transform:none;letter-spacing:normal">
|
|
334
|
-
<span class="chip__dot"></span>passed
|
|
335
|
-
</span>
|
|
336
|
-
<div class="spec">raw <code>fontSize: 11</code>, <code>fontWeight: 600</code> — no variant</div>
|
|
337
|
-
</div>
|
|
338
|
-
<div class="cmp__cell" style="border-color:var(--success-main)">
|
|
339
|
-
<div class="cmp__head"><code>overline</code> — chosen</div>
|
|
340
|
-
<span class="chip chip--status t-success"><span class="chip__dot"></span>passed</span>
|
|
341
|
-
<div class="spec">11/600 — identical metrics, <strong>plus uppercase + .4 px tracking</strong></div>
|
|
342
|
-
</div>
|
|
343
|
-
<div class="cmp__cell">
|
|
344
|
-
<div class="cmp__head">caveat, as authored</div>
|
|
345
|
-
<span class="chip t-warning"><span class="chip__dot"></span>Provisional ranges</span>
|
|
346
|
-
<div class="spec">raw <code>fontSize: 12</code>, <code>fontWeight: 500</code></div>
|
|
347
|
-
</div>
|
|
348
|
-
<div class="cmp__cell">
|
|
349
|
-
<div class="cmp__head">baseline <code>caption</code></div>
|
|
350
|
-
<span class="chip t-warning" style="font-weight:400"><span class="chip__dot"></span>Provisional ranges</span>
|
|
351
|
-
<div class="spec">12/<strong>400</strong> — the nearest variant, one weight step lighter</div>
|
|
352
|
-
</div>
|
|
353
|
-
</div>
|
|
354
|
-
|
|
355
|
-
<div class="flag">
|
|
356
|
-
<strong>Two clean ways out, and they are not equivalent.</strong>
|
|
357
|
-
Use <code>overline</code> for <em>status</em> and accept uppercase — which changes how every status
|
|
358
|
-
chip reads, from <span style="white-space:nowrap">“passed”</span> to
|
|
359
|
-
<span style="white-space:nowrap">“PASSED”</span>. Or add one variant to the baseline for chip text
|
|
360
|
-
and let both variants reference it — which is a baseline change, so an app-level decision that does
|
|
361
|
-
not belong inside a component promotion. <em>caveat</em> has the same shape of problem at 12/500
|
|
362
|
-
against <code>caption</code>'s 12/400: visually a hair bolder, but there is no variant for it.
|
|
363
|
-
</div>
|
|
364
|
-
|
|
365
|
-
<!-- ================= the two builds ================= -->
|
|
366
|
-
<h2 id="divergences">Both components exist twice already — and the differences are the decision</h2>
|
|
367
|
-
<p class="lede">
|
|
368
|
-
The second build of each is an <strong>inline component inside a page</strong>, not a file, which is
|
|
369
|
-
why a filename search misses it. The promotion rule is met: two independent builds each, three
|
|
370
|
-
apps consuming.
|
|
371
|
-
</p>
|
|
372
|
-
|
|
373
|
-
<h3>StatTile — hram vs fitness-monitor</h3>
|
|
374
|
-
<div class="frames">
|
|
375
|
-
<div class="frame frame--desktop">
|
|
376
|
-
<div class="frame__bar">hram — <code>ResearchComponents/StatTile.jsx</code></div>
|
|
377
|
-
<div class="frame__body">
|
|
378
|
-
<div class="stat-row">
|
|
379
|
-
<div class="stat-tile" style="flex:0 0 auto">
|
|
380
|
-
<span class="stat-tile__label">Recovered</span>
|
|
381
|
-
<div class="stat-tile__value" style="font-size:16px;line-height:1.35">0.8397</div>
|
|
382
|
-
<span class="stat-tile__caption">bias −0.0024</span>
|
|
383
|
-
</div>
|
|
384
|
-
</div>
|
|
385
|
-
<div class="spec">
|
|
386
|
-
value <code>h6</code> 16/600 · <strong>tabular-nums</strong> · padding 12/8 fixed ·
|
|
387
|
-
<code>minWidth</code> 120 · caption sub-line · <code>children</code> slot
|
|
388
|
-
</div>
|
|
389
|
-
</div>
|
|
390
|
-
</div>
|
|
391
|
-
<div class="frame frame--desktop">
|
|
392
|
-
<div class="frame__bar">fitness-monitor — <code>BodyHistoryPage.jsx:554</code></div>
|
|
393
|
-
<div class="frame__body">
|
|
394
|
-
<div class="stat-row">
|
|
395
|
-
<div class="stat-tile" style="flex:1">
|
|
396
|
-
<span class="stat-tile__label">Body fat</span>
|
|
397
|
-
<div class="stat-tile__value" style="font-size:18px;font-variant-numeric:normal">18.4 %</div>
|
|
398
|
-
</div>
|
|
399
|
-
<div class="stat-tile stat-tile--accent" style="flex:1">
|
|
400
|
-
<span class="stat-tile__label">Lean mass</span>
|
|
401
|
-
<div class="stat-tile__value" style="font-variant-numeric:normal">62.1 kg</div>
|
|
402
|
-
</div>
|
|
403
|
-
</div>
|
|
404
|
-
<div class="spec">
|
|
405
|
-
value <code>h5</code> 18/600 · <strong>no tabular-nums</strong> · padding responsive
|
|
406
|
-
<code>{xs:1, sm:1.5}</code> · <code>flex: 1</code> · <strong><code>accent</code></strong>
|
|
407
|
-
= 2 px <code>primary.main</code> border (right-hand tile)
|
|
408
|
-
</div>
|
|
409
|
-
</div>
|
|
410
|
-
</div>
|
|
411
|
-
</div>
|
|
412
|
-
<p class="note">
|
|
413
|
-
Five decisions fall out of this, and none is arbitrary: <strong>h6 or h5</strong> for the value;
|
|
414
|
-
<strong>tabular-nums</strong> (hram has it, fm does not — for a KPI row it is what makes digits line
|
|
415
|
-
up between tiles, so this one has a right answer); whether <strong><code>accent</code></strong>
|
|
416
|
-
survives as a variant; <strong>fixed or responsive padding</strong>; and
|
|
417
|
-
<strong><code>flex: 1</code> vs <code>minWidth</code></strong>, which is the 375 px wrap behaviour
|
|
418
|
-
above expressed as an API choice.
|
|
419
|
-
</p>
|
|
420
|
-
|
|
421
|
-
<h3>SoftChip — hram vs cockpit</h3>
|
|
422
|
-
<div class="cmp">
|
|
423
|
-
<div class="cmp__cell">
|
|
424
|
-
<div class="cmp__head">hram — <code>SoftChip.jsx</code>, status variant</div>
|
|
425
|
-
<span class="chip chip--status t-success"><span class="chip__dot"></span>passed</span>
|
|
426
|
-
<div class="spec">
|
|
427
|
-
11/<strong>600</strong> · lowercase · 6 px dot · <strong>1 px border</strong> at
|
|
428
|
-
<code>alpha(main,.30)</code> · fill <code>alpha(main,.12)</code> · auto height
|
|
429
|
-
</div>
|
|
430
|
-
</div>
|
|
431
|
-
<div class="cmp__cell">
|
|
432
|
-
<div class="cmp__head">cockpit — <code>BoardView.jsx:65</code>, lane pill</div>
|
|
433
|
-
<span class="chip chip--status t-info"
|
|
434
|
-
style="text-transform:uppercase;letter-spacing:.4px;font-weight:700;border-color:transparent;height:22px;padding:0 9px">
|
|
435
|
-
<span class="chip__dot"></span>recurring 3
|
|
436
|
-
</span>
|
|
437
|
-
<div class="spec">
|
|
438
|
-
11/<strong>700</strong> · <strong>uppercase + .4 px tracking</strong> · leading
|
|
439
|
-
<strong>icon</strong>, not a dot · <strong>no border</strong> · fixed height 22 ·
|
|
440
|
-
tabular-nums
|
|
441
|
-
</div>
|
|
442
|
-
</div>
|
|
443
|
-
</div>
|
|
444
|
-
|
|
445
|
-
<div class="flag">
|
|
446
|
-
<strong>cockpit's build resolves the typography question the section above left open.</strong>
|
|
447
|
-
Its pill is already 11-with-uppercase-and-.4 px-tracking — which is the baseline's
|
|
448
|
-
<code>overline</code> in all but the weight step. So <code>overline</code> is not an imposition on
|
|
449
|
-
the shared component; it is what the second consumer independently chose, and hram's lowercase is
|
|
450
|
-
the outlier. That turned “changes how every status chip reads” from a cost into a
|
|
451
|
-
<em>one-app</em> cost — which is how it was decided.
|
|
452
|
-
</div>
|
|
453
|
-
|
|
454
|
-
<!-- ================= resolved ================= -->
|
|
455
|
-
<h2 id="decided">Decided — the promoted spec</h2>
|
|
456
|
-
<p class="lede">
|
|
457
|
-
Operator decisions, 2026-08-12. Everything rendered above the divergence section already reflects
|
|
458
|
-
them; the two comparison panels keep the original values as the record of what changed.
|
|
459
|
-
</p>
|
|
460
|
-
|
|
461
|
-
<div class="panel panel--flush">
|
|
462
|
-
<table>
|
|
463
|
-
<thead>
|
|
464
|
-
<tr><th>Divergence</th><th>Decision</th><th>Which app changes</th></tr>
|
|
465
|
-
</thead>
|
|
466
|
-
<tbody>
|
|
467
|
-
<tr>
|
|
468
|
-
<td>StatTile value size</td>
|
|
469
|
-
<td><strong>h5 — 18/600</strong></td>
|
|
470
|
-
<td>hram (16 → 18)</td>
|
|
471
|
-
</tr>
|
|
472
|
-
<tr>
|
|
473
|
-
<td>StatTile digit alignment</td>
|
|
474
|
-
<td><strong>tabular-nums, always</strong> — the reason a KPI row reads as a row</td>
|
|
475
|
-
<td>fitness-monitor</td>
|
|
476
|
-
</tr>
|
|
477
|
-
<tr>
|
|
478
|
-
<td>StatTile row behaviour</td>
|
|
479
|
-
<td><strong><code>flex: 1</code> with a <code>minWidth</code> floor</strong> — covers both
|
|
480
|
-
existing behaviours with one rule, no prop</td>
|
|
481
|
-
<td>hram (tiles now share the row)</td>
|
|
482
|
-
</tr>
|
|
483
|
-
<tr>
|
|
484
|
-
<td>StatTile <code>accent</code></td>
|
|
485
|
-
<td><strong>kept</strong> — 2 px <code>primary.main</code>; without it fitness-monitor cannot
|
|
486
|
-
adopt</td>
|
|
487
|
-
<td>neither</td>
|
|
488
|
-
</tr>
|
|
489
|
-
<tr>
|
|
490
|
-
<td>StatTile padding</td>
|
|
491
|
-
<td><strong>responsive</strong> <code>{xs: 1, sm: 1.5}</code></td>
|
|
492
|
-
<td>hram (was fixed)</td>
|
|
493
|
-
</tr>
|
|
494
|
-
<tr>
|
|
495
|
-
<td>SoftChip status typography</td>
|
|
496
|
-
<td><strong><code>overline</code> — 11/600, uppercase, .4 px tracking.</strong> No new
|
|
497
|
-
baseline variant, so <code>THEME-4</code> is satisfied without a theme change</td>
|
|
498
|
-
<td>hram (<span style="white-space:nowrap">passed → PASSED</span>); cockpit drops 700 → 600</td>
|
|
499
|
-
</tr>
|
|
500
|
-
<tr>
|
|
501
|
-
<td>SoftChip leading element + border</td>
|
|
502
|
-
<td><strong>dot by default, any icon via prop; border optional</strong></td>
|
|
503
|
-
<td>neither — both adopt unchanged</td>
|
|
504
|
-
</tr>
|
|
505
|
-
</tbody>
|
|
506
|
-
</table>
|
|
507
|
-
</div>
|
|
508
|
-
|
|
509
|
-
<h3>The promoted components, as decided</h3>
|
|
510
|
-
<div class="frames">
|
|
511
|
-
<div class="frame frame--desktop">
|
|
512
|
-
<div class="frame__bar">1280 px</div>
|
|
513
|
-
<div class="frame__body">
|
|
514
|
-
<div class="stat-row">
|
|
515
|
-
<div class="stat-tile">
|
|
516
|
-
<span class="stat-tile__label">Coverage at budget</span>
|
|
517
|
-
<div class="stat-tile__value">71.4 %</div>
|
|
518
|
-
<span class="stat-tile__caption">of maximum realizable</span>
|
|
519
|
-
</div>
|
|
520
|
-
<div class="stat-tile">
|
|
521
|
-
<span class="stat-tile__label">Deaths averted</span>
|
|
522
|
-
<div class="stat-tile__value">63.8 %</div>
|
|
523
|
-
<span class="stat-tile__caption">of max avertable</span>
|
|
524
|
-
</div>
|
|
525
|
-
<div class="stat-tile stat-tile--accent">
|
|
526
|
-
<span class="stat-tile__label">Lean mass</span>
|
|
527
|
-
<div class="stat-tile__value">62.1 kg</div>
|
|
528
|
-
<span class="stat-tile__caption">accent variant</span>
|
|
529
|
-
</div>
|
|
530
|
-
</div>
|
|
531
|
-
<div style="margin-top:14px" class="chip-row">
|
|
532
|
-
<span class="chip chip--status t-success"><span class="chip__dot"></span>passed</span>
|
|
533
|
-
<span class="chip chip--status t-warning"><span class="chip__dot"></span>degraded</span>
|
|
534
|
-
<span class="chip chip--status t-error chip--borderless"><span class="chip__dot"></span>failed</span>
|
|
535
|
-
<span class="chip t-info"><span class="chip__dot"></span>Derived value</span>
|
|
536
|
-
</div>
|
|
537
|
-
<div class="spec">
|
|
538
|
-
third chip borderless · fourth is the <code>caveat</code> variant, unchanged at 12/500
|
|
539
|
-
</div>
|
|
540
|
-
</div>
|
|
541
|
-
</div>
|
|
542
|
-
<div class="frame frame--mobile">
|
|
543
|
-
<div class="frame__bar">375 px</div>
|
|
544
|
-
<div class="frame__body">
|
|
545
|
-
<div class="stat-row">
|
|
546
|
-
<div class="stat-tile">
|
|
547
|
-
<span class="stat-tile__label">Coverage at budget</span>
|
|
548
|
-
<div class="stat-tile__value">71.4 %</div>
|
|
549
|
-
</div>
|
|
550
|
-
<div class="stat-tile stat-tile--accent">
|
|
551
|
-
<span class="stat-tile__label">Lean mass</span>
|
|
552
|
-
<div class="stat-tile__value">62.1 kg</div>
|
|
553
|
-
</div>
|
|
554
|
-
</div>
|
|
555
|
-
<div style="margin-top:12px" class="chip-row">
|
|
556
|
-
<span class="chip chip--status t-success"><span class="chip__dot"></span>passed</span>
|
|
557
|
-
<span class="chip chip--status t-warning"><span class="chip__dot"></span>degraded</span>
|
|
558
|
-
</div>
|
|
559
|
-
</div>
|
|
560
|
-
</div>
|
|
561
|
-
</div>
|
|
562
|
-
|
|
563
|
-
<div class="flag">
|
|
564
|
-
<strong>Still open, and not part of the promotion:</strong> the <code>caveat</code> variant keeps its
|
|
565
|
-
raw 12/500, which has no baseline variant (<code>caption</code> is 12/400). It is left as-is
|
|
566
|
-
deliberately — resolving it needs either a baseline addition or a visible weight change, and neither
|
|
567
|
-
belongs in the same change as the promotion. It will surface as a <code>THEME-4</code> finding on the
|
|
568
|
-
promoted component and should be exempted with that reason, not silently flattened to 400.
|
|
569
|
-
</div>
|
|
570
|
-
<p class="note">
|
|
571
|
-
Not shown, because it cannot be: motion, focus and hover states, and how the chips read on a real
|
|
572
|
-
dense results screen rather than a specimen sheet.
|
|
573
|
-
</p>
|
|
574
|
-
|
|
575
|
-
</div>
|
|
576
|
-
|
|
577
|
-
<script>
|
|
578
|
-
// Contrast computed from the blended fill. Alpha-aware on purpose:
|
|
579
|
-
// getContrastRatio() ignores alpha and would answer a different question.
|
|
580
|
-
const TONES = [
|
|
581
|
-
['success', [27, 128, 56], [19, 90, 39]],
|
|
582
|
-
['warning', [151, 97, 0], [106, 68, 0]],
|
|
583
|
-
['error', [191, 50, 39], [134, 35, 27]],
|
|
584
|
-
['info', [1, 87, 155], [1, 61, 109]],
|
|
585
|
-
];
|
|
586
|
-
const PAPER = [255, 255, 255];
|
|
587
|
-
const FILL_ALPHA = 0.12;
|
|
588
|
-
|
|
589
|
-
const hex = ([r, g, b]) =>
|
|
590
|
-
'#' + [r, g, b].map((v) => v.toString(16).padStart(2, '0').toUpperCase()).join('');
|
|
591
|
-
|
|
592
|
-
const blend = (fg, bg, a) => fg.map((c, i) => Math.round(c * a + bg[i] * (1 - a)));
|
|
593
|
-
|
|
594
|
-
const lum = ([r, g, b]) => {
|
|
595
|
-
const f = (v) => {
|
|
596
|
-
const s = v / 255;
|
|
597
|
-
return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
|
|
598
|
-
};
|
|
599
|
-
return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
|
|
600
|
-
};
|
|
601
|
-
|
|
602
|
-
const ratio = (a, b) => {
|
|
603
|
-
const [hi, lo] = [lum(a), lum(b)].sort((x, y) => y - x);
|
|
604
|
-
return (hi + 0.05) / (lo + 0.05);
|
|
605
|
-
};
|
|
606
|
-
|
|
607
|
-
const tbody = document.querySelector('#contrast tbody');
|
|
608
|
-
TONES.forEach(([name, main, dark]) => {
|
|
609
|
-
const fill = blend(main, PAPER, FILL_ALPHA);
|
|
610
|
-
const r = ratio(dark, fill);
|
|
611
|
-
const ok = r >= 4.5;
|
|
612
|
-
tbody.insertAdjacentHTML('beforeend', `
|
|
613
|
-
<tr>
|
|
614
|
-
<td>${name}</td>
|
|
615
|
-
<td class="num">${hex(main)}</td>
|
|
616
|
-
<td class="num">${hex(dark)}</td>
|
|
617
|
-
<td class="num">${hex(fill)}</td>
|
|
618
|
-
<td class="num">${r.toFixed(2)}</td>
|
|
619
|
-
<td class="verdict ${ok ? 'pass' : 'fail'}">${ok ? 'pass' : 'FAIL'}</td>
|
|
620
|
-
</tr>`);
|
|
621
|
-
});
|
|
622
|
-
</script>
|
|
623
|
-
</body>
|
|
624
|
-
</html>
|