@fastwork/xosmoz-theme 0.70.0 → 0.72.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/dist/base.css +6 -0
- package/dist/figma-plugin.zip +0 -0
- package/dist/llms.txt +449 -611
- package/package.json +1 -1
package/dist/base.css
CHANGED
package/dist/figma-plugin.zip
CHANGED
|
Binary file
|
package/dist/llms.txt
CHANGED
|
@@ -1,818 +1,656 @@
|
|
|
1
|
-
# @fastwork/xosmoz-theme —
|
|
1
|
+
# @fastwork/xosmoz-theme — Color Token Reference
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Semantic color tokens for theme-aware UIs. All tokens auto-switch between light and dark mode via CSS variables on `data-theme`.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Core Rules
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
1. **Never use palette tokens** (`--xz-color-fastwork`, `--xz-color-gray`, etc.) directly in UI. Always use semantic tokens.
|
|
10
|
+
2. **Pair `bg-100` / `bg-200` with `text-fg`** for readable text on solid-color backgrounds.
|
|
11
|
+
3. **`text-100` vs `text-200`**: Use `text-100` (lighter) for colored text on surface backgrounds (links, messages, ghost buttons). Use `text-200` (darker) for text on soft/tinted backgrounds (soft buttons, soft badges) — the darker tone provides contrast against the tinted fill.
|
|
12
|
+
4. **`soft-*` vs `soft-solid-*`**: Use `soft-100` (transparent) when the element sits on the page background. Use `soft-solid-100` (opaque) when it sits on a card or modal (`surface-200`+) to prevent the tint from showing the underlying surface color bleeding through.
|
|
13
|
+
5. **All tokens are theme-aware.** They auto-adapt in dark mode. No manual overrides needed.
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
npm install @fastwork/xosmoz-theme
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
### CSS Imports
|
|
15
|
+
---
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
/* Base styles: CSS reset, font imports, typography/spacing tokens */
|
|
19
|
-
@import '@fastwork/xosmoz-theme/base.css';
|
|
17
|
+
## Base Tokens
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
@import '@fastwork/xosmoz-theme/themes.css';
|
|
19
|
+
### Surfaces
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
@import '@fastwork/xosmoz-theme/themes/light.css';
|
|
26
|
-
@import '@fastwork/xosmoz-theme/themes/dark.css';
|
|
27
|
-
```
|
|
21
|
+
The surface system creates visual depth through layering. `surface-50` and `surface-100` are the two most important tokens — understanding when to use each is critical.
|
|
28
22
|
|
|
29
|
-
|
|
23
|
+
**`surface-50` vs `surface-100`**: `surface-50` is the absolute purest background (pure white in light mode, deepest black in dark mode). `surface-100` is the standard page background, which is slightly tinted/off-white in light mode and slightly lighter than pure black in dark mode. Usually we use `surface-100` as the main page background so that `surface-50` elements (inputs, popups, active tabs) have subtle contrast against it — white on near-white. `surface-50` can also be used as the main background in some cases, but `surface-100` is the default choice.
|
|
30
24
|
|
|
31
|
-
|
|
25
|
+
| Token | Purpose | Used by |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `--xz-color-surface-50` | Purest base — inset/recessed elements against the page | Input field background, radio inner dot, tab-list active item background, popup/popover background, card background over surface-100 |
|
|
28
|
+
| `--xz-color-surface-100` | Default page background — the standard canvas | Page body, dashboard container, app background |
|
|
29
|
+
| `--xz-color-surface-200` | Elevated surface — sits above the page | Cards, modals, dialogs, sidebar panels, stat cards |
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
<html>...</html> <!-- Light theme (default) -->
|
|
35
|
-
<html data-theme="dark">...</html> <!-- Dark theme -->
|
|
36
|
-
```
|
|
31
|
+
### Inverted Backgrounds
|
|
37
32
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
| Token | Purpose | Used by |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `--xz-color-bg-100` | Near-black (light) / near-white (dark) | Default button fill, chip active state, dark footer |
|
|
36
|
+
| `--xz-color-bg-200` | Secondary inverted | Default button hover |
|
|
37
|
+
| `--xz-color-text-fg` | Text on bg-100 / bg-200 | Default button text, chip active text |
|
|
43
38
|
|
|
44
|
-
|
|
39
|
+
### Text
|
|
45
40
|
|
|
46
|
-
|
|
41
|
+
| Token | Purpose | Used by |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `--xz-color-text-100` | Primary text | Body text, headings, labels, checkbox/radio labels, chip text |
|
|
44
|
+
| `--xz-color-text-200` | Secondary / muted text | Subtitles, timestamps, descriptions, tab-list inactive, button-group inactive, disabled checkbox labels |
|
|
45
|
+
| `--xz-color-text-300` | Placeholder / disabled text | Input placeholder, field description, input prefix/suffix |
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
### Lines
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
| Token | Purpose | Used by |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `--xz-color-line-50` | Subtle divider | Table cell borders, activity feed separators, settings row dividers, button-group border |
|
|
52
|
+
| `--xz-color-line-100` | Default border | Input border, card border, table wrap border |
|
|
53
|
+
| `--xz-color-line-200` | Emphasized border | Input hover, checkbox/radio unchecked border, switch track border |
|
|
54
|
+
| `--xz-color-line-300` | Strongest border | Maximum emphasis separator |
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
--xz-color-fastwork (brand blue-purple)
|
|
55
|
-
--xz-color-gray
|
|
56
|
-
--xz-color-green
|
|
57
|
-
--xz-color-yellow
|
|
58
|
-
--xz-color-red
|
|
59
|
-
--xz-color-orange
|
|
60
|
-
--xz-color-purple
|
|
61
|
-
--xz-color-cyan
|
|
62
|
-
```
|
|
56
|
+
---
|
|
63
57
|
|
|
64
|
-
|
|
58
|
+
## Semantic Categories
|
|
65
59
|
|
|
66
|
-
|
|
67
|
-
These tokens change values between light and dark themes. Always use these for UI components, text, borders, and backgrounds.
|
|
60
|
+
Eight categories. Replace `{name}` in token patterns with any of these:
|
|
68
61
|
|
|
69
|
-
|
|
62
|
+
| Category | Intent | Real usage from Storybook |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| `primary` | Brand action, main CTA | Primary button, active button-group, checkbox/radio checked, switch on, link, focus ring, active tab indicator |
|
|
65
|
+
| `danger` | Destructive action, error | Danger button, delete action, danger-zone card border, form validation error, "Inactive" badge |
|
|
66
|
+
| `success` | Positive outcome, completion | Success button, "Active"/"Online" badge, verified input, activity completion icon |
|
|
67
|
+
| `warning` | Caution, attention needed | Warning button, "Pending"/"Away" badge, pending review stat icon |
|
|
68
|
+
| `info` | Informational notice | Info message, system update banner, "On Leave" badge |
|
|
69
|
+
| `neutral` | Non-semantic, default UI | Soft button default, chip default, tab-list background, blank-slate, loader, disabled input, "Offline" badge |
|
|
70
|
+
| `orange` | Special accent | Premium/pro badge, trending indicator |
|
|
71
|
+
| `purple` | Special accent | AI feature badge, beta indicator, "View Reports" action |
|
|
70
72
|
|
|
71
73
|
---
|
|
72
74
|
|
|
73
|
-
##
|
|
75
|
+
## 12 Tokens Per Category
|
|
74
76
|
|
|
75
|
-
|
|
77
|
+
Pattern: `--xz-color-{name}-{token}`
|
|
76
78
|
|
|
77
|
-
|
|
|
79
|
+
| Token | Purpose | Pair with |
|
|
78
80
|
|---|---|---|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
83
|
-
|
|
|
84
|
-
|
|
|
85
|
-
|
|
|
86
|
-
|
|
|
87
|
-
|
|
|
88
|
-
|
|
|
89
|
-
|
|
|
90
|
-
|
|
|
91
|
-
| `--xz-color-line-100` | Default border | Input border, card border, table cell border, tab bar bottom border |
|
|
92
|
-
| `--xz-color-line-200` | Emphasized border | Active/focus input border, emphasized separator, selected tab underline, strong divider |
|
|
93
|
-
| `--xz-color-line-300` | Strongest border | Maximum emphasis divider, high-contrast separator, strongest active outline |
|
|
81
|
+
| `soft-100` | Transparent tinted background | `text-200` for buttons/badges; `text-100` for messages |
|
|
82
|
+
| `soft-200` | Hover/pressed state of soft background | same as soft-100 |
|
|
83
|
+
| `soft-solid-100` | Opaque tinted background (use on cards/modals) | `text-200` |
|
|
84
|
+
| `soft-solid-200` | Opaque tinted hover/pressed | `text-200` |
|
|
85
|
+
| `line-100` | Subtle colored border | — |
|
|
86
|
+
| `line-200` | Default colored border | — |
|
|
87
|
+
| `line-300` | Strong colored border | — |
|
|
88
|
+
| `bg-100` | Solid fill background | `text-fg` |
|
|
89
|
+
| `bg-200` | Solid fill hover/pressed | `text-fg` |
|
|
90
|
+
| `text-fg` | Text/icon on solid bg | place on `bg-100` / `bg-200` |
|
|
91
|
+
| `text-100` | Colored text on surfaces (lighter) | place on `surface-*` backgrounds |
|
|
92
|
+
| `text-200` | Colored text on tinted bg (darker) | place on `soft-*` backgrounds |
|
|
94
93
|
|
|
95
94
|
---
|
|
96
95
|
|
|
97
|
-
##
|
|
96
|
+
## Component Recipes
|
|
98
97
|
|
|
99
|
-
|
|
98
|
+
Exact token combinations from the real SCSS source files.
|
|
100
99
|
|
|
101
|
-
###
|
|
100
|
+
### Button
|
|
102
101
|
|
|
103
|
-
|
|
102
|
+
**Default button** (no variant):
|
|
103
|
+
```
|
|
104
|
+
background: var(--xz-color-bg-100);
|
|
105
|
+
color: var(--xz-color-text-fg);
|
|
106
|
+
hover → background: var(--xz-color-bg-200);
|
|
107
|
+
```
|
|
104
108
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
| `--xz-color-{name}-line-100` | Subtle colored border |
|
|
112
|
-
| `--xz-color-{name}-line-200` | Default colored border |
|
|
113
|
-
| `--xz-color-{name}-line-300` | Strong colored border |
|
|
114
|
-
| `--xz-color-{name}-bg-100` | Solid fill background — buttons, chips, badges |
|
|
115
|
-
| `--xz-color-{name}-bg-200` | Solid fill hover/pressed state |
|
|
116
|
-
| `--xz-color-{name}-text-fg` | Text/icon on solid bg — **always pair with bg-100 / bg-200** |
|
|
117
|
-
| `--xz-color-{name}-text-100` | Colored text on light surfaces — links, status labels |
|
|
109
|
+
**Solid** — `is-variant-{name}` (primary, danger, success, warning, orange, purple):
|
|
110
|
+
```
|
|
111
|
+
background: var(--xz-color-{name}-bg-100);
|
|
112
|
+
color: var(--xz-color-{name}-text-fg);
|
|
113
|
+
hover → background: var(--xz-color-{name}-bg-200);
|
|
114
|
+
```
|
|
118
115
|
|
|
119
|
-
|
|
116
|
+
**Soft** — `is-variant-{name}-soft`:
|
|
117
|
+
```
|
|
118
|
+
background: var(--xz-color-{name}-soft-100);
|
|
119
|
+
color: var(--xz-color-{name}-text-200);
|
|
120
|
+
hover → background: var(--xz-color-{name}-soft-200);
|
|
121
|
+
```
|
|
122
|
+
Default soft (no category): `background: neutral-soft-100, color: text-100, hover: neutral-soft-200`
|
|
120
123
|
|
|
121
|
-
|
|
124
|
+
**Outline** — `is-variant-{name}-outline`:
|
|
125
|
+
```
|
|
126
|
+
border: 1px solid var(--xz-color-{name}-line-100);
|
|
127
|
+
background: transparent;
|
|
128
|
+
color: var(--xz-color-{name}-text-100);
|
|
129
|
+
hover → background: var(--xz-color-{name}-soft-100);
|
|
130
|
+
```
|
|
131
|
+
Default outline: `border: neutral-line-100, color: text-100, hover: neutral-soft-100`
|
|
122
132
|
|
|
123
|
-
|
|
133
|
+
**Ghost** — `is-variant-{name}-ghost`:
|
|
134
|
+
```
|
|
135
|
+
background: transparent;
|
|
136
|
+
color: var(--xz-color-{name}-text-100);
|
|
137
|
+
hover → background: var(--xz-color-{name}-soft-100);
|
|
138
|
+
```
|
|
139
|
+
Default ghost: `color: text-100, hover: neutral-soft-100`
|
|
124
140
|
|
|
125
|
-
|
|
126
|
-
|---|---|---|
|
|
127
|
-
| `primary` | Brand action, main interaction | CTA buttons, links, active tab indicator, selected checkbox/radio, progress bar fill, focused input ring, pagination current page |
|
|
128
|
-
| `danger` | Destructive action, error state | Delete/remove buttons, form validation error message, declined/rejected status badge, overdue indicator, "leave without saving" prompt |
|
|
129
|
-
| `success` | Positive outcome, completion | Success alert/toast, "completed" status badge, verified checkmark, approval indicator, "payment received" label, online status dot |
|
|
130
|
-
| `warning` | Caution, attention needed | Warning banner, "expiring soon" label, pending review status, low stock indicator, unsaved changes notice, trial ending alert |
|
|
131
|
-
| `info` | Informational, neutral notice | Info banner, help tooltip, "new feature" badge, system maintenance notice, changelog highlight, onboarding tip |
|
|
132
|
-
| `neutral` | Non-semantic, default UI | Secondary/ghost buttons, default tags/chips, inactive tabs, neutral badges (count), toggle off state, breadcrumb separator |
|
|
133
|
-
| `orange` | Special accent | Premium/pro plan badge, trending indicator, notification dot, highlight/featured card border, "hot" label, points/rewards |
|
|
134
|
-
| `purple` | Special accent | AI-powered feature badge, creator/author tag, premium tier indicator, special promotion label, "beta" badge |
|
|
135
|
-
|
|
136
|
-
### Key Rules for Semantic Tokens
|
|
137
|
-
|
|
138
|
-
- **`bg-100` + `text-fg`**: Solid fill components (buttons, solid badges). `text-fg` provides correct contrast (white or dark depending on the category color).
|
|
139
|
-
- **`soft-100` + `text-100` + `line-100`**: Soft/tinted style (alerts, soft badges, highlighted rows).
|
|
140
|
-
- **`soft-solid-*`**: Use instead of `soft-*` when the component sits on a non-transparent surface. Example: a success badge inside a card (`surface-200`) — use `soft-solid-100` so the tint mixes with the surface color and doesn't show the card color bleeding through. If the badge were on the page background directly, `soft-100` (transparent) is fine.
|
|
141
|
-
- **`text-100`**: Use for colored text that sits on surface backgrounds (not on solid fills). Examples: link text, status label text, tag text.
|
|
142
|
-
- **`line-*`**: Colored borders. Use `line-200` as the default, `line-100` for subtle, `line-300` for strong/emphasized.
|
|
141
|
+
**Disabled**: `opacity: 0.4` (all variants)
|
|
143
142
|
|
|
144
143
|
---
|
|
145
144
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
These use a 100–1000 scale representing opacity from 0.1 to 1.0.
|
|
145
|
+
### Badge
|
|
149
146
|
|
|
147
|
+
**Solid** — `is-variant-{name}` (default is neutral):
|
|
148
|
+
```
|
|
149
|
+
background: var(--xz-color-{name}-bg-100);
|
|
150
|
+
color: var(--xz-color-{name}-text-fg);
|
|
150
151
|
```
|
|
151
|
-
--xz-color-black-alpha-100 (black at 10% opacity)
|
|
152
|
-
--xz-color-black-alpha-200 (black at 20% opacity)
|
|
153
|
-
...
|
|
154
|
-
--xz-color-black-alpha-1000 (black at 100% opacity)
|
|
155
152
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
--xz-color-
|
|
153
|
+
**Soft** — `is-variant-{name}-soft`:
|
|
154
|
+
```
|
|
155
|
+
background: var(--xz-color-{name}-soft-100);
|
|
156
|
+
color: var(--xz-color-{name}-text-200);
|
|
157
|
+
```
|
|
159
158
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
--xz-color-
|
|
159
|
+
**Soft-Solid** — `is-variant-{name}-soft-solid`:
|
|
160
|
+
```
|
|
161
|
+
background: var(--xz-color-{name}-soft-solid-100);
|
|
162
|
+
color: var(--xz-color-{name}-text-200);
|
|
163
163
|
```
|
|
164
|
+
Use soft-solid when the badge sits on a card (`surface-200`) to avoid transparency bleed-through.
|
|
164
165
|
|
|
165
|
-
|
|
166
|
+
---
|
|
166
167
|
|
|
167
|
-
|
|
168
|
-
|---|---|
|
|
169
|
-
| `--xz-color-overlay-400` to `--xz-color-overlay-600` | Modal/dialog backdrop (use `overlay-600` as default), drawer overlay, confirmation prompt scrim |
|
|
170
|
-
| `--xz-color-overlay-800` to `--xz-color-overlay-1000` | Immersive overlay — image lightbox, fullscreen video player, focus mode |
|
|
171
|
-
| `--xz-color-black-alpha-100` to `--xz-color-black-alpha-300` | Skeleton loader shimmer, disabled state overlay on light surfaces, subtle shadow layers |
|
|
172
|
-
| `--xz-color-black-alpha-400` to `--xz-color-black-alpha-600` | Text protection gradient on images (e.g., card hero image with title overlay), thumbnail scrim, image caption background |
|
|
173
|
-
| `--xz-color-white-alpha-100` to `--xz-color-white-alpha-300` | Glass/frost effect on dark backgrounds, subtle glow behind floating elements, dark-mode hover highlight |
|
|
174
|
-
| `--xz-color-white-alpha-400` to `--xz-color-white-alpha-600` | Text protection on dark images, light scrim for readability on dark hero sections |
|
|
168
|
+
### Message / Alert
|
|
175
169
|
|
|
176
|
-
|
|
170
|
+
**Default** (neutral):
|
|
171
|
+
```
|
|
172
|
+
border: 1px solid var(--xz-color-neutral-line-100);
|
|
173
|
+
background: var(--xz-color-neutral-soft-100);
|
|
174
|
+
color: var(--xz-color-neutral-text-100);
|
|
175
|
+
```
|
|
177
176
|
|
|
178
|
-
|
|
177
|
+
**Colored** — `is-variant-{name}` (primary, success, danger, warning, info, orange, purple):
|
|
178
|
+
```
|
|
179
|
+
border: 1px solid var(--xz-color-{name}-line-100);
|
|
180
|
+
background: var(--xz-color-{name}-soft-100);
|
|
181
|
+
color: var(--xz-color-{name}-text-100);
|
|
182
|
+
```
|
|
179
183
|
|
|
180
|
-
|
|
184
|
+
Note: Messages use `text-100` (not `text-200`) because they are content containers on transparent tinted backgrounds.
|
|
181
185
|
|
|
182
|
-
|
|
183
|
-
|---|---|
|
|
184
|
-
| Page background | `--xz-color-surface-100` |
|
|
185
|
-
| Card, modal, dialog | `--xz-color-surface-200` |
|
|
186
|
-
| Nested card or secondary panel | `--xz-color-surface-300` |
|
|
187
|
-
| Popover, dropdown, tooltip | `--xz-color-surface-400` |
|
|
188
|
-
| Inverted/dark block on page | `--xz-color-bg-100` |
|
|
189
|
-
| Text on inverted block | `--xz-color-text-fg` |
|
|
186
|
+
---
|
|
190
187
|
|
|
191
|
-
###
|
|
188
|
+
### Input
|
|
192
189
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
190
|
+
```
|
|
191
|
+
background: var(--xz-color-surface-50);
|
|
192
|
+
border: 1px solid var(--xz-color-line-100);
|
|
193
|
+
color: var(--xz-color-text-100);
|
|
194
|
+
hover → border-color: var(--xz-color-line-200);
|
|
195
|
+
focus → border-color: var(--xz-color-primary-line-200);
|
|
196
|
+
box-shadow: 0 0 0 0.175rem var(--xz-color-primary-soft-200);
|
|
197
|
+
```
|
|
199
198
|
|
|
200
|
-
|
|
199
|
+
Prefix/suffix: `color: var(--xz-color-text-300)`
|
|
200
|
+
Readonly/Disabled: `background: var(--xz-color-neutral-soft-100)`
|
|
201
201
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
| Default input or card border | `--xz-color-line-100` |
|
|
206
|
-
| Strong border, active outline | `--xz-color-line-200` |
|
|
207
|
-
| Strongest border, maximum emphasis | `--xz-color-line-300` |
|
|
208
|
-
| Colored border (semantic) | `--xz-color-{name}-line-100/200/300` |
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
### Field (validation wrapper around Input/Textarea)
|
|
209
205
|
|
|
210
|
-
|
|
206
|
+
Label: `color: var(--xz-color-text-100)`
|
|
207
|
+
Description: `color: var(--xz-color-text-300)`
|
|
208
|
+
Info text: `color: var(--xz-color-text-300)` (default)
|
|
211
209
|
|
|
210
|
+
**Success** — `is-variant-success`:
|
|
212
211
|
```
|
|
213
|
-
|
|
214
|
-
color:
|
|
215
|
-
|
|
212
|
+
info text → color: var(--xz-color-success-text-100);
|
|
213
|
+
input → border-color: var(--xz-color-success-line-200);
|
|
214
|
+
focus → box-shadow: 0 0 0 0.175rem var(--xz-color-success-soft-200);
|
|
216
215
|
```
|
|
217
216
|
|
|
218
|
-
|
|
219
|
-
|
|
217
|
+
**Danger** — `is-variant-danger`:
|
|
220
218
|
```
|
|
221
|
-
|
|
222
|
-
color:
|
|
223
|
-
|
|
219
|
+
info text → color: var(--xz-color-danger-text-100);
|
|
220
|
+
input → border-color: var(--xz-color-danger-line-200);
|
|
221
|
+
focus → box-shadow: 0 0 0 0.175rem var(--xz-color-danger-soft-200);
|
|
224
222
|
```
|
|
225
223
|
|
|
226
|
-
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
### Checkbox
|
|
227
227
|
|
|
228
228
|
```
|
|
229
|
-
|
|
230
|
-
color:
|
|
231
|
-
|
|
229
|
+
Unchecked: border-color: var(--xz-color-line-200);
|
|
230
|
+
Checked: border-color + fill: var(--xz-color-primary-bg-100);
|
|
231
|
+
Disabled: background: var(--xz-color-neutral-soft-100); opacity: 0.7;
|
|
232
|
+
Disabled label: color: var(--xz-color-text-200);
|
|
233
|
+
Label: color: var(--xz-color-text-100);
|
|
232
234
|
```
|
|
233
235
|
|
|
234
|
-
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
### Radio
|
|
235
239
|
|
|
236
240
|
```
|
|
237
|
-
border-color: --xz-color-
|
|
238
|
-
|
|
241
|
+
Unchecked: border-color: var(--xz-color-line-200);
|
|
242
|
+
Checked: border + background: var(--xz-color-primary-bg-100);
|
|
243
|
+
inner dot: var(--xz-color-surface-50) inset shadow;
|
|
244
|
+
Disabled: background: var(--xz-color-neutral-soft-100); opacity: 0.7;
|
|
245
|
+
Disabled label: color: var(--xz-color-text-200);
|
|
246
|
+
Label: color: var(--xz-color-text-100);
|
|
239
247
|
```
|
|
240
248
|
|
|
241
|
-
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
### Switch
|
|
242
252
|
|
|
243
253
|
```
|
|
244
|
-
|
|
254
|
+
Off track: var(--xz-color-neutral-soft-solid-200);
|
|
255
|
+
On track: var(--xz-color-primary-bg-100);
|
|
256
|
+
Handle: white;
|
|
257
|
+
Disabled off: track: var(--xz-color-neutral-soft-200);
|
|
258
|
+
background: var(--xz-color-neutral-soft-100);
|
|
259
|
+
Label: color: var(--xz-color-text-100);
|
|
245
260
|
```
|
|
246
261
|
|
|
247
262
|
---
|
|
248
263
|
|
|
249
|
-
|
|
264
|
+
### Link
|
|
250
265
|
|
|
251
|
-
|
|
266
|
+
**Default**:
|
|
267
|
+
```
|
|
268
|
+
color: var(--xz-color-text-100);
|
|
269
|
+
hover → color: var(--xz-color-text-200);
|
|
270
|
+
```
|
|
252
271
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
border: none;
|
|
258
|
-
}
|
|
259
|
-
.btn-primary:hover {
|
|
260
|
-
background: var(--xz-color-primary-bg-200);
|
|
261
|
-
}
|
|
272
|
+
**Colored** — `is-variant-{name}` (primary, danger, success, warning, info):
|
|
273
|
+
```
|
|
274
|
+
color: var(--xz-color-{name}-text-100);
|
|
275
|
+
hover → color: var(--xz-color-{name}-text-200);
|
|
262
276
|
```
|
|
263
277
|
|
|
264
|
-
|
|
278
|
+
---
|
|
265
279
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
}
|
|
280
|
+
### Chip
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
Default: background: var(--xz-color-neutral-soft-100);
|
|
284
|
+
color: var(--xz-color-text-100);
|
|
285
|
+
Hover: background: var(--xz-color-neutral-soft-200);
|
|
286
|
+
Active: background: var(--xz-color-bg-100);
|
|
287
|
+
color: var(--xz-color-text-fg);
|
|
275
288
|
```
|
|
276
289
|
|
|
277
|
-
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
### Tab List
|
|
278
293
|
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
.btn-danger:hover {
|
|
286
|
-
background: var(--xz-color-danger-bg-200);
|
|
287
|
-
}
|
|
294
|
+
```
|
|
295
|
+
Container: background: var(--xz-color-neutral-soft-100);
|
|
296
|
+
Inactive: color: var(--xz-color-text-200);
|
|
297
|
+
Hover: background: var(--xz-color-neutral-soft-200);
|
|
298
|
+
Active: background: var(--xz-color-surface-50);
|
|
299
|
+
color: var(--xz-color-text-100);
|
|
288
300
|
```
|
|
289
301
|
|
|
290
|
-
|
|
302
|
+
---
|
|
291
303
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
304
|
+
### Button Group
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
Default: border: 1px solid var(--xz-color-line-50);
|
|
308
|
+
color: var(--xz-color-text-200);
|
|
309
|
+
Hover: background: var(--xz-color-neutral-soft-100);
|
|
310
|
+
Active: border-color: var(--xz-color-primary-line-300);
|
|
311
|
+
background: var(--xz-color-primary-soft-100);
|
|
312
|
+
color: var(--xz-color-primary-text-100);
|
|
298
313
|
```
|
|
299
314
|
|
|
300
|
-
|
|
315
|
+
---
|
|
301
316
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
color: var(--xz-color-success-text-100);
|
|
307
|
-
border: 1px solid var(--xz-color-success-line-100);
|
|
308
|
-
}
|
|
309
|
-
.alert-danger {
|
|
310
|
-
background: var(--xz-color-danger-soft-100);
|
|
311
|
-
color: var(--xz-color-danger-text-100);
|
|
312
|
-
border: 1px solid var(--xz-color-danger-line-100);
|
|
313
|
-
}
|
|
314
|
-
.alert-warning {
|
|
315
|
-
background: var(--xz-color-warning-soft-100);
|
|
316
|
-
color: var(--xz-color-warning-text-100);
|
|
317
|
-
border: 1px solid var(--xz-color-warning-line-100);
|
|
318
|
-
}
|
|
319
|
-
.alert-info {
|
|
320
|
-
background: var(--xz-color-info-soft-100);
|
|
321
|
-
color: var(--xz-color-info-text-100);
|
|
322
|
-
border: 1px solid var(--xz-color-info-line-100);
|
|
323
|
-
}
|
|
317
|
+
### Loader
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
Dot color: var(--xz-color-neutral-bg-200);
|
|
324
321
|
```
|
|
325
322
|
|
|
326
|
-
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
### Blank Slate
|
|
327
326
|
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
color: var(--xz-color-success-text-100);
|
|
332
|
-
}
|
|
327
|
+
```
|
|
328
|
+
background: var(--xz-color-neutral-soft-100);
|
|
329
|
+
text: color: var(--xz-color-neutral-text-100);
|
|
333
330
|
```
|
|
334
331
|
|
|
335
|
-
|
|
332
|
+
---
|
|
336
333
|
|
|
337
|
-
|
|
338
|
-
.badge-danger-solid {
|
|
339
|
-
background: var(--xz-color-danger-bg-100);
|
|
340
|
-
color: var(--xz-color-danger-text-fg);
|
|
341
|
-
}
|
|
342
|
-
```
|
|
334
|
+
## Layout Patterns (from KitchenSink Storybook)
|
|
343
335
|
|
|
344
|
-
|
|
336
|
+
These patterns come from the KitchenSink story — a real dashboard layout demonstrating how tokens combine.
|
|
345
337
|
|
|
338
|
+
### Dashboard Container
|
|
346
339
|
```css
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
color: var(--xz-color-text-100);
|
|
350
|
-
border: 1px solid var(--xz-color-line-100);
|
|
351
|
-
}
|
|
352
|
-
.input::placeholder {
|
|
353
|
-
color: var(--xz-color-text-300);
|
|
354
|
-
}
|
|
355
|
-
.input:focus {
|
|
356
|
-
border-color: var(--xz-color-primary-line-200);
|
|
357
|
-
box-shadow: 0 0 0 3px var(--xz-color-primary-soft-100);
|
|
358
|
-
outline: none;
|
|
359
|
-
}
|
|
360
|
-
.input.error {
|
|
361
|
-
border-color: var(--xz-color-danger-line-200);
|
|
362
|
-
box-shadow: 0 0 0 3px var(--xz-color-danger-soft-100);
|
|
363
|
-
}
|
|
340
|
+
background: var(--xz-color-surface-100);
|
|
341
|
+
color: var(--xz-color-text-100);
|
|
364
342
|
```
|
|
365
343
|
|
|
366
|
-
###
|
|
367
|
-
|
|
344
|
+
### Card
|
|
368
345
|
```css
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
.text-link { color: var(--xz-color-primary-text-100); }
|
|
373
|
-
.text-danger { color: var(--xz-color-danger-text-100); }
|
|
374
|
-
.text-success { color: var(--xz-color-success-text-100); }
|
|
346
|
+
background: var(--xz-color-surface-200);
|
|
347
|
+
/* Danger zone card: add border */
|
|
348
|
+
border: 1px solid var(--xz-color-danger-line-100);
|
|
375
349
|
```
|
|
376
350
|
|
|
377
|
-
###
|
|
378
|
-
|
|
351
|
+
### Data Table
|
|
379
352
|
```css
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
.navbar-link { color: var(--xz-color-text-200); }
|
|
386
|
-
.navbar-link:hover { color: var(--xz-color-text-100); }
|
|
387
|
-
.navbar-link.active { color: var(--xz-color-primary-text-100); }
|
|
353
|
+
thead { background: var(--xz-color-surface-300); }
|
|
354
|
+
thead { border-bottom: 2px solid var(--xz-color-line-100); }
|
|
355
|
+
td { border-bottom: 1px solid var(--xz-color-line-50); }
|
|
356
|
+
tr:hover { background: var(--xz-color-surface-300); }
|
|
388
357
|
```
|
|
389
358
|
|
|
390
|
-
###
|
|
391
|
-
|
|
359
|
+
### Stat Card Icon
|
|
392
360
|
```css
|
|
393
|
-
|
|
394
|
-
.
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
color: var(--xz-color-text-100);
|
|
398
|
-
}
|
|
399
|
-
.sidebar-item.active {
|
|
400
|
-
background: var(--xz-color-primary-soft-100);
|
|
401
|
-
color: var(--xz-color-primary-text-100);
|
|
402
|
-
}
|
|
403
|
-
.sidebar-section-label {
|
|
404
|
-
font: var(--xz-font-subtitle3-bold);
|
|
405
|
-
color: var(--xz-color-text-300);
|
|
361
|
+
/* Replace {name} with: primary, success, warning, danger */
|
|
362
|
+
.stat-icon {
|
|
363
|
+
background: var(--xz-color-{name}-soft-100);
|
|
364
|
+
color: var(--xz-color-{name}-text-100);
|
|
406
365
|
}
|
|
407
366
|
```
|
|
408
367
|
|
|
409
|
-
###
|
|
410
|
-
|
|
368
|
+
### Avatar
|
|
411
369
|
```css
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
.table td { border-top: 1px solid var(--xz-color-line-50); font: var(--xz-font-body2); color: var(--xz-color-text-100); }
|
|
415
|
-
.table tr:hover { background: var(--xz-color-neutral-soft-100); }
|
|
416
|
-
.table tr.selected { background: var(--xz-color-primary-soft-100); }
|
|
370
|
+
background: var(--xz-color-primary-soft-200);
|
|
371
|
+
color: var(--xz-color-primary-text-100);
|
|
417
372
|
```
|
|
418
373
|
|
|
419
|
-
###
|
|
420
|
-
|
|
374
|
+
### Activity Feed Item
|
|
421
375
|
```css
|
|
422
|
-
|
|
423
|
-
.
|
|
424
|
-
.
|
|
376
|
+
border-bottom: 1px solid var(--xz-color-line-50);
|
|
377
|
+
.description { color: var(--xz-color-text-200); }
|
|
378
|
+
.timestamp { color: var(--xz-color-text-200); }
|
|
425
379
|
```
|
|
426
380
|
|
|
427
|
-
###
|
|
428
|
-
|
|
381
|
+
### Settings Row
|
|
429
382
|
```css
|
|
430
|
-
|
|
431
|
-
.
|
|
432
|
-
background: var(--xz-color-success-soft-solid-100);
|
|
433
|
-
color: var(--xz-color-success-text-100);
|
|
434
|
-
border-left: 4px solid var(--xz-color-success-bg-100);
|
|
435
|
-
box-shadow: var(--xz-shadow-300);
|
|
436
|
-
}
|
|
383
|
+
border-bottom: 1px solid var(--xz-color-line-50);
|
|
384
|
+
.description { color: var(--xz-color-text-200); }
|
|
437
385
|
```
|
|
438
386
|
|
|
439
|
-
###
|
|
440
|
-
|
|
387
|
+
### Subtitle / Muted Text
|
|
441
388
|
```css
|
|
442
|
-
|
|
443
|
-
background: var(--xz-color-neutral-soft-100);
|
|
444
|
-
color: var(--xz-color-neutral-text-100);
|
|
445
|
-
border: 1px solid var(--xz-color-neutral-line-100);
|
|
446
|
-
font: var(--xz-font-body3);
|
|
447
|
-
}
|
|
448
|
-
.chip-remove { color: var(--xz-color-neutral-text-200); }
|
|
449
|
-
.chip-remove:hover { color: var(--xz-color-danger-text-100); }
|
|
389
|
+
color: var(--xz-color-text-200);
|
|
450
390
|
```
|
|
451
391
|
|
|
452
|
-
|
|
392
|
+
---
|
|
453
393
|
|
|
454
|
-
|
|
455
|
-
.status-dot { border: 2px solid var(--xz-color-surface-200); }
|
|
456
|
-
.status-dot.online { background: var(--xz-color-success-bg-100); }
|
|
457
|
-
.status-dot.busy { background: var(--xz-color-danger-bg-100); }
|
|
458
|
-
.status-dot.away { background: var(--xz-color-warning-bg-100); }
|
|
459
|
-
.status-dot.offline { background: var(--xz-color-neutral-bg-100); }
|
|
460
|
-
```
|
|
394
|
+
## Box Shadow Tokens
|
|
461
395
|
|
|
462
|
-
|
|
396
|
+
Four elevation levels. Theme-aware (shadows are stronger in dark mode).
|
|
397
|
+
|
|
398
|
+
| Token | Value (light) | Use for |
|
|
399
|
+
|---|---|---|
|
|
400
|
+
| `--xz-box-shadow-100` | `0 1px 2px 0 rgba(0,0,0,0.08)` | Subtle lift — tab-list active item |
|
|
401
|
+
| `--xz-box-shadow-200` | `0 2px 6px 0 rgba(0,0,0,0.10)` | Cards on hover, floating elements |
|
|
402
|
+
| `--xz-box-shadow-300` | `0 4px 16px 0 rgba(0,0,0,0.12)` | Dropdown, popover, autocomplete |
|
|
403
|
+
| `--xz-box-shadow-400` | `0 8px 20px 0 rgba(0,0,0,0.14)` | Modal, drawer, lightbox |
|
|
463
404
|
|
|
405
|
+
### Shadow with or without border
|
|
406
|
+
|
|
407
|
+
Cards and elevated elements can use **shadow only**, **border only**, or **both**. The choice depends on how much visual separation you need:
|
|
408
|
+
|
|
409
|
+
**Shadow only** (no border) — clean, modern look. Use when the element floats above the page and the shadow provides enough contrast:
|
|
464
410
|
```css
|
|
465
|
-
.
|
|
466
|
-
background: var(--xz-color-
|
|
467
|
-
|
|
468
|
-
animation: skeleton-pulse 1.5s ease-in-out infinite;
|
|
469
|
-
}
|
|
470
|
-
@keyframes skeleton-pulse {
|
|
471
|
-
50% { opacity: 0.5; }
|
|
411
|
+
.card {
|
|
412
|
+
background: var(--xz-color-surface-200);
|
|
413
|
+
box-shadow: var(--xz-box-shadow-200);
|
|
472
414
|
}
|
|
473
415
|
```
|
|
474
416
|
|
|
475
|
-
|
|
476
|
-
|
|
417
|
+
**Border only** (no shadow) — flat, subtle look. Use for inline elements that sit flush with the page:
|
|
477
418
|
```css
|
|
478
|
-
.
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
.pricing-cta-primary { background: var(--xz-color-primary-bg-100); color: var(--xz-color-primary-text-fg); }
|
|
483
|
-
.pricing-cta-secondary { background: transparent; color: var(--xz-color-neutral-text-100); border: 1px solid var(--xz-color-neutral-line-200); }
|
|
419
|
+
.card {
|
|
420
|
+
background: var(--xz-color-surface-200);
|
|
421
|
+
border: 1px solid var(--xz-color-line-50);
|
|
422
|
+
}
|
|
484
423
|
```
|
|
485
424
|
|
|
486
|
-
|
|
425
|
+
**Both shadow and border** — maximum definition. Use when you need strong separation, especially in dark mode where shadows alone can be hard to see:
|
|
426
|
+
```css
|
|
427
|
+
.card {
|
|
428
|
+
background: var(--xz-color-surface-200);
|
|
429
|
+
border: 1px solid var(--xz-color-line-50);
|
|
430
|
+
box-shadow: var(--xz-box-shadow-200);
|
|
431
|
+
}
|
|
432
|
+
```
|
|
487
433
|
|
|
434
|
+
**Shadow on hover** — adds lift interaction to cards:
|
|
488
435
|
```css
|
|
489
|
-
.
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
.
|
|
436
|
+
.card {
|
|
437
|
+
background: var(--xz-color-surface-200);
|
|
438
|
+
transition: box-shadow 0.2s ease;
|
|
439
|
+
}
|
|
440
|
+
.card:hover {
|
|
441
|
+
box-shadow: var(--xz-box-shadow-200);
|
|
442
|
+
}
|
|
494
443
|
```
|
|
495
444
|
|
|
496
445
|
---
|
|
497
446
|
|
|
498
|
-
##
|
|
499
|
-
|
|
500
|
-
Figma variables mirror the CSS token system exactly. Every CSS variable has a corresponding Figma variable in the same collection.
|
|
447
|
+
## Alpha & Overlay Tokens
|
|
501
448
|
|
|
502
|
-
|
|
449
|
+
Utility tokens with a 100–1000 scale (10%–100% opacity).
|
|
503
450
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
451
|
+
### Overlay (`--xz-color-overlay-{scale}`)
|
|
452
|
+
| Range | Use |
|
|
453
|
+
|---|---|
|
|
454
|
+
| `400`–`600` | Modal/dialog backdrop (default: `overlay-600`) |
|
|
455
|
+
| `800`–`1000` | Immersive overlay — lightbox, fullscreen video |
|
|
507
456
|
|
|
508
|
-
###
|
|
457
|
+
### Black Alpha (`--xz-color-black-alpha-{scale}`)
|
|
458
|
+
| Range | Use |
|
|
459
|
+
|---|---|
|
|
460
|
+
| `100`–`300` | Skeleton shimmer, disabled overlay on light surfaces |
|
|
461
|
+
| `400`–`600` | Text protection gradient on images, thumbnail scrim |
|
|
509
462
|
|
|
510
|
-
|
|
463
|
+
### White Alpha (`--xz-color-white-alpha-{scale}`)
|
|
464
|
+
| Range | Use |
|
|
465
|
+
|---|---|
|
|
466
|
+
| `100`–`300` | Glass/frost effect on dark backgrounds, dark-mode hover |
|
|
467
|
+
| `400`–`600` | Text protection on dark images, light scrim |
|
|
511
468
|
|
|
512
|
-
|
|
513
|
-
|---|---|---|
|
|
514
|
-
| Base theme token | `theme/base/{property}/{scale}` | `--xz-color-{property}-{scale}` |
|
|
515
|
-
| Semantic theme token | `theme/{category}/{property}/{scale}` | `--xz-color-{category}-{property}-{scale}` |
|
|
516
|
-
| Alpha token | `theme/blackAlpha/{scale}` | `--xz-color-black-alpha-{scale}` |
|
|
517
|
-
| Alpha token | `theme/whiteAlpha/{scale}` | `--xz-color-white-alpha-{scale}` |
|
|
518
|
-
| Overlay token | `theme/overlay/{scale}` | `--xz-color-overlay-{scale}` |
|
|
519
|
-
| Palette primitive | `palette/{name}` | `--xz-color-{name}` |
|
|
469
|
+
---
|
|
520
470
|
|
|
521
|
-
|
|
471
|
+
## Typography Tokens
|
|
522
472
|
|
|
523
|
-
|
|
473
|
+
Typography tokens are defined in `base.css` (not theme files). They do not change between light and dark themes. All font shorthand tokens are automatically responsive — at `max-width: 768px` they scale down via a media query. No extra breakpoint code needed.
|
|
524
474
|
|
|
525
|
-
|
|
526
|
-
|---|---|
|
|
527
|
-
| `theme/base/bg/100` | `--xz-color-bg-100` |
|
|
528
|
-
| `theme/base/bg/200` | `--xz-color-bg-200` |
|
|
529
|
-
| `theme/base/surface/50` | `--xz-color-surface-50` |
|
|
530
|
-
| `theme/base/surface/100` | `--xz-color-surface-100` |
|
|
531
|
-
| `theme/base/surface/200` | `--xz-color-surface-200` |
|
|
532
|
-
| `theme/base/surface/300` | `--xz-color-surface-300` |
|
|
533
|
-
| `theme/base/surface/400` | `--xz-color-surface-400` |
|
|
534
|
-
| `theme/base/text/fg` | `--xz-color-text-fg` |
|
|
535
|
-
| `theme/base/text/100` | `--xz-color-text-100` |
|
|
536
|
-
| `theme/base/text/200` | `--xz-color-text-200` |
|
|
537
|
-
| `theme/base/text/300` | `--xz-color-text-300` |
|
|
538
|
-
| `theme/base/line/50` | `--xz-color-line-50` |
|
|
539
|
-
| `theme/base/line/100` | `--xz-color-line-100` |
|
|
540
|
-
| `theme/base/line/200` | `--xz-color-line-200` |
|
|
541
|
-
| `theme/base/line/300` | `--xz-color-line-300` |
|
|
542
|
-
|
|
543
|
-
#### Semantic Categories (11 variables each; neutral has 12)
|
|
544
|
-
|
|
545
|
-
Same pattern for all 8 categories: `primary`, `danger`, `success`, `warning`, `info`, `neutral`, `orange`, `purple`.
|
|
546
|
-
|
|
547
|
-
| Figma Variable | CSS Variable |
|
|
548
|
-
|---|---|
|
|
549
|
-
| `theme/{name}/soft/100` | `--xz-color-{name}-soft-100` |
|
|
550
|
-
| `theme/{name}/soft/200` | `--xz-color-{name}-soft-200` |
|
|
551
|
-
| `theme/{name}/softSolid/100` | `--xz-color-{name}-soft-solid-100` |
|
|
552
|
-
| `theme/{name}/softSolid/200` | `--xz-color-{name}-soft-solid-200` |
|
|
553
|
-
| `theme/{name}/line/100` | `--xz-color-{name}-line-100` |
|
|
554
|
-
| `theme/{name}/line/200` | `--xz-color-{name}-line-200` |
|
|
555
|
-
| `theme/{name}/line/300` | `--xz-color-{name}-line-300` |
|
|
556
|
-
| `theme/{name}/bg/100` | `--xz-color-{name}-bg-100` |
|
|
557
|
-
| `theme/{name}/bg/200` | `--xz-color-{name}-bg-200` |
|
|
558
|
-
| `theme/{name}/text/fg` | `--xz-color-{name}-text-fg` |
|
|
559
|
-
| `theme/{name}/text/100` | `--xz-color-{name}-text-100` |
|
|
560
|
-
|
|
561
|
-
> **`neutral` exception:** also includes `theme/neutral/text/200` → `--xz-color-neutral-text-200`.
|
|
562
|
-
|
|
563
|
-
#### Black Alpha (10 variables)
|
|
564
|
-
|
|
565
|
-
| Figma Variable | CSS Variable |
|
|
566
|
-
|---|---|
|
|
567
|
-
| `theme/blackAlpha/100` | `--xz-color-black-alpha-100` |
|
|
568
|
-
| `theme/blackAlpha/200` | `--xz-color-black-alpha-200` |
|
|
569
|
-
| `theme/blackAlpha/300` | `--xz-color-black-alpha-300` |
|
|
570
|
-
| `theme/blackAlpha/400` | `--xz-color-black-alpha-400` |
|
|
571
|
-
| `theme/blackAlpha/500` | `--xz-color-black-alpha-500` |
|
|
572
|
-
| `theme/blackAlpha/600` | `--xz-color-black-alpha-600` |
|
|
573
|
-
| `theme/blackAlpha/700` | `--xz-color-black-alpha-700` |
|
|
574
|
-
| `theme/blackAlpha/800` | `--xz-color-black-alpha-800` |
|
|
575
|
-
| `theme/blackAlpha/900` | `--xz-color-black-alpha-900` |
|
|
576
|
-
| `theme/blackAlpha/1000` | `--xz-color-black-alpha-1000` |
|
|
577
|
-
|
|
578
|
-
#### White Alpha (10 variables)
|
|
579
|
-
|
|
580
|
-
| Figma Variable | CSS Variable |
|
|
581
|
-
|---|---|
|
|
582
|
-
| `theme/whiteAlpha/100` | `--xz-color-white-alpha-100` |
|
|
583
|
-
| `theme/whiteAlpha/200` | `--xz-color-white-alpha-200` |
|
|
584
|
-
| `theme/whiteAlpha/300` | `--xz-color-white-alpha-300` |
|
|
585
|
-
| `theme/whiteAlpha/400` | `--xz-color-white-alpha-400` |
|
|
586
|
-
| `theme/whiteAlpha/500` | `--xz-color-white-alpha-500` |
|
|
587
|
-
| `theme/whiteAlpha/600` | `--xz-color-white-alpha-600` |
|
|
588
|
-
| `theme/whiteAlpha/700` | `--xz-color-white-alpha-700` |
|
|
589
|
-
| `theme/whiteAlpha/800` | `--xz-color-white-alpha-800` |
|
|
590
|
-
| `theme/whiteAlpha/900` | `--xz-color-white-alpha-900` |
|
|
591
|
-
| `theme/whiteAlpha/1000` | `--xz-color-white-alpha-1000` |
|
|
592
|
-
|
|
593
|
-
#### Overlay (10 variables)
|
|
594
|
-
|
|
595
|
-
| Figma Variable | CSS Variable |
|
|
596
|
-
|---|---|
|
|
597
|
-
| `theme/overlay/100` | `--xz-color-overlay-100` |
|
|
598
|
-
| `theme/overlay/200` | `--xz-color-overlay-200` |
|
|
599
|
-
| `theme/overlay/300` | `--xz-color-overlay-300` |
|
|
600
|
-
| `theme/overlay/400` | `--xz-color-overlay-400` |
|
|
601
|
-
| `theme/overlay/500` | `--xz-color-overlay-500` |
|
|
602
|
-
| `theme/overlay/600` | `--xz-color-overlay-600` |
|
|
603
|
-
| `theme/overlay/700` | `--xz-color-overlay-700` |
|
|
604
|
-
| `theme/overlay/800` | `--xz-color-overlay-800` |
|
|
605
|
-
| `theme/overlay/900` | `--xz-color-overlay-900` |
|
|
606
|
-
| `theme/overlay/1000` | `--xz-color-overlay-1000` |
|
|
607
|
-
|
|
608
|
-
#### Palette (8 variables)
|
|
609
|
-
|
|
610
|
-
| Figma Variable | CSS Variable |
|
|
611
|
-
|---|---|
|
|
612
|
-
| `palette/fastwork` | `--xz-color-fastwork` |
|
|
613
|
-
| `palette/gray` | `--xz-color-gray` |
|
|
614
|
-
| `palette/green` | `--xz-color-green` |
|
|
615
|
-
| `palette/yellow` | `--xz-color-yellow` |
|
|
616
|
-
| `palette/red` | `--xz-color-red` |
|
|
617
|
-
| `palette/orange` | `--xz-color-orange` |
|
|
618
|
-
| `palette/purple` | `--xz-color-purple` |
|
|
619
|
-
| `palette/cyan` | `--xz-color-cyan` |
|
|
475
|
+
### Font Families
|
|
620
476
|
|
|
621
|
-
|
|
477
|
+
| Token | Fonts | Use for |
|
|
478
|
+
|---|---|---|
|
|
479
|
+
| `--xz-font-family-primary` | Google Sans + system sans-serif stack | Body text, input values, badges |
|
|
480
|
+
| `--xz-font-family-secondary` | Noto Sans Thai, Noto Sans + system stack | Buttons, chips, labels, field labels, tab-list, button-group, blank-slate titles, headings |
|
|
622
481
|
|
|
623
|
-
|
|
624
|
-
2. In the Fill or Stroke panel, click the color swatch
|
|
625
|
-
3. Switch to the **Variables** tab in the color picker
|
|
626
|
-
4. Pick from the `colors` collection
|
|
482
|
+
**Rule**: `--xz-font-family-secondary` is the default for interactive/UI elements (buttons, chips, tabs, labels). `--xz-font-family-primary` is for content text (body, inputs, badges).
|
|
627
483
|
|
|
628
|
-
|
|
629
|
-
- Always use `theme/*` variables for component fills, text colors, and stroke colors
|
|
630
|
-
- Use `palette/*` variables only as references — not directly on components
|
|
631
|
-
- Use `theme/base/surface/100` for page backgrounds, `theme/base/surface/200` for cards
|
|
632
|
-
- Use `theme/{name}/bg/100` for solid-filled elements and `theme/{name}/text/fg` for text on top of them
|
|
633
|
-
- Switch between Light/Dark previews using the **Mode** toggle on the variable collection
|
|
484
|
+
### Font Shorthand Tokens
|
|
634
485
|
|
|
635
|
-
|
|
486
|
+
Apply with `font: var(--xz-font-{name})`. Each token encodes: `{weight} {size}/{line-height} {font-family}`.
|
|
636
487
|
|
|
637
|
-
|
|
488
|
+
#### Headings (secondary font, weight 700, responsive)
|
|
638
489
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
490
|
+
| Token | Desktop | Mobile (≤768px) |
|
|
491
|
+
|---|---|---|
|
|
492
|
+
| `--xz-font-heading1` | 4.5rem (72px) | 3rem (48px) |
|
|
493
|
+
| `--xz-font-heading2` | 4rem (64px) | 2.6875rem (43px) |
|
|
494
|
+
| `--xz-font-heading3` | 3.5rem (56px) | 2.375rem (38px) |
|
|
495
|
+
| `--xz-font-heading4` | 3rem (48px) | 2rem (32px) |
|
|
496
|
+
| `--xz-font-heading5` | 2.5rem (40px) | 1.625rem (26px) |
|
|
497
|
+
| `--xz-font-heading6` | 2rem (32px) | 1.5rem (24px) |
|
|
643
498
|
|
|
644
|
-
|
|
499
|
+
#### Titles (primary font, weight 700, responsive)
|
|
645
500
|
|
|
646
|
-
|
|
501
|
+
| Token | Desktop | Mobile (≤768px) |
|
|
502
|
+
|---|---|---|
|
|
503
|
+
| `--xz-font-title1` | 1.5rem (24px) | 1.5rem (24px) |
|
|
504
|
+
| `--xz-font-title2` | 1.25rem (20px) | 1.25rem (20px) |
|
|
505
|
+
| `--xz-font-title3` | 1.125rem (18px) | 1.125rem (18px) |
|
|
506
|
+
| `--xz-font-title4` | 1rem (16px) | 1rem (16px) |
|
|
647
507
|
|
|
648
|
-
|
|
508
|
+
#### Subtitles (primary font, responsive)
|
|
649
509
|
|
|
650
|
-
|
|
510
|
+
| Token | Weight | Desktop | Mobile (≤768px) |
|
|
511
|
+
|---|---|---|---|
|
|
512
|
+
| `--xz-font-subtitle1-bold` | 700 | 1rem (16px) | 1rem (16px) |
|
|
513
|
+
| `--xz-font-subtitle1-regular` | 400 | 1rem (16px) | 1rem (16px) |
|
|
514
|
+
| `--xz-font-subtitle2-bold` | 700 | 0.875rem (14px) | 0.875rem (14px) |
|
|
515
|
+
| `--xz-font-subtitle2-regular` | 400 | 0.875rem (14px) | 0.875rem (14px) |
|
|
516
|
+
| `--xz-font-subtitle3-bold` | 700 | 0.75rem (12px) | 0.75rem (12px) |
|
|
517
|
+
| `--xz-font-subtitle3-regular` | 400 | 0.75rem (12px) | 0.75rem (12px) |
|
|
651
518
|
|
|
652
|
-
|
|
519
|
+
#### Body (primary font, weight 400, responsive)
|
|
653
520
|
|
|
654
|
-
|
|
|
521
|
+
| Token | Desktop | Mobile (≤768px) |
|
|
655
522
|
|---|---|---|
|
|
656
|
-
| `--xz-font-
|
|
657
|
-
| `--xz-font-
|
|
523
|
+
| `--xz-font-body1` | 1rem (16px) | 1rem (16px) |
|
|
524
|
+
| `--xz-font-body2` | 0.875rem (14px) | 0.875rem (14px) |
|
|
525
|
+
| `--xz-font-body3` | 0.75rem (12px) | 0.75rem (12px) |
|
|
526
|
+
| `--xz-font-body4` | 0.625rem (10px) | 0.625rem (10px) |
|
|
658
527
|
|
|
659
|
-
**
|
|
528
|
+
> **Warning**: `body4` is 10px — very small. Avoid using it unless absolutely necessary (e.g., price strikethrough, micro timestamps). Prefer `body3` (12px) as the minimum readable size for most UI text.
|
|
660
529
|
|
|
661
530
|
### Font Size Scale
|
|
662
531
|
|
|
663
|
-
17 sizes
|
|
532
|
+
17 individual sizes. Use `--xz-font-size-{key}` when you need granular control outside the shorthand tokens.
|
|
664
533
|
|
|
665
|
-
|
|
|
666
|
-
|
|
667
|
-
| `--xz-font-size-50` | 0.5rem
|
|
668
|
-
| `--xz-font-size-100` | 0.625rem
|
|
669
|
-
| `--xz-font-size-200` | 0.75rem
|
|
670
|
-
| `--xz-font-size-300` | 0.875rem
|
|
671
|
-
| `--xz-font-size-400` | 1rem
|
|
672
|
-
| `--xz-font-size-500` | 1.125rem
|
|
673
|
-
| `--xz-font-size-600` | 1.25rem
|
|
674
|
-
| `--xz-font-size-700` | 1.5rem
|
|
675
|
-
| `--xz-font-size-800` | 1.625rem
|
|
676
|
-
| `--xz-font-size-900` | 2rem
|
|
677
|
-
| `--xz-font-size-1000` | 2.375rem
|
|
678
|
-
| `--xz-font-size-1100` | 2.5rem
|
|
679
|
-
| `--xz-font-size-1200` | 2.6875rem
|
|
680
|
-
| `--xz-font-size-1300` | 3rem
|
|
681
|
-
| `--xz-font-size-1400` | 3.5rem
|
|
682
|
-
| `--xz-font-size-1500` | 4rem
|
|
683
|
-
| `--xz-font-size-1600` | 4.5rem
|
|
534
|
+
| Token | Size |
|
|
535
|
+
|---|---|
|
|
536
|
+
| `--xz-font-size-50` | 0.5rem (8px) |
|
|
537
|
+
| `--xz-font-size-100` | 0.625rem (10px) |
|
|
538
|
+
| `--xz-font-size-200` | 0.75rem (12px) |
|
|
539
|
+
| `--xz-font-size-300` | 0.875rem (14px) |
|
|
540
|
+
| `--xz-font-size-400` | 1rem (16px) |
|
|
541
|
+
| `--xz-font-size-500` | 1.125rem (18px) |
|
|
542
|
+
| `--xz-font-size-600` | 1.25rem (20px) |
|
|
543
|
+
| `--xz-font-size-700` | 1.5rem (24px) |
|
|
544
|
+
| `--xz-font-size-800` | 1.625rem (26px) |
|
|
545
|
+
| `--xz-font-size-900` | 2rem (32px) |
|
|
546
|
+
| `--xz-font-size-1000` | 2.375rem (38px) |
|
|
547
|
+
| `--xz-font-size-1100` | 2.5rem (40px) |
|
|
548
|
+
| `--xz-font-size-1200` | 2.6875rem (43px) |
|
|
549
|
+
| `--xz-font-size-1300` | 3rem (48px) |
|
|
550
|
+
| `--xz-font-size-1400` | 3.5rem (56px) |
|
|
551
|
+
| `--xz-font-size-1500` | 4rem (64px) |
|
|
552
|
+
| `--xz-font-size-1600` | 4.5rem (72px) |
|
|
684
553
|
|
|
685
554
|
### Line Heights
|
|
686
555
|
|
|
687
|
-
|
|
|
556
|
+
| Token | Value |
|
|
688
557
|
|---|---|
|
|
689
558
|
| `--xz-line-height-100pct` | 1 |
|
|
690
559
|
| `--xz-line-height-125pct` | 1.25 |
|
|
691
560
|
| `--xz-line-height-135pct` | 1.35 |
|
|
692
|
-
| `--xz-line-height-150pct` | 1.5 (default for all tokens) |
|
|
561
|
+
| `--xz-line-height-150pct` | 1.5 (default for all shorthand tokens) |
|
|
693
562
|
| `--xz-line-height-165pct` | 1.65 |
|
|
694
563
|
| `--xz-line-height-200pct` | 2 |
|
|
695
564
|
|
|
696
|
-
###
|
|
697
|
-
|
|
698
|
-
These are **CSS font shorthand** variables. Apply with `font: var(--xz-font-{name})`.
|
|
565
|
+
### How to Use Each Token (with real examples)
|
|
699
566
|
|
|
700
|
-
|
|
567
|
+
All tokens are CSS font shorthands. Apply with `font: var(--xz-font-{name})`.
|
|
701
568
|
|
|
702
|
-
#### Headings
|
|
569
|
+
#### Headings — large display text, secondary font
|
|
703
570
|
|
|
704
|
-
|
|
571
|
+
Use for hero sections, landing pages, and major page-level headers. These are the only tokens that use `--xz-font-family-secondary` and they scale down significantly on mobile.
|
|
705
572
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
| `--xz-font-heading2` | 4rem (64px) | 2.6875rem (43px) |
|
|
710
|
-
| `--xz-font-heading3` | 3.5rem (56px) | 2.375rem (38px) |
|
|
711
|
-
| `--xz-font-heading4` | 3rem (48px) | 2rem (32px) |
|
|
712
|
-
| `--xz-font-heading5` | 2.5rem (40px) | 1.625rem (26px) |
|
|
713
|
-
| `--xz-font-heading6` | 2rem (32px) | 1.5rem (24px) |
|
|
573
|
+
```css
|
|
574
|
+
/* Landing page hero */
|
|
575
|
+
.hero-title { font: var(--xz-font-heading1); color: var(--xz-color-text-100); }
|
|
714
576
|
|
|
715
|
-
|
|
577
|
+
/* Section header on a content page */
|
|
578
|
+
.section-title { font: var(--xz-font-heading5); color: var(--xz-color-text-100); }
|
|
579
|
+
```
|
|
716
580
|
|
|
717
|
-
|
|
581
|
+
Real usage: PlayStore hero title uses `--xz-font-title3`, not heading — headings are reserved for truly large display text.
|
|
718
582
|
|
|
719
|
-
|
|
720
|
-
|---|---|---|
|
|
721
|
-
| `--xz-font-title1` | 1.5rem (24px) | 1.25rem (20px) |
|
|
722
|
-
| `--xz-font-title2` | 1.25rem (20px) | 1.125rem (18px) |
|
|
723
|
-
| `--xz-font-title3` | 1.125rem (18px) | 1rem (16px) |
|
|
724
|
-
| `--xz-font-title4` | 1rem (16px) | 0.875rem (14px) |
|
|
583
|
+
#### Titles — card/section headers, primary font, bold
|
|
725
584
|
|
|
726
|
-
|
|
585
|
+
Use for card titles, dialog headers, subsection titles. Smaller than headings but still bold and prominent.
|
|
727
586
|
|
|
728
|
-
|
|
587
|
+
```css
|
|
588
|
+
/* Card header */
|
|
589
|
+
.card-title { font: var(--xz-font-title2); color: var(--xz-color-text-100); }
|
|
729
590
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
| `--xz-font-subtitle1-bold` | 700 | 1rem (16px) | 0.875rem (14px) |
|
|
733
|
-
| `--xz-font-subtitle1-regular` | 400 | 1rem (16px) | 0.875rem (14px) |
|
|
734
|
-
| `--xz-font-subtitle2-bold` | 700 | 0.875rem (14px) | 0.75rem (12px) |
|
|
735
|
-
| `--xz-font-subtitle2-regular` | 400 | 0.875rem (14px) | 0.75rem (12px) |
|
|
736
|
-
| `--xz-font-subtitle3-bold` | 700 | 0.75rem (12px) | 0.625rem (10px) |
|
|
737
|
-
| `--xz-font-subtitle3-regular` | 400 | 0.75rem (12px) | 0.625rem (10px) |
|
|
591
|
+
/* Modal/dialog header */
|
|
592
|
+
.modal-title { font: var(--xz-font-title1); color: var(--xz-color-text-100); }
|
|
738
593
|
|
|
739
|
-
|
|
594
|
+
/* Small section title */
|
|
595
|
+
.section-label { font: var(--xz-font-title4); color: var(--xz-color-text-100); }
|
|
596
|
+
```
|
|
740
597
|
|
|
741
|
-
|
|
598
|
+
Real usage: CactusStore and PlayStore use `title3` for hero section titles within cards.
|
|
742
599
|
|
|
743
|
-
|
|
744
|
-
|---|---|---|
|
|
745
|
-
| `--xz-font-body1` | 1rem (16px) | 0.875rem (14px) |
|
|
746
|
-
| `--xz-font-body2` | 0.875rem (14px) | 0.75rem (12px) |
|
|
747
|
-
| `--xz-font-body3` | 0.75rem (12px) | 0.625rem (10px) |
|
|
748
|
-
| `--xz-font-body4` | 0.625rem (10px) | 0.5rem (8px) |
|
|
600
|
+
#### Subtitles — emphasized labels and supporting text
|
|
749
601
|
|
|
750
|
-
|
|
602
|
+
**Bold variants** — for labels that need emphasis: product names, prices, table headers, stat values, section headers within cards.
|
|
751
603
|
|
|
752
|
-
|
|
753
|
-
|---|---|
|
|
754
|
-
| Hero / landing page headline | `--xz-font-heading1` to `--xz-font-heading3` |
|
|
755
|
-
| Section heading | `--xz-font-heading4` to `--xz-font-heading6` |
|
|
756
|
-
| Card title, dialog title, modal header | `--xz-font-title1` to `--xz-font-title3` |
|
|
757
|
-
| Small section title, form group label | `--xz-font-title4` |
|
|
758
|
-
| Emphasized label, table header, stat value | `--xz-font-subtitle1-bold` or `--xz-font-subtitle2-bold` |
|
|
759
|
-
| Supporting label, metadata, timestamp | `--xz-font-subtitle2-regular` or `--xz-font-subtitle3-regular` |
|
|
760
|
-
| Navigation menu item, tab label | `--xz-font-subtitle2-bold` |
|
|
761
|
-
| Breadcrumb text | `--xz-font-body3` or `--xz-font-subtitle3-regular` |
|
|
762
|
-
| Default body text, paragraphs | `--xz-font-body1` or `--xz-font-body2` |
|
|
763
|
-
| Tooltip text | `--xz-font-body3` |
|
|
764
|
-
| Small print, captions, helper text | `--xz-font-body3` |
|
|
765
|
-
| Empty state message | `--xz-font-body1` (message) + `--xz-font-title3` (title) |
|
|
766
|
-
| Price display, number callout | `--xz-font-heading5` or `--xz-font-title1` |
|
|
767
|
-
| Micro text (badges, counters, dots) | `--xz-font-body4` |
|
|
768
|
-
|
|
769
|
-
### Typography CSS Examples
|
|
604
|
+
**Regular variants** — for secondary/supporting labels: metadata, timestamps, category names.
|
|
770
605
|
|
|
771
606
|
```css
|
|
772
|
-
/*
|
|
773
|
-
|
|
774
|
-
h2 { font: var(--xz-font-heading2); }
|
|
775
|
-
p { font: var(--xz-font-body2); }
|
|
607
|
+
/* Product name in a list */
|
|
608
|
+
.product-name { font: var(--xz-font-subtitle1-bold); color: var(--xz-color-text-100); }
|
|
776
609
|
|
|
777
|
-
/*
|
|
778
|
-
.
|
|
779
|
-
.card-body { font: var(--xz-font-body2); color: var(--xz-color-text-200); }
|
|
610
|
+
/* Product price */
|
|
611
|
+
.price { font: var(--xz-font-subtitle2-bold); color: var(--xz-color-text-100); }
|
|
780
612
|
|
|
781
|
-
/*
|
|
782
|
-
.
|
|
783
|
-
.helper { font: var(--xz-font-body3); color: var(--xz-color-text-300); }
|
|
613
|
+
/* Table column header */
|
|
614
|
+
.th { font: var(--xz-font-subtitle3-bold); color: var(--xz-color-text-100); }
|
|
784
615
|
|
|
785
|
-
/*
|
|
786
|
-
.
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
}
|
|
616
|
+
/* Timestamp / metadata */
|
|
617
|
+
.meta { font: var(--xz-font-subtitle2-regular); color: var(--xz-color-text-200); }
|
|
618
|
+
|
|
619
|
+
/* Category label */
|
|
620
|
+
.category { font: var(--xz-font-subtitle3-regular); color: var(--xz-color-text-200); }
|
|
791
621
|
```
|
|
792
622
|
|
|
793
|
-
|
|
623
|
+
Real usage: Watchtower dashboard uses `subtitle1-bold` for card titles, `subtitle2-bold` for stat labels and table headers, `subtitle3-bold` for section category labels.
|
|
794
624
|
|
|
795
|
-
|
|
625
|
+
#### Body — paragraph text and descriptions
|
|
796
626
|
|
|
797
|
-
|
|
627
|
+
`body2` (14px) is the most commonly used body size. `body1` (16px) for larger content areas. `body3` (12px) for secondary text, ratings, helper hints.
|
|
798
628
|
|
|
799
|
-
|
|
629
|
+
```css
|
|
630
|
+
/* Default body text */
|
|
631
|
+
.description { font: var(--xz-font-body2); color: var(--xz-color-text-200); }
|
|
800
632
|
|
|
801
|
-
|
|
633
|
+
/* Search input placeholder style */
|
|
634
|
+
.search-text { font: var(--xz-font-body2); color: var(--xz-color-text-100); }
|
|
802
635
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
636
|
+
/* Ratings, secondary labels, "View more" links */
|
|
637
|
+
.secondary { font: var(--xz-font-body3); color: var(--xz-color-text-200); }
|
|
638
|
+
|
|
639
|
+
/* Form helper text */
|
|
640
|
+
.helper { font: var(--xz-font-body3); color: var(--xz-color-text-300); }
|
|
641
|
+
|
|
642
|
+
/* Micro text — only when necessary (10px is very small) */
|
|
643
|
+
.price-original { font: var(--xz-font-body4); color: var(--xz-color-text-300); text-decoration: line-through; }
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
Real usage: PlayStore uses `body2` for search input and category names, `body3` for ratings and "View more" links, `body4` only for crossed-out original prices and micro timestamps.
|
|
647
|
+
|
|
648
|
+
#### Granular control (when shorthand doesn't fit)
|
|
809
649
|
|
|
810
650
|
```css
|
|
811
|
-
.
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
.modal { box-shadow: var(--xz-shadow-400); }
|
|
817
|
-
.drawer { box-shadow: var(--xz-shadow-400); }
|
|
651
|
+
.custom {
|
|
652
|
+
font-family: var(--xz-font-family-primary);
|
|
653
|
+
font-size: var(--xz-font-size-300);
|
|
654
|
+
line-height: var(--xz-line-height-150pct);
|
|
655
|
+
}
|
|
818
656
|
```
|