@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
@@ -171,14 +171,14 @@ function copyFromDefault(locale: string): void {
171
171
  gap: 12px;
172
172
  }
173
173
  .sa-trans-lang {
174
- border: 1px solid var(--sa-border);
174
+ border: 1px solid var(--sa-color-border);
175
175
  border-radius: 10px;
176
- background: #fff;
176
+ background: var(--sa-color-bg-surface);
177
177
  padding: 10px 12px;
178
178
  }
179
179
  .sa-trans-lang--source {
180
- background: var(--sa-bg-surface-2);
181
- border-color: #cbd5e1;
180
+ background: var(--sa-color-bg-sunken);
181
+ border-color: var(--sa-color-border-strong);
182
182
  }
183
183
  .sa-trans-lang__head {
184
184
  display: flex;
@@ -187,31 +187,31 @@ function copyFromDefault(locale: string): void {
187
187
  margin-bottom: 8px;
188
188
  }
189
189
  .sa-trans-lang__code {
190
- font-size: 10px;
190
+ font-size: var(--sa-text-2xs);
191
191
  font-weight: 700;
192
- background: var(--sa-heading);
193
- color: #fff;
192
+ background: var(--sa-color-inverse-bg);
193
+ color: var(--sa-color-fg-on-accent);
194
194
  padding: 2px 6px;
195
195
  border-radius: 5px;
196
196
  }
197
197
  .sa-trans-lang__name {
198
- font-size: 12px;
198
+ font-size: var(--sa-text-sm);
199
199
  font-weight: 600;
200
- color: #334155;
200
+ color: var(--sa-color-fg-body);
201
201
  flex: 1;
202
202
  }
203
203
  .sa-trans-lang__badge {
204
- font-size: 9px;
204
+ font-size: var(--sa-text-2xs);
205
205
  font-weight: 700;
206
206
  text-transform: uppercase;
207
207
  letter-spacing: 0.5px;
208
- color: var(--sa-muted-dark);
209
- background: var(--sa-border);
208
+ color: var(--sa-color-fg-secondary);
209
+ background: var(--sa-color-border);
210
210
  padding: 2px 6px;
211
211
  border-radius: 5px;
212
212
  }
213
213
  .sa-trans-lang__copy {
214
- color: var(--sa-muted-dark);
214
+ color: var(--sa-color-fg-secondary);
215
215
  }
216
216
  .sa-trans-fields {
217
217
  display: flex;
@@ -224,17 +224,17 @@ function copyFromDefault(locale: string): void {
224
224
  gap: 3px;
225
225
  }
226
226
  .sa-trans-field__cap {
227
- font-size: 10px;
227
+ font-size: var(--sa-text-2xs);
228
228
  font-weight: 600;
229
229
  text-transform: uppercase;
230
230
  letter-spacing: 0.3px;
231
- color: var(--sa-muted-light);
231
+ color: var(--sa-color-fg-subtle);
232
232
  }
233
233
  .sa-trans-locked {
234
- font-size: 13px;
235
- color: #334155;
236
- background: var(--sa-border-soft);
237
- border: 1px dashed #cbd5e1;
234
+ font-size: var(--sa-text-md);
235
+ color: var(--sa-color-fg-body);
236
+ background: var(--sa-color-border-soft);
237
+ border: 1px dashed var(--sa-color-border-strong);
238
238
  border-radius: 6px;
239
239
  padding: 6px 10px;
240
240
  display: flex;
@@ -242,17 +242,17 @@ function copyFromDefault(locale: string): void {
242
242
  gap: 8px;
243
243
  }
244
244
  .sa-trans-locked__hint {
245
- font-size: 10px;
246
- color: var(--sa-muted-light);
245
+ font-size: var(--sa-text-2xs);
246
+ color: var(--sa-color-fg-subtle);
247
247
  text-transform: uppercase;
248
248
  }
249
249
  .sa-trans__empty {
250
250
  grid-column: 1 / -1;
251
251
  padding: 16px;
252
252
  text-align: center;
253
- font-size: 12px;
254
- color: var(--sa-muted-light);
255
- border: 1px dashed #cbd5e1;
253
+ font-size: var(--sa-text-sm);
254
+ color: var(--sa-color-fg-subtle);
255
+ border: 1px dashed var(--sa-color-border-strong);
256
256
  border-radius: 10px;
257
257
  }
258
258
  </style>
@@ -90,17 +90,17 @@ function isNew(cap: CapabilityCatalogEntryRow): boolean {
90
90
  display: flex;
91
91
  gap: 10px;
92
92
  align-items: flex-start;
93
- background: #fff;
94
- border: 1px solid var(--sa-border);
93
+ background: var(--sa-color-bg-surface);
94
+ border: 1px solid var(--sa-color-border);
95
95
  border-radius: 8px;
96
96
  padding: 8px 10px;
97
97
  }
98
98
  .sa-caps-row.dep {
99
- border-color: #fecaca;
100
- background: #fef2f2;
99
+ border-color: var(--sa-color-negative-border);
100
+ background: var(--sa-color-negative-surface);
101
101
  }
102
102
  .sa-caps-row__kind {
103
- font-size: 9px;
103
+ font-size: var(--sa-text-2xs);
104
104
  font-weight: 700;
105
105
  text-transform: uppercase;
106
106
  padding: 2px 6px;
@@ -120,30 +120,30 @@ function isNew(cap: CapabilityCatalogEntryRow): boolean {
120
120
  flex-wrap: wrap;
121
121
  }
122
122
  .sa-caps-row__key {
123
- font-size: 11px;
123
+ font-size: var(--sa-text-xs);
124
124
  font-weight: 700;
125
125
  }
126
126
  .sa-caps-row__flag {
127
- font-size: 9px;
127
+ font-size: var(--sa-text-2xs);
128
128
  font-weight: 700;
129
129
  padding: 1px 5px;
130
130
  border-radius: 4px;
131
131
  }
132
132
  .sa-caps-row__flag--new {
133
- background: #fef3c7;
134
- color: #92400e;
133
+ background: var(--sa-color-warning-surface-strong);
134
+ color: var(--sa-color-warning-fg);
135
135
  }
136
136
  .sa-caps-row__flag--exp {
137
- background: #ede9fe;
138
- color: #6d28d9;
137
+ background: var(--sa-color-feature-surface);
138
+ color: var(--sa-color-feature-fg);
139
139
  }
140
140
  .sa-caps-row__flag--dep {
141
- background: #fee2e2;
142
- color: #b91c1c;
141
+ background: var(--sa-color-negative-surface-strong);
142
+ color: var(--sa-color-negative-fg);
143
143
  }
144
144
  .sa-caps-row__flag--gone {
145
- background: var(--sa-border);
146
- color: var(--sa-muted);
145
+ background: var(--sa-color-border);
146
+ color: var(--sa-color-fg-muted);
147
147
  }
148
148
  .sa-caps-row.gone {
149
149
  opacity: 0.6;
@@ -152,21 +152,21 @@ function isNew(cap: CapabilityCatalogEntryRow): boolean {
152
152
  display: flex;
153
153
  gap: 12px;
154
154
  flex-wrap: wrap;
155
- font-size: 11px;
156
- color: var(--sa-muted-dark);
155
+ font-size: var(--sa-text-xs);
156
+ color: var(--sa-color-fg-secondary);
157
157
  margin-top: 1px;
158
158
  }
159
159
  .sa-caps-row__meta code {
160
- font-size: 10px;
160
+ font-size: var(--sa-text-2xs);
161
161
  }
162
162
  .sa-caps__empty {
163
163
  display: flex;
164
164
  align-items: center;
165
165
  gap: 6px;
166
- font-size: 11px;
167
- color: #b45309;
168
- background: var(--sa-warning-bg);
169
- border: 1px dashed #fde68a;
166
+ font-size: var(--sa-text-xs);
167
+ color: var(--sa-color-warning-fg);
168
+ background: var(--sa-color-warning-surface);
169
+ border: 1px dashed var(--sa-color-warning-border);
170
170
  border-radius: 8px;
171
171
  padding: 10px 12px;
172
172
  }
@@ -269,14 +269,14 @@ function coverage(locale: string): number {
269
269
 
270
270
  <style scoped>
271
271
  .sa-fc {
272
- border: 1px solid var(--sa-border);
272
+ border: 1px solid var(--sa-color-border);
273
273
  border-radius: 10px;
274
- background: #fff;
274
+ background: var(--sa-color-bg-surface);
275
275
  overflow: hidden;
276
276
  }
277
277
  .sa-fc.expanded {
278
- border-color: #c7d2fe;
279
- box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
278
+ border-color: var(--sa-color-scheduled-border);
279
+ box-shadow: 0 1px 3px var(--sa-shadow-tint-2);
280
280
  }
281
281
  .sa-fc__head {
282
282
  display: flex;
@@ -286,7 +286,7 @@ function coverage(locale: string): number {
286
286
  cursor: pointer;
287
287
  }
288
288
  .sa-fc__icon {
289
- color: var(--sa-muted-dark);
289
+ color: var(--sa-color-fg-secondary);
290
290
  flex-shrink: 0;
291
291
  }
292
292
  .sa-fc__main {
@@ -300,55 +300,55 @@ function coverage(locale: string): number {
300
300
  flex-wrap: wrap;
301
301
  }
302
302
  .sa-fc__key {
303
- font-size: 11px;
303
+ font-size: var(--sa-text-xs);
304
304
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
305
- background: var(--sa-border-soft);
306
- color: var(--sa-muted-dark);
305
+ background: var(--sa-color-border-soft);
306
+ color: var(--sa-color-fg-secondary);
307
307
  padding: 2px 6px;
308
308
  border-radius: 5px;
309
309
  white-space: nowrap;
310
310
  }
311
311
  .sa-fc__label {
312
- font-size: 13px;
312
+ font-size: var(--sa-text-md);
313
313
  font-weight: 600;
314
- color: var(--sa-heading);
314
+ color: var(--sa-color-fg-heading);
315
315
  }
316
316
  .sa-fc__flag {
317
- font-size: 10px;
317
+ font-size: var(--sa-text-2xs);
318
318
  font-weight: 700;
319
319
  padding: 1px 6px;
320
320
  border-radius: 5px;
321
321
  }
322
322
  .sa-fc__flag--new {
323
- background: #fef3c7;
324
- color: #92400e;
323
+ background: var(--sa-color-warning-surface-strong);
324
+ color: var(--sa-color-warning-fg);
325
325
  }
326
326
  .sa-fc__flag--dep {
327
- background: #fee2e2;
328
- color: #b91c1c;
327
+ background: var(--sa-color-negative-surface-strong);
328
+ color: var(--sa-color-negative-fg);
329
329
  }
330
330
  .sa-fc__flag--succ {
331
- background: #fef3c7;
332
- color: #92400e;
331
+ background: var(--sa-color-warning-surface-strong);
332
+ color: var(--sa-color-warning-fg);
333
333
  }
334
334
  .sa-fc__flag--repl {
335
- background: #dbeafe;
336
- color: #1e40af;
335
+ background: var(--sa-color-info-surface-strong);
336
+ color: var(--sa-color-info-fg);
337
337
  }
338
338
  .sa-fc__sub {
339
- font-size: 11px;
340
- color: var(--sa-muted);
339
+ font-size: var(--sa-text-xs);
340
+ color: var(--sa-color-fg-muted);
341
341
  margin-top: 1px;
342
342
  }
343
343
  .sa-fc__dot {
344
344
  margin: 0 4px;
345
- color: #cbd5e1;
345
+ color: var(--sa-color-fg-disabled);
346
346
  }
347
347
  .sa-fc__tier {
348
348
  font-weight: 700;
349
349
  text-transform: uppercase;
350
350
  letter-spacing: 0.3px;
351
- color: #4f46e5;
351
+ color: var(--sa-color-scheduled);
352
352
  }
353
353
  .sa-fc__coverage {
354
354
  display: flex;
@@ -356,39 +356,39 @@ function coverage(locale: string): number {
356
356
  flex-shrink: 0;
357
357
  }
358
358
  .sa-fc__chev {
359
- color: var(--sa-muted-light);
359
+ color: var(--sa-color-fg-subtle);
360
360
  transition: transform 0.15s;
361
361
  }
362
362
  .sa-fc__chev.open {
363
363
  transform: rotate(90deg);
364
364
  }
365
365
  .sa-fc__body {
366
- border-top: 1px solid var(--sa-border-soft);
366
+ border-top: 1px solid var(--sa-color-border-soft);
367
367
  padding: 12px;
368
- background: var(--sa-bg-surface-2);
368
+ background: var(--sa-color-bg-sunken);
369
369
  }
370
370
  .sa-fc__banner {
371
371
  display: flex;
372
372
  align-items: center;
373
373
  gap: 8px;
374
- font-size: 12px;
374
+ font-size: var(--sa-text-sm);
375
375
  border-radius: 8px;
376
376
  padding: 8px 12px;
377
377
  margin-bottom: 10px;
378
378
  }
379
379
  .sa-fc__banner.warn {
380
- background: var(--sa-warning-bg);
381
- border: 1px solid #fde68a;
382
- color: #92400e;
380
+ background: var(--sa-color-warning-surface);
381
+ border: 1px solid var(--sa-color-warning-border);
382
+ color: var(--sa-color-warning-fg);
383
383
  }
384
384
  .sa-fc__banner.mute {
385
- background: var(--sa-border-soft);
386
- border: 1px solid var(--sa-border);
387
- color: var(--sa-muted-dark);
385
+ background: var(--sa-color-border-soft);
386
+ border: 1px solid var(--sa-color-border);
387
+ color: var(--sa-color-fg-secondary);
388
388
  }
389
389
  .sa-fc__subtabs {
390
390
  margin-bottom: 12px;
391
- border-bottom: 1px solid var(--sa-border);
391
+ border-bottom: 1px solid var(--sa-color-border);
392
392
  }
393
393
  .sa-fc__split {
394
394
  display: grid;
@@ -396,18 +396,18 @@ function coverage(locale: string): number {
396
396
  gap: 14px;
397
397
  }
398
398
  .sa-fc__split-head {
399
- font-size: 11px;
399
+ font-size: var(--sa-text-xs);
400
400
  font-weight: 700;
401
401
  text-transform: uppercase;
402
402
  letter-spacing: 0.5px;
403
- color: var(--sa-muted-light);
403
+ color: var(--sa-color-fg-subtle);
404
404
  margin-bottom: 8px;
405
405
  }
406
406
  .sa-fc__split-count {
407
407
  font-weight: 600;
408
408
  text-transform: none;
409
409
  letter-spacing: 0;
410
- color: #cbd5e1;
410
+ color: var(--sa-color-fg-disabled);
411
411
  margin-left: 6px;
412
412
  }
413
413
  .sa-fc__fields {
@@ -421,9 +421,9 @@ function coverage(locale: string): number {
421
421
  gap: 3px;
422
422
  }
423
423
  .sa-fc-field__cap {
424
- font-size: 11px;
424
+ font-size: var(--sa-text-xs);
425
425
  font-weight: 600;
426
426
  text-transform: uppercase;
427
- color: var(--sa-muted-light);
427
+ color: var(--sa-color-fg-subtle);
428
428
  }
429
429
  </style>
@@ -154,17 +154,17 @@ function coverage(locale: string): number {
154
154
 
155
155
  <style scoped>
156
156
  .sa-qc {
157
- border: 1px solid var(--sa-border);
157
+ border: 1px solid var(--sa-color-border);
158
158
  border-radius: 10px;
159
- background: #fff;
159
+ background: var(--sa-color-bg-surface);
160
160
  overflow: hidden;
161
161
  }
162
162
  .sa-qc.warn {
163
- border-color: #fecaca;
163
+ border-color: var(--sa-color-negative-border);
164
164
  }
165
165
  .sa-qc.expanded {
166
- border-color: #c7d2fe;
167
- box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
166
+ border-color: var(--sa-color-scheduled-border);
167
+ box-shadow: 0 1px 3px var(--sa-shadow-tint-2);
168
168
  }
169
169
  .sa-qc__head {
170
170
  display: flex;
@@ -174,7 +174,7 @@ function coverage(locale: string): number {
174
174
  cursor: pointer;
175
175
  }
176
176
  .sa-qc.warn .sa-qc__head {
177
- background: #fef2f2;
177
+ background: var(--sa-color-negative-surface);
178
178
  }
179
179
  .sa-qc__icon {
180
180
  flex-shrink: 0;
@@ -191,38 +191,38 @@ function coverage(locale: string): number {
191
191
  }
192
192
  .sa-qc__label {
193
193
  font-weight: 600;
194
- font-size: 13px;
195
- color: var(--sa-heading);
194
+ font-size: var(--sa-text-md);
195
+ color: var(--sa-color-fg-heading);
196
196
  }
197
197
  .sa-qc__key {
198
- font-size: 11px;
198
+ font-size: var(--sa-text-xs);
199
199
  }
200
200
  .sa-qc__flag {
201
- font-size: 10px;
201
+ font-size: var(--sa-text-2xs);
202
202
  font-weight: 700;
203
203
  padding: 1px 6px;
204
204
  border-radius: 5px;
205
205
  }
206
206
  .sa-qc__flag--succ {
207
- background: #fef3c7;
208
- color: #92400e;
207
+ background: var(--sa-color-warning-surface-strong);
208
+ color: var(--sa-color-warning-fg);
209
209
  }
210
210
  .sa-qc__flag--repl {
211
- background: #dbeafe;
212
- color: #1e40af;
211
+ background: var(--sa-color-info-surface-strong);
212
+ color: var(--sa-color-info-fg);
213
213
  }
214
214
  .sa-qc__sub {
215
- font-size: 11px;
216
- color: var(--sa-muted);
215
+ font-size: var(--sa-text-xs);
216
+ color: var(--sa-color-fg-muted);
217
217
  margin-top: 2px;
218
218
  }
219
219
  .sa-qc__missing {
220
- color: #b91c1c;
220
+ color: var(--sa-color-negative-fg);
221
221
  font-weight: 700;
222
222
  }
223
223
  .sa-qc__warning {
224
- font-size: 11px;
225
- color: #b91c1c;
224
+ font-size: var(--sa-text-xs);
225
+ color: var(--sa-color-negative-fg);
226
226
  margin-top: 4px;
227
227
  }
228
228
  .sa-qc__coverage {
@@ -231,27 +231,27 @@ function coverage(locale: string): number {
231
231
  flex-shrink: 0;
232
232
  }
233
233
  .sa-qc__chev {
234
- color: var(--sa-muted-light);
234
+ color: var(--sa-color-fg-subtle);
235
235
  transition: transform 0.15s;
236
236
  }
237
237
  .sa-qc__chev.open {
238
238
  transform: rotate(90deg);
239
239
  }
240
240
  .sa-qc__body {
241
- border-top: 1px solid var(--sa-border-soft);
241
+ border-top: 1px solid var(--sa-color-border-soft);
242
242
  padding: 12px;
243
- background: var(--sa-bg-surface-2);
243
+ background: var(--sa-color-bg-sunken);
244
244
  }
245
245
  .sa-qc__banner {
246
246
  display: flex;
247
247
  align-items: center;
248
248
  gap: 8px;
249
- font-size: 12px;
249
+ font-size: var(--sa-text-sm);
250
250
  border-radius: 8px;
251
251
  padding: 8px 12px;
252
252
  margin-bottom: 10px;
253
- background: var(--sa-warning-bg);
254
- border: 1px solid #fde68a;
255
- color: #92400e;
253
+ background: var(--sa-color-warning-surface);
254
+ border: 1px solid var(--sa-color-warning-border);
255
+ color: var(--sa-color-warning-fg);
256
256
  }
257
257
  </style>
@@ -71,6 +71,6 @@ const menu = computed(() => reviewMenuActions(props.status, msg.value));
71
71
  flex-shrink: 0;
72
72
  }
73
73
  .sa-stc__danger {
74
- color: #b91c1c;
74
+ color: var(--sa-color-negative-fg);
75
75
  }
76
76
  </style>
@@ -122,16 +122,19 @@ export function reviewMenuActions(
122
122
 
123
123
  // ─── Capability kind styling (read-only code facts, #20) ─────────────────────
124
124
 
125
- const KIND_COLORS: Record<string, string> = {
126
- endpoint: '#2563eb',
127
- service: '#7c3aed',
128
- job: '#0891b2',
129
- event: '#f59e0b',
125
+ // A capability kind is a category with no ranking, so it takes the identity
126
+ // ramp rather than a status colour: an endpoint is not "better" than a job.
127
+ import { IDENTITY_NEUTRAL, identityChipStyle } from '../../client/identity-accents.js';
128
+
129
+ const KIND_ACCENTS: Record<string, string> = {
130
+ endpoint: 'var(--sa-color-identity-1)',
131
+ service: 'var(--sa-color-identity-2)',
132
+ job: 'var(--sa-color-identity-5)',
133
+ event: 'var(--sa-color-identity-4)',
130
134
  };
131
135
 
132
136
  export function kindStyle(kind: string): Record<string, string> {
133
- const c = KIND_COLORS[kind] ?? '#64748b';
134
- return { background: `${c}1a`, color: c, borderColor: `${c}33` };
137
+ return identityChipStyle(KIND_ACCENTS[kind] ?? IDENTITY_NEUTRAL);
135
138
  }
136
139
 
137
140
  /**
@@ -26,11 +26,7 @@
26
26
  <div class="sa-marketing-plan-cell">
27
27
  <div
28
28
  class="sa-marketing-plan-mark"
29
- :style="{
30
- background: row.accent + '15',
31
- color: row.accent,
32
- borderColor: row.accent + '33',
33
- }"
29
+ :style="identityChipStyle(row.accent)"
34
30
  >
35
31
  {{ row.plan.planKey.slice(0, 3) }}
36
32
  </div>
@@ -462,6 +458,7 @@
462
458
 
463
459
  <script setup lang="ts">
464
460
  import type { MarketingTopFeature, PlanRow, PlanVersionRow } from '@saasicat/types';
461
+ import { identityChipStyle } from '../../client/identity-accents.js';
465
462
  import { formatMessage } from '../../client/i18n/format.js';
466
463
  import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
467
464
  import type { FeatureSuggestion, MarketingRow, ResolvedMarketing } from './types.js';
@@ -11,10 +11,7 @@
11
11
  </div>
12
12
  <div v-else class="sa-pv-diff-card">
13
13
  <header class="sa-pv-diff-card__head">
14
- <span
15
- class="sa-pv-diff-card__accent"
16
- :style="{ background: `${accent}14`, borderColor: `${accent}40` }"
17
- >
14
+ <span class="sa-pv-diff-card__accent" :style="accentWashStyle">
18
15
  <q-icon name="inventory_2" size="14px" :style="{ color: accent }" />
19
16
  </span>
20
17
  <span class="sa-pv-diff-card__name">{{ title }}</span>
@@ -38,6 +35,7 @@
38
35
  <script setup lang="ts">
39
36
  import { computed } from 'vue';
40
37
  import type { VersionChange } from '@saasicat/types';
38
+ import { identityChipStyle } from '../../client/identity-accents.js';
41
39
  import { formatMessage } from '../../client/i18n/format.js';
42
40
  import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
43
41
  import VersionDiffPreview from '../../components/VersionDiffPreview.vue';
@@ -52,6 +50,15 @@ const props = defineProps<{
52
50
  }>();
53
51
 
54
52
  const msg = useSaMessages('planVersions');
53
+
54
+ // The wash and the edge this badge always had — deliberately not the chip
55
+ // helper's third property. `identityChipStyle` also sets a text colour, and
56
+ // the icon inside already sets its own; no fixture renders this card, so a
57
+ // change nobody can observe is a change nobody should make.
58
+ const accentWashStyle = computed(() => {
59
+ const { background, borderColor } = identityChipStyle(props.accent);
60
+ return { background, borderColor };
61
+ });
55
62
  const common = useSaMessages('common');
56
63
 
57
64
  const changeCountLabel = computed(() => {
@@ -63,8 +70,8 @@ const changeCountLabel = computed(() => {
63
70
 
64
71
  <style scoped>
65
72
  .sa-pv-diff-card {
66
- background: #fff;
67
- border: 1px solid var(--sa-border, var(--sa-border));
73
+ background: var(--sa-color-bg-surface);
74
+ border: 1px solid var(--sa-color-border);
68
75
  border-radius: 10px;
69
76
  margin-bottom: 12px;
70
77
  overflow: hidden;
@@ -81,22 +88,22 @@ const changeCountLabel = computed(() => {
81
88
  width: 28px;
82
89
  height: 28px;
83
90
  border-radius: 7px;
84
- background: var(--sa-positive-soft, rgba(4, 120, 87, 0.1));
91
+ background: var(--sa-color-positive-surface);
85
92
  display: flex;
86
93
  align-items: center;
87
94
  justify-content: center;
88
95
  }
89
96
  .sa-pv-diff-card__noop-icon :deep(.q-icon) {
90
- color: var(--sa-positive, #047857);
97
+ color: var(--sa-color-positive-fg);
91
98
  }
92
99
 
93
100
  .sa-pv-diff-card__head {
94
101
  padding: 12px 16px;
95
- border-bottom: 1px solid var(--sa-border-soft, var(--sa-border-soft));
102
+ border-bottom: 1px solid var(--sa-color-border-soft);
96
103
  display: flex;
97
104
  align-items: center;
98
105
  gap: 12px;
99
- background: #fafbfc;
106
+ background: var(--sa-color-bg-surface-raised);
100
107
  }
101
108
  .sa-pv-diff-card__accent {
102
109
  width: 28px;
@@ -109,29 +116,29 @@ const changeCountLabel = computed(() => {
109
116
  }
110
117
  .sa-pv-diff-card__name {
111
118
  font-weight: 700;
112
- font-size: 14px;
113
- color: var(--sa-heading, var(--sa-heading));
119
+ font-size: var(--sa-text-lg);
120
+ color: var(--sa-color-fg-heading);
114
121
  font-family: var(--sa-font-head, system-ui, sans-serif);
115
122
  }
116
123
  .sa-pv-diff-card__ver {
117
124
  font-family: var(--sa-font-mono, ui-monospace, monospace);
118
- font-size: 11px;
125
+ font-size: var(--sa-text-xs);
119
126
  font-weight: 600;
120
- color: var(--sa-muted, var(--sa-muted));
121
- background: var(--sa-border-soft);
127
+ color: var(--sa-color-fg-muted);
128
+ background: var(--sa-color-border-soft);
122
129
  padding: 2px 6px;
123
130
  border-radius: 4px;
124
131
  }
125
132
  .sa-pv-diff-card__sub {
126
- font-size: 11.5px;
127
- color: var(--sa-muted, var(--sa-muted));
133
+ font-size: var(--sa-text-sm);
134
+ color: var(--sa-color-fg-muted);
128
135
  }
129
136
  .sa-pv-diff-card__count {
130
- font-size: 11px;
137
+ font-size: var(--sa-text-xs);
131
138
  font-weight: 700;
132
139
  letter-spacing: 0.06em;
133
- background: var(--sa-warning-soft, rgba(245, 158, 11, 0.1));
134
- color: var(--sa-warning, #b45309);
140
+ background: var(--sa-color-warning-surface-strong);
141
+ color: var(--sa-color-warning-fg);
135
142
  padding: 2px 8px;
136
143
  border-radius: 4px;
137
144
  margin-left: auto;