@saasicat/ui-vue 0.22.2 → 0.24.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 (119) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-LY52T4N4.js → chunk-TQQMKWN6.js} +58 -1
  3. package/dist/{chunk-XMMFN2WJ.js → chunk-VYMTWCTT.js} +51 -1
  4. package/dist/client/index.cjs +57 -0
  5. package/dist/client/index.d.cts +58 -1
  6. package/dist/client/index.d.ts +58 -1
  7. package/dist/client/index.js +15 -1
  8. package/dist/index.cjs +321 -159
  9. package/dist/index.d.cts +67 -4
  10. package/dist/index.d.ts +67 -4
  11. package/dist/index.js +72 -2
  12. package/dist/quasar/index.cjs +116 -20
  13. package/dist/quasar/index.d.cts +48 -3
  14. package/dist/quasar/index.d.ts +48 -3
  15. package/dist/quasar/index.js +58 -3
  16. package/dist/{use-super-admin-i18n-CgTuNi8h.d.cts → use-sa-theme-B5t7oXph.d.cts} +51 -1
  17. package/dist/{use-super-admin-i18n-CHNdsSlm.d.ts → use-sa-theme-OUBlaqgl.d.ts} +51 -1
  18. package/package.json +5 -2
  19. package/src/client/identity-accents.ts +129 -0
  20. package/src/client/index.ts +1 -0
  21. package/src/components/BundleVersionPublishDialog.vue +17 -17
  22. package/src/components/KvBlock.vue +6 -6
  23. package/src/components/MarketingPromotionsTab.vue +84 -80
  24. package/src/components/MfaPromptDialog.vue +2 -2
  25. package/src/components/TenantActionConfirmDialog.vue +5 -5
  26. package/src/components/VersionDiffPreview.vue +18 -18
  27. package/src/components/bundle-editor/BundleCreatePanel.vue +52 -52
  28. package/src/components/bundle-editor/BundleFeaturesEditor.vue +20 -20
  29. package/src/components/bundle-editor/BundlePlanCompatPicker.vue +33 -33
  30. package/src/components/bundle-editor/BundleQuotasEditor.vue +26 -26
  31. package/src/components/bundle-editor/BundleStatusBanner.vue +21 -21
  32. package/src/components/bundle-editor/BundleVersionInlineEditor.vue +49 -49
  33. package/src/components/bundle-editor/BundleVersionStrip.vue +30 -30
  34. package/src/components/dialogs/PilotCreateDialog.vue +20 -20
  35. package/src/components/dialogs/PilotEditDialog.vue +6 -6
  36. package/src/components/dialogs/PromoCodeCreateDialog.vue +9 -9
  37. package/src/components/dialogs/PromoCodeDialogFields.vue +64 -63
  38. package/src/components/dialogs/PromoCodeEditDialog.vue +11 -11
  39. package/src/components/dialogs/pilot-dialog.css +48 -48
  40. package/src/components/plan/PlanCycleToggle.vue +9 -16
  41. package/src/components/plan/PlanGrid.vue +30 -34
  42. package/src/components/plan/PriceSummary.vue +35 -35
  43. package/src/components/plan/PromoCodeInput.vue +26 -26
  44. package/src/components/plan/PublicBundleGrid.vue +32 -28
  45. package/src/components/plan-create-dialog/PlanCreateDialog.vue +50 -50
  46. package/src/components/plan-detail/PlanDetail.vue +178 -157
  47. package/src/components/plan-detail/PlanTitleEdit.vue +11 -11
  48. package/src/components/plan-list/PlanList.vue +116 -100
  49. package/src/components/plan-matrix/PlanMatrix.vue +97 -114
  50. package/src/components/plan-review/PlanReview.vue +61 -57
  51. package/src/components/plan-version-editor/PlanVersionEditor.vue +246 -203
  52. package/src/components/wizard-stepper/WizardStepper.vue +17 -17
  53. package/src/index.ts +1 -0
  54. package/src/pages-standard/AdminLayout.vue +58 -37
  55. package/src/pages-standard/AdminManifestErrorPage.vue +6 -6
  56. package/src/pages-standard/AuditPage.vue +3 -3
  57. package/src/pages-standard/BundlesPage.vue +37 -37
  58. package/src/pages-standard/DashboardPage.vue +22 -19
  59. package/src/pages-standard/DiscoveryPage.vue +55 -49
  60. package/src/pages-standard/EmailHistoryPage.vue +53 -71
  61. package/src/pages-standard/MarketingCatalogPage.vue +245 -221
  62. package/src/pages-standard/PilotsPage.vue +7 -6
  63. package/src/pages-standard/PlatformEmailPage.vue +18 -18
  64. package/src/pages-standard/PromoCodeDetailPage.vue +3 -3
  65. package/src/pages-standard/PromoCodesPage.vue +10 -7
  66. package/src/pages-standard/SuperAdminLoginPage.vue +39 -25
  67. package/src/pages-standard/SuperAdminSetupWizard.vue +44 -33
  68. package/src/pages-standard/TenantDetailPage.vue +7 -7
  69. package/src/pages-standard/TenantsPage.vue +16 -50
  70. package/src/pages-standard/bundles-page/BundleAccordionList.vue +13 -13
  71. package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +24 -24
  72. package/src/pages-standard/discovery-page/DiscoveryCapList.vue +22 -22
  73. package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +39 -39
  74. package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +26 -26
  75. package/src/pages-standard/discovery-page/DiscoveryStatusControl.vue +1 -1
  76. package/src/pages-standard/discovery-page/discovery-ui.ts +10 -7
  77. package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +2 -5
  78. package/src/pages-standard/plan-versions/PlanDiffCard.vue +27 -20
  79. package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +24 -16
  80. package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +45 -45
  81. package/src/pages-standard/plans-page/PlanBundleOverview.vue +21 -15
  82. package/src/pages-standard/plans-page/PlanPublishDialog.vue +4 -4
  83. package/src/pages-standard/plans-page/PlansPageToast.vue +6 -6
  84. package/src/pages-standard/sa-theme.css +9 -687
  85. package/src/pages-standard/tenants/StatusPill.vue +13 -13
  86. package/src/pages-standard/tenants/format.ts +11 -12
  87. package/src/pages-tenant/LimitsRow.vue +4 -4
  88. package/src/pages-tenant/MySubscriptionBundlesPage.vue +70 -61
  89. package/src/pages-tenant/OnboardingConfigurator.vue +25 -25
  90. package/src/pages-tenant/PackageSnapshotPanel.vue +10 -16
  91. package/src/pages-tenant/PendingVersionBanner.vue +12 -12
  92. package/src/pages-tenant/PlanChangeWizard.vue +22 -76
  93. package/src/pages-tenant/TenantPlanSection.vue +19 -69
  94. package/src/pages-tenant/UsageBar.vue +7 -7
  95. package/src/pages-tenant/default-i18n.ts +113 -0
  96. package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +14 -14
  97. package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +10 -10
  98. package/src/pages-tenant/tenant-plan-section/TenantFeatureMatrix.vue +2 -2
  99. package/src/quasar/create-super-admin-app.ts +96 -1
  100. package/src/quasar/dark-bridge.ts +66 -0
  101. package/src/quasar/index.ts +1 -0
  102. package/src/ui/theme/_breakpoints.scss +34 -0
  103. package/src/ui/theme/base.css +50 -0
  104. package/src/ui/theme/components/body.css +23 -0
  105. package/src/ui/theme/components/button.css +158 -0
  106. package/src/ui/theme/components/card.css +74 -0
  107. package/src/ui/theme/components/field.css +38 -0
  108. package/src/ui/theme/components/hero.css +46 -0
  109. package/src/ui/theme/components/paginator.css +63 -0
  110. package/src/ui/theme/components/section.css +67 -0
  111. package/src/ui/theme/components/statistics.css +189 -0
  112. package/src/ui/theme/components/table.css +60 -0
  113. package/src/ui/theme/index.css +42 -0
  114. package/src/ui/theme/tokens.legacy.css +147 -0
  115. package/src/ui/theme/tokens.primitive.css +112 -0
  116. package/src/ui/theme/tokens.scale.css +103 -0
  117. package/src/ui/theme/tokens.semantic.dark.css +185 -0
  118. package/src/ui/theme/tokens.semantic.light.css +242 -0
  119. package/src/vue/use-sa-theme.ts +154 -0
@@ -55,8 +55,8 @@ defineProps<{
55
55
  align-items: center;
56
56
  gap: 6px;
57
57
  padding: 14px 26px;
58
- background: var(--sa-bg-surface);
59
- border-bottom: 1px solid var(--sa-border);
58
+ background: var(--sa-color-bg-surface);
59
+ border-bottom: 1px solid var(--sa-color-border);
60
60
  }
61
61
  .wz-step {
62
62
  display: flex;
@@ -64,44 +64,44 @@ defineProps<{
64
64
  gap: 8px;
65
65
  padding: 6px 12px;
66
66
  border-radius: 999px;
67
- font: 500 12.5px var(--sa-font-body);
68
- color: var(--sa-muted);
67
+ font: 500 var(--sa-text-md) var(--sa-font-body);
68
+ color: var(--sa-color-fg-muted);
69
69
  }
70
70
  .wz-step--current {
71
- background: var(--sa-heading);
72
- color: #fff;
71
+ background: var(--sa-color-inverse-bg);
72
+ color: var(--sa-color-fg-on-accent);
73
73
  }
74
74
  .wz-step--done {
75
- color: var(--sa-positive);
75
+ color: var(--sa-color-positive);
76
76
  }
77
77
  .wz-step-num {
78
78
  width: 20px;
79
79
  height: 20px;
80
80
  border-radius: 50%;
81
- background: var(--sa-border);
82
- color: var(--sa-muted-dark);
81
+ background: var(--sa-color-border);
82
+ color: var(--sa-color-fg-secondary);
83
83
  display: grid;
84
84
  place-items: center;
85
- font: 700 11px var(--sa-font-body);
85
+ font: 700 var(--sa-text-xs) var(--sa-font-body);
86
86
  flex: 0 0 auto;
87
87
  }
88
88
  .wz-step--current .wz-step-num {
89
- background: rgba(255, 255, 255, 0.18);
90
- color: #fff;
89
+ background: var(--sa-color-inverse-border-strong);
90
+ color: var(--sa-color-fg-on-accent);
91
91
  }
92
92
  .wz-step--done .wz-step-num {
93
- background: var(--sa-positive-soft);
94
- color: var(--sa-positive);
93
+ background: var(--sa-color-positive-surface);
94
+ color: var(--sa-color-positive);
95
95
  }
96
96
  .wz-step-sep {
97
97
  width: 14px;
98
98
  height: 1px;
99
- background: var(--sa-border);
99
+ background: var(--sa-color-border);
100
100
  margin: 0 2px;
101
101
  }
102
102
  .wz-stepper-hint {
103
103
  margin-left: auto;
104
- font-size: 11px;
105
- color: var(--sa-muted);
104
+ font-size: var(--sa-text-xs);
105
+ color: var(--sa-color-fg-muted);
106
106
  }
107
107
  </style>
package/src/index.ts CHANGED
@@ -33,6 +33,7 @@ export * from './vue/super-admin-context.js';
33
33
  export * from './vue/ui-notify.js';
34
34
  export * from './vue/use-super-admin-context.js';
35
35
  export * from './vue/use-super-admin-i18n.js';
36
+ export * from './vue/use-sa-theme.js';
36
37
 
37
38
  // ---------------------------------------------------------------------------
38
39
  // Vue layer: composables, guards, hosts, store factory.
@@ -309,31 +309,42 @@ const currentPageTitle = computed(() => {
309
309
  justify-content: center;
310
310
  gap: 8px;
311
311
  padding: 6px 12px;
312
- font-size: 12px;
312
+ font-size: var(--sa-text-sm);
313
313
  letter-spacing: 0.05em;
314
314
  text-transform: uppercase;
315
315
  }
316
316
  .sa-admin-banner--prod {
317
- background: linear-gradient(90deg, #b91c1c, #dc2626);
318
- color: #fff;
317
+ /* Invariant on purpose: this strip says "you are on production", and its
318
+ * white text has to stay readable in both themes. The `negative` roles
319
+ * lighten in dark — for text ON dark surfaces — and would take this one to
320
+ * 1.9:1. */
321
+ background: linear-gradient(
322
+ 90deg,
323
+ var(--sa-color-inverse-danger),
324
+ var(--sa-color-inverse-danger-strong)
325
+ );
326
+ color: var(--sa-color-inverse-fg);
319
327
  }
320
328
 
321
329
  .sa-admin-header {
322
- background: var(--sa-admin-header-bg, linear-gradient(90deg, var(--sa-heading), #1e293b));
323
- color: var(--sa-admin-header-fg, #fff);
330
+ background: var(
331
+ --sa-admin-header-bg,
332
+ linear-gradient(90deg, var(--sa-color-inverse-bg), var(--sa-color-inverse-surface))
333
+ );
334
+ color: var(--sa-admin-header-fg, var(--sa-color-inverse-fg));
324
335
  }
325
336
  .sa-admin-header__sub {
326
- font-size: 11px;
327
- color: var(--sa-admin-header-sub, #fbbf24);
337
+ font-size: var(--sa-text-xs);
338
+ color: var(--sa-admin-header-sub, var(--sa-color-inverse-accent));
328
339
  font-weight: 400;
329
340
  }
330
341
 
331
342
  .sa-admin-badge {
332
- background: var(--sa-admin-badge-bg, #f59e0b);
333
- color: var(--sa-admin-badge-fg, var(--sa-heading));
343
+ background: var(--sa-admin-badge-bg, var(--sa-color-inverse-accent));
344
+ color: var(--sa-admin-badge-fg, var(--sa-color-inverse-accent-fg));
334
345
  font-weight: 800;
335
346
  letter-spacing: 0.08em;
336
- font-size: 10px;
347
+ font-size: var(--sa-text-2xs);
337
348
  padding: 4px 8px;
338
349
  }
339
350
 
@@ -343,21 +354,21 @@ const currentPageTitle = computed(() => {
343
354
  gap: 8px;
344
355
  }
345
356
  .sa-admin-user__avatar {
346
- background: var(--sa-admin-user-avatar-bg, #f59e0b);
347
- color: var(--sa-admin-user-avatar-fg, #fff);
357
+ background: var(--sa-admin-user-avatar-bg, var(--sa-color-inverse-accent));
358
+ color: var(--sa-admin-user-avatar-fg, var(--sa-color-inverse-accent-fg));
348
359
  }
349
360
  .sa-admin-user__name {
350
361
  line-height: 1.05;
351
362
  }
352
363
  .sa-admin-user__email {
353
- color: var(--sa-admin-user-email, #fbbf24);
364
+ color: var(--sa-admin-user-email, var(--sa-color-inverse-accent));
354
365
  }
355
366
 
356
367
  .sa-admin-drawer :deep(.q-drawer),
357
368
  .sa-admin-drawer :deep(.q-drawer__content),
358
369
  .sa-admin-drawer__stack {
359
- background: var(--sa-admin-drawer-bg, #0b1220);
360
- color: var(--sa-admin-drawer-fg, var(--sa-border-soft));
370
+ background: var(--sa-admin-drawer-bg, var(--sa-color-inverse-bg));
371
+ color: var(--sa-admin-drawer-fg, var(--sa-color-inverse-fg-muted));
361
372
  }
362
373
  .sa-admin-drawer__stack {
363
374
  display: flex;
@@ -370,14 +381,21 @@ const currentPageTitle = computed(() => {
370
381
  align-items: center;
371
382
  gap: 12px;
372
383
  padding: 18px 16px;
373
- border-bottom: 1px solid rgba(255, 255, 255, 0.08);
384
+ border-bottom: 1px solid var(--sa-color-inverse-border);
374
385
  }
375
386
  .sa-admin-drawer__logo {
376
387
  width: 36px;
377
388
  height: 36px;
378
389
  border-radius: 10px;
379
- background: var(--sa-admin-drawer-logo-bg, linear-gradient(135deg, #f59e0b, #d97706));
380
- color: var(--sa-admin-drawer-logo-fg, var(--sa-heading));
390
+ background: var(
391
+ --sa-admin-drawer-logo-bg,
392
+ linear-gradient(
393
+ 135deg,
394
+ var(--sa-color-inverse-accent),
395
+ var(--sa-color-inverse-accent-strong)
396
+ )
397
+ );
398
+ color: var(--sa-admin-drawer-logo-fg, var(--sa-color-inverse-accent-fg));
381
399
  font-weight: 800;
382
400
  display: flex;
383
401
  align-items: center;
@@ -385,11 +403,11 @@ const currentPageTitle = computed(() => {
385
403
  }
386
404
  .sa-admin-drawer__brand-name {
387
405
  font-weight: 800;
388
- color: #fff;
406
+ color: var(--sa-color-inverse-fg);
389
407
  }
390
408
  .sa-admin-drawer__brand-tag {
391
- font-size: 11px;
392
- color: var(--sa-admin-drawer-brand-tag, #fbbf24);
409
+ font-size: var(--sa-text-xs);
410
+ color: var(--sa-admin-drawer-brand-tag, var(--sa-color-inverse-accent));
393
411
  text-transform: uppercase;
394
412
  letter-spacing: 0.08em;
395
413
  }
@@ -399,20 +417,20 @@ const currentPageTitle = computed(() => {
399
417
  padding: 6px 4px;
400
418
  }
401
419
  .sa-admin-drawer__section {
402
- font-size: 10px;
420
+ font-size: var(--sa-text-2xs);
403
421
  text-transform: uppercase;
404
422
  letter-spacing: 0.12em;
405
- color: var(--sa-admin-drawer-section-fg, var(--sa-muted));
423
+ color: var(--sa-admin-drawer-section-fg, var(--sa-color-inverse-fg-muted));
406
424
  padding: 14px 18px 6px;
407
425
  font-weight: 600;
408
426
  }
409
427
  .sa-admin-drawer__list :deep(.q-item) {
410
- color: var(--sa-admin-drawer-item-fg, #cbd5e1);
428
+ color: var(--sa-admin-drawer-item-fg, var(--sa-color-inverse-fg-muted));
411
429
  border-radius: 7px;
412
430
  margin: 1px 6px;
413
431
  min-height: 36px;
414
432
  padding: 6px 12px;
415
- font-size: 13.5px;
433
+ font-size: var(--sa-text-md);
416
434
  font-weight: 500;
417
435
  }
418
436
  .sa-admin-drawer__list :deep(.q-item__section--avatar) {
@@ -420,40 +438,43 @@ const currentPageTitle = computed(() => {
420
438
  padding-right: 8px;
421
439
  }
422
440
  .sa-admin-drawer__list :deep(.q-item .q-icon) {
423
- color: var(--sa-border);
441
+ color: var(--sa-color-inverse-fg-subtle);
424
442
  }
425
443
  .sa-admin-drawer__list :deep(.q-item:hover) {
426
- background: var(--sa-admin-drawer-hover-bg, rgba(245, 158, 11, 0.15));
427
- color: var(--sa-admin-drawer-hover-fg, #fbbf24);
444
+ background: var(--sa-admin-drawer-hover-bg, var(--sa-color-inverse-accent-surface));
445
+ color: var(--sa-admin-drawer-hover-fg, var(--sa-color-inverse-accent));
428
446
  }
429
447
  .sa-admin-drawer__list :deep(.q-item:hover .q-icon) {
430
- color: var(--sa-admin-drawer-hover-fg, #fbbf24);
448
+ color: var(--sa-admin-drawer-hover-fg, var(--sa-color-inverse-accent));
431
449
  }
432
450
  .sa-admin-drawer__list :deep(.sa-admin-drawer__item--active) {
433
- background: var(--sa-admin-drawer-active-bg, rgba(245, 158, 11, 0.22)) !important;
434
- color: var(--sa-admin-drawer-active-fg, #fbbf24) !important;
451
+ background: var(
452
+ --sa-admin-drawer-active-bg,
453
+ var(--sa-color-inverse-accent-surface-strong)
454
+ ) !important;
455
+ color: var(--sa-admin-drawer-active-fg, var(--sa-color-inverse-accent)) !important;
435
456
  font-weight: 600;
436
457
  }
437
458
  .sa-admin-drawer__list :deep(.sa-admin-drawer__item--active .q-icon) {
438
- color: var(--sa-admin-drawer-active-fg, #fbbf24);
459
+ color: var(--sa-admin-drawer-active-fg, var(--sa-color-inverse-accent));
439
460
  }
440
461
 
441
462
  .sa-admin-drawer__footer {
442
463
  padding: 12px 16px;
443
- border-top: 1px solid rgba(255, 255, 255, 0.08);
444
- font-size: 11px;
445
- color: #cbd5e1;
464
+ border-top: 1px solid var(--sa-color-inverse-border);
465
+ font-size: var(--sa-text-xs);
466
+ color: var(--sa-color-inverse-fg-muted);
446
467
  }
447
468
  .sa-admin-drawer__doc {
448
469
  display: inline-flex;
449
470
  align-items: center;
450
471
  gap: 6px;
451
472
  margin-top: 6px;
452
- color: var(--sa-border);
473
+ color: var(--sa-color-inverse-fg-muted);
453
474
  text-decoration: none;
454
475
  }
455
476
  .sa-admin-drawer__doc:hover {
456
- color: var(--sa-admin-drawer-hover-fg, #fbbf24);
477
+ color: var(--sa-admin-drawer-hover-fg, var(--sa-color-inverse-accent));
457
478
  }
458
479
 
459
480
  .sa-admin-content {
@@ -124,22 +124,22 @@ function logout(): void | Promise<void> {
124
124
  }
125
125
  .sa-manifest-error__title {
126
126
  margin: 0;
127
- font-size: 22px;
127
+ font-size: var(--sa-text-2xl);
128
128
  }
129
129
  .sa-manifest-error__lead,
130
130
  .sa-manifest-error__detail {
131
131
  margin: 0 0 12px;
132
- color: var(--sa-muted-dark);
132
+ color: var(--sa-color-fg-secondary);
133
133
  line-height: 1.6;
134
134
  }
135
135
  .sa-manifest-error__detail {
136
- background: #fef2f2;
137
- border-left: 3px solid #dc2626;
136
+ background: var(--sa-color-negative-surface);
137
+ border-left: 3px solid var(--sa-color-negative);
138
138
  padding: 8px 12px;
139
139
  border-radius: 4px;
140
140
  font-family: ui-monospace, SFMono-Regular, monospace;
141
- font-size: 13px;
142
- color: #991b1b;
141
+ font-size: var(--sa-text-md);
142
+ color: var(--sa-color-negative-fg);
143
143
  }
144
144
  .sa-manifest-error__actions {
145
145
  display: flex;
@@ -206,11 +206,11 @@ function formatTs(iso: string | null | undefined): string {
206
206
 
207
207
  <style scoped>
208
208
  .sa-audit__kv {
209
- background: var(--sa-bg-surface-2);
210
- border: 1px solid var(--sa-border, var(--sa-border));
209
+ background: var(--sa-color-bg-sunken);
210
+ border: 1px solid var(--sa-color-border);
211
211
  border-radius: 8px;
212
212
  padding: 12px;
213
- font-size: 12px;
213
+ font-size: var(--sa-text-sm);
214
214
  margin: 0;
215
215
  overflow-x: auto;
216
216
  max-height: 50vh;
@@ -664,10 +664,10 @@ const classifyDiff = computed(() => props.classifyDiff);
664
664
  gap: 14px;
665
665
  }
666
666
  .sa-bundles__error {
667
- border-left: 4px solid #dc2626;
667
+ border-left: 4px solid var(--sa-color-negative);
668
668
  }
669
669
  .sa-bundles__empty {
670
- border-left: 4px solid #31ccec;
670
+ border-left: 4px solid var(--sa-color-info-strong);
671
671
  }
672
672
  .sa-bundles__filter-row {
673
673
  display: flex;
@@ -688,13 +688,13 @@ const classifyDiff = computed(() => props.classifyDiff);
688
688
  gap: 8px;
689
689
  }
690
690
  .sa-bd-card {
691
- background: #fff;
692
- border: 1px solid var(--sa-border);
691
+ background: var(--sa-color-bg-surface);
692
+ border: 1px solid var(--sa-color-border);
693
693
  border-radius: 10px;
694
694
  overflow: hidden;
695
695
  }
696
696
  .sa-bd-card.open {
697
- border-color: #3f6bff;
697
+ border-color: var(--sa-color-accent);
698
698
  }
699
699
  .sa-bd-card__head {
700
700
  display: flex;
@@ -707,8 +707,8 @@ const classifyDiff = computed(() => props.classifyDiff);
707
707
  width: 34px;
708
708
  height: 34px;
709
709
  border-radius: 8px;
710
- background: var(--sa-primary-50);
711
- color: var(--sa-primary-strong);
710
+ background: var(--sa-color-accent-surface-strong);
711
+ color: var(--sa-color-accent-strong);
712
712
  display: flex;
713
713
  align-items: center;
714
714
  justify-content: center;
@@ -725,36 +725,36 @@ const classifyDiff = computed(() => props.classifyDiff);
725
725
  }
726
726
  .sa-bd-card__key {
727
727
  font-weight: 700;
728
- font-size: 12px;
728
+ font-size: var(--sa-text-sm);
729
729
  font-family: var(--sa-font-mono, ui-monospace, monospace);
730
730
  }
731
731
  .sa-bd-card__name {
732
- font-size: 13px;
732
+ font-size: var(--sa-text-md);
733
733
  font-weight: 600;
734
734
  margin-top: 2px;
735
735
  }
736
736
  .sa-bd-card__desc {
737
- font-size: 12px;
738
- color: var(--sa-muted);
737
+ font-size: var(--sa-text-sm);
738
+ color: var(--sa-color-fg-muted);
739
739
  }
740
740
  .sa-bd-card__chev {
741
741
  transition: transform 0.15s;
742
- color: var(--sa-muted-light);
742
+ color: var(--sa-color-fg-subtle);
743
743
  }
744
744
  .sa-bd-card__chev.open {
745
745
  transform: rotate(90deg);
746
746
  }
747
747
  .sa-bd-card__body {
748
- border-top: 1px solid var(--sa-border);
748
+ border-top: 1px solid var(--sa-color-border);
749
749
  padding: 14px;
750
- background: var(--sa-bg-surface-2);
750
+ background: var(--sa-color-bg-sunken);
751
751
  }
752
752
  .sa-bd-grid {
753
753
  display: grid;
754
754
  grid-template-columns: minmax(280px, 360px) 1fr;
755
755
  gap: 18px;
756
756
  }
757
- @media (max-width: 980px) {
757
+ @media (max-width: 1023.98px) {
758
758
  .sa-bd-grid {
759
759
  grid-template-columns: 1fr;
760
760
  }
@@ -774,11 +774,11 @@ const classifyDiff = computed(() => props.classifyDiff);
774
774
  margin-top: 4px;
775
775
  }
776
776
  .sa-bd-section-label {
777
- font-size: 11px;
777
+ font-size: var(--sa-text-xs);
778
778
  font-weight: 700;
779
779
  text-transform: uppercase;
780
780
  letter-spacing: 0.5px;
781
- color: var(--sa-muted-dark);
781
+ color: var(--sa-color-fg-secondary);
782
782
  display: flex;
783
783
  justify-content: space-between;
784
784
  }
@@ -786,7 +786,7 @@ const classifyDiff = computed(() => props.classifyDiff);
786
786
  margin-top: 10px;
787
787
  }
788
788
  .sa-bd-section-count {
789
- color: var(--sa-muted-light);
789
+ color: var(--sa-color-fg-subtle);
790
790
  font-weight: 600;
791
791
  }
792
792
  .sa-bundles__form {
@@ -795,17 +795,17 @@ const classifyDiff = computed(() => props.classifyDiff);
795
795
  gap: 10px;
796
796
  }
797
797
  .sa-bd-i18n-hint {
798
- font-size: 11px;
799
- color: var(--sa-muted-light);
798
+ font-size: var(--sa-text-xs);
799
+ color: var(--sa-color-fg-subtle);
800
800
  }
801
801
  .sa-bd-i18n-block {
802
802
  display: flex;
803
803
  flex-direction: column;
804
804
  gap: 6px;
805
805
  padding: 8px;
806
- border: 1px solid var(--sa-border);
806
+ border: 1px solid var(--sa-color-border);
807
807
  border-radius: 8px;
808
- background: #fff;
808
+ background: var(--sa-color-bg-surface);
809
809
  }
810
810
  .sa-bd-i18n-head {
811
811
  display: flex;
@@ -813,15 +813,15 @@ const classifyDiff = computed(() => props.classifyDiff);
813
813
  align-items: center;
814
814
  }
815
815
  .sa-bd-i18n-code {
816
- font-size: 10px;
816
+ font-size: var(--sa-text-2xs);
817
817
  font-weight: 700;
818
- background: var(--sa-border-soft);
818
+ background: var(--sa-color-border-soft);
819
819
  padding: 2px 7px;
820
820
  border-radius: 5px;
821
821
  }
822
822
  .sa-bd-i18n-fallback {
823
- font-size: 10px;
824
- color: #b45309;
823
+ font-size: var(--sa-text-2xs);
824
+ color: var(--sa-color-warning-fg);
825
825
  }
826
826
  .sa-bd-save {
827
827
  margin-top: 8px;
@@ -835,8 +835,8 @@ const classifyDiff = computed(() => props.classifyDiff);
835
835
  display: flex;
836
836
  gap: 10px;
837
837
  align-items: flex-start;
838
- background: #fff;
839
- border: 1px solid var(--sa-border);
838
+ background: var(--sa-color-bg-surface);
839
+ border: 1px solid var(--sa-color-border);
840
840
  border-radius: 8px;
841
841
  padding: 10px;
842
842
  }
@@ -850,8 +850,8 @@ const classifyDiff = computed(() => props.classifyDiff);
850
850
  align-items: center;
851
851
  }
852
852
  .sa-bd-version__sub {
853
- font-size: 11px;
854
- color: var(--sa-muted);
853
+ font-size: var(--sa-text-xs);
854
+ color: var(--sa-color-fg-muted);
855
855
  margin: 2px 0;
856
856
  }
857
857
  .sa-bd-version__feats {
@@ -860,8 +860,8 @@ const classifyDiff = computed(() => props.classifyDiff);
860
860
  gap: 4px;
861
861
  }
862
862
  .sa-bd-feat-chip {
863
- font-size: 10px;
864
- background: var(--sa-border-soft);
863
+ font-size: var(--sa-text-2xs);
864
+ background: var(--sa-color-border-soft);
865
865
  padding: 2px 6px;
866
866
  border-radius: 5px;
867
867
  }
@@ -872,17 +872,17 @@ const classifyDiff = computed(() => props.classifyDiff);
872
872
  .sa-bd-empty-row {
873
873
  padding: 20px;
874
874
  text-align: center;
875
- color: var(--sa-muted-light);
876
- font-size: 12px;
877
- border: 1px dashed #cbd5e1;
875
+ color: var(--sa-color-fg-subtle);
876
+ font-size: var(--sa-text-sm);
877
+ border: 1px dashed var(--sa-color-border-strong);
878
878
  border-radius: 8px;
879
879
  }
880
880
  .sa-bundles__warnings-banner {
881
- border-left: 4px solid #f2c037;
881
+ border-left: 4px solid var(--sa-color-warning-strong);
882
882
  }
883
883
  .sa-bundles__warnings-list {
884
884
  margin: 8px 0 0;
885
885
  padding-left: 20px;
886
- font-size: 13px;
886
+ font-size: var(--sa-text-md);
887
887
  }
888
888
  </style>
@@ -215,7 +215,10 @@ const cards = reactive<KpiCardState[]>([]);
215
215
  const loading = ref(false);
216
216
  const error = ref<Error | null>(null);
217
217
 
218
- const defaultBarColor = 'linear-gradient(90deg, #3f6bff, #1d4ed8)';
218
+ // Two stops of the brand accent rather than two fixed blues: a host that sets
219
+ // its own `$primary` had a brand-coloured admin with platform-blue KPI bars.
220
+ const defaultBarColor =
221
+ 'linear-gradient(90deg, var(--sa-color-accent), var(--sa-color-accent-strong))';
219
222
 
220
223
  watch(
221
224
  () => props.manifest,
@@ -402,7 +405,7 @@ function barWidth(value: number, max?: number): number {
402
405
  /* Header look comes from the global .sa-page-head — only a margin tweak here. */
403
406
 
404
407
  .sa-kpi__icon :deep(.q-icon) {
405
- color: var(--sa-primary, #3f6bff);
408
+ color: var(--sa-color-accent);
406
409
  }
407
410
 
408
411
  .sa-dashboard__rows {
@@ -412,16 +415,16 @@ function barWidth(value: number, max?: number): number {
412
415
  margin-bottom: 14px;
413
416
  align-items: start;
414
417
  }
415
- @media (max-width: 1280px) {
418
+ @media (max-width: 1439.98px) {
416
419
  .sa-dashboard__rows {
417
420
  grid-template-columns: 1fr;
418
421
  }
419
422
  }
420
423
 
421
424
  .sa-dashboard__count {
422
- background: var(--sa-primary-soft, rgba(63, 107, 255, 0.08));
423
- color: var(--sa-primary, #3f6bff);
424
- font-size: 11px;
425
+ background: var(--sa-color-accent-surface);
426
+ color: var(--sa-color-accent);
427
+ font-size: var(--sa-text-xs);
425
428
  font-weight: 700;
426
429
  padding: 2px 7px;
427
430
  border-radius: 5px;
@@ -440,14 +443,14 @@ function barWidth(value: number, max?: number): number {
440
443
  grid-template-columns: 130px 1fr 50px;
441
444
  align-items: center;
442
445
  gap: 8px;
443
- font-size: 13px;
446
+ font-size: var(--sa-text-md);
444
447
  }
445
448
  .sa-dashboard__bar-name {
446
449
  font-weight: 600;
447
- color: var(--sa-heading, var(--sa-heading));
450
+ color: var(--sa-color-fg-heading);
448
451
  }
449
452
  .sa-dashboard__bar-track {
450
- background: var(--sa-border-soft);
453
+ background: var(--sa-color-border-soft);
451
454
  height: 8px;
452
455
  border-radius: 999px;
453
456
  overflow: hidden;
@@ -461,7 +464,7 @@ function barWidth(value: number, max?: number): number {
461
464
  .sa-dashboard__bar-count {
462
465
  font-variant-numeric: tabular-nums;
463
466
  text-align: right;
464
- color: var(--sa-muted-dark, var(--sa-muted-dark));
467
+ color: var(--sa-color-fg-secondary);
465
468
  }
466
469
 
467
470
  .sa-dashboard__shortcuts {
@@ -477,36 +480,36 @@ function barWidth(value: number, max?: number): number {
477
480
  gap: 12px;
478
481
  align-items: flex-start;
479
482
  padding: 12px 14px;
480
- border: 1px solid var(--sa-border, var(--sa-border));
483
+ border: 1px solid var(--sa-color-border);
481
484
  border-radius: 10px;
482
485
  text-decoration: none;
483
486
  color: inherit;
484
- background: #fafbfc;
487
+ background: var(--sa-color-bg-surface-raised);
485
488
  transition: all 0.12s;
486
489
  }
487
490
  .sa-dashboard__shortcut:hover {
488
- background: var(--sa-primary-soft, rgba(63, 107, 255, 0.08));
489
- border-color: var(--sa-primary-border, rgba(63, 107, 255, 0.18));
491
+ background: var(--sa-color-accent-surface);
492
+ border-color: var(--sa-color-accent-border);
490
493
  }
491
494
  .sa-dashboard__shortcut :deep(.q-icon) {
492
- color: var(--sa-primary, #3f6bff);
495
+ color: var(--sa-color-accent);
493
496
  flex-shrink: 0;
494
497
  }
495
498
  .sa-dashboard__shortcut-title {
496
499
  font-weight: 700;
497
- color: var(--sa-heading, var(--sa-heading));
500
+ color: var(--sa-color-fg-heading);
498
501
  font-family: var(--sa-font-head, system-ui, sans-serif);
499
502
  }
500
503
  .sa-dashboard__shortcut-sub {
501
- font-size: 12px;
502
- color: var(--sa-muted, var(--sa-muted));
504
+ font-size: var(--sa-text-sm);
505
+ color: var(--sa-color-fg-muted);
503
506
  margin-top: 2px;
504
507
  }
505
508
 
506
509
  .sa-dashboard__loading,
507
510
  .sa-dashboard__empty {
508
511
  padding: 32px 28px;
509
- color: var(--sa-muted, var(--sa-muted));
512
+ color: var(--sa-color-fg-muted);
510
513
  display: flex;
511
514
  align-items: center;
512
515
  gap: 12px;