@fastwork/xosmoz-theme 0.47.0 → 0.49.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 +7 -6
- package/dist/base.css +14 -14
- package/dist/dart/xz_colors.generated.dart +52 -50
- package/dist/figma-plugin.zip +0 -0
- package/dist/figma-tokens/Dark.json +29 -16
- package/dist/figma-tokens/Light.json +188 -175
- package/dist/index.js +32 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +32 -30
- package/dist/index.mjs.map +1 -1
- package/dist/llms.txt +822 -0
- package/dist/themes/dark.css +7 -6
- package/dist/themes/light.css +11 -10
- package/dist/themes.css +18 -16
- package/dist/tokens.js +14 -14
- package/dist/tokens.js.map +1 -1
- package/dist/tokens.mjs +14 -14
- package/dist/tokens.mjs.map +1 -1
- package/package.json +4 -5
- package/llms.txt +0 -502
package/dist/llms.txt
ADDED
|
@@ -0,0 +1,822 @@
|
|
|
1
|
+
# @fastwork/xosmoz-theme — Design Tokens Reference
|
|
2
|
+
|
|
3
|
+
> Design token system for Xosmoz. Uses OKLCH color space. Supports light and dark themes via CSS variables and `data-theme` attribute. This guide covers color tokens, typography tokens, and box shadows (CSS variables).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
### Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @fastwork/xosmoz-theme
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### CSS Imports
|
|
16
|
+
|
|
17
|
+
```css
|
|
18
|
+
/* Base styles: CSS reset, font imports, typography/spacing tokens */
|
|
19
|
+
@import '@fastwork/xosmoz-theme/base.css';
|
|
20
|
+
|
|
21
|
+
/* All themes (light + dark) */
|
|
22
|
+
@import '@fastwork/xosmoz-theme/themes.css';
|
|
23
|
+
|
|
24
|
+
/* OR import a specific theme only */
|
|
25
|
+
@import '@fastwork/xosmoz-theme/themes/light.css';
|
|
26
|
+
@import '@fastwork/xosmoz-theme/themes/dark.css';
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Theme Switching
|
|
30
|
+
|
|
31
|
+
Light theme is the default. Set `data-theme="dark"` on `<html>` for dark mode.
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<html>...</html> <!-- Light theme (default) -->
|
|
35
|
+
<html data-theme="dark">...</html> <!-- Dark theme -->
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
// Switch at runtime
|
|
40
|
+
document.documentElement.setAttribute('data-theme', 'dark');
|
|
41
|
+
document.documentElement.removeAttribute('data-theme'); // back to light
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Color Token Architecture
|
|
47
|
+
|
|
48
|
+
The system has two layers:
|
|
49
|
+
|
|
50
|
+
### Layer 1 — Palette Tokens (primitives)
|
|
51
|
+
Eight raw color values. These are single CSS variables (no numbered scales). They are the same in both light and dark themes.
|
|
52
|
+
|
|
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
|
+
```
|
|
63
|
+
|
|
64
|
+
**Rule: Do not use palette tokens directly in UI.** They exist as internal primitives. Always use semantic tokens instead.
|
|
65
|
+
|
|
66
|
+
### Layer 2 — Semantic Tokens (theme-aware)
|
|
67
|
+
These tokens change values between light and dark themes. Always use these for UI components, text, borders, and backgrounds.
|
|
68
|
+
|
|
69
|
+
Pattern: `--xz-color-{category}-{property}-{scale}`
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Base Tokens
|
|
74
|
+
|
|
75
|
+
Base tokens cover surfaces, text, borders, and neutral overlays. They are theme-aware (change in dark mode).
|
|
76
|
+
|
|
77
|
+
| CSS Variable | Purpose | When to use |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `--xz-color-surface-50` | Absolute white/darkest background | Iframe embed background, fullscreen canvas, outermost page wrapper |
|
|
80
|
+
| `--xz-color-surface-100` | Default page background | Main app body, full-page background, content area behind cards |
|
|
81
|
+
| `--xz-color-surface-200` | Elevated surface | Cards, modals, dialogs, sidebar panels, sheet bottoms |
|
|
82
|
+
| `--xz-color-surface-300` | Secondary elevated surface | Nested card inside a card, accordion content area, secondary panel, table header row background |
|
|
83
|
+
| `--xz-color-surface-400` | Tertiary elevated surface | Popover, dropdown menu, tooltip, context menu, autocomplete suggestion list, command palette |
|
|
84
|
+
| `--xz-color-bg-100` | Extreme base (near-black in light) | Footer dark band, inverted hero section, dark navbar, cookie banner |
|
|
85
|
+
| `--xz-color-bg-200` | Secondary extreme base | Dark sidebar variant, secondary inverted section, code block background |
|
|
86
|
+
| `--xz-color-fg-100` | Text/icon on bg-100 / bg-200 | White text on dark footer, icon on inverted navbar, button text on dark hero CTA |
|
|
87
|
+
| `--xz-color-text-100` | Primary text | Body text, headings, button labels, nav links, input values, table cell text |
|
|
88
|
+
| `--xz-color-text-200` | Secondary / muted text (70%) | Timestamps, helper text below inputs, subtitle under heading, metadata, breadcrumb inactive items |
|
|
89
|
+
| `--xz-color-text-300` | Disabled / placeholder text (60%) | Input placeholder, disabled button text, watermark text, empty state hint |
|
|
90
|
+
| `--xz-color-soft-100` | Very subtle neutral overlay (5%) | Hover highlight on table rows, subtle active state on sidebar items, zebra stripe alternate row |
|
|
91
|
+
| `--xz-color-soft-200` | Subtle neutral overlay (10%) | Selected/active row in list, pressed state on neutral elements, drag-over drop zone highlight |
|
|
92
|
+
| `--xz-color-line-50` | Subtle border | Horizontal divider between list items, subtle card border, separator between nav sections |
|
|
93
|
+
| `--xz-color-line-100` | Default border | Input border, card border, table cell border, tab bar bottom border |
|
|
94
|
+
| `--xz-color-line-200` | Emphasized border | Active/focus input border, emphasized separator, selected tab underline, strong divider |
|
|
95
|
+
| `--xz-color-line-300` | Strongest border | Maximum emphasis divider, high-contrast separator, strongest active outline |
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Semantic Tokens
|
|
100
|
+
|
|
101
|
+
Eight categories. Categories: `primary`, `danger`, `success`, `warning`, `info`, `neutral`, `orange`, `purple`. Most categories have 11 tokens; `neutral` has 12 (includes an extra `text-200`).
|
|
102
|
+
|
|
103
|
+
### Token Pattern per Category
|
|
104
|
+
|
|
105
|
+
Replace `{name}` with the category:
|
|
106
|
+
|
|
107
|
+
| CSS Variable | Purpose |
|
|
108
|
+
|---|---|
|
|
109
|
+
| `--xz-color-{name}-soft-100` | Tinted transparent background — lightest (10% opacity of base color) |
|
|
110
|
+
| `--xz-color-{name}-soft-200` | Tinted transparent background — stronger (16% opacity), use for hover |
|
|
111
|
+
| `--xz-color-{name}-soft-solid-100` | Opaque version of soft-100 (mixed into surface-100) — use on overlapping surfaces |
|
|
112
|
+
| `--xz-color-{name}-soft-solid-200` | Opaque version of soft-200 |
|
|
113
|
+
| `--xz-color-{name}-line-100` | Subtle colored border |
|
|
114
|
+
| `--xz-color-{name}-line-200` | Default colored border |
|
|
115
|
+
| `--xz-color-{name}-line-300` | Strong colored border |
|
|
116
|
+
| `--xz-color-{name}-bg-100` | Solid fill background — buttons, chips, badges |
|
|
117
|
+
| `--xz-color-{name}-bg-200` | Solid fill hover/pressed state |
|
|
118
|
+
| `--xz-color-{name}-fg-100` | Text/icon on solid bg — **always pair with bg-100 / bg-200** |
|
|
119
|
+
| `--xz-color-{name}-text-100` | Colored text on light surfaces — links, status labels |
|
|
120
|
+
|
|
121
|
+
> **`neutral` exception:** also includes `--xz-color-neutral-text-200` — Muted neutral text, lighter than `text-100`. Use for supporting content, secondary labels.
|
|
122
|
+
|
|
123
|
+
### Semantic Category Usage Map
|
|
124
|
+
|
|
125
|
+
When choosing a category, match the **intent** of the UI element:
|
|
126
|
+
|
|
127
|
+
| Category | Intent | Example scenarios |
|
|
128
|
+
|---|---|---|
|
|
129
|
+
| `primary` | Brand action, main interaction | CTA buttons, links, active tab indicator, selected checkbox/radio, progress bar fill, focused input ring, pagination current page |
|
|
130
|
+
| `danger` | Destructive action, error state | Delete/remove buttons, form validation error message, declined/rejected status badge, overdue indicator, "leave without saving" prompt |
|
|
131
|
+
| `success` | Positive outcome, completion | Success alert/toast, "completed" status badge, verified checkmark, approval indicator, "payment received" label, online status dot |
|
|
132
|
+
| `warning` | Caution, attention needed | Warning banner, "expiring soon" label, pending review status, low stock indicator, unsaved changes notice, trial ending alert |
|
|
133
|
+
| `info` | Informational, neutral notice | Info banner, help tooltip, "new feature" badge, system maintenance notice, changelog highlight, onboarding tip |
|
|
134
|
+
| `neutral` | Non-semantic, default UI | Secondary/ghost buttons, default tags/chips, inactive tabs, neutral badges (count), toggle off state, breadcrumb separator |
|
|
135
|
+
| `orange` | Special accent | Premium/pro plan badge, trending indicator, notification dot, highlight/featured card border, "hot" label, points/rewards |
|
|
136
|
+
| `purple` | Special accent | AI-powered feature badge, creator/author tag, premium tier indicator, special promotion label, "beta" badge |
|
|
137
|
+
|
|
138
|
+
### Key Rules for Semantic Tokens
|
|
139
|
+
|
|
140
|
+
- **`bg-100` + `fg-100`**: Solid fill components (buttons, solid badges). `fg-100` provides correct contrast (white or dark depending on the category color).
|
|
141
|
+
- **`soft-100` + `text-100` + `line-100`**: Soft/tinted style (alerts, soft badges, highlighted rows).
|
|
142
|
+
- **`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.
|
|
143
|
+
- **`text-100`**: Use for colored text that sits on surface backgrounds (not on solid fills). Examples: link text, status label text, tag text.
|
|
144
|
+
- **`line-*`**: Colored borders. Use `line-200` as the default, `line-100` for subtle, `line-300` for strong/emphasized.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Alpha & Overlay Tokens
|
|
149
|
+
|
|
150
|
+
These use a 100–1000 scale representing opacity from 0.1 to 1.0.
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
--xz-color-black-alpha-100 (black at 10% opacity)
|
|
154
|
+
--xz-color-black-alpha-200 (black at 20% opacity)
|
|
155
|
+
...
|
|
156
|
+
--xz-color-black-alpha-1000 (black at 100% opacity)
|
|
157
|
+
|
|
158
|
+
--xz-color-white-alpha-100 (white at 10% opacity)
|
|
159
|
+
...
|
|
160
|
+
--xz-color-white-alpha-1000 (white at 100% opacity)
|
|
161
|
+
|
|
162
|
+
--xz-color-overlay-100 (dark overlay at 10% opacity)
|
|
163
|
+
...
|
|
164
|
+
--xz-color-overlay-1000 (dark overlay at 100% opacity)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### When to use each range
|
|
168
|
+
|
|
169
|
+
| Token range | Scenario |
|
|
170
|
+
|---|---|
|
|
171
|
+
| `--xz-color-overlay-400` to `--xz-color-overlay-600` | Modal/dialog backdrop (use `overlay-600` as default), drawer overlay, confirmation prompt scrim |
|
|
172
|
+
| `--xz-color-overlay-800` to `--xz-color-overlay-1000` | Immersive overlay — image lightbox, fullscreen video player, focus mode |
|
|
173
|
+
| `--xz-color-black-alpha-100` to `--xz-color-black-alpha-300` | Skeleton loader shimmer, disabled state overlay on light surfaces, subtle shadow layers |
|
|
174
|
+
| `--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 |
|
|
175
|
+
| `--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 |
|
|
176
|
+
| `--xz-color-white-alpha-400` to `--xz-color-white-alpha-600` | Text protection on dark images, light scrim for readability on dark hero sections |
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Usage Guidelines
|
|
181
|
+
|
|
182
|
+
### Backgrounds & Surfaces
|
|
183
|
+
|
|
184
|
+
| Situation | Use |
|
|
185
|
+
|---|---|
|
|
186
|
+
| Page background | `--xz-color-surface-100` |
|
|
187
|
+
| Card, modal, dialog | `--xz-color-surface-200` |
|
|
188
|
+
| Nested card or secondary panel | `--xz-color-surface-300` |
|
|
189
|
+
| Popover, dropdown, tooltip | `--xz-color-surface-400` |
|
|
190
|
+
| Inverted/dark block on page | `--xz-color-bg-100` |
|
|
191
|
+
| Text on inverted block | `--xz-color-fg-100` |
|
|
192
|
+
|
|
193
|
+
### Text
|
|
194
|
+
|
|
195
|
+
| Situation | Use |
|
|
196
|
+
|---|---|
|
|
197
|
+
| Body text, headings | `--xz-color-text-100` |
|
|
198
|
+
| Secondary / helper text | `--xz-color-text-200` |
|
|
199
|
+
| Placeholder / disabled text | `--xz-color-text-300` |
|
|
200
|
+
| Colored status text (link, tag, label) | `--xz-color-{name}-text-100` |
|
|
201
|
+
|
|
202
|
+
### Borders
|
|
203
|
+
|
|
204
|
+
| Situation | Use |
|
|
205
|
+
|---|---|
|
|
206
|
+
| Subtle separator, divider | `--xz-color-line-50` |
|
|
207
|
+
| Default input or card border | `--xz-color-line-100` |
|
|
208
|
+
| Strong border, active outline | `--xz-color-line-200` |
|
|
209
|
+
| Strongest border, maximum emphasis | `--xz-color-line-300` |
|
|
210
|
+
| Colored border (semantic) | `--xz-color-{name}-line-100/200/300` |
|
|
211
|
+
|
|
212
|
+
### Solid Components (Buttons, Solid Badges)
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
background: --xz-color-{name}-bg-100
|
|
216
|
+
color: --xz-color-{name}-fg-100 ← always use fg-100 on bg-100
|
|
217
|
+
hover bg: --xz-color-{name}-bg-200
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Soft/Tinted Components (Alerts, Soft Badges)
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
background: --xz-color-{name}-soft-100
|
|
224
|
+
color: --xz-color-{name}-text-100
|
|
225
|
+
border: 1px solid --xz-color-{name}-line-100
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Outline/Ghost Components
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
background: transparent
|
|
232
|
+
color: --xz-color-{name}-text-100
|
|
233
|
+
border: 1px solid --xz-color-{name}-line-200
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Focus Ring
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
border-color: --xz-color-{name}-line-200
|
|
240
|
+
box-shadow: 0 0 0 3px --xz-color-{name}-soft-100
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Modal Backdrop
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
background: --xz-color-overlay-600
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Common UI Patterns
|
|
252
|
+
|
|
253
|
+
### Primary Button
|
|
254
|
+
|
|
255
|
+
```css
|
|
256
|
+
.btn-primary {
|
|
257
|
+
background: var(--xz-color-primary-bg-100);
|
|
258
|
+
color: var(--xz-color-primary-fg-100);
|
|
259
|
+
border: none;
|
|
260
|
+
}
|
|
261
|
+
.btn-primary:hover {
|
|
262
|
+
background: var(--xz-color-primary-bg-200);
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Outline Button
|
|
267
|
+
|
|
268
|
+
```css
|
|
269
|
+
.btn-outline {
|
|
270
|
+
background: transparent;
|
|
271
|
+
color: var(--xz-color-primary-text-100);
|
|
272
|
+
border: 1px solid var(--xz-color-primary-line-200);
|
|
273
|
+
}
|
|
274
|
+
.btn-outline:hover {
|
|
275
|
+
background: var(--xz-color-primary-soft-100);
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Danger Button
|
|
280
|
+
|
|
281
|
+
```css
|
|
282
|
+
.btn-danger {
|
|
283
|
+
background: var(--xz-color-danger-bg-100);
|
|
284
|
+
color: var(--xz-color-danger-fg-100);
|
|
285
|
+
border: none;
|
|
286
|
+
}
|
|
287
|
+
.btn-danger:hover {
|
|
288
|
+
background: var(--xz-color-danger-bg-200);
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Card
|
|
293
|
+
|
|
294
|
+
```css
|
|
295
|
+
.card {
|
|
296
|
+
background: var(--xz-color-surface-200);
|
|
297
|
+
color: var(--xz-color-text-100);
|
|
298
|
+
border: 1px solid var(--xz-color-line-50);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Alert (soft style)
|
|
303
|
+
|
|
304
|
+
```css
|
|
305
|
+
/* Replace {name} with: success | danger | warning | info */
|
|
306
|
+
.alert-success {
|
|
307
|
+
background: var(--xz-color-success-soft-100);
|
|
308
|
+
color: var(--xz-color-success-text-100);
|
|
309
|
+
border: 1px solid var(--xz-color-success-line-100);
|
|
310
|
+
}
|
|
311
|
+
.alert-danger {
|
|
312
|
+
background: var(--xz-color-danger-soft-100);
|
|
313
|
+
color: var(--xz-color-danger-text-100);
|
|
314
|
+
border: 1px solid var(--xz-color-danger-line-100);
|
|
315
|
+
}
|
|
316
|
+
.alert-warning {
|
|
317
|
+
background: var(--xz-color-warning-soft-100);
|
|
318
|
+
color: var(--xz-color-warning-text-100);
|
|
319
|
+
border: 1px solid var(--xz-color-warning-line-100);
|
|
320
|
+
}
|
|
321
|
+
.alert-info {
|
|
322
|
+
background: var(--xz-color-info-soft-100);
|
|
323
|
+
color: var(--xz-color-info-text-100);
|
|
324
|
+
border: 1px solid var(--xz-color-info-line-100);
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Badge — Soft
|
|
329
|
+
|
|
330
|
+
```css
|
|
331
|
+
.badge-success {
|
|
332
|
+
background: var(--xz-color-success-soft-100);
|
|
333
|
+
color: var(--xz-color-success-text-100);
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Badge — Solid
|
|
338
|
+
|
|
339
|
+
```css
|
|
340
|
+
.badge-danger-solid {
|
|
341
|
+
background: var(--xz-color-danger-bg-100);
|
|
342
|
+
color: var(--xz-color-danger-fg-100);
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Form Input
|
|
347
|
+
|
|
348
|
+
```css
|
|
349
|
+
.input {
|
|
350
|
+
background: var(--xz-color-surface-100);
|
|
351
|
+
color: var(--xz-color-text-100);
|
|
352
|
+
border: 1px solid var(--xz-color-line-100);
|
|
353
|
+
}
|
|
354
|
+
.input::placeholder {
|
|
355
|
+
color: var(--xz-color-text-300);
|
|
356
|
+
}
|
|
357
|
+
.input:focus {
|
|
358
|
+
border-color: var(--xz-color-primary-line-200);
|
|
359
|
+
box-shadow: 0 0 0 3px var(--xz-color-primary-soft-100);
|
|
360
|
+
outline: none;
|
|
361
|
+
}
|
|
362
|
+
.input.error {
|
|
363
|
+
border-color: var(--xz-color-danger-line-200);
|
|
364
|
+
box-shadow: 0 0 0 3px var(--xz-color-danger-soft-100);
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Text Hierarchy
|
|
369
|
+
|
|
370
|
+
```css
|
|
371
|
+
.text-primary { color: var(--xz-color-text-100); }
|
|
372
|
+
.text-muted { color: var(--xz-color-text-200); }
|
|
373
|
+
.text-disabled { color: var(--xz-color-text-300); }
|
|
374
|
+
.text-link { color: var(--xz-color-primary-text-100); }
|
|
375
|
+
.text-danger { color: var(--xz-color-danger-text-100); }
|
|
376
|
+
.text-success { color: var(--xz-color-success-text-100); }
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Navbar
|
|
380
|
+
|
|
381
|
+
```css
|
|
382
|
+
.navbar {
|
|
383
|
+
background: var(--xz-color-surface-200);
|
|
384
|
+
border-bottom: 1px solid var(--xz-color-line-50);
|
|
385
|
+
box-shadow: var(--xz-shadow-100);
|
|
386
|
+
}
|
|
387
|
+
.navbar-link { color: var(--xz-color-text-200); }
|
|
388
|
+
.navbar-link:hover { color: var(--xz-color-text-100); }
|
|
389
|
+
.navbar-link.active { color: var(--xz-color-primary-text-100); }
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Sidebar Navigation
|
|
393
|
+
|
|
394
|
+
```css
|
|
395
|
+
.sidebar { background: var(--xz-color-surface-200); }
|
|
396
|
+
.sidebar-item { color: var(--xz-color-text-200); }
|
|
397
|
+
.sidebar-item:hover {
|
|
398
|
+
background: var(--xz-color-soft-100);
|
|
399
|
+
color: var(--xz-color-text-100);
|
|
400
|
+
}
|
|
401
|
+
.sidebar-item.active {
|
|
402
|
+
background: var(--xz-color-primary-soft-100);
|
|
403
|
+
color: var(--xz-color-primary-text-100);
|
|
404
|
+
}
|
|
405
|
+
.sidebar-section-label {
|
|
406
|
+
font: var(--xz-font-subtitle3-bold);
|
|
407
|
+
color: var(--xz-color-text-300);
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Data Table
|
|
412
|
+
|
|
413
|
+
```css
|
|
414
|
+
.table { border: 1px solid var(--xz-color-line-100); }
|
|
415
|
+
.table th { background: var(--xz-color-surface-300); font: var(--xz-font-subtitle2-bold); color: var(--xz-color-text-100); }
|
|
416
|
+
.table td { border-top: 1px solid var(--xz-color-line-50); font: var(--xz-font-body2); color: var(--xz-color-text-100); }
|
|
417
|
+
.table tr:hover { background: var(--xz-color-soft-100); }
|
|
418
|
+
.table tr.selected { background: var(--xz-color-primary-soft-100); }
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Tabs
|
|
422
|
+
|
|
423
|
+
```css
|
|
424
|
+
.tab { color: var(--xz-color-neutral-text-100); border-bottom: 2px solid transparent; }
|
|
425
|
+
.tab:hover { color: var(--xz-color-text-100); background: var(--xz-color-soft-100); }
|
|
426
|
+
.tab.active { color: var(--xz-color-primary-text-100); border-bottom-color: var(--xz-color-primary-bg-100); }
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Toast / Snackbar
|
|
430
|
+
|
|
431
|
+
```css
|
|
432
|
+
/* Replace {name} with: success | danger | warning | info */
|
|
433
|
+
.toast {
|
|
434
|
+
background: var(--xz-color-success-soft-solid-100);
|
|
435
|
+
color: var(--xz-color-success-text-100);
|
|
436
|
+
border-left: 4px solid var(--xz-color-success-bg-100);
|
|
437
|
+
box-shadow: var(--xz-shadow-300);
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Chip / Tag with Remove
|
|
442
|
+
|
|
443
|
+
```css
|
|
444
|
+
.chip {
|
|
445
|
+
background: var(--xz-color-neutral-soft-100);
|
|
446
|
+
color: var(--xz-color-neutral-text-100);
|
|
447
|
+
border: 1px solid var(--xz-color-neutral-line-100);
|
|
448
|
+
font: var(--xz-font-body3);
|
|
449
|
+
}
|
|
450
|
+
.chip-remove { color: var(--xz-color-neutral-text-200); }
|
|
451
|
+
.chip-remove:hover { color: var(--xz-color-danger-text-100); }
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Avatar with Status Dot
|
|
455
|
+
|
|
456
|
+
```css
|
|
457
|
+
.status-dot { border: 2px solid var(--xz-color-surface-200); }
|
|
458
|
+
.status-dot.online { background: var(--xz-color-success-bg-100); }
|
|
459
|
+
.status-dot.busy { background: var(--xz-color-danger-bg-100); }
|
|
460
|
+
.status-dot.away { background: var(--xz-color-warning-bg-100); }
|
|
461
|
+
.status-dot.offline { background: var(--xz-color-neutral-bg-100); }
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Skeleton Loader
|
|
465
|
+
|
|
466
|
+
```css
|
|
467
|
+
.skeleton {
|
|
468
|
+
background: var(--xz-color-soft-200);
|
|
469
|
+
border-radius: 4px;
|
|
470
|
+
animation: skeleton-pulse 1.5s ease-in-out infinite;
|
|
471
|
+
}
|
|
472
|
+
@keyframes skeleton-pulse {
|
|
473
|
+
50% { opacity: 0.5; }
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### Pricing Card
|
|
478
|
+
|
|
479
|
+
```css
|
|
480
|
+
.pricing-card { background: var(--xz-color-surface-200); border: 1px solid var(--xz-color-line-50); }
|
|
481
|
+
.pricing-card.featured { border-color: var(--xz-color-primary-line-200); }
|
|
482
|
+
.pricing-price { font: var(--xz-font-heading5); color: var(--xz-color-text-100); }
|
|
483
|
+
.pricing-period { font: var(--xz-font-body3); color: var(--xz-color-text-200); }
|
|
484
|
+
.pricing-cta-primary { background: var(--xz-color-primary-bg-100); color: var(--xz-color-primary-fg-100); }
|
|
485
|
+
.pricing-cta-secondary { background: transparent; color: var(--xz-color-neutral-text-100); border: 1px solid var(--xz-color-neutral-line-200); }
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### Stepper / Progress
|
|
489
|
+
|
|
490
|
+
```css
|
|
491
|
+
.step.completed .step-circle { background: var(--xz-color-success-bg-100); color: var(--xz-color-success-fg-100); }
|
|
492
|
+
.step.current .step-circle { background: var(--xz-color-primary-bg-100); color: var(--xz-color-primary-fg-100); }
|
|
493
|
+
.step.pending .step-circle { background: var(--xz-color-neutral-soft-100); color: var(--xz-color-neutral-text-200); }
|
|
494
|
+
.step-connector.completed { background: var(--xz-color-success-bg-100); }
|
|
495
|
+
.step-connector.pending { background: var(--xz-color-line-100); }
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## Figma Variables Guide
|
|
501
|
+
|
|
502
|
+
Figma variables mirror the CSS token system exactly. Every CSS variable has a corresponding Figma variable in the same collection.
|
|
503
|
+
|
|
504
|
+
### Collection Structure
|
|
505
|
+
|
|
506
|
+
- **Collection name**: `colors`
|
|
507
|
+
- **Modes**: `Light` and `Dark`
|
|
508
|
+
- **Total variables**: ~160 color variables
|
|
509
|
+
|
|
510
|
+
### Naming Pattern
|
|
511
|
+
|
|
512
|
+
Figma uses slash-separated paths. The mapping to CSS is direct:
|
|
513
|
+
|
|
514
|
+
| Variable type | Figma path | CSS variable |
|
|
515
|
+
|---|---|---|
|
|
516
|
+
| Base theme token | `theme/base/{property}/{scale}` | `--xz-color-{property}-{scale}` |
|
|
517
|
+
| Semantic theme token | `theme/{category}/{property}/{scale}` | `--xz-color-{category}-{property}-{scale}` |
|
|
518
|
+
| Alpha token | `theme/blackAlpha/{scale}` | `--xz-color-black-alpha-{scale}` |
|
|
519
|
+
| Alpha token | `theme/whiteAlpha/{scale}` | `--xz-color-white-alpha-{scale}` |
|
|
520
|
+
| Overlay token | `theme/overlay/{scale}` | `--xz-color-overlay-{scale}` |
|
|
521
|
+
| Palette primitive | `palette/{name}` | `--xz-color-{name}` |
|
|
522
|
+
|
|
523
|
+
### Complete Figma → CSS Mapping
|
|
524
|
+
|
|
525
|
+
#### Base (17 variables)
|
|
526
|
+
|
|
527
|
+
| Figma Variable | CSS Variable |
|
|
528
|
+
|---|---|
|
|
529
|
+
| `theme/base/bg/100` | `--xz-color-bg-100` |
|
|
530
|
+
| `theme/base/bg/200` | `--xz-color-bg-200` |
|
|
531
|
+
| `theme/base/surface/50` | `--xz-color-surface-50` |
|
|
532
|
+
| `theme/base/surface/100` | `--xz-color-surface-100` |
|
|
533
|
+
| `theme/base/surface/200` | `--xz-color-surface-200` |
|
|
534
|
+
| `theme/base/surface/300` | `--xz-color-surface-300` |
|
|
535
|
+
| `theme/base/surface/400` | `--xz-color-surface-400` |
|
|
536
|
+
| `theme/base/fg/100` | `--xz-color-fg-100` |
|
|
537
|
+
| `theme/base/soft/100` | `--xz-color-soft-100` |
|
|
538
|
+
| `theme/base/soft/200` | `--xz-color-soft-200` |
|
|
539
|
+
| `theme/base/text/100` | `--xz-color-text-100` |
|
|
540
|
+
| `theme/base/text/200` | `--xz-color-text-200` |
|
|
541
|
+
| `theme/base/text/300` | `--xz-color-text-300` |
|
|
542
|
+
| `theme/base/line/50` | `--xz-color-line-50` |
|
|
543
|
+
| `theme/base/line/100` | `--xz-color-line-100` |
|
|
544
|
+
| `theme/base/line/200` | `--xz-color-line-200` |
|
|
545
|
+
| `theme/base/line/300` | `--xz-color-line-300` |
|
|
546
|
+
|
|
547
|
+
#### Semantic Categories (11 variables each; neutral has 12)
|
|
548
|
+
|
|
549
|
+
Same pattern for all 8 categories: `primary`, `danger`, `success`, `warning`, `info`, `neutral`, `orange`, `purple`.
|
|
550
|
+
|
|
551
|
+
| Figma Variable | CSS Variable |
|
|
552
|
+
|---|---|
|
|
553
|
+
| `theme/{name}/soft/100` | `--xz-color-{name}-soft-100` |
|
|
554
|
+
| `theme/{name}/soft/200` | `--xz-color-{name}-soft-200` |
|
|
555
|
+
| `theme/{name}/softSolid/100` | `--xz-color-{name}-soft-solid-100` |
|
|
556
|
+
| `theme/{name}/softSolid/200` | `--xz-color-{name}-soft-solid-200` |
|
|
557
|
+
| `theme/{name}/line/100` | `--xz-color-{name}-line-100` |
|
|
558
|
+
| `theme/{name}/line/200` | `--xz-color-{name}-line-200` |
|
|
559
|
+
| `theme/{name}/line/300` | `--xz-color-{name}-line-300` |
|
|
560
|
+
| `theme/{name}/bg/100` | `--xz-color-{name}-bg-100` |
|
|
561
|
+
| `theme/{name}/bg/200` | `--xz-color-{name}-bg-200` |
|
|
562
|
+
| `theme/{name}/fg/100` | `--xz-color-{name}-fg-100` |
|
|
563
|
+
| `theme/{name}/text/100` | `--xz-color-{name}-text-100` |
|
|
564
|
+
|
|
565
|
+
> **`neutral` exception:** also includes `theme/neutral/text/200` → `--xz-color-neutral-text-200`.
|
|
566
|
+
|
|
567
|
+
#### Black Alpha (10 variables)
|
|
568
|
+
|
|
569
|
+
| Figma Variable | CSS Variable |
|
|
570
|
+
|---|---|
|
|
571
|
+
| `theme/blackAlpha/100` | `--xz-color-black-alpha-100` |
|
|
572
|
+
| `theme/blackAlpha/200` | `--xz-color-black-alpha-200` |
|
|
573
|
+
| `theme/blackAlpha/300` | `--xz-color-black-alpha-300` |
|
|
574
|
+
| `theme/blackAlpha/400` | `--xz-color-black-alpha-400` |
|
|
575
|
+
| `theme/blackAlpha/500` | `--xz-color-black-alpha-500` |
|
|
576
|
+
| `theme/blackAlpha/600` | `--xz-color-black-alpha-600` |
|
|
577
|
+
| `theme/blackAlpha/700` | `--xz-color-black-alpha-700` |
|
|
578
|
+
| `theme/blackAlpha/800` | `--xz-color-black-alpha-800` |
|
|
579
|
+
| `theme/blackAlpha/900` | `--xz-color-black-alpha-900` |
|
|
580
|
+
| `theme/blackAlpha/1000` | `--xz-color-black-alpha-1000` |
|
|
581
|
+
|
|
582
|
+
#### White Alpha (10 variables)
|
|
583
|
+
|
|
584
|
+
| Figma Variable | CSS Variable |
|
|
585
|
+
|---|---|
|
|
586
|
+
| `theme/whiteAlpha/100` | `--xz-color-white-alpha-100` |
|
|
587
|
+
| `theme/whiteAlpha/200` | `--xz-color-white-alpha-200` |
|
|
588
|
+
| `theme/whiteAlpha/300` | `--xz-color-white-alpha-300` |
|
|
589
|
+
| `theme/whiteAlpha/400` | `--xz-color-white-alpha-400` |
|
|
590
|
+
| `theme/whiteAlpha/500` | `--xz-color-white-alpha-500` |
|
|
591
|
+
| `theme/whiteAlpha/600` | `--xz-color-white-alpha-600` |
|
|
592
|
+
| `theme/whiteAlpha/700` | `--xz-color-white-alpha-700` |
|
|
593
|
+
| `theme/whiteAlpha/800` | `--xz-color-white-alpha-800` |
|
|
594
|
+
| `theme/whiteAlpha/900` | `--xz-color-white-alpha-900` |
|
|
595
|
+
| `theme/whiteAlpha/1000` | `--xz-color-white-alpha-1000` |
|
|
596
|
+
|
|
597
|
+
#### Overlay (10 variables)
|
|
598
|
+
|
|
599
|
+
| Figma Variable | CSS Variable |
|
|
600
|
+
|---|---|
|
|
601
|
+
| `theme/overlay/100` | `--xz-color-overlay-100` |
|
|
602
|
+
| `theme/overlay/200` | `--xz-color-overlay-200` |
|
|
603
|
+
| `theme/overlay/300` | `--xz-color-overlay-300` |
|
|
604
|
+
| `theme/overlay/400` | `--xz-color-overlay-400` |
|
|
605
|
+
| `theme/overlay/500` | `--xz-color-overlay-500` |
|
|
606
|
+
| `theme/overlay/600` | `--xz-color-overlay-600` |
|
|
607
|
+
| `theme/overlay/700` | `--xz-color-overlay-700` |
|
|
608
|
+
| `theme/overlay/800` | `--xz-color-overlay-800` |
|
|
609
|
+
| `theme/overlay/900` | `--xz-color-overlay-900` |
|
|
610
|
+
| `theme/overlay/1000` | `--xz-color-overlay-1000` |
|
|
611
|
+
|
|
612
|
+
#### Palette (8 variables)
|
|
613
|
+
|
|
614
|
+
| Figma Variable | CSS Variable |
|
|
615
|
+
|---|---|
|
|
616
|
+
| `palette/fastwork` | `--xz-color-fastwork` |
|
|
617
|
+
| `palette/gray` | `--xz-color-gray` |
|
|
618
|
+
| `palette/green` | `--xz-color-green` |
|
|
619
|
+
| `palette/yellow` | `--xz-color-yellow` |
|
|
620
|
+
| `palette/red` | `--xz-color-red` |
|
|
621
|
+
| `palette/orange` | `--xz-color-orange` |
|
|
622
|
+
| `palette/purple` | `--xz-color-purple` |
|
|
623
|
+
| `palette/cyan` | `--xz-color-cyan` |
|
|
624
|
+
|
|
625
|
+
### How to Use Figma Variables in Designs
|
|
626
|
+
|
|
627
|
+
1. Select a layer in Figma (frame, text, shape, etc.)
|
|
628
|
+
2. In the Fill or Stroke panel, click the color swatch
|
|
629
|
+
3. Switch to the **Variables** tab in the color picker
|
|
630
|
+
4. Pick from the `colors` collection
|
|
631
|
+
|
|
632
|
+
**Rules for Figma:**
|
|
633
|
+
- Always use `theme/*` variables for component fills, text colors, and stroke colors
|
|
634
|
+
- Use `palette/*` variables only as references — not directly on components
|
|
635
|
+
- Use `theme/base/surface/100` for page backgrounds, `theme/base/surface/200` for cards
|
|
636
|
+
- Use `theme/{name}/bg/100` for solid-filled elements and `theme/{name}/fg/100` for text on top of them
|
|
637
|
+
- Switch between Light/Dark previews using the **Mode** toggle on the variable collection
|
|
638
|
+
|
|
639
|
+
### Keeping Figma in Sync with Code
|
|
640
|
+
|
|
641
|
+
Variables are synced from the npm package via the **XOSMOZ Theme Sync** plugin:
|
|
642
|
+
|
|
643
|
+
1. Open **Plugins → Development → XOSMOZ Theme Sync** in Figma
|
|
644
|
+
2. Select your variable collection from the dropdown
|
|
645
|
+
3. Click **"Check for Updates"** to see if any colors changed
|
|
646
|
+
4. Click **"Update Variables"** to apply changes to both Light and Dark modes at once
|
|
647
|
+
|
|
648
|
+
If starting a new Figma file, use **"Create New Collection"** to generate all variables from scratch.
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
## Typography Tokens
|
|
653
|
+
|
|
654
|
+
Typography tokens are defined in `base.css` (not theme files). They do not change between light and dark themes.
|
|
655
|
+
|
|
656
|
+
### Font Families
|
|
657
|
+
|
|
658
|
+
| CSS Variable | Value | Use for |
|
|
659
|
+
|---|---|---|
|
|
660
|
+
| `--xz-font-family-primary` | System sans-serif stack (`-apple-system, system-ui, ...`) | Body text, titles, subtitles, UI labels |
|
|
661
|
+
| `--xz-font-family-secondary` | `"Fastwork", "Noto Sans Thai", "Noto Sans", ...` (system fallbacks) | Display headings (h1–h6) |
|
|
662
|
+
|
|
663
|
+
**Rule:** Use `--xz-font-family-primary` for all UI text. Only use `--xz-font-family-secondary` for large display headings (heading1–heading6).
|
|
664
|
+
|
|
665
|
+
### Font Size Scale
|
|
666
|
+
|
|
667
|
+
17 sizes on a numbered scale. Use `--xz-font-size-{key}`.
|
|
668
|
+
|
|
669
|
+
| CSS Variable | rem | px |
|
|
670
|
+
|---|---|---|
|
|
671
|
+
| `--xz-font-size-50` | 0.5rem | 8px |
|
|
672
|
+
| `--xz-font-size-100` | 0.625rem | 10px |
|
|
673
|
+
| `--xz-font-size-200` | 0.75rem | 12px |
|
|
674
|
+
| `--xz-font-size-300` | 0.875rem | 14px |
|
|
675
|
+
| `--xz-font-size-400` | 1rem | 16px (base) |
|
|
676
|
+
| `--xz-font-size-500` | 1.125rem | 18px |
|
|
677
|
+
| `--xz-font-size-600` | 1.25rem | 20px |
|
|
678
|
+
| `--xz-font-size-700` | 1.5rem | 24px |
|
|
679
|
+
| `--xz-font-size-800` | 1.625rem | 26px |
|
|
680
|
+
| `--xz-font-size-900` | 2rem | 32px |
|
|
681
|
+
| `--xz-font-size-1000` | 2.375rem | 38px |
|
|
682
|
+
| `--xz-font-size-1100` | 2.5rem | 40px |
|
|
683
|
+
| `--xz-font-size-1200` | 2.6875rem | 43px |
|
|
684
|
+
| `--xz-font-size-1300` | 3rem | 48px |
|
|
685
|
+
| `--xz-font-size-1400` | 3.5rem | 56px |
|
|
686
|
+
| `--xz-font-size-1500` | 4rem | 64px |
|
|
687
|
+
| `--xz-font-size-1600` | 4.5rem | 72px |
|
|
688
|
+
|
|
689
|
+
### Line Heights
|
|
690
|
+
|
|
691
|
+
| CSS Variable | Value |
|
|
692
|
+
|---|---|
|
|
693
|
+
| `--xz-line-height-100pct` | 1 |
|
|
694
|
+
| `--xz-line-height-125pct` | 1.25 |
|
|
695
|
+
| `--xz-line-height-135pct` | 1.35 |
|
|
696
|
+
| `--xz-line-height-150pct` | 1.5 (default for all tokens) |
|
|
697
|
+
| `--xz-line-height-165pct` | 1.65 |
|
|
698
|
+
| `--xz-line-height-200pct` | 2 |
|
|
699
|
+
|
|
700
|
+
### Font Shorthand Tokens
|
|
701
|
+
|
|
702
|
+
These are **CSS font shorthand** variables. Apply with `font: var(--xz-font-{name})`.
|
|
703
|
+
|
|
704
|
+
Each token encodes: `{weight} {size}/{line-height} {font-family}`.
|
|
705
|
+
|
|
706
|
+
#### Headings (secondary font, weight 700, responsive)
|
|
707
|
+
|
|
708
|
+
Headings use `--xz-font-family-secondary` (Fastwork). They scale down on mobile (≤768px).
|
|
709
|
+
|
|
710
|
+
| CSS Variable | Desktop size | Mobile size (≤768px) |
|
|
711
|
+
|---|---|---|
|
|
712
|
+
| `--xz-font-heading1` | 4.5rem (72px) | 3rem (48px) |
|
|
713
|
+
| `--xz-font-heading2` | 4rem (64px) | 2.6875rem (43px) |
|
|
714
|
+
| `--xz-font-heading3` | 3.5rem (56px) | 2.375rem (38px) |
|
|
715
|
+
| `--xz-font-heading4` | 3rem (48px) | 2rem (32px) |
|
|
716
|
+
| `--xz-font-heading5` | 2.5rem (40px) | 1.625rem (26px) |
|
|
717
|
+
| `--xz-font-heading6` | 2rem (32px) | 1.5rem (24px) |
|
|
718
|
+
|
|
719
|
+
#### Titles (primary font, weight 700, responsive)
|
|
720
|
+
|
|
721
|
+
Titles use `--xz-font-family-primary`. They scale down one step on mobile.
|
|
722
|
+
|
|
723
|
+
| CSS Variable | Desktop size | Mobile size (≤768px) |
|
|
724
|
+
|---|---|---|
|
|
725
|
+
| `--xz-font-title1` | 1.5rem (24px) | 1.25rem (20px) |
|
|
726
|
+
| `--xz-font-title2` | 1.25rem (20px) | 1.125rem (18px) |
|
|
727
|
+
| `--xz-font-title3` | 1.125rem (18px) | 1rem (16px) |
|
|
728
|
+
| `--xz-font-title4` | 1rem (16px) | 0.875rem (14px) |
|
|
729
|
+
|
|
730
|
+
#### Subtitles (primary font, responsive)
|
|
731
|
+
|
|
732
|
+
Bold (700) and Regular (400) variants. Scale down one step on mobile.
|
|
733
|
+
|
|
734
|
+
| CSS Variable | Weight | Desktop size | Mobile size (≤768px) |
|
|
735
|
+
|---|---|---|---|
|
|
736
|
+
| `--xz-font-subtitle1-bold` | 700 | 1rem (16px) | 0.875rem (14px) |
|
|
737
|
+
| `--xz-font-subtitle1-regular` | 400 | 1rem (16px) | 0.875rem (14px) |
|
|
738
|
+
| `--xz-font-subtitle2-bold` | 700 | 0.875rem (14px) | 0.75rem (12px) |
|
|
739
|
+
| `--xz-font-subtitle2-regular` | 400 | 0.875rem (14px) | 0.75rem (12px) |
|
|
740
|
+
| `--xz-font-subtitle3-bold` | 700 | 0.75rem (12px) | 0.625rem (10px) |
|
|
741
|
+
| `--xz-font-subtitle3-regular` | 400 | 0.75rem (12px) | 0.625rem (10px) |
|
|
742
|
+
|
|
743
|
+
#### Body (primary font, weight 400, responsive)
|
|
744
|
+
|
|
745
|
+
Body text scales down one step on mobile.
|
|
746
|
+
|
|
747
|
+
| CSS Variable | Desktop size | Mobile size (≤768px) |
|
|
748
|
+
|---|---|---|
|
|
749
|
+
| `--xz-font-body1` | 1rem (16px) | 0.875rem (14px) |
|
|
750
|
+
| `--xz-font-body2` | 0.875rem (14px) | 0.75rem (12px) |
|
|
751
|
+
| `--xz-font-body3` | 0.75rem (12px) | 0.625rem (10px) |
|
|
752
|
+
| `--xz-font-body4` | 0.625rem (10px) | 0.5rem (8px) |
|
|
753
|
+
|
|
754
|
+
### Typography Usage Guidelines
|
|
755
|
+
|
|
756
|
+
| Situation | Use |
|
|
757
|
+
|---|---|
|
|
758
|
+
| Hero / landing page headline | `--xz-font-heading1` to `--xz-font-heading3` |
|
|
759
|
+
| Section heading | `--xz-font-heading4` to `--xz-font-heading6` |
|
|
760
|
+
| Card title, dialog title, modal header | `--xz-font-title1` to `--xz-font-title3` |
|
|
761
|
+
| Small section title, form group label | `--xz-font-title4` |
|
|
762
|
+
| Emphasized label, table header, stat value | `--xz-font-subtitle1-bold` or `--xz-font-subtitle2-bold` |
|
|
763
|
+
| Supporting label, metadata, timestamp | `--xz-font-subtitle2-regular` or `--xz-font-subtitle3-regular` |
|
|
764
|
+
| Navigation menu item, tab label | `--xz-font-subtitle2-bold` |
|
|
765
|
+
| Breadcrumb text | `--xz-font-body3` or `--xz-font-subtitle3-regular` |
|
|
766
|
+
| Default body text, paragraphs | `--xz-font-body1` or `--xz-font-body2` |
|
|
767
|
+
| Tooltip text | `--xz-font-body3` |
|
|
768
|
+
| Small print, captions, helper text | `--xz-font-body3` |
|
|
769
|
+
| Empty state message | `--xz-font-body1` (message) + `--xz-font-title3` (title) |
|
|
770
|
+
| Price display, number callout | `--xz-font-heading5` or `--xz-font-title1` |
|
|
771
|
+
| Micro text (badges, counters, dots) | `--xz-font-body4` |
|
|
772
|
+
|
|
773
|
+
### Typography CSS Examples
|
|
774
|
+
|
|
775
|
+
```css
|
|
776
|
+
/* Apply a font shorthand token */
|
|
777
|
+
h1 { font: var(--xz-font-heading1); }
|
|
778
|
+
h2 { font: var(--xz-font-heading2); }
|
|
779
|
+
p { font: var(--xz-font-body2); }
|
|
780
|
+
|
|
781
|
+
/* Card with title */
|
|
782
|
+
.card-title { font: var(--xz-font-title2); color: var(--xz-color-text-100); }
|
|
783
|
+
.card-body { font: var(--xz-font-body2); color: var(--xz-color-text-200); }
|
|
784
|
+
|
|
785
|
+
/* Form label + helper */
|
|
786
|
+
.label { font: var(--xz-font-subtitle2-bold); color: var(--xz-color-text-100); }
|
|
787
|
+
.helper { font: var(--xz-font-body3); color: var(--xz-color-text-300); }
|
|
788
|
+
|
|
789
|
+
/* Use individual tokens when you need granular control */
|
|
790
|
+
.custom {
|
|
791
|
+
font-family: var(--xz-font-family-primary);
|
|
792
|
+
font-size: var(--xz-font-size-300);
|
|
793
|
+
line-height: var(--xz-line-height-150pct);
|
|
794
|
+
}
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
### Responsive Behavior
|
|
798
|
+
|
|
799
|
+
All `--xz-font-*` shorthand tokens are automatically responsive. At `max-width: 768px`, they switch to their mobile sizes via a CSS media query in `base.css`. No extra breakpoint code is needed — just use the token and it adapts.
|
|
800
|
+
|
|
801
|
+
---
|
|
802
|
+
|
|
803
|
+
## Box Shadow Tokens
|
|
804
|
+
|
|
805
|
+
Four elevation levels. Theme-aware (shadows are stronger in dark mode).
|
|
806
|
+
|
|
807
|
+
| CSS Variable | Light theme value | Use for |
|
|
808
|
+
|---|---|---|
|
|
809
|
+
| `--xz-shadow-100` | `0 1px 2px 0 rgba(0,0,0,0.08)` | Subtle lift — inline action buttons, tag hover, navbar bottom edge, input focus ring complement |
|
|
810
|
+
| `--xz-shadow-200` | `0 2px 6px 0 rgba(0,0,0,0.10)` | Cards at rest, sticky header on scroll, floating action button, small floating elements |
|
|
811
|
+
| `--xz-shadow-300` | `0 4px 16px 0 rgba(0,0,0,0.12)` | Dropdown menu, popover, autocomplete suggestions, select options list, date picker |
|
|
812
|
+
| `--xz-shadow-400` | `0 8px 20px 0 rgba(0,0,0,0.14)` | Modal dialog, drawer panel, lightbox, command palette, fullscreen overlay panels |
|
|
813
|
+
|
|
814
|
+
```css
|
|
815
|
+
.btn:hover { box-shadow: var(--xz-shadow-100); }
|
|
816
|
+
.card { box-shadow: var(--xz-shadow-200); }
|
|
817
|
+
.sticky-nav { box-shadow: var(--xz-shadow-200); }
|
|
818
|
+
.dropdown { box-shadow: var(--xz-shadow-300); }
|
|
819
|
+
.popover { box-shadow: var(--xz-shadow-300); }
|
|
820
|
+
.modal { box-shadow: var(--xz-shadow-400); }
|
|
821
|
+
.drawer { box-shadow: var(--xz-shadow-400); }
|
|
822
|
+
```
|