@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
@@ -223,6 +223,7 @@ import PlanGrid from '../components/plan/PlanGrid.vue';
223
223
  import { useSuperAdminI18n } from '../vue/use-super-admin-i18n.js';
224
224
  import type { BillingCycleStr, PlanChangePreviewShape } from '../vue/use-tenant-billing.js';
225
225
  import type { CatalogPlan } from '../vue/use-tenant-billing-catalog.js';
226
+ import type { PlanChangeWizardI18n } from './default-i18n.js';
226
227
 
227
228
  // PlanChangeWizard — 3-step dialog for plan changes.
228
229
  //
@@ -231,54 +232,6 @@ import type { CatalogPlan } from '../vue/use-tenant-billing-catalog.js';
231
232
  // the limits check + proration + feature diff + blockers, step 3 calls `changePlan`.
232
233
  // Data-driven via the passed `catalogQuotaKeys[]` — no hard-coded trinity.
233
234
 
234
- interface I18nStrings {
235
- title: string;
236
- close: string;
237
- currentLabel: string;
238
- cycleMonthly: string;
239
- cycleYearly: string;
240
- badgeCurrent: string;
241
- badgePopular: string;
242
- priceUnitMonthly: string;
243
- priceUnitYearly: string;
244
- priceOnRequest: string;
245
- stepChoose: string;
246
- stepChooseIntro: string;
247
- stepPreview: string;
248
- stepConfirm: string;
249
- next: string;
250
- back: string;
251
- previewLoading: string;
252
- effectiveAtLabel: string;
253
- effectiveImmediate: string;
254
- prorationTitle: string;
255
- prorationLine: string;
256
- prorationDays: string;
257
- limitsTitle: string;
258
- limitsUsed: string;
259
- limitsCurrent: string;
260
- limitsTarget: string;
261
- featuresGained: string;
262
- featuresLost: string;
263
- blockersTitle: string;
264
- confirmImmediate: string;
265
- confirmScheduled: string;
266
- confirmAction: string;
267
- confirmInProgress: string;
268
- confirmPriceTitle: string;
269
- confirmProratedNow: string;
270
- confirmRecurringNext: string;
271
- confirmRecurringFrom: string;
272
- perCycleMonthly: string;
273
- perCycleYearly: string;
274
- confirmTrialNote: string;
275
- confirmRecurringTrialEnd: string;
276
- changeTypeUpgrade: string;
277
- changeTypeDowngrade: string;
278
- changeTypeCycle: string;
279
- changeTypeNoop: string;
280
- }
281
-
282
235
  interface Props {
283
236
  modelValue: boolean;
284
237
  plans: CatalogPlan[];
@@ -314,7 +267,7 @@ interface Props {
314
267
  /** Preview caller (passed through from the consumer composable). */
315
268
  previewPlanChange: (plan: string, cycle: BillingCycleStr) => Promise<PlanChangePreviewShape>;
316
269
  changePlan: (plan: string, cycle: BillingCycleStr, immediate: boolean) => Promise<void>;
317
- i18n: I18nStrings;
270
+ i18n: PlanChangeWizardI18n;
318
271
  }
319
272
 
320
273
  const props = defineProps<Props>();
@@ -511,18 +464,11 @@ watch(
511
464
  }
512
465
  /* CSS vars for light + dark mode */
513
466
  .sp-wizard {
514
- --sp-wiz-border: rgba(0, 0, 0, 0.08);
515
- --sp-wiz-text-strong: rgba(0, 0, 0, 0.87);
516
- --sp-wiz-text-muted: rgba(0, 0, 0, 0.6);
517
- --sp-wiz-text-faint: rgba(0, 0, 0, 0.55);
518
- --sp-wiz-border-soft: rgba(0, 0, 0, 0.1);
519
- }
520
- :global(.body--dark) .sp-wizard {
521
- --sp-wiz-border: rgba(255, 255, 255, 0.12);
522
- --sp-wiz-text-strong: rgba(255, 255, 255, 0.92);
523
- --sp-wiz-text-muted: rgba(255, 255, 255, 0.7);
524
- --sp-wiz-text-faint: rgba(255, 255, 255, 0.6);
525
- --sp-wiz-border-soft: rgba(255, 255, 255, 0.18);
467
+ --sp-wiz-border: var(--sa-color-border);
468
+ --sp-wiz-text-strong: var(--sa-color-fg-heading);
469
+ --sp-wiz-text-muted: var(--sa-color-fg-secondary);
470
+ --sp-wiz-text-faint: var(--sa-color-fg-muted);
471
+ --sp-wiz-border-soft: var(--sa-color-border-soft);
526
472
  }
527
473
  .sp-wizard__head {
528
474
  display: flex;
@@ -531,13 +477,13 @@ watch(
531
477
  border-bottom: 1px solid var(--sp-wiz-border);
532
478
  }
533
479
  .sp-wizard__title {
534
- font-size: 18px;
480
+ font-size: var(--sa-text-xl);
535
481
  font-weight: 600;
536
482
  color: var(--sp-wiz-text-strong);
537
483
  }
538
484
  .sp-wizard__sub {
539
485
  color: var(--sp-wiz-text-muted);
540
- font-size: 13px;
486
+ font-size: var(--sa-text-md);
541
487
  }
542
488
  .sp-wizard__intro {
543
489
  color: var(--sp-wiz-text-muted);
@@ -550,8 +496,8 @@ watch(
550
496
  padding: 24px 0;
551
497
  }
552
498
  .sp-wizard__error {
553
- color: var(--q-negative, #c10015);
554
- background: rgba(193, 0, 21, 0.08);
499
+ color: var(--sa-color-negative);
500
+ background: var(--sa-color-negative-surface);
555
501
  padding: 12px;
556
502
  border-radius: 4px;
557
503
  }
@@ -559,14 +505,14 @@ watch(
559
505
  margin-bottom: 12px;
560
506
  }
561
507
  .sp-wizard__proration {
562
- background: rgba(25, 118, 210, 0.06);
508
+ background: var(--sa-color-info-surface);
563
509
  padding: 12px 14px;
564
510
  border-radius: 4px;
565
511
  margin-top: 12px;
566
512
  }
567
513
  .sp-wizard__proration h4 {
568
514
  margin: 0 0 6px;
569
- font-size: 14px;
515
+ font-size: var(--sa-text-lg);
570
516
  }
571
517
  .sp-wizard__proration p {
572
518
  margin: 0;
@@ -579,7 +525,7 @@ watch(
579
525
  .sp-wizard__limits thead th {
580
526
  padding: 6px 12px;
581
527
  text-align: left;
582
- font-size: 12px;
528
+ font-size: var(--sa-text-sm);
583
529
  color: var(--sp-wiz-text-faint);
584
530
  text-transform: uppercase;
585
531
  border-bottom: 1px solid var(--sp-wiz-border-soft);
@@ -592,33 +538,33 @@ watch(
592
538
  .sp-wizard__feat h4,
593
539
  .sp-wizard__blockers h4 {
594
540
  margin: 0 0 6px;
595
- font-size: 14px;
541
+ font-size: var(--sa-text-lg);
596
542
  }
597
543
  .sp-wizard__feat--warn {
598
- color: rgba(193, 0, 21, 0.8);
544
+ color: var(--sa-color-negative);
599
545
  }
600
546
  .sp-wizard__blockers {
601
- color: var(--q-negative, #c10015);
602
- background: rgba(193, 0, 21, 0.06);
547
+ color: var(--sa-color-negative);
548
+ background: var(--sa-color-negative-surface);
603
549
  padding: 12px 14px;
604
550
  border-radius: 4px;
605
551
  }
606
552
  .sp-wizard__warnings {
607
- color: var(--q-warning, #c87b00);
608
- font-size: 13px;
553
+ color: var(--sa-color-warning);
554
+ font-size: var(--sa-text-md);
609
555
  }
610
556
  .sp-wizard__confirm-line {
611
557
  color: var(--sp-wiz-text-muted);
612
558
  }
613
559
  .sp-wizard__price-summary {
614
560
  margin-top: 16px;
615
- background: rgba(25, 118, 210, 0.06);
561
+ background: var(--sa-color-info-surface);
616
562
  padding: 12px 14px;
617
563
  border-radius: 4px;
618
564
  }
619
565
  .sp-wizard__price-summary h4 {
620
566
  margin: 0 0 8px;
621
- font-size: 14px;
567
+ font-size: var(--sa-text-lg);
622
568
  }
623
569
  .sp-wizard__price-row {
624
570
  display: flex;
@@ -198,7 +198,11 @@ import { computed, ref } from 'vue';
198
198
  import PackageSnapshotPanel from './PackageSnapshotPanel.vue';
199
199
  import PendingVersionBanner from './PendingVersionBanner.vue';
200
200
  import PlanChangeWizard from './PlanChangeWizard.vue';
201
- import { defaultTenantPlanSectionI18n, type TenantPlanSectionI18n } from './default-i18n.js';
201
+ import {
202
+ defaultTenantPlanSectionI18n,
203
+ planChangeWizardI18n,
204
+ type TenantPlanSectionI18n,
205
+ } from './default-i18n.js';
202
206
  import BundlePreviewDialog from './tenant-plan-section/BundlePreviewDialog.vue';
203
207
  import TenantBundleStore from './tenant-plan-section/TenantBundleStore.vue';
204
208
  import TenantFeatureMatrix from './tenant-plan-section/TenantFeatureMatrix.vue';
@@ -429,53 +433,7 @@ const statusColor = computed(() => {
429
433
  }
430
434
  });
431
435
 
432
- const wizardI18n = computed(() => ({
433
- title: effectiveI18n.value.wizardTitle,
434
- close: effectiveI18n.value.wizardClose,
435
- currentLabel: effectiveI18n.value.wizardCurrent,
436
- cycleMonthly: effectiveI18n.value.cycleMonthly,
437
- cycleYearly: effectiveI18n.value.cycleYearly,
438
- badgeCurrent: effectiveI18n.value.wizardBadgeCurrent,
439
- badgePopular: effectiveI18n.value.wizardBadgePopular,
440
- priceUnitMonthly: effectiveI18n.value.wizardPriceUnitMonthly,
441
- priceUnitYearly: effectiveI18n.value.wizardPriceUnitYearly,
442
- priceOnRequest: effectiveI18n.value.wizardPriceOnRequest,
443
- stepChoose: effectiveI18n.value.wizardStepChoose,
444
- stepChooseIntro: effectiveI18n.value.wizardStepChooseIntro,
445
- stepPreview: effectiveI18n.value.wizardStepPreview,
446
- stepConfirm: effectiveI18n.value.wizardStepConfirm,
447
- next: effectiveI18n.value.wizardNext,
448
- back: effectiveI18n.value.wizardBack,
449
- previewLoading: effectiveI18n.value.wizardPreviewLoading,
450
- effectiveAtLabel: effectiveI18n.value.wizardEffectiveAtLabel,
451
- effectiveImmediate: effectiveI18n.value.wizardEffectiveImmediate,
452
- prorationTitle: effectiveI18n.value.wizardProrationTitle,
453
- prorationLine: effectiveI18n.value.wizardProrationLine,
454
- prorationDays: effectiveI18n.value.wizardProrationDays,
455
- limitsTitle: effectiveI18n.value.wizardLimitsTitle,
456
- limitsUsed: effectiveI18n.value.wizardLimitsUsed,
457
- limitsCurrent: effectiveI18n.value.wizardLimitsCurrent,
458
- limitsTarget: effectiveI18n.value.wizardLimitsTarget,
459
- featuresGained: effectiveI18n.value.wizardFeaturesGained,
460
- featuresLost: effectiveI18n.value.wizardFeaturesLost,
461
- blockersTitle: effectiveI18n.value.wizardBlockersTitle,
462
- confirmImmediate: effectiveI18n.value.wizardConfirmImmediate,
463
- confirmScheduled: effectiveI18n.value.wizardConfirmScheduled,
464
- confirmAction: effectiveI18n.value.wizardConfirmAction,
465
- confirmInProgress: effectiveI18n.value.wizardConfirmInProgress,
466
- confirmPriceTitle: effectiveI18n.value.wizardConfirmPriceTitle,
467
- confirmProratedNow: effectiveI18n.value.wizardConfirmProratedNow,
468
- confirmRecurringNext: effectiveI18n.value.wizardConfirmRecurringNext,
469
- confirmRecurringFrom: effectiveI18n.value.wizardConfirmRecurringFrom,
470
- perCycleMonthly: effectiveI18n.value.wizardConfirmPerCycleMonthly,
471
- perCycleYearly: effectiveI18n.value.wizardConfirmPerCycleYearly,
472
- confirmTrialNote: effectiveI18n.value.wizardConfirmTrialNote,
473
- confirmRecurringTrialEnd: effectiveI18n.value.wizardConfirmRecurringTrialEnd,
474
- changeTypeUpgrade: effectiveI18n.value.wizardChangeTypeUpgrade,
475
- changeTypeDowngrade: effectiveI18n.value.wizardChangeTypeDowngrade,
476
- changeTypeCycle: effectiveI18n.value.wizardChangeTypeCycle,
477
- changeTypeNoop: effectiveI18n.value.wizardChangeTypeNoop,
478
- }));
436
+ const wizardI18n = computed(() => planChangeWizardI18n(effectiveI18n.value));
479
437
 
480
438
  // Helper hooks with defaults
481
439
  function quotaLabelResolved(key: string): string {
@@ -616,25 +574,17 @@ async function changePlan(plan: string, cycle: 'MONTHLY' | 'YEARLY', immediate:
616
574
 
617
575
  <style>
618
576
  .sp-plan-section {
619
- --sp-text-secondary: rgba(0, 0, 0, 0.6);
620
- --sp-text-muted: rgba(0, 0, 0, 0.55);
621
- --sp-text-disabled: rgba(0, 0, 0, 0.5);
622
- --sp-text-strong: rgba(0, 0, 0, 0.7);
623
- --sp-border: rgba(0, 0, 0, 0.08);
624
- --sp-summary-bg: rgba(25, 118, 210, 0.06);
577
+ --sp-text-secondary: var(--sa-color-fg-secondary);
578
+ --sp-text-muted: var(--sa-color-fg-muted);
579
+ --sp-text-disabled: var(--sa-color-fg-subtle);
580
+ --sp-text-strong: var(--sa-color-fg-body);
581
+ --sp-border: var(--sa-color-border);
582
+ --sp-summary-bg: var(--sa-color-info-surface);
625
583
 
626
584
  display: flex;
627
585
  flex-direction: column;
628
586
  gap: 16px;
629
587
  }
630
- body.body--dark .sp-plan-section {
631
- --sp-text-secondary: rgba(255, 255, 255, 0.72);
632
- --sp-text-muted: rgba(255, 255, 255, 0.62);
633
- --sp-text-disabled: rgba(255, 255, 255, 0.5);
634
- --sp-text-strong: rgba(255, 255, 255, 0.85);
635
- --sp-border: rgba(255, 255, 255, 0.16);
636
- --sp-summary-bg: rgba(25, 118, 210, 0.18);
637
- }
638
588
  .sp-plan-section__loading,
639
589
  .sp-plan-section__empty {
640
590
  display: flex;
@@ -644,8 +594,8 @@ body.body--dark .sp-plan-section {
644
594
  color: var(--sp-text-secondary);
645
595
  }
646
596
  .sp-plan-section__error {
647
- color: var(--q-negative, #c10015);
648
- background: rgba(193, 0, 21, 0.08);
597
+ color: var(--sa-color-negative);
598
+ background: var(--sa-color-negative-surface);
649
599
  padding: 12px 16px;
650
600
  border-radius: 4px;
651
601
  }
@@ -657,7 +607,7 @@ body.body--dark .sp-plan-section {
657
607
  flex-wrap: wrap;
658
608
  }
659
609
  .sp-plan-section__eyebrow {
660
- font-size: 12px;
610
+ font-size: var(--sa-text-sm);
661
611
  text-transform: uppercase;
662
612
  letter-spacing: 0.05em;
663
613
  color: var(--sp-text-muted);
@@ -665,7 +615,7 @@ body.body--dark .sp-plan-section {
665
615
  }
666
616
  .sp-plan-section__plan-name {
667
617
  margin: 0 0 8px;
668
- font-size: 22px;
618
+ font-size: var(--sa-text-2xl);
669
619
  font-weight: 600;
670
620
  }
671
621
  .sp-plan-section__meta {
@@ -683,7 +633,7 @@ body.body--dark .sp-plan-section {
683
633
  .sp-plan-section__sub {
684
634
  margin: 6px 0 0;
685
635
  color: var(--sp-text-muted);
686
- font-size: 13px;
636
+ font-size: var(--sa-text-md);
687
637
  }
688
638
  .sp-plan-section__usage-title {
689
639
  font-weight: 600;
@@ -716,10 +666,10 @@ body.body--dark .sp-plan-section {
716
666
  }
717
667
  .sp-plan-section__item-price {
718
668
  color: var(--sp-text-secondary);
719
- font-size: 13px;
669
+ font-size: var(--sa-text-md);
720
670
  }
721
671
  .sp-plan-section__item-canceled {
722
672
  color: var(--sp-text-disabled);
723
- font-size: 13px;
673
+ font-size: var(--sa-text-md);
724
674
  }
725
675
  </style>
@@ -73,20 +73,20 @@ const formattedMax = computed(() => {
73
73
  display: flex;
74
74
  justify-content: space-between;
75
75
  align-items: center;
76
- font-size: 13px;
76
+ font-size: var(--sa-text-md);
77
77
  }
78
78
  .sp-usage-bar__label {
79
- color: var(--q-secondary, #555);
79
+ color: var(--sa-color-fg-secondary);
80
80
  font-weight: 500;
81
81
  }
82
82
  .sp-usage-bar__values {
83
83
  font-variant-numeric: tabular-nums;
84
- color: var(--q-secondary, #555);
84
+ color: var(--sa-color-fg-secondary);
85
85
  }
86
86
  .sp-usage-bar__track {
87
87
  width: 100%;
88
88
  height: 8px;
89
- background: rgba(0, 0, 0, 0.08);
89
+ background: var(--sa-color-bg-sunken);
90
90
  border-radius: 4px;
91
91
  overflow: hidden;
92
92
  }
@@ -96,12 +96,12 @@ const formattedMax = computed(() => {
96
96
  border-radius: 4px;
97
97
  }
98
98
  .sp-usage-bar--ok .sp-usage-bar__fill {
99
- background: var(--q-positive, #21ba45);
99
+ background: var(--sa-color-positive);
100
100
  }
101
101
  .sp-usage-bar--warn .sp-usage-bar__fill {
102
- background: var(--q-warning, #f2c037);
102
+ background: var(--sa-color-warning-strong);
103
103
  }
104
104
  .sp-usage-bar--full .sp-usage-bar__fill {
105
- background: var(--q-negative, #c10015);
105
+ background: var(--sa-color-negative);
106
106
  }
107
107
  </style>
@@ -494,3 +494,116 @@ export const DEFAULT_I18N_EN: TenantPlanSectionI18n = {
494
494
  export function defaultTenantPlanSectionI18n(locale: SaLocale): TenantPlanSectionI18n {
495
495
  return locale === 'en' ? DEFAULT_I18N_EN : DEFAULT_I18N_DE;
496
496
  }
497
+
498
+ /**
499
+ * The strings `PlanChangeWizard` takes.
500
+ *
501
+ * A projection of `TenantPlanSectionI18n` with the `wizard` prefix dropped, so
502
+ * the wizard's own template reads `i18n.stepChoose` rather than
503
+ * `i18n.wizardStepChoose`.
504
+ */
505
+ export interface PlanChangeWizardI18n {
506
+ title: string;
507
+ close: string;
508
+ currentLabel: string;
509
+ cycleMonthly: string;
510
+ cycleYearly: string;
511
+ badgeCurrent: string;
512
+ badgePopular: string;
513
+ priceUnitMonthly: string;
514
+ priceUnitYearly: string;
515
+ priceOnRequest: string;
516
+ stepChoose: string;
517
+ stepChooseIntro: string;
518
+ stepPreview: string;
519
+ stepConfirm: string;
520
+ next: string;
521
+ back: string;
522
+ previewLoading: string;
523
+ effectiveAtLabel: string;
524
+ effectiveImmediate: string;
525
+ prorationTitle: string;
526
+ prorationLine: string;
527
+ prorationDays: string;
528
+ limitsTitle: string;
529
+ limitsUsed: string;
530
+ limitsCurrent: string;
531
+ limitsTarget: string;
532
+ featuresGained: string;
533
+ featuresLost: string;
534
+ blockersTitle: string;
535
+ confirmImmediate: string;
536
+ confirmScheduled: string;
537
+ confirmAction: string;
538
+ confirmInProgress: string;
539
+ confirmPriceTitle: string;
540
+ confirmProratedNow: string;
541
+ confirmRecurringNext: string;
542
+ confirmRecurringFrom: string;
543
+ perCycleMonthly: string;
544
+ perCycleYearly: string;
545
+ confirmTrialNote: string;
546
+ confirmRecurringTrialEnd: string;
547
+ changeTypeUpgrade: string;
548
+ changeTypeDowngrade: string;
549
+ changeTypeCycle: string;
550
+ changeTypeNoop: string;
551
+ }
552
+
553
+ /**
554
+ * Builds the wizard's strings from the section's.
555
+ *
556
+ * Here rather than inline in `TenantPlanSection.vue`, because the wizard is an
557
+ * exported component: a consumer who mounts it directly would otherwise have to
558
+ * reproduce all 44 keys of this mapping by hand, and a visual fixture had to do
559
+ * exactly that before it moved.
560
+ */
561
+ export function planChangeWizardI18n(i18n: TenantPlanSectionI18n): PlanChangeWizardI18n {
562
+ return {
563
+ title: i18n.wizardTitle,
564
+ close: i18n.wizardClose,
565
+ currentLabel: i18n.wizardCurrent,
566
+ cycleMonthly: i18n.cycleMonthly,
567
+ cycleYearly: i18n.cycleYearly,
568
+ badgeCurrent: i18n.wizardBadgeCurrent,
569
+ badgePopular: i18n.wizardBadgePopular,
570
+ priceUnitMonthly: i18n.wizardPriceUnitMonthly,
571
+ priceUnitYearly: i18n.wizardPriceUnitYearly,
572
+ priceOnRequest: i18n.wizardPriceOnRequest,
573
+ stepChoose: i18n.wizardStepChoose,
574
+ stepChooseIntro: i18n.wizardStepChooseIntro,
575
+ stepPreview: i18n.wizardStepPreview,
576
+ stepConfirm: i18n.wizardStepConfirm,
577
+ next: i18n.wizardNext,
578
+ back: i18n.wizardBack,
579
+ previewLoading: i18n.wizardPreviewLoading,
580
+ effectiveAtLabel: i18n.wizardEffectiveAtLabel,
581
+ effectiveImmediate: i18n.wizardEffectiveImmediate,
582
+ prorationTitle: i18n.wizardProrationTitle,
583
+ prorationLine: i18n.wizardProrationLine,
584
+ prorationDays: i18n.wizardProrationDays,
585
+ limitsTitle: i18n.wizardLimitsTitle,
586
+ limitsUsed: i18n.wizardLimitsUsed,
587
+ limitsCurrent: i18n.wizardLimitsCurrent,
588
+ limitsTarget: i18n.wizardLimitsTarget,
589
+ featuresGained: i18n.wizardFeaturesGained,
590
+ featuresLost: i18n.wizardFeaturesLost,
591
+ blockersTitle: i18n.wizardBlockersTitle,
592
+ confirmImmediate: i18n.wizardConfirmImmediate,
593
+ confirmScheduled: i18n.wizardConfirmScheduled,
594
+ confirmAction: i18n.wizardConfirmAction,
595
+ confirmInProgress: i18n.wizardConfirmInProgress,
596
+ confirmPriceTitle: i18n.wizardConfirmPriceTitle,
597
+ confirmProratedNow: i18n.wizardConfirmProratedNow,
598
+ confirmRecurringNext: i18n.wizardConfirmRecurringNext,
599
+ confirmRecurringFrom: i18n.wizardConfirmRecurringFrom,
600
+ perCycleMonthly: i18n.wizardConfirmPerCycleMonthly,
601
+ perCycleYearly: i18n.wizardConfirmPerCycleYearly,
602
+ confirmTrialNote: i18n.wizardConfirmTrialNote,
603
+ confirmRecurringTrialEnd: i18n.wizardConfirmRecurringTrialEnd,
604
+ changeTypeUpgrade: i18n.wizardChangeTypeUpgrade,
605
+ changeTypeDowngrade: i18n.wizardChangeTypeDowngrade,
606
+ changeTypeCycle: i18n.wizardChangeTypeCycle,
607
+ changeTypeNoop: i18n.wizardChangeTypeNoop,
608
+ };
609
+ }
@@ -246,32 +246,32 @@ function close() {
246
246
  padding-bottom: 8px;
247
247
  }
248
248
  .sp-bundle-preview__title {
249
- font-size: 16px;
249
+ font-size: var(--sa-text-lg);
250
250
  font-weight: 600;
251
251
  }
252
252
  .sp-bundle-preview__bundle {
253
253
  margin-top: 2px;
254
- color: var(--sp-text-secondary, rgba(0, 0, 0, 0.6));
254
+ color: var(--sp-text-secondary, var(--sa-color-fg-secondary));
255
255
  }
256
256
  .sp-bundle-preview__loading {
257
257
  display: flex;
258
258
  align-items: center;
259
259
  gap: 12px;
260
- color: var(--sp-text-secondary, rgba(0, 0, 0, 0.6));
260
+ color: var(--sp-text-secondary, var(--sa-color-fg-secondary));
261
261
  }
262
262
  .sp-bundle-preview__error {
263
- color: var(--q-negative, #c10015);
263
+ color: var(--sa-color-negative);
264
264
  }
265
265
  .sp-bundle-preview__blockers {
266
- background: rgba(193, 0, 21, 0.08);
267
- color: var(--q-negative, #c10015);
266
+ background: var(--sa-color-negative-surface);
267
+ color: var(--sa-color-negative);
268
268
  }
269
269
  .sp-bundle-preview__warnings {
270
- background: rgba(242, 192, 55, 0.12);
270
+ background: var(--sa-color-warning-surface-strong);
271
271
  }
272
272
  .sp-bundle-preview__block-title {
273
273
  font-weight: 600;
274
- font-size: 13px;
274
+ font-size: var(--sa-text-md);
275
275
  margin-bottom: 6px;
276
276
  }
277
277
  .sp-bundle-preview__block-subtitle {
@@ -281,26 +281,26 @@ function close() {
281
281
  .sp-bundle-preview__warnings ul {
282
282
  margin: 0;
283
283
  padding-left: 18px;
284
- font-size: 13px;
284
+ font-size: var(--sa-text-md);
285
285
  }
286
286
  .sp-bundle-preview__requires {
287
287
  margin-top: 6px;
288
- font-size: 13px;
288
+ font-size: var(--sa-text-md);
289
289
  }
290
290
  .sp-bundle-preview__price-row {
291
291
  display: flex;
292
292
  justify-content: space-between;
293
293
  gap: 16px;
294
294
  padding: 4px 0;
295
- font-size: 14px;
295
+ font-size: var(--sa-text-lg);
296
296
  }
297
297
  .sp-bundle-preview__price-row small {
298
298
  font-weight: 400;
299
- color: var(--sp-text-muted, rgba(0, 0, 0, 0.55));
299
+ color: var(--sp-text-muted, var(--sa-color-fg-muted));
300
300
  }
301
301
  .sp-bundle-preview__note {
302
- font-size: 13px;
303
- color: var(--sp-text-muted, rgba(0, 0, 0, 0.55));
302
+ font-size: var(--sa-text-md);
303
+ color: var(--sp-text-muted, var(--sa-color-fg-muted));
304
304
  padding: 4px 0;
305
305
  }
306
306
  </style>
@@ -246,9 +246,9 @@ const availableRows = computed<AvailableRow[]>(() =>
246
246
 
247
247
  <style scoped>
248
248
  .sp-bundle-store__subtitle {
249
- font-size: 13px;
249
+ font-size: var(--sa-text-md);
250
250
  font-weight: 600;
251
- color: var(--sp-text-strong, rgba(0, 0, 0, 0.7));
251
+ color: var(--sp-text-strong, var(--sa-color-fg-body));
252
252
  margin: 4px 0 8px;
253
253
  }
254
254
  .sp-bundle-store__available {
@@ -260,8 +260,8 @@ const availableRows = computed<AvailableRow[]>(() =>
260
260
  gap: 12px;
261
261
  }
262
262
  .sp-bundle-store__empty {
263
- color: var(--sp-text-muted, rgba(0, 0, 0, 0.55));
264
- font-size: 13px;
263
+ color: var(--sp-text-muted, var(--sa-color-fg-muted));
264
+ font-size: var(--sa-text-md);
265
265
  }
266
266
  .sp-bundle-store__grid {
267
267
  display: grid;
@@ -288,7 +288,7 @@ const availableRows = computed<AvailableRow[]>(() =>
288
288
  }
289
289
  .sp-bundle-store__card-name {
290
290
  font-weight: 600;
291
- font-size: 15px;
291
+ font-size: var(--sa-text-lg);
292
292
  }
293
293
  .sp-bundle-store__card-price {
294
294
  font-weight: 600;
@@ -296,16 +296,16 @@ const availableRows = computed<AvailableRow[]>(() =>
296
296
  }
297
297
  .sp-bundle-store__card-price small {
298
298
  font-weight: 400;
299
- color: var(--sp-text-muted, rgba(0, 0, 0, 0.55));
299
+ color: var(--sp-text-muted, var(--sa-color-fg-muted));
300
300
  }
301
301
  .sp-bundle-store__card-desc {
302
302
  margin: 0;
303
- font-size: 13px;
304
- color: var(--sp-text-secondary, rgba(0, 0, 0, 0.6));
303
+ font-size: var(--sa-text-md);
304
+ color: var(--sp-text-secondary, var(--sa-color-fg-secondary));
305
305
  }
306
306
  .sp-bundle-store__card-feats {
307
- font-size: 12px;
308
- color: var(--sp-text-muted, rgba(0, 0, 0, 0.55));
307
+ font-size: var(--sa-text-sm);
308
+ color: var(--sp-text-muted, var(--sa-color-fg-muted));
309
309
  }
310
310
  .sp-bundle-store__card-feats-label {
311
311
  font-weight: 500;
@@ -118,8 +118,8 @@ const features = computed<FeatureRow[]>(() => {
118
118
  flex-wrap: wrap;
119
119
  }
120
120
  .sp-feature-matrix__desc {
121
- font-size: 12px;
122
- color: var(--sp-text-muted, rgba(0, 0, 0, 0.55));
121
+ font-size: var(--sa-text-sm);
122
+ color: var(--sp-text-muted, var(--sa-color-fg-muted));
123
123
  margin-top: 2px;
124
124
  }
125
125
  </style>