@saasicat/ui-vue 0.22.2 → 0.23.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 (108) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-LY52T4N4.js → chunk-TQQMKWN6.js} +58 -1
  3. package/dist/index.cjs +213 -159
  4. package/dist/index.d.cts +2 -2
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +7 -1
  7. package/dist/quasar/index.cjs +116 -20
  8. package/dist/quasar/index.d.cts +48 -3
  9. package/dist/quasar/index.d.ts +48 -3
  10. package/dist/quasar/index.js +58 -3
  11. package/dist/{use-super-admin-i18n-CgTuNi8h.d.cts → use-sa-theme-B5t7oXph.d.cts} +51 -1
  12. package/dist/{use-super-admin-i18n-CHNdsSlm.d.ts → use-sa-theme-OUBlaqgl.d.ts} +51 -1
  13. package/package.json +5 -2
  14. package/src/components/BundleVersionPublishDialog.vue +17 -17
  15. package/src/components/KvBlock.vue +6 -6
  16. package/src/components/MarketingPromotionsTab.vue +78 -78
  17. package/src/components/MfaPromptDialog.vue +2 -2
  18. package/src/components/TenantActionConfirmDialog.vue +5 -5
  19. package/src/components/VersionDiffPreview.vue +18 -18
  20. package/src/components/bundle-editor/BundleCreatePanel.vue +52 -52
  21. package/src/components/bundle-editor/BundleFeaturesEditor.vue +20 -20
  22. package/src/components/bundle-editor/BundlePlanCompatPicker.vue +33 -33
  23. package/src/components/bundle-editor/BundleQuotasEditor.vue +26 -26
  24. package/src/components/bundle-editor/BundleStatusBanner.vue +21 -21
  25. package/src/components/bundle-editor/BundleVersionInlineEditor.vue +48 -48
  26. package/src/components/bundle-editor/BundleVersionStrip.vue +30 -30
  27. package/src/components/dialogs/PilotCreateDialog.vue +20 -20
  28. package/src/components/dialogs/PilotEditDialog.vue +6 -6
  29. package/src/components/dialogs/PromoCodeCreateDialog.vue +9 -9
  30. package/src/components/dialogs/PromoCodeDialogFields.vue +61 -61
  31. package/src/components/dialogs/PromoCodeEditDialog.vue +11 -11
  32. package/src/components/dialogs/pilot-dialog.css +48 -48
  33. package/src/components/plan/PlanCycleToggle.vue +9 -16
  34. package/src/components/plan/PlanGrid.vue +30 -34
  35. package/src/components/plan/PriceSummary.vue +35 -35
  36. package/src/components/plan/PromoCodeInput.vue +26 -26
  37. package/src/components/plan/PublicBundleGrid.vue +32 -28
  38. package/src/components/plan-create-dialog/PlanCreateDialog.vue +49 -49
  39. package/src/components/plan-detail/PlanDetail.vue +172 -156
  40. package/src/components/plan-detail/PlanTitleEdit.vue +11 -11
  41. package/src/components/plan-list/PlanList.vue +98 -77
  42. package/src/components/plan-matrix/PlanMatrix.vue +89 -89
  43. package/src/components/plan-review/PlanReview.vue +60 -56
  44. package/src/components/plan-version-editor/PlanVersionEditor.vue +224 -200
  45. package/src/components/wizard-stepper/WizardStepper.vue +17 -17
  46. package/src/index.ts +1 -0
  47. package/src/pages-standard/AdminLayout.vue +58 -37
  48. package/src/pages-standard/AdminManifestErrorPage.vue +6 -6
  49. package/src/pages-standard/AuditPage.vue +3 -3
  50. package/src/pages-standard/BundlesPage.vue +36 -36
  51. package/src/pages-standard/DashboardPage.vue +17 -17
  52. package/src/pages-standard/DiscoveryPage.vue +55 -49
  53. package/src/pages-standard/EmailHistoryPage.vue +53 -71
  54. package/src/pages-standard/MarketingCatalogPage.vue +226 -218
  55. package/src/pages-standard/PilotsPage.vue +7 -6
  56. package/src/pages-standard/PlatformEmailPage.vue +18 -18
  57. package/src/pages-standard/PromoCodeDetailPage.vue +3 -3
  58. package/src/pages-standard/PromoCodesPage.vue +7 -6
  59. package/src/pages-standard/SuperAdminLoginPage.vue +39 -25
  60. package/src/pages-standard/SuperAdminSetupWizard.vue +44 -33
  61. package/src/pages-standard/TenantDetailPage.vue +7 -7
  62. package/src/pages-standard/TenantsPage.vue +11 -46
  63. package/src/pages-standard/bundles-page/BundleAccordionList.vue +13 -13
  64. package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +24 -24
  65. package/src/pages-standard/discovery-page/DiscoveryCapList.vue +22 -22
  66. package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +39 -39
  67. package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +26 -26
  68. package/src/pages-standard/discovery-page/DiscoveryStatusControl.vue +1 -1
  69. package/src/pages-standard/plan-versions/PlanDiffCard.vue +16 -16
  70. package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +21 -15
  71. package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +45 -45
  72. package/src/pages-standard/plans-page/PlanBundleOverview.vue +21 -15
  73. package/src/pages-standard/plans-page/PlanPublishDialog.vue +4 -4
  74. package/src/pages-standard/plans-page/PlansPageToast.vue +6 -6
  75. package/src/pages-standard/sa-theme.css +9 -687
  76. package/src/pages-standard/tenants/StatusPill.vue +13 -13
  77. package/src/pages-tenant/LimitsRow.vue +4 -4
  78. package/src/pages-tenant/MySubscriptionBundlesPage.vue +61 -61
  79. package/src/pages-tenant/OnboardingConfigurator.vue +24 -24
  80. package/src/pages-tenant/PackageSnapshotPanel.vue +10 -16
  81. package/src/pages-tenant/PendingVersionBanner.vue +12 -12
  82. package/src/pages-tenant/PlanChangeWizard.vue +20 -27
  83. package/src/pages-tenant/TenantPlanSection.vue +13 -21
  84. package/src/pages-tenant/UsageBar.vue +7 -7
  85. package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +14 -14
  86. package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +10 -10
  87. package/src/pages-tenant/tenant-plan-section/TenantFeatureMatrix.vue +2 -2
  88. package/src/quasar/create-super-admin-app.ts +96 -1
  89. package/src/quasar/dark-bridge.ts +66 -0
  90. package/src/quasar/index.ts +1 -0
  91. package/src/ui/theme/_breakpoints.scss +28 -0
  92. package/src/ui/theme/base.css +50 -0
  93. package/src/ui/theme/components/body.css +23 -0
  94. package/src/ui/theme/components/button.css +158 -0
  95. package/src/ui/theme/components/card.css +48 -0
  96. package/src/ui/theme/components/field.css +38 -0
  97. package/src/ui/theme/components/hero.css +46 -0
  98. package/src/ui/theme/components/paginator.css +63 -0
  99. package/src/ui/theme/components/section.css +67 -0
  100. package/src/ui/theme/components/statistics.css +189 -0
  101. package/src/ui/theme/components/table.css +60 -0
  102. package/src/ui/theme/index.css +42 -0
  103. package/src/ui/theme/tokens.legacy.css +147 -0
  104. package/src/ui/theme/tokens.primitive.css +108 -0
  105. package/src/ui/theme/tokens.scale.css +103 -0
  106. package/src/ui/theme/tokens.semantic.dark.css +173 -0
  107. package/src/ui/theme/tokens.semantic.light.css +212 -0
  108. package/src/vue/use-sa-theme.ts +154 -0
@@ -47,16 +47,17 @@
47
47
  >
48
48
  <template #row-actions="{ row }">
49
49
  <slot name="row-actions" :row="row">
50
- <q-btn
50
+ <button
51
51
  v-for="action in visibleActions(row)"
52
52
  :key="action.id"
53
- flat
54
- dense
55
- :icon="action.icon"
53
+ type="button"
54
+ class="sa-icon-btn"
55
+ :class="action.color === 'negative' ? 'sa-icon-btn--negative' : ''"
56
56
  :title="action.label"
57
- :color="action.color ?? 'grey-7'"
58
57
  @click="action.handler(row)"
59
- />
58
+ >
59
+ <q-icon :name="action.icon" size="18px" />
60
+ </button>
60
61
  </slot>
61
62
  </template>
62
63
  </AdminTable>
@@ -36,30 +36,30 @@
36
36
  </q-td>
37
37
  </template>
38
38
  <template #row-actions="{ row }">
39
- <q-btn
40
- flat
41
- dense
42
- icon="send"
43
- color="primary"
39
+ <button
40
+ type="button"
41
+ class="sa-icon-btn"
44
42
  :title="msg.provider.sendTestMail"
45
43
  @click="openTest(row)"
46
- />
47
- <q-btn
48
- flat
49
- dense
50
- icon="edit"
51
- color="grey-7"
44
+ >
45
+ <q-icon name="send" size="18px" />
46
+ </button>
47
+ <button
48
+ type="button"
49
+ class="sa-icon-btn"
52
50
  :title="common.edit"
53
51
  @click="openEdit(row)"
54
- />
55
- <q-btn
56
- flat
57
- dense
58
- icon="delete"
59
- color="negative"
52
+ >
53
+ <q-icon name="edit" size="18px" />
54
+ </button>
55
+ <button
56
+ type="button"
57
+ class="sa-icon-btn sa-icon-btn--negative"
60
58
  :title="common.delete"
61
59
  @click="onDelete(row)"
62
- />
60
+ >
61
+ <q-icon name="delete" size="18px" />
62
+ </button>
63
63
  </template>
64
64
  </AdminTable>
65
65
  </AdminSection>
@@ -297,11 +297,11 @@ const redemptionRows = computed(() => data.value?.redemptions ?? []);
297
297
  gap: 14px;
298
298
  }
299
299
  .sa-promo-detail__kv {
300
- background: #fafbfc;
301
- border: 1px solid var(--sa-border);
300
+ background: var(--sa-color-bg-surface-raised);
301
+ border: 1px solid var(--sa-color-border);
302
302
  border-radius: 8px;
303
303
  padding: 12px;
304
- font-size: 12px;
304
+ font-size: var(--sa-text-sm);
305
305
  margin: 0;
306
306
  overflow-x: auto;
307
307
  font-family: var(--sa-font-mono);
@@ -66,16 +66,17 @@
66
66
  </template>
67
67
  <template #row-actions="{ row }">
68
68
  <slot name="row-actions" :row="row" :reload="reload">
69
- <q-btn
69
+ <button
70
70
  v-for="action in visibleActions(row)"
71
71
  :key="action.id"
72
- flat
73
- dense
74
- :icon="action.icon"
72
+ type="button"
73
+ class="sa-icon-btn"
74
+ :class="action.color === 'negative' ? 'sa-icon-btn--negative' : ''"
75
75
  :title="action.label"
76
- :color="action.color ?? 'grey-7'"
77
76
  @click="action.handler(row)"
78
- />
77
+ >
78
+ <q-icon :name="action.icon" size="18px" />
79
+ </button>
79
80
  </slot>
80
81
  </template>
81
82
  </AdminTable>
@@ -199,7 +199,7 @@ async function handleSubmit(): Promise<void> {
199
199
  on top of the centered card on short viewports. */
200
200
  margin-left: auto;
201
201
  align-self: flex-start;
202
- color: var(--sa-login-tag-color, var(--sa-muted-dark));
202
+ color: var(--sa-login-tag-color, var(--sa-color-fg-secondary));
203
203
  }
204
204
  .sa-login-wrap {
205
205
  min-height: 100vh;
@@ -208,15 +208,19 @@ async function handleSubmit(): Promise<void> {
208
208
  align-items: center;
209
209
  justify-content: center;
210
210
  padding: 24px;
211
- background: linear-gradient(180deg, var(--sa-heading) 0%, #1e293b 100%);
211
+ background: linear-gradient(
212
+ 180deg,
213
+ var(--sa-color-inverse-bg) 0%,
214
+ var(--sa-color-inverse-surface) 100%
215
+ );
212
216
  }
213
217
  .sa-login-card {
214
218
  width: 420px;
215
219
  max-width: 92vw;
216
- background: #fff;
220
+ background: var(--sa-color-bg-surface);
217
221
  border-radius: 18px;
218
222
  padding: 32px;
219
- box-shadow: 0 24px 48px rgba(0, 0, 0, 0.25);
223
+ box-shadow: 0 24px 48px var(--sa-shadow-tint-4);
220
224
  }
221
225
  .sa-login-brand {
222
226
  display: flex;
@@ -234,10 +238,20 @@ async function handleSubmit(): Promise<void> {
234
238
  overflow: hidden;
235
239
  }
236
240
  .sa-login-logo--text {
237
- background: var(--sa-login-logo-bg, linear-gradient(135deg, var(--sa-muted-dark), #1e293b));
238
- color: var(--sa-login-logo-color, #fff);
241
+ background: var(
242
+ --sa-login-logo-bg,
243
+ linear-gradient(
244
+ 135deg,
245
+ var(--sa-color-inverse-surface-soft),
246
+ var(--sa-color-inverse-surface)
247
+ )
248
+ );
249
+ /* The fallback has to match the fallback background above, which is the
250
+ * invariant dark gradient — not the accent. An app that sets its own
251
+ * `--sa-login-logo-bg` sets `--sa-login-logo-color` with it. */
252
+ color: var(--sa-login-logo-color, var(--sa-color-inverse-fg));
239
253
  font-weight: 800;
240
- font-size: 18px;
254
+ font-size: var(--sa-text-xl);
241
255
  text-transform: uppercase;
242
256
  }
243
257
  .sa-login-logo--img img {
@@ -247,26 +261,26 @@ async function handleSubmit(): Promise<void> {
247
261
  }
248
262
  .sa-login-brand__name {
249
263
  font-weight: 800;
250
- font-size: 16px;
251
- color: var(--sa-heading);
264
+ font-size: var(--sa-text-lg);
265
+ color: var(--sa-color-fg-heading);
252
266
  line-height: 1.1;
253
267
  }
254
268
  .sa-login-brand__tag {
255
- font-size: 12px;
256
- color: var(--sa-login-tag-color, var(--sa-muted-dark));
269
+ font-size: var(--sa-text-sm);
270
+ color: var(--sa-login-tag-color, var(--sa-color-fg-secondary));
257
271
  text-transform: uppercase;
258
272
  letter-spacing: 0.08em;
259
273
  }
260
274
 
261
275
  .sa-login-title {
262
- font-size: 22px;
276
+ font-size: var(--sa-text-2xl);
263
277
  font-weight: 800;
264
- color: var(--sa-heading);
278
+ color: var(--sa-color-fg-heading);
265
279
  margin: 0 0 6px;
266
280
  }
267
281
  .sa-login-subtitle {
268
- font-size: 13px;
269
- color: var(--sa-muted-dark);
282
+ font-size: var(--sa-text-md);
283
+ color: var(--sa-color-fg-secondary);
270
284
  margin: 0 0 20px;
271
285
  line-height: 1.5;
272
286
  }
@@ -279,10 +293,10 @@ async function handleSubmit(): Promise<void> {
279
293
  width: 100%;
280
294
  }
281
295
  .sa-login-error {
282
- background: #fef2f2;
283
- border: 1px solid #fecaca;
284
- color: #b91c1c;
285
- font-size: 13px;
296
+ background: var(--sa-color-negative-surface);
297
+ border: 1px solid var(--sa-color-negative-border);
298
+ color: var(--sa-color-negative-fg);
299
+ font-size: var(--sa-text-md);
286
300
  margin-top: 4px;
287
301
  padding: 8px 12px;
288
302
  border-radius: 8px;
@@ -290,20 +304,20 @@ async function handleSubmit(): Promise<void> {
290
304
  .sa-login-hint {
291
305
  margin-top: 18px;
292
306
  padding: 10px 12px;
293
- background: var(--sa-border-soft);
307
+ background: var(--sa-color-border-soft);
294
308
  border-radius: 8px;
295
- font-size: 12px;
296
- color: var(--sa-muted-dark);
309
+ font-size: var(--sa-text-sm);
310
+ color: var(--sa-color-fg-secondary);
297
311
  }
298
312
  .sa-login-hint code {
299
- background: var(--sa-border);
313
+ background: var(--sa-color-border);
300
314
  padding: 1px 5px;
301
315
  border-radius: 4px;
302
316
  }
303
317
  .sa-login-env {
304
318
  margin-top: 18px;
305
- color: #cbd5e1;
306
- font-size: 12px;
319
+ color: var(--sa-color-inverse-fg-muted);
320
+ font-size: var(--sa-text-sm);
307
321
  text-transform: uppercase;
308
322
  letter-spacing: 0.08em;
309
323
  }
@@ -277,15 +277,19 @@ async function submitConfirm(): Promise<void> {
277
277
  align-items: center;
278
278
  justify-content: center;
279
279
  padding: 24px;
280
- background: linear-gradient(180deg, var(--sa-heading) 0%, #1e293b 100%);
280
+ background: linear-gradient(
281
+ 180deg,
282
+ var(--sa-color-inverse-bg) 0%,
283
+ var(--sa-color-inverse-surface) 100%
284
+ );
281
285
  }
282
286
  .sa-setup-card {
283
287
  width: 460px;
284
288
  max-width: 92vw;
285
- background: #fff;
289
+ background: var(--sa-color-bg-surface);
286
290
  border-radius: 18px;
287
291
  padding: 32px;
288
- box-shadow: 0 24px 48px rgba(0, 0, 0, 0.25);
292
+ box-shadow: 0 24px 48px var(--sa-shadow-tint-4);
289
293
  }
290
294
  .sa-setup-head {
291
295
  display: flex;
@@ -296,7 +300,7 @@ async function submitConfirm(): Promise<void> {
296
300
  .sa-setup-locale {
297
301
  margin-left: auto;
298
302
  align-self: flex-start;
299
- color: var(--sa-muted-dark);
303
+ color: var(--sa-color-fg-secondary);
300
304
  }
301
305
  .sa-setup-badge {
302
306
  width: 44px;
@@ -305,31 +309,38 @@ async function submitConfirm(): Promise<void> {
305
309
  display: flex;
306
310
  align-items: center;
307
311
  justify-content: center;
308
- background: linear-gradient(135deg, var(--sa-muted-dark), #1e293b);
309
- color: #fff;
312
+ background: linear-gradient(
313
+ 135deg,
314
+ var(--sa-color-inverse-surface-soft),
315
+ var(--sa-color-inverse-surface)
316
+ );
317
+ /* The gradient never moves, so the text on it must not either.
318
+ * `--sa-color-fg-on-accent` is white today but belongs to the accent, and
319
+ * the design guide tells a light brand to override it to something dark. */
320
+ color: var(--sa-color-inverse-fg);
310
321
  font-weight: 800;
311
- font-size: 18px;
322
+ font-size: var(--sa-text-xl);
312
323
  text-transform: uppercase;
313
324
  }
314
325
  .sa-setup-title {
315
326
  margin: 0;
316
327
  font-weight: 800;
317
- font-size: 18px;
318
- color: var(--sa-heading);
328
+ font-size: var(--sa-text-xl);
329
+ color: var(--sa-color-fg-heading);
319
330
  line-height: 1.1;
320
331
  }
321
332
  .sa-setup-sub {
322
- font-size: 12px;
323
- color: var(--sa-muted-dark);
333
+ font-size: var(--sa-text-sm);
334
+ color: var(--sa-color-fg-secondary);
324
335
  }
325
336
  .sa-setup-hint {
326
- font-size: 13px;
327
- color: var(--sa-muted-dark);
337
+ font-size: var(--sa-text-md);
338
+ color: var(--sa-color-fg-secondary);
328
339
  line-height: 1.5;
329
340
  margin: 0 0 16px;
330
341
  }
331
342
  .sa-setup-hint code {
332
- background: var(--sa-border);
343
+ background: var(--sa-color-border);
333
344
  padding: 1px 5px;
334
345
  border-radius: 4px;
335
346
  }
@@ -341,10 +352,10 @@ async function submitConfirm(): Promise<void> {
341
352
  width: 100%;
342
353
  }
343
354
  .sa-setup-error {
344
- background: #fef2f2;
345
- border: 1px solid #fecaca;
346
- color: #b91c1c;
347
- font-size: 13px;
355
+ background: var(--sa-color-negative-surface);
356
+ border: 1px solid var(--sa-color-negative-border);
357
+ color: var(--sa-color-negative-fg);
358
+ font-size: var(--sa-text-md);
348
359
  margin-bottom: 16px;
349
360
  padding: 8px 12px;
350
361
  border-radius: 8px;
@@ -357,46 +368,46 @@ async function submitConfirm(): Promise<void> {
357
368
  margin-bottom: 12px;
358
369
  }
359
370
  .sa-setup-qr img {
360
- border: 1px solid var(--sa-border);
371
+ border: 1px solid var(--sa-color-border);
361
372
  border-radius: 8px;
362
373
  padding: 8px;
363
- background: #fff;
374
+ background: var(--sa-color-bg-surface);
364
375
  }
365
376
  .sa-setup-qr__hint {
366
- font-size: 12px;
367
- color: var(--sa-muted);
377
+ font-size: var(--sa-text-sm);
378
+ color: var(--sa-color-fg-muted);
368
379
  }
369
380
  .sa-setup-secret {
370
- background: var(--sa-border-soft);
381
+ background: var(--sa-color-border-soft);
371
382
  border-radius: 8px;
372
383
  padding: 10px 12px;
373
384
  margin-bottom: 10px;
374
385
  }
375
386
  .sa-setup-secret__label {
376
- font-size: 11px;
387
+ font-size: var(--sa-text-xs);
377
388
  text-transform: uppercase;
378
389
  letter-spacing: 0.06em;
379
- color: var(--sa-muted);
390
+ color: var(--sa-color-fg-muted);
380
391
  margin-bottom: 4px;
381
392
  }
382
393
  .sa-setup-secret__value {
383
- font-size: 15px;
394
+ font-size: var(--sa-text-lg);
384
395
  font-weight: 700;
385
- color: var(--sa-heading);
396
+ color: var(--sa-color-fg-heading);
386
397
  word-break: break-all;
387
398
  letter-spacing: 0.04em;
388
399
  }
389
400
  .sa-setup-uri {
390
401
  margin: 4px 0 4px;
391
- font-size: 12px;
392
- color: var(--sa-muted-dark);
402
+ font-size: var(--sa-text-sm);
403
+ color: var(--sa-color-fg-secondary);
393
404
  }
394
405
  .sa-setup-uri__value {
395
406
  display: block;
396
407
  margin-top: 6px;
397
408
  word-break: break-all;
398
- color: #334155;
399
- background: var(--sa-bg-surface-2);
409
+ color: var(--sa-color-fg-body);
410
+ background: var(--sa-color-bg-sunken);
400
411
  padding: 6px 8px;
401
412
  border-radius: 6px;
402
413
  }
@@ -405,8 +416,8 @@ async function submitConfirm(): Promise<void> {
405
416
  width: 100%;
406
417
  background: none;
407
418
  border: none;
408
- color: var(--sa-muted);
409
- font-size: 12px;
419
+ color: var(--sa-color-fg-muted);
420
+ font-size: var(--sa-text-sm);
410
421
  cursor: pointer;
411
422
  text-decoration: underline;
412
423
  }
@@ -327,13 +327,13 @@ const defaultUserColumns = computed<QTableColumn[]>(() => [
327
327
  display: flex;
328
328
  justify-content: space-between;
329
329
  align-items: center;
330
- border-bottom: 1px solid var(--sa-border-soft);
330
+ border-bottom: 1px solid var(--sa-color-border-soft);
331
331
  padding-bottom: 14px;
332
332
  margin-bottom: 16px;
333
333
  }
334
334
  .sa-tenant-detail__card-sub {
335
- color: var(--sa-muted);
336
- font-size: 13px;
335
+ color: var(--sa-color-fg-muted);
336
+ font-size: var(--sa-text-md);
337
337
  margin: 4px 0 0;
338
338
  }
339
339
  .sa-tenant-detail__card-actions {
@@ -343,13 +343,13 @@ const defaultUserColumns = computed<QTableColumn[]>(() => [
343
343
  align-items: center;
344
344
  }
345
345
  .sa-tenant-detail__empty {
346
- color: var(--sa-muted);
347
- font-size: 13px;
346
+ color: var(--sa-color-fg-muted);
347
+ font-size: var(--sa-text-md);
348
348
  }
349
349
  code {
350
- background: rgba(15, 23, 42, 0.06);
350
+ background: var(--sa-color-bg-sunken);
351
351
  padding: 1px 6px;
352
352
  border-radius: 4px;
353
- font-size: 12px;
353
+ font-size: var(--sa-text-sm);
354
354
  }
355
355
  </style>
@@ -119,8 +119,8 @@
119
119
  v-for="action in visibleActions(row)"
120
120
  :key="action.id"
121
121
  :href="action.to ? action.to(row) : undefined"
122
- class="sa-tenants__icon-btn"
123
- :class="action.tone ? `sa-tenants__icon-btn--${action.tone}` : ''"
122
+ class="sa-icon-btn"
123
+ :class="action.tone ? `sa-icon-btn--${action.tone}` : ''"
124
124
  :title="action.label"
125
125
  @click="action.handler ? action.handler(row) : undefined"
126
126
  >
@@ -543,7 +543,7 @@ function visibleActions(row: TenantRow): TenantRowAction[] {
543
543
  AdminTable, behind a prop. */
544
544
  .sa-tenants__mono {
545
545
  font-family: var(--sa-font-mono, ui-monospace, monospace);
546
- font-size: 12px;
546
+ font-size: var(--sa-text-sm);
547
547
  }
548
548
 
549
549
  .sa-tenants__tenant {
@@ -556,7 +556,7 @@ function visibleActions(row: TenantRow): TenantRowAction[] {
556
556
  height: 32px;
557
557
  border-radius: 8px;
558
558
  font-weight: 800;
559
- font-size: 12px;
559
+ font-size: var(--sa-text-sm);
560
560
  font-family: var(--sa-font-head, system-ui, sans-serif);
561
561
  display: flex;
562
562
  align-items: center;
@@ -564,13 +564,13 @@ function visibleActions(row: TenantRow): TenantRowAction[] {
564
564
  flex-shrink: 0;
565
565
  }
566
566
  .sa-tenants__name {
567
- font-size: 13px;
567
+ font-size: var(--sa-text-md);
568
568
  font-weight: 600;
569
- color: var(--sa-heading, var(--sa-heading));
569
+ color: var(--sa-color-fg-heading);
570
570
  }
571
571
  .sa-tenants__slug {
572
- font-size: 11px;
573
- color: var(--sa-muted, var(--sa-muted));
572
+ font-size: var(--sa-text-xs);
573
+ color: var(--sa-color-fg-muted);
574
574
  font-family: var(--sa-font-mono, ui-monospace, monospace);
575
575
  }
576
576
 
@@ -595,46 +595,11 @@ function visibleActions(row: TenantRow): TenantRowAction[] {
595
595
  display: inline-flex;
596
596
  align-items: center;
597
597
  gap: 4px;
598
- font-size: 12px;
599
- color: var(--sa-muted-dark, var(--sa-muted-dark));
598
+ font-size: var(--sa-text-sm);
599
+ color: var(--sa-color-fg-secondary);
600
600
  margin-left: 8px;
601
601
  }
602
602
  .sa-tenants__usage :deep(.q-icon) {
603
- color: var(--sa-muted, var(--sa-muted));
604
- }
605
-
606
- .sa-tenants__icon-btn {
607
- background: transparent;
608
- border: none;
609
- cursor: pointer;
610
- width: 28px;
611
- height: 28px;
612
- border-radius: 6px;
613
- display: inline-flex;
614
- align-items: center;
615
- justify-content: center;
616
- text-decoration: none;
617
- color: var(--sa-muted, var(--sa-muted));
618
- }
619
- .sa-tenants__icon-btn:hover {
620
- background: var(--sa-border-soft);
621
- }
622
- .sa-tenants__icon-btn :deep(.q-icon) {
623
- color: inherit;
624
- }
625
- .sa-tenants__icon-btn--negative {
626
- color: var(--sa-negative, #dc2626);
627
- }
628
- .sa-tenants__icon-btn--positive {
629
- color: var(--sa-positive, #047857);
630
- }
631
- .sa-tenants__icon-btn--primary {
632
- color: var(--sa-primary, #3f6bff);
633
- }
634
- .sa-tenants__icon-btn--warning {
635
- color: var(--sa-warning, #d97706);
636
- }
637
- .sa-tenants__icon-btn--accent {
638
- color: var(--sa-accent, #7c3aed);
603
+ color: var(--sa-color-fg-muted);
639
604
  }
640
605
  </style>
@@ -100,31 +100,31 @@ function translationCount(bundle: BundleRow): string {
100
100
  DiscoveryPage.vue would otherwise override .sa-bundle-chip--live (same specificity,
101
101
  later source order) and render the "Live" tag grey instead of green. */
102
102
  .sa-bundle-chip {
103
- font-size: 10px;
103
+ font-size: var(--sa-text-2xs);
104
104
  font-weight: 600;
105
105
  padding: 2px 7px;
106
106
  border-radius: 6px;
107
- background: var(--sa-border-soft);
108
- color: var(--sa-muted-dark);
107
+ background: var(--sa-color-border-soft);
108
+ color: var(--sa-color-fg-secondary);
109
109
  }
110
110
  .sa-bundle-chip--info {
111
- background: var(--sa-primary-50);
112
- color: var(--sa-primary-strong);
111
+ background: var(--sa-color-accent-surface-strong);
112
+ color: var(--sa-color-accent-strong);
113
113
  }
114
114
  .sa-bundle-chip--live {
115
- background: #dcfce7;
116
- color: #166534;
115
+ background: var(--sa-color-positive-surface-strong);
116
+ color: var(--sa-color-positive-fg);
117
117
  }
118
118
  .sa-bundle-chip--draft {
119
- background: #fef3c7;
120
- color: #92400e;
119
+ background: var(--sa-color-warning-surface-strong);
120
+ color: var(--sa-color-warning-fg);
121
121
  }
122
122
  .sa-bundle-chip--supersed {
123
- background: var(--sa-border);
124
- color: var(--sa-muted);
123
+ background: var(--sa-color-border);
124
+ color: var(--sa-color-fg-muted);
125
125
  }
126
126
  .sa-bundle-chip--scheduled {
127
- background: #fef3c7;
128
- color: #92400e;
127
+ background: var(--sa-color-warning-surface-strong);
128
+ color: var(--sa-color-warning-fg);
129
129
  }
130
130
  </style>