@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.
- package/README.md +1 -1
- package/dist/{chunk-LY52T4N4.js → chunk-TQQMKWN6.js} +58 -1
- package/dist/index.cjs +213 -159
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -1
- package/dist/quasar/index.cjs +116 -20
- package/dist/quasar/index.d.cts +48 -3
- package/dist/quasar/index.d.ts +48 -3
- package/dist/quasar/index.js +58 -3
- package/dist/{use-super-admin-i18n-CgTuNi8h.d.cts → use-sa-theme-B5t7oXph.d.cts} +51 -1
- package/dist/{use-super-admin-i18n-CHNdsSlm.d.ts → use-sa-theme-OUBlaqgl.d.ts} +51 -1
- package/package.json +5 -2
- package/src/components/BundleVersionPublishDialog.vue +17 -17
- package/src/components/KvBlock.vue +6 -6
- package/src/components/MarketingPromotionsTab.vue +78 -78
- package/src/components/MfaPromptDialog.vue +2 -2
- package/src/components/TenantActionConfirmDialog.vue +5 -5
- package/src/components/VersionDiffPreview.vue +18 -18
- package/src/components/bundle-editor/BundleCreatePanel.vue +52 -52
- package/src/components/bundle-editor/BundleFeaturesEditor.vue +20 -20
- package/src/components/bundle-editor/BundlePlanCompatPicker.vue +33 -33
- package/src/components/bundle-editor/BundleQuotasEditor.vue +26 -26
- package/src/components/bundle-editor/BundleStatusBanner.vue +21 -21
- package/src/components/bundle-editor/BundleVersionInlineEditor.vue +48 -48
- package/src/components/bundle-editor/BundleVersionStrip.vue +30 -30
- package/src/components/dialogs/PilotCreateDialog.vue +20 -20
- package/src/components/dialogs/PilotEditDialog.vue +6 -6
- package/src/components/dialogs/PromoCodeCreateDialog.vue +9 -9
- package/src/components/dialogs/PromoCodeDialogFields.vue +61 -61
- package/src/components/dialogs/PromoCodeEditDialog.vue +11 -11
- package/src/components/dialogs/pilot-dialog.css +48 -48
- package/src/components/plan/PlanCycleToggle.vue +9 -16
- package/src/components/plan/PlanGrid.vue +30 -34
- package/src/components/plan/PriceSummary.vue +35 -35
- package/src/components/plan/PromoCodeInput.vue +26 -26
- package/src/components/plan/PublicBundleGrid.vue +32 -28
- package/src/components/plan-create-dialog/PlanCreateDialog.vue +49 -49
- package/src/components/plan-detail/PlanDetail.vue +172 -156
- package/src/components/plan-detail/PlanTitleEdit.vue +11 -11
- package/src/components/plan-list/PlanList.vue +98 -77
- package/src/components/plan-matrix/PlanMatrix.vue +89 -89
- package/src/components/plan-review/PlanReview.vue +60 -56
- package/src/components/plan-version-editor/PlanVersionEditor.vue +224 -200
- package/src/components/wizard-stepper/WizardStepper.vue +17 -17
- package/src/index.ts +1 -0
- package/src/pages-standard/AdminLayout.vue +58 -37
- package/src/pages-standard/AdminManifestErrorPage.vue +6 -6
- package/src/pages-standard/AuditPage.vue +3 -3
- package/src/pages-standard/BundlesPage.vue +36 -36
- package/src/pages-standard/DashboardPage.vue +17 -17
- package/src/pages-standard/DiscoveryPage.vue +55 -49
- package/src/pages-standard/EmailHistoryPage.vue +53 -71
- package/src/pages-standard/MarketingCatalogPage.vue +226 -218
- package/src/pages-standard/PilotsPage.vue +7 -6
- package/src/pages-standard/PlatformEmailPage.vue +18 -18
- package/src/pages-standard/PromoCodeDetailPage.vue +3 -3
- package/src/pages-standard/PromoCodesPage.vue +7 -6
- package/src/pages-standard/SuperAdminLoginPage.vue +39 -25
- package/src/pages-standard/SuperAdminSetupWizard.vue +44 -33
- package/src/pages-standard/TenantDetailPage.vue +7 -7
- package/src/pages-standard/TenantsPage.vue +11 -46
- package/src/pages-standard/bundles-page/BundleAccordionList.vue +13 -13
- package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +24 -24
- package/src/pages-standard/discovery-page/DiscoveryCapList.vue +22 -22
- package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +39 -39
- package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +26 -26
- package/src/pages-standard/discovery-page/DiscoveryStatusControl.vue +1 -1
- package/src/pages-standard/plan-versions/PlanDiffCard.vue +16 -16
- package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +21 -15
- package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +45 -45
- package/src/pages-standard/plans-page/PlanBundleOverview.vue +21 -15
- package/src/pages-standard/plans-page/PlanPublishDialog.vue +4 -4
- package/src/pages-standard/plans-page/PlansPageToast.vue +6 -6
- package/src/pages-standard/sa-theme.css +9 -687
- package/src/pages-standard/tenants/StatusPill.vue +13 -13
- package/src/pages-tenant/LimitsRow.vue +4 -4
- package/src/pages-tenant/MySubscriptionBundlesPage.vue +61 -61
- package/src/pages-tenant/OnboardingConfigurator.vue +24 -24
- package/src/pages-tenant/PackageSnapshotPanel.vue +10 -16
- package/src/pages-tenant/PendingVersionBanner.vue +12 -12
- package/src/pages-tenant/PlanChangeWizard.vue +20 -27
- package/src/pages-tenant/TenantPlanSection.vue +13 -21
- package/src/pages-tenant/UsageBar.vue +7 -7
- package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +14 -14
- package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +10 -10
- package/src/pages-tenant/tenant-plan-section/TenantFeatureMatrix.vue +2 -2
- package/src/quasar/create-super-admin-app.ts +96 -1
- package/src/quasar/dark-bridge.ts +66 -0
- package/src/quasar/index.ts +1 -0
- package/src/ui/theme/_breakpoints.scss +28 -0
- package/src/ui/theme/base.css +50 -0
- package/src/ui/theme/components/body.css +23 -0
- package/src/ui/theme/components/button.css +158 -0
- package/src/ui/theme/components/card.css +48 -0
- package/src/ui/theme/components/field.css +38 -0
- package/src/ui/theme/components/hero.css +46 -0
- package/src/ui/theme/components/paginator.css +63 -0
- package/src/ui/theme/components/section.css +67 -0
- package/src/ui/theme/components/statistics.css +189 -0
- package/src/ui/theme/components/table.css +60 -0
- package/src/ui/theme/index.css +42 -0
- package/src/ui/theme/tokens.legacy.css +147 -0
- package/src/ui/theme/tokens.primitive.css +108 -0
- package/src/ui/theme/tokens.scale.css +103 -0
- package/src/ui/theme/tokens.semantic.dark.css +173 -0
- package/src/ui/theme/tokens.semantic.light.css +212 -0
- package/src/vue/use-sa-theme.ts +154 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* Lists (see AdminTable). The package shipped no table rules at all until
|
|
2
|
+
* this, which is why nine pages each looked slightly different.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/* The surface under the rows. Measured on the promo-codes page in dark mode:
|
|
6
|
+
* the `.q-table__container.q-table__card.q-dark` element resolved to
|
|
7
|
+
* rgb(29, 29, 29) while the section around it was rgb(15, 23, 42) — Quasar's
|
|
8
|
+
* neutral grey inside our slate. Only `thead th` and `tbody td` were ours, and
|
|
9
|
+
* neither of them is the table's background. */
|
|
10
|
+
.sa-page .q-table__container,
|
|
11
|
+
.sa-portal .q-table__container {
|
|
12
|
+
background: var(--sa-color-bg-surface);
|
|
13
|
+
color: var(--sa-color-fg-body);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.sa-page .q-table thead th {
|
|
17
|
+
font-size: var(--sa-text-xs);
|
|
18
|
+
font-weight: 700;
|
|
19
|
+
letter-spacing: 0.04em;
|
|
20
|
+
text-transform: uppercase;
|
|
21
|
+
color: var(--sa-color-fg-muted);
|
|
22
|
+
background: var(--sa-color-bg-sunken);
|
|
23
|
+
border-bottom: 1px solid var(--sa-color-border);
|
|
24
|
+
padding: 10px 14px;
|
|
25
|
+
white-space: nowrap;
|
|
26
|
+
}
|
|
27
|
+
.sa-page .q-table tbody td {
|
|
28
|
+
font-size: var(--sa-text-md);
|
|
29
|
+
color: var(--sa-color-fg-body);
|
|
30
|
+
border-bottom: 1px solid var(--sa-color-border-soft);
|
|
31
|
+
padding: 10px 14px;
|
|
32
|
+
}
|
|
33
|
+
.sa-page .q-table tbody tr:last-child td {
|
|
34
|
+
border-bottom: 0;
|
|
35
|
+
}
|
|
36
|
+
.sa-page .q-table tbody tr:hover td {
|
|
37
|
+
background: var(--sa-color-bg-sunken);
|
|
38
|
+
}
|
|
39
|
+
/* Sorted column: the header carries the state, not just the arrow. */
|
|
40
|
+
.sa-page .q-table thead th.sortable:hover,
|
|
41
|
+
.sa-page .q-table thead th[aria-sort]:not([aria-sort='none']) {
|
|
42
|
+
color: var(--sa-color-fg-heading);
|
|
43
|
+
}
|
|
44
|
+
.sa-page .q-table thead th[aria-sort]:not([aria-sort='none']) {
|
|
45
|
+
background: var(--sa-color-accent-surface-strong);
|
|
46
|
+
}
|
|
47
|
+
.sa-table__actions {
|
|
48
|
+
white-space: nowrap;
|
|
49
|
+
}
|
|
50
|
+
.sa-table__empty {
|
|
51
|
+
color: var(--sa-color-fg-muted);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* The pager sits below the list, separated by a line that runs the full width
|
|
55
|
+
* of the surface — hence the pull-out by the section's own padding token. */
|
|
56
|
+
.sa-table__foot {
|
|
57
|
+
margin: 0 calc(-1 * var(--sa-pad-section)) calc(-1 * var(--sa-pad-section));
|
|
58
|
+
padding: 0 var(--sa-pad-section) 10px;
|
|
59
|
+
border-top: 1px solid var(--sa-color-border);
|
|
60
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* The SaaSiCat admin theme. One import: `@saasicat/ui-vue/theme.css`.
|
|
2
|
+
*
|
|
3
|
+
* ── The three layers, and why there are three ──────────────────────────────
|
|
4
|
+
*
|
|
5
|
+
* L1 tokens.primitive.css the palette references nothing
|
|
6
|
+
* tokens.scale.css space/type/… references nothing
|
|
7
|
+
* L2 tokens.semantic.*.css roles references L1 and --q-*
|
|
8
|
+
* L3 components/*.css the shell chrome references L2
|
|
9
|
+
*
|
|
10
|
+
* A component asks for a ROLE (`--sa-color-fg-muted`), never for a value
|
|
11
|
+
* (`--sa-neutral-500`), and never for a literal. That one rule is what makes
|
|
12
|
+
* the dark theme a file instead of a project: only L2 knows the difference
|
|
13
|
+
* between light and dark, so only L2 has two versions.
|
|
14
|
+
*
|
|
15
|
+
* The direction is enforced by `tests/theme-layer-discipline.test.js`
|
|
16
|
+
* (rule 22) and the key parity of the two L2 files by
|
|
17
|
+
* `tests/theme-token-parity.test.js` (rule 21).
|
|
18
|
+
*
|
|
19
|
+
* ── Order is the cascade ───────────────────────────────────────────────────
|
|
20
|
+
*
|
|
21
|
+
* Tokens first, because everything below reads them; dark after light, because
|
|
22
|
+
* it overrides. Within `components/`, the order is the order the old single
|
|
23
|
+
* stylesheet had — several rules there share a specificity and settle it by
|
|
24
|
+
* position, so this list is not alphabetical and must not be sorted.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
@import './tokens.primitive.css';
|
|
28
|
+
@import './tokens.scale.css';
|
|
29
|
+
@import './tokens.semantic.light.css';
|
|
30
|
+
@import './tokens.semantic.dark.css';
|
|
31
|
+
@import './tokens.legacy.css';
|
|
32
|
+
|
|
33
|
+
@import './base.css';
|
|
34
|
+
@import './components/hero.css';
|
|
35
|
+
@import './components/button.css';
|
|
36
|
+
@import './components/field.css';
|
|
37
|
+
@import './components/statistics.css';
|
|
38
|
+
@import './components/body.css';
|
|
39
|
+
@import './components/section.css';
|
|
40
|
+
@import './components/card.css';
|
|
41
|
+
@import './components/paginator.css';
|
|
42
|
+
@import './components/table.css';
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/* The pre-role token names, kept alive as aliases for one release.
|
|
2
|
+
*
|
|
3
|
+
* Every name below is what `sa-theme.css` published before the role layer
|
|
4
|
+
* existed. They are aliases, not values: each resolves to the role it turned
|
|
5
|
+
* out to mean, so a consumer stylesheet that still says `var(--sa-muted)` keeps
|
|
6
|
+
* working — and starts following the dark theme for free.
|
|
7
|
+
*
|
|
8
|
+
* ── They are aliases in ONE direction ──────────────────────────────────────
|
|
9
|
+
*
|
|
10
|
+
* Reading an old name still works. OVERRIDING one no longer does: setting
|
|
11
|
+
* `--sa-primary` in your own `:root` used to re-tint the admin, and now the
|
|
12
|
+
* role it feeds is `--sa-color-accent`, which reads Quasar's `--q-primary`.
|
|
13
|
+
* The replacement is better than what it removes — set `$primary` and the
|
|
14
|
+
* admin, Quasar's own components and the tenant-facing pages all follow one
|
|
15
|
+
* value instead of three. At runtime, use
|
|
16
|
+
* `setCssVar('primary', value, document.documentElement)`; the default target
|
|
17
|
+
* is `<body>`, which the roles on `:root` cannot see.
|
|
18
|
+
*
|
|
19
|
+
* To override a ROLE rather than the brand, write both of its values, on the
|
|
20
|
+
* same selectors the theme uses — `:root` for light, and
|
|
21
|
+
* `[data-sa-theme='dark'], body.body--dark` for dark. A role has two values, so
|
|
22
|
+
* an override has two, and `:root` alone silently loses in the Quasar-triggered
|
|
23
|
+
* dark path. `docs/design-guide.md#overriding-a-role` has the measurements.
|
|
24
|
+
*
|
|
25
|
+
* Nothing in this repository or in the scaffolder template overrode an `--sa-*`
|
|
26
|
+
* name; that was checked before choosing this direction.
|
|
27
|
+
*
|
|
28
|
+
* ── Consolidations, so a moved colour is not a surprise ────────────────────
|
|
29
|
+
*
|
|
30
|
+
* Five names had no role of their own and now share one, which is the point of
|
|
31
|
+
* the exercise rather than a side effect:
|
|
32
|
+
*
|
|
33
|
+
* --sa-border-strong #d1d5db → --sa-color-border-strong (#cbd5e1, the slate
|
|
34
|
+
* ramp — the grey ramp had exactly this one member)
|
|
35
|
+
* --sa-positive-soft, --sa-warning-soft translucent tints → the opaque
|
|
36
|
+
* `-surface` roles, so they stack predictably
|
|
37
|
+
* --sa-amber-light #fbbf24 → --sa-color-warning-strong (#f59e0b)
|
|
38
|
+
* --sa-primary-50 #eff6ff → --sa-color-accent-surface-strong, which now
|
|
39
|
+
* follows the host's brand instead of staying blue
|
|
40
|
+
*
|
|
41
|
+
* This file is deleted in 1.0. Its contents are the migration checklist.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
:root {
|
|
45
|
+
--sa-bg-app: var(--sa-color-bg-app);
|
|
46
|
+
--sa-bg-surface: var(--sa-color-bg-surface);
|
|
47
|
+
--sa-bg-surface-2: var(--sa-color-bg-sunken);
|
|
48
|
+
|
|
49
|
+
--sa-primary: var(--sa-color-accent);
|
|
50
|
+
--sa-primary-strong: var(--sa-color-accent-strong);
|
|
51
|
+
--sa-primary-soft: var(--sa-color-accent-surface);
|
|
52
|
+
--sa-primary-softer: var(--sa-color-accent-surface-soft);
|
|
53
|
+
--sa-primary-border: var(--sa-color-accent-border);
|
|
54
|
+
--sa-primary-50: var(--sa-color-accent-surface-strong);
|
|
55
|
+
|
|
56
|
+
--sa-positive: var(--sa-color-positive);
|
|
57
|
+
--sa-positive-light: var(--sa-color-positive-strong);
|
|
58
|
+
--sa-positive-soft: var(--sa-color-positive-surface);
|
|
59
|
+
--sa-positive-bg: var(--sa-color-positive-surface);
|
|
60
|
+
|
|
61
|
+
--sa-negative: var(--sa-color-negative);
|
|
62
|
+
--sa-negative-soft: var(--sa-color-negative-surface);
|
|
63
|
+
|
|
64
|
+
--sa-warning: var(--sa-color-warning);
|
|
65
|
+
--sa-warning-soft: var(--sa-color-warning-surface);
|
|
66
|
+
--sa-warning-bg: var(--sa-color-warning-surface);
|
|
67
|
+
--sa-amber: var(--sa-color-warning-strong);
|
|
68
|
+
--sa-amber-light: var(--sa-color-warning-strong);
|
|
69
|
+
--sa-amber-border: var(--sa-color-warning-border);
|
|
70
|
+
|
|
71
|
+
/* Read by `TenantsPage` as `var(--sa-accent, #7c3aed)` and never declared
|
|
72
|
+
* anywhere — the fallback was the only value it ever had. It marked the
|
|
73
|
+
* catalogue-feature action, which is now a role. */
|
|
74
|
+
--sa-accent: var(--sa-color-feature);
|
|
75
|
+
|
|
76
|
+
--sa-heading: var(--sa-color-fg-heading);
|
|
77
|
+
--sa-body: var(--sa-color-fg-body);
|
|
78
|
+
--sa-muted: var(--sa-color-fg-muted);
|
|
79
|
+
--sa-muted-dark: var(--sa-color-fg-secondary);
|
|
80
|
+
--sa-muted-light: var(--sa-color-fg-subtle);
|
|
81
|
+
|
|
82
|
+
--sa-border: var(--sa-color-border);
|
|
83
|
+
--sa-border-soft: var(--sa-color-border-soft);
|
|
84
|
+
--sa-border-strong: var(--sa-color-border-strong);
|
|
85
|
+
|
|
86
|
+
--sa-section-pad: var(--sa-pad-section);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* The same declarations again, under the dark triggers.
|
|
90
|
+
*
|
|
91
|
+
* Not redundancy — an alias is computed WHERE it is declared. `--sa-heading` on
|
|
92
|
+
* `:root` substitutes whatever `--sa-color-fg-heading` resolves to ON `:root`,
|
|
93
|
+
* and descendants inherit that finished value. Quasar's trigger redeclares the
|
|
94
|
+
* roles on `<body>`, which never re-evaluates an alias computed one level up:
|
|
95
|
+
* a consumer still reading `var(--sa-heading)` kept light text while everything
|
|
96
|
+
* around it went dark, and this file promises the opposite for one release.
|
|
97
|
+
*
|
|
98
|
+
* The attribute trigger sits on `:root` itself and would not need this, but the
|
|
99
|
+
* pair is written the way the design guide tells consumers to write an override
|
|
100
|
+
* — both values, on the selectors the theme uses. A file that documents a rule
|
|
101
|
+
* and then exempts itself from it teaches the exemption.
|
|
102
|
+
*/
|
|
103
|
+
[data-sa-theme='dark'],
|
|
104
|
+
body.body--dark {
|
|
105
|
+
--sa-bg-app: var(--sa-color-bg-app);
|
|
106
|
+
--sa-bg-surface: var(--sa-color-bg-surface);
|
|
107
|
+
--sa-bg-surface-2: var(--sa-color-bg-sunken);
|
|
108
|
+
|
|
109
|
+
--sa-primary: var(--sa-color-accent);
|
|
110
|
+
--sa-primary-strong: var(--sa-color-accent-strong);
|
|
111
|
+
--sa-primary-soft: var(--sa-color-accent-surface);
|
|
112
|
+
--sa-primary-softer: var(--sa-color-accent-surface-soft);
|
|
113
|
+
--sa-primary-border: var(--sa-color-accent-border);
|
|
114
|
+
--sa-primary-50: var(--sa-color-accent-surface-strong);
|
|
115
|
+
|
|
116
|
+
--sa-positive: var(--sa-color-positive);
|
|
117
|
+
--sa-positive-light: var(--sa-color-positive-strong);
|
|
118
|
+
--sa-positive-soft: var(--sa-color-positive-surface);
|
|
119
|
+
--sa-positive-bg: var(--sa-color-positive-surface);
|
|
120
|
+
|
|
121
|
+
--sa-negative: var(--sa-color-negative);
|
|
122
|
+
--sa-negative-soft: var(--sa-color-negative-surface);
|
|
123
|
+
|
|
124
|
+
--sa-warning: var(--sa-color-warning);
|
|
125
|
+
--sa-warning-soft: var(--sa-color-warning-surface);
|
|
126
|
+
--sa-warning-bg: var(--sa-color-warning-surface);
|
|
127
|
+
--sa-amber: var(--sa-color-warning-strong);
|
|
128
|
+
--sa-amber-light: var(--sa-color-warning-strong);
|
|
129
|
+
--sa-amber-border: var(--sa-color-warning-border);
|
|
130
|
+
|
|
131
|
+
/* Read by `TenantsPage` as `var(--sa-accent, #7c3aed)` and never declared
|
|
132
|
+
* anywhere — the fallback was the only value it ever had. It marked the
|
|
133
|
+
* catalogue-feature action, which is now a role. */
|
|
134
|
+
--sa-accent: var(--sa-color-feature);
|
|
135
|
+
|
|
136
|
+
--sa-heading: var(--sa-color-fg-heading);
|
|
137
|
+
--sa-body: var(--sa-color-fg-body);
|
|
138
|
+
--sa-muted: var(--sa-color-fg-muted);
|
|
139
|
+
--sa-muted-dark: var(--sa-color-fg-secondary);
|
|
140
|
+
--sa-muted-light: var(--sa-color-fg-subtle);
|
|
141
|
+
|
|
142
|
+
--sa-border: var(--sa-color-border);
|
|
143
|
+
--sa-border-soft: var(--sa-color-border-soft);
|
|
144
|
+
--sa-border-strong: var(--sa-color-border-strong);
|
|
145
|
+
|
|
146
|
+
--sa-section-pad: var(--sa-pad-section);
|
|
147
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/* Layer 1 — primitives. The raw palette, and nothing else.
|
|
2
|
+
*
|
|
3
|
+
* A primitive says WHAT a colour is (`--sa-red-600` is a particular red). It
|
|
4
|
+
* never says what the colour is FOR — that is layer 2's job, and it is the only
|
|
5
|
+
* layer that changes between light and dark. Consequently:
|
|
6
|
+
*
|
|
7
|
+
* - nothing in this file may reference another variable;
|
|
8
|
+
* - nothing outside `tokens.semantic.*.css` may reference this file.
|
|
9
|
+
*
|
|
10
|
+
* A component reaching for `--sa-red-600` instead of `--sa-color-negative` is
|
|
11
|
+
* the bug this split exists to prevent: it is invisible in review, and it is
|
|
12
|
+
* the reason a dark theme costs 62 files instead of one. Rule 22 in the
|
|
13
|
+
* layer-discipline test enforces both directions.
|
|
14
|
+
*
|
|
15
|
+
* The ramps are the ones the admin surface already used. Steps that no role
|
|
16
|
+
* consumes are absent on purpose: a palette with unused rungs invites people to
|
|
17
|
+
* pick one, and then the role layer is no longer the single answer.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
:root {
|
|
21
|
+
/* ── Neutral (slate). Carries text, surfaces and lines. ─────────────── */
|
|
22
|
+
--sa-white: #ffffff;
|
|
23
|
+
--sa-black: #000000;
|
|
24
|
+
--sa-neutral-25: #fbfbfd;
|
|
25
|
+
--sa-neutral-50: #f8fafc;
|
|
26
|
+
--sa-neutral-100: #f1f5f9;
|
|
27
|
+
--sa-neutral-200: #e2e8f0;
|
|
28
|
+
--sa-neutral-300: #cbd5e1;
|
|
29
|
+
--sa-neutral-400: #94a3b8;
|
|
30
|
+
/* Between 400 and 500, and it exists for a measured reason: `fg-subtle` at
|
|
31
|
+
* slate-400 reads 2.56:1 on a white card and 2.34:1 on the page canvas —
|
|
32
|
+
* under the 3:1 floor, i.e. captions and price units that are decoration
|
|
33
|
+
* rather than information. Slate-500 is the next rung and too dark to stay
|
|
34
|
+
* quiet. This one clears 3:1 on both. */
|
|
35
|
+
--sa-neutral-450: #7c8aa0;
|
|
36
|
+
--sa-neutral-500: #64748b;
|
|
37
|
+
--sa-neutral-600: #475569;
|
|
38
|
+
--sa-neutral-700: #334155;
|
|
39
|
+
--sa-neutral-800: #1e293b;
|
|
40
|
+
--sa-neutral-900: #0f172a;
|
|
41
|
+
--sa-neutral-950: #0b1220;
|
|
42
|
+
--sa-neutral-975: #070d18;
|
|
43
|
+
|
|
44
|
+
/* ── Blue. The `info` tone. ─────────────────────────────────────────── */
|
|
45
|
+
--sa-blue-50: #eff6ff;
|
|
46
|
+
--sa-blue-100: #dbeafe;
|
|
47
|
+
--sa-blue-200: #bfdbfe;
|
|
48
|
+
--sa-blue-300: #93c5fd;
|
|
49
|
+
--sa-blue-500: #3b82f6;
|
|
50
|
+
--sa-blue-600: #2563eb;
|
|
51
|
+
--sa-blue-700: #1d4ed8;
|
|
52
|
+
--sa-blue-800: #1e40af;
|
|
53
|
+
|
|
54
|
+
/* The platform's own brand blue. Kept out of the blue ramp because it is
|
|
55
|
+
* not a step in it: it is the value the accent role falls back to when the
|
|
56
|
+
* host application declares no Quasar `$primary` of its own. */
|
|
57
|
+
--sa-brand-blue: #3f6bff;
|
|
58
|
+
|
|
59
|
+
/* ── Green (emerald). `positive`. ───────────────────────────────────── */
|
|
60
|
+
--sa-green-50: #ecfdf5;
|
|
61
|
+
--sa-green-100: #d1fae5;
|
|
62
|
+
--sa-green-200: #a7f3d0;
|
|
63
|
+
--sa-green-500: #10b981;
|
|
64
|
+
--sa-green-700: #047857;
|
|
65
|
+
--sa-green-800: #065f46;
|
|
66
|
+
|
|
67
|
+
/* ── Amber. `warning`, and every "draft / scheduled / pending" state. ─ */
|
|
68
|
+
--sa-amber-50: #fffbeb;
|
|
69
|
+
--sa-amber-100: #fef3c7;
|
|
70
|
+
--sa-amber-200: #fde68a;
|
|
71
|
+
--sa-amber-300: #fcd34d;
|
|
72
|
+
--sa-amber-400: #fbbf24;
|
|
73
|
+
--sa-amber-500: #f59e0b;
|
|
74
|
+
--sa-amber-600: #d97706;
|
|
75
|
+
--sa-amber-700: #b45309;
|
|
76
|
+
--sa-amber-800: #92400e;
|
|
77
|
+
|
|
78
|
+
/* ── Red. `negative`. ───────────────────────────────────────────────── */
|
|
79
|
+
--sa-red-50: #fef2f2;
|
|
80
|
+
--sa-red-100: #fee2e2;
|
|
81
|
+
--sa-red-200: #fecaca;
|
|
82
|
+
--sa-red-300: #fca5a5;
|
|
83
|
+
--sa-red-500: #ef4444;
|
|
84
|
+
--sa-red-600: #dc2626;
|
|
85
|
+
--sa-red-700: #b91c1c;
|
|
86
|
+
--sa-red-800: #991b1b;
|
|
87
|
+
|
|
88
|
+
/* ── Indigo. `scheduled` — a version that is planned but not yet live. */
|
|
89
|
+
--sa-indigo-50: #eef2ff;
|
|
90
|
+
--sa-indigo-100: #e0e7ff;
|
|
91
|
+
--sa-indigo-200: #c7d2fe;
|
|
92
|
+
--sa-indigo-400: #818cf8;
|
|
93
|
+
--sa-indigo-700: #4338ca;
|
|
94
|
+
|
|
95
|
+
/* ── Violet and sky. The two catalogue entities, feature and quota. ── */
|
|
96
|
+
--sa-violet-50: #ede9fe;
|
|
97
|
+
--sa-violet-200: #ddd6fe;
|
|
98
|
+
--sa-violet-500: #8b5cf6;
|
|
99
|
+
--sa-violet-700: #6d28d9;
|
|
100
|
+
--sa-sky-50: #f0f9ff;
|
|
101
|
+
--sa-sky-200: #bae6fd;
|
|
102
|
+
--sa-sky-500: #0ea5e9;
|
|
103
|
+
|
|
104
|
+
/* ── Type families. ─────────────────────────────────────────────────── */
|
|
105
|
+
--sa-font-head: 'Plus Jakarta Sans', 'Inter', system-ui, sans-serif;
|
|
106
|
+
--sa-font-body: 'Inter', system-ui, sans-serif;
|
|
107
|
+
--sa-font-mono: ui-monospace, 'SF Mono', Menlo, monospace;
|
|
108
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/* Layer 1 — scales. Sizes, not colours, and identical in every theme.
|
|
2
|
+
*
|
|
3
|
+
* The point of a scale is that the choice is already made. You do not decide
|
|
4
|
+
* between 11px and 11.5px; you decide whether a piece of text is a caption or a
|
|
5
|
+
* body line, and the scale answers with a number. That is why the admin surface
|
|
6
|
+
* had 23 font sizes and 80 pixel values: with no scale, every author decided
|
|
7
|
+
* again, and nobody could tell a decision from a leftover.
|
|
8
|
+
*
|
|
9
|
+
* Breakpoints are the one scale that CANNOT live here — custom properties are
|
|
10
|
+
* not valid in a `@media` condition. They are in `_breakpoints.scss` for SCSS
|
|
11
|
+
* blocks, and for plain CSS the five values are an allow-list the lint enforces.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
:root {
|
|
15
|
+
/* ── Spacing. A 4px base with two half-steps below it, because hairline
|
|
16
|
+
* gaps (2px) and icon insets (4px) are real and rounding them up moves
|
|
17
|
+
* every dense row in the product. ───────────────────────────────────── */
|
|
18
|
+
--sa-space-0: 0;
|
|
19
|
+
--sa-space-1: 2px;
|
|
20
|
+
--sa-space-2: 4px;
|
|
21
|
+
--sa-space-3: 8px;
|
|
22
|
+
--sa-space-4: 12px;
|
|
23
|
+
--sa-space-5: 16px;
|
|
24
|
+
--sa-space-6: 20px;
|
|
25
|
+
--sa-space-7: 24px;
|
|
26
|
+
--sa-space-8: 32px;
|
|
27
|
+
--sa-space-9: 40px;
|
|
28
|
+
--sa-space-10: 48px;
|
|
29
|
+
--sa-space-11: 64px;
|
|
30
|
+
|
|
31
|
+
/* Named spacings, so a rule can say what the gap is for rather than how
|
|
32
|
+
* big it is. These are the six the admin surface actually distinguishes. */
|
|
33
|
+
--sa-gap-inline: var(--sa-space-3);
|
|
34
|
+
--sa-gap-stack: var(--sa-space-5);
|
|
35
|
+
--sa-pad-page: var(--sa-space-6);
|
|
36
|
+
--sa-pad-section: var(--sa-space-6);
|
|
37
|
+
--sa-pad-control: var(--sa-space-3);
|
|
38
|
+
--sa-pad-cell: var(--sa-space-4);
|
|
39
|
+
|
|
40
|
+
/* ── Type. Eight steps, each with the line-height it was drawn for.
|
|
41
|
+
*
|
|
42
|
+
* The ladder is dense at the bottom because that is where the admin lives:
|
|
43
|
+
* table cells, chips and captions are three quarters of every page, and one
|
|
44
|
+
* pixel there is the difference between a dense list and a cramped one. It
|
|
45
|
+
* spreads out at the top, where the steps are titles and there are few. */
|
|
46
|
+
--sa-text-2xs: 10px;
|
|
47
|
+
--sa-text-xs: 11px;
|
|
48
|
+
--sa-text-sm: 12px;
|
|
49
|
+
--sa-text-md: 13px;
|
|
50
|
+
--sa-text-lg: 15px;
|
|
51
|
+
--sa-text-xl: 18px;
|
|
52
|
+
--sa-text-2xl: 22px;
|
|
53
|
+
--sa-text-3xl: 28px;
|
|
54
|
+
/* A ninth rung the plan did not foresee, added for a measured reason: the
|
|
55
|
+
* price totals and the marketing headline sit at 32–38px, and collapsing
|
|
56
|
+
* them into 28px would have shrunk the biggest number in the product to
|
|
57
|
+
* hit a target of eight. A step the product uses for a distinct job is a
|
|
58
|
+
* step. */
|
|
59
|
+
--sa-text-4xl: 32px;
|
|
60
|
+
|
|
61
|
+
--sa-leading-2xs: 1.4;
|
|
62
|
+
--sa-leading-xs: 1.45;
|
|
63
|
+
--sa-leading-sm: 1.5;
|
|
64
|
+
--sa-leading-md: 1.55;
|
|
65
|
+
--sa-leading-lg: 1.5;
|
|
66
|
+
--sa-leading-xl: 1.4;
|
|
67
|
+
--sa-leading-2xl: 1.3;
|
|
68
|
+
--sa-leading-3xl: 1.25;
|
|
69
|
+
--sa-leading-4xl: 1.15;
|
|
70
|
+
|
|
71
|
+
--sa-weight-regular: 400;
|
|
72
|
+
--sa-weight-medium: 500;
|
|
73
|
+
--sa-weight-semibold: 600;
|
|
74
|
+
--sa-weight-bold: 700;
|
|
75
|
+
|
|
76
|
+
--sa-tracking-tight: -0.02em;
|
|
77
|
+
--sa-tracking-normal: 0;
|
|
78
|
+
--sa-tracking-wide: 0.04em;
|
|
79
|
+
--sa-tracking-wider: 0.06em;
|
|
80
|
+
|
|
81
|
+
/* ── Corner radii, largest to smallest, so the nesting reads as hierarchy:
|
|
82
|
+
* a section is a bigger block than the cards inside it, a card bigger than
|
|
83
|
+
* a tile. `--sa-radius-tile` is the single declaration every statistic tile
|
|
84
|
+
* in the admin surface resolves to. ─────────────────────────────────── */
|
|
85
|
+
--sa-radius-hero: 16px;
|
|
86
|
+
--sa-radius-section: 14px;
|
|
87
|
+
--sa-radius-card: 12px;
|
|
88
|
+
--sa-radius-head: 10px;
|
|
89
|
+
--sa-radius-tile: 10px;
|
|
90
|
+
--sa-radius-field: 8px;
|
|
91
|
+
--sa-radius-control: 7px;
|
|
92
|
+
--sa-radius-pill: 999px;
|
|
93
|
+
|
|
94
|
+
/* ── Stacking. Aligned with Quasar's own layers rather than invented above
|
|
95
|
+
* them: a platform overlay that outranks Quasar's dialog would cover the
|
|
96
|
+
* dialog a consumer opened from it. ─────────────────────────────────── */
|
|
97
|
+
--sa-z-base: 0;
|
|
98
|
+
--sa-z-sticky: 100;
|
|
99
|
+
--sa-z-drawer: 3000;
|
|
100
|
+
--sa-z-overlay: 5900;
|
|
101
|
+
--sa-z-dialog: 6000;
|
|
102
|
+
--sa-z-toast: 9500;
|
|
103
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/* Layer 2 — roles, dark theme. The same keys as `tokens.semantic.light.css`,
|
|
2
|
+
* with other values. That sentence is the whole design: nothing else in the
|
|
3
|
+
* package knows a dark theme exists.
|
|
4
|
+
*
|
|
5
|
+
* ── Two ways in, and why there is no third ─────────────────────────────────
|
|
6
|
+
*
|
|
7
|
+
* [data-sa-theme='dark'] the app decided — `handle.theme.scheme.value`
|
|
8
|
+
* body.body--dark Quasar decided — `$q.dark.set(true)`
|
|
9
|
+
*
|
|
10
|
+
* Both mean "the application decided", and that is the point: the application
|
|
11
|
+
* is the only party that can decide for BOTH halves of the screen. Quasar
|
|
12
|
+
* paints its own cards, dialogs, steppers and separators, and it does so only
|
|
13
|
+
* under `body--dark` — it has no `prefers-color-scheme` support of its own.
|
|
14
|
+
*
|
|
15
|
+
* ── Why this file does NOT follow the operating system ─────────────────────
|
|
16
|
+
*
|
|
17
|
+
* It used to, via `@media (prefers-color-scheme: dark)`, and that was wrong in
|
|
18
|
+
* the one case it was supposed to serve. An app that loads this stylesheet
|
|
19
|
+
* without running the bridge — every consumer embedding `pages-tenant/*` into
|
|
20
|
+
* its own frontend — would have had the platform's surfaces go dark from the
|
|
21
|
+
* operating system while Quasar's stayed light. Measured, on an embedded page
|
|
22
|
+
* with the OS set to dark:
|
|
23
|
+
*
|
|
24
|
+
* .sa-section rgb(15, 23, 42) ← dark
|
|
25
|
+
* .q-card rgb(255, 255, 255) ← white, with rgb(226, 232, 240) text
|
|
26
|
+
* .q-separator rgba(0, 0, 0, 0.12) ← a black hairline on near-black
|
|
27
|
+
*
|
|
28
|
+
* That is not "light cards beside dark surfaces", it is white-on-white at
|
|
29
|
+
* about 1.15:1. A stylesheet must not overrule the application that loaded it,
|
|
30
|
+
* because it cannot see the half of the screen it does not paint.
|
|
31
|
+
*
|
|
32
|
+
* Following the operating system is not lost — it moved to where both halves
|
|
33
|
+
* can be moved together. `createSaTheme({ scheme: 'system' })` is the default,
|
|
34
|
+
* it subscribes to `prefers-color-scheme` live, and `bindSaThemeToDocument`
|
|
35
|
+
* sets the attribute AND Quasar's `Dark`. `createSuperAdminApp` wires that up,
|
|
36
|
+
* so the admin shell follows the OS out of the box. An app that wants the same
|
|
37
|
+
* for an embedded surface calls those two functions; that is the one line that
|
|
38
|
+
* makes it actually work.
|
|
39
|
+
*
|
|
40
|
+
* `tests-e2e/theme-contrast.spec.ts` holds the counter-proof: with the OS set
|
|
41
|
+
* to dark and no bridge, the platform stays in step with Quasar.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
[data-sa-theme='dark'],
|
|
45
|
+
body.body--dark {
|
|
46
|
+
--sa-color-bg-app: var(--sa-neutral-975);
|
|
47
|
+
--sa-color-bg-surface: var(--sa-neutral-900);
|
|
48
|
+
--sa-color-bg-surface-raised: var(--sa-neutral-800);
|
|
49
|
+
--sa-color-bg-sunken: var(--sa-neutral-950);
|
|
50
|
+
--sa-color-bg-overlay: color-mix(in srgb, var(--sa-black) 70%, transparent);
|
|
51
|
+
|
|
52
|
+
--sa-color-fg-heading: var(--sa-neutral-50);
|
|
53
|
+
--sa-color-fg-body: var(--sa-neutral-200);
|
|
54
|
+
--sa-color-fg-secondary: var(--sa-neutral-300);
|
|
55
|
+
--sa-color-fg-muted: var(--sa-neutral-400);
|
|
56
|
+
--sa-color-fg-subtle: var(--sa-neutral-500);
|
|
57
|
+
--sa-color-fg-disabled: var(--sa-neutral-600);
|
|
58
|
+
--sa-color-fg-on-accent: var(--sa-white);
|
|
59
|
+
|
|
60
|
+
--sa-color-border: var(--sa-neutral-700);
|
|
61
|
+
--sa-color-border-soft: var(--sa-neutral-800);
|
|
62
|
+
--sa-color-border-strong: var(--sa-neutral-600);
|
|
63
|
+
--sa-color-border-focus: var(--sa-color-accent);
|
|
64
|
+
|
|
65
|
+
/* The brand does not flip — a green product stays green in the dark. Only
|
|
66
|
+
* the derivations change: `-strong` lightens instead of darkening, because
|
|
67
|
+
* "more emphatic" means "closer to the paper" here, and every tint needs
|
|
68
|
+
* more of the accent to register against a dark surface. */
|
|
69
|
+
--sa-color-accent: var(--q-primary, var(--sa-brand-blue));
|
|
70
|
+
--sa-color-accent-strong: color-mix(in srgb, var(--sa-color-accent) 82%, var(--sa-white));
|
|
71
|
+
--sa-color-accent-surface: color-mix(in srgb, var(--sa-color-accent) 16%, transparent);
|
|
72
|
+
--sa-color-accent-surface-soft: color-mix(in srgb, var(--sa-color-accent) 8%, transparent);
|
|
73
|
+
--sa-color-accent-surface-strong: color-mix(
|
|
74
|
+
in srgb,
|
|
75
|
+
var(--sa-color-accent) 22%,
|
|
76
|
+
var(--sa-color-bg-surface)
|
|
77
|
+
);
|
|
78
|
+
--sa-color-accent-border: color-mix(in srgb, var(--sa-color-accent) 32%, transparent);
|
|
79
|
+
|
|
80
|
+
/* Each tone rises one or two steps up its ramp, because the dark shades
|
|
81
|
+
* that read as "deep red" on white read as "almost black" on slate. The
|
|
82
|
+
* surfaces become translucent so that a chip on a raised card and a chip on
|
|
83
|
+
* the page canvas both keep their contrast. */
|
|
84
|
+
--sa-color-positive: var(--sa-green-500);
|
|
85
|
+
--sa-color-positive-strong: var(--sa-green-500);
|
|
86
|
+
--sa-color-positive-fg: var(--sa-green-200);
|
|
87
|
+
--sa-color-positive-surface: color-mix(in srgb, var(--sa-green-500) 14%, transparent);
|
|
88
|
+
--sa-color-positive-surface-strong: color-mix(in srgb, var(--sa-green-500) 24%, transparent);
|
|
89
|
+
--sa-color-positive-border: color-mix(in srgb, var(--sa-green-500) 36%, transparent);
|
|
90
|
+
|
|
91
|
+
--sa-color-warning: var(--sa-amber-400);
|
|
92
|
+
--sa-color-warning-strong: var(--sa-amber-400);
|
|
93
|
+
--sa-color-warning-fg: var(--sa-amber-200);
|
|
94
|
+
--sa-color-warning-surface: color-mix(in srgb, var(--sa-amber-500) 14%, transparent);
|
|
95
|
+
--sa-color-warning-surface-strong: color-mix(in srgb, var(--sa-amber-500) 24%, transparent);
|
|
96
|
+
--sa-color-warning-border: color-mix(in srgb, var(--sa-amber-500) 36%, transparent);
|
|
97
|
+
|
|
98
|
+
--sa-color-negative: var(--sa-red-500);
|
|
99
|
+
--sa-color-negative-strong: var(--sa-red-500);
|
|
100
|
+
--sa-color-negative-fg: var(--sa-red-300);
|
|
101
|
+
--sa-color-negative-surface: color-mix(in srgb, var(--sa-red-500) 14%, transparent);
|
|
102
|
+
--sa-color-negative-surface-strong: color-mix(in srgb, var(--sa-red-500) 24%, transparent);
|
|
103
|
+
--sa-color-negative-border: color-mix(in srgb, var(--sa-red-500) 36%, transparent);
|
|
104
|
+
|
|
105
|
+
--sa-color-info: var(--sa-blue-500);
|
|
106
|
+
--sa-color-info-strong: var(--sa-blue-500);
|
|
107
|
+
--sa-color-info-fg: var(--sa-blue-200);
|
|
108
|
+
--sa-color-info-surface: color-mix(in srgb, var(--sa-blue-500) 14%, transparent);
|
|
109
|
+
--sa-color-info-surface-strong: color-mix(in srgb, var(--sa-blue-500) 24%, transparent);
|
|
110
|
+
--sa-color-info-border: color-mix(in srgb, var(--sa-blue-500) 36%, transparent);
|
|
111
|
+
|
|
112
|
+
--sa-color-scheduled: var(--sa-indigo-400);
|
|
113
|
+
--sa-color-scheduled-strong: var(--sa-indigo-400);
|
|
114
|
+
--sa-color-scheduled-fg: var(--sa-indigo-200);
|
|
115
|
+
--sa-color-scheduled-surface: color-mix(in srgb, var(--sa-indigo-400) 14%, transparent);
|
|
116
|
+
--sa-color-scheduled-surface-strong: color-mix(in srgb, var(--sa-indigo-400) 24%, transparent);
|
|
117
|
+
--sa-color-scheduled-border: color-mix(in srgb, var(--sa-indigo-400) 36%, transparent);
|
|
118
|
+
|
|
119
|
+
--sa-color-feature: var(--sa-violet-500);
|
|
120
|
+
--sa-color-feature-fg: var(--sa-violet-200);
|
|
121
|
+
--sa-color-feature-surface: color-mix(in srgb, var(--sa-violet-500) 16%, transparent);
|
|
122
|
+
--sa-color-quota: var(--sa-sky-500);
|
|
123
|
+
--sa-color-quota-surface: color-mix(in srgb, var(--sa-sky-500) 16%, transparent);
|
|
124
|
+
--sa-color-quota-border: color-mix(in srgb, var(--sa-sky-500) 36%, transparent);
|
|
125
|
+
--sa-color-bundle: var(--sa-amber-500);
|
|
126
|
+
--sa-color-bundle-surface: color-mix(in srgb, var(--sa-amber-500) 16%, transparent);
|
|
127
|
+
|
|
128
|
+
/* Identical to the light theme, and that is the point — see there. */
|
|
129
|
+
--sa-color-inverse-bg: var(--sa-neutral-950);
|
|
130
|
+
--sa-color-inverse-surface: var(--sa-neutral-800);
|
|
131
|
+
--sa-color-inverse-surface-soft: var(--sa-neutral-600);
|
|
132
|
+
--sa-color-inverse-fg: var(--sa-white);
|
|
133
|
+
--sa-color-inverse-fg-muted: var(--sa-neutral-300);
|
|
134
|
+
--sa-color-inverse-accent: var(--sa-amber-400);
|
|
135
|
+
--sa-color-inverse-accent-strong: var(--sa-amber-600);
|
|
136
|
+
--sa-color-inverse-accent-surface: color-mix(in srgb, var(--sa-amber-500) 15%, transparent);
|
|
137
|
+
--sa-color-inverse-accent-surface-strong: color-mix(
|
|
138
|
+
in srgb,
|
|
139
|
+
var(--sa-amber-500) 22%,
|
|
140
|
+
transparent
|
|
141
|
+
);
|
|
142
|
+
--sa-color-inverse-accent-fg: var(--sa-neutral-900);
|
|
143
|
+
--sa-color-inverse-danger: var(--sa-red-700);
|
|
144
|
+
--sa-color-inverse-danger-strong: var(--sa-red-600);
|
|
145
|
+
--sa-color-inverse-notice: var(--sa-amber-600);
|
|
146
|
+
--sa-color-inverse-notice-strong: var(--sa-amber-700);
|
|
147
|
+
--sa-color-inverse-fg-subtle: color-mix(in srgb, var(--sa-white) 55%, transparent);
|
|
148
|
+
--sa-color-inverse-border: color-mix(in srgb, var(--sa-white) 8%, transparent);
|
|
149
|
+
--sa-color-inverse-border-strong: color-mix(in srgb, var(--sa-white) 16%, transparent);
|
|
150
|
+
|
|
151
|
+
--sa-color-focus-ring: color-mix(in srgb, var(--sa-color-accent) 45%, transparent);
|
|
152
|
+
--sa-color-selection: color-mix(in srgb, var(--sa-color-accent) 30%, transparent);
|
|
153
|
+
|
|
154
|
+
/* Black ink and roughly double the alpha: a slate shadow at 6% is invisible
|
|
155
|
+
* on a slate surface, so the depth cue has to come from real darkness. */
|
|
156
|
+
--sa-shadow-ink: var(--sa-black);
|
|
157
|
+
--sa-shadow-tint-1: color-mix(in srgb, var(--sa-shadow-ink) 24%, transparent);
|
|
158
|
+
--sa-shadow-tint-2: color-mix(in srgb, var(--sa-shadow-ink) 32%, transparent);
|
|
159
|
+
--sa-shadow-tint-3: color-mix(in srgb, var(--sa-shadow-ink) 44%, transparent);
|
|
160
|
+
--sa-shadow-tint-4: color-mix(in srgb, var(--sa-shadow-ink) 60%, transparent);
|
|
161
|
+
|
|
162
|
+
--sa-shadow-0: none;
|
|
163
|
+
--sa-shadow-1: 0 1px 2px var(--sa-shadow-tint-1);
|
|
164
|
+
--sa-shadow-2: 0 2px 6px var(--sa-shadow-tint-2);
|
|
165
|
+
--sa-shadow-3: 0 8px 20px var(--sa-shadow-tint-3);
|
|
166
|
+
--sa-shadow-4: 0 20px 48px var(--sa-shadow-tint-4);
|
|
167
|
+
--sa-shadow-focus: 0 0 0 3px var(--sa-color-focus-ring);
|
|
168
|
+
|
|
169
|
+
--sa-elevation-tile: var(--sa-shadow-1);
|
|
170
|
+
--sa-elevation-card: var(--sa-shadow-2);
|
|
171
|
+
--sa-elevation-menu: var(--sa-shadow-3);
|
|
172
|
+
--sa-elevation-dialog: var(--sa-shadow-4);
|
|
173
|
+
}
|