@cupped/tokens 0.1.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/CHANGELOG.md +17 -0
- package/README.md +79 -0
- package/dist/css/components.css +183 -0
- package/dist/css/tokens.css +144 -0
- package/dist/json/tokens.dtcg.json +1501 -0
- package/dist/json/tokens.flat.json +102 -0
- package/dist/native/index.cjs +281 -0
- package/dist/native/index.d.ts +285 -0
- package/dist/native/index.js +279 -0
- package/dist/tailwind/theme.css +164 -0
- package/docs/expo.md +141 -0
- package/docs/phoenix.md +153 -0
- package/docs/releasing.md +93 -0
- package/docs/rules.md +62 -0
- package/docs/versioning.md +59 -0
- package/package.json +56 -0
- package/tokens/primitive/color.tokens.json +94 -0
- package/tokens/primitive/dimension.tokens.json +18 -0
- package/tokens/primitive/duration.tokens.json +10 -0
- package/tokens/primitive/font.tokens.json +29 -0
- package/tokens/semantic/color.tokens.json +172 -0
- package/tokens/semantic/elevation.tokens.json +38 -0
- package/tokens/semantic/materials.tokens.json +34 -0
- package/tokens/semantic/motion.tokens.json +52 -0
- package/tokens/semantic/radius.tokens.json +11 -0
- package/tokens/semantic/spacing.tokens.json +13 -0
- package/tokens/semantic/typography.tokens.json +60 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @cupped/tokens
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
Initial release. DTCG token source under `tokens/` with generated, committed
|
|
6
|
+
targets in `dist/`:
|
|
7
|
+
|
|
8
|
+
- React Native theme object (`@cupped/tokens`) — literal-typed, unitless dp.
|
|
9
|
+
- CSS custom properties (`@cupped/tokens/css`) with alias `var()` chains.
|
|
10
|
+
- Web component classes (`@cupped/tokens/css/components`).
|
|
11
|
+
- Tailwind v4 `@theme` (`@cupped/tokens/tailwind`).
|
|
12
|
+
- Flat and DTCG JSON (`@cupped/tokens/json`, `@cupped/tokens/json/dtcg`).
|
|
13
|
+
|
|
14
|
+
Published to GitHub Packages (`@cupped` scope); also installable as a git
|
|
15
|
+
dependency. Subsequent releases are managed with Changesets — see
|
|
16
|
+
[docs/releasing.md](./docs/releasing.md) and
|
|
17
|
+
[docs/versioning.md](./docs/versioning.md).
|
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# @cupped/tokens
|
|
2
|
+
|
|
3
|
+
Framework-agnostic design tokens for the **Cupped** design system — a
|
|
4
|
+
community-first coffee-logging platform. The canonical source is
|
|
5
|
+
platform-neutral [DTCG](https://www.designtokens.org/TR/drafts/format/)-style
|
|
6
|
+
JSON under [`tokens/`](./tokens); every consumable artifact in
|
|
7
|
+
[`dist/`](./dist) is **generated** from it and committed. The package is
|
|
8
|
+
published to **GitHub Packages** (`@cupped` scope), and because `dist/` is
|
|
9
|
+
committed it also works as a plain git dependency — no registry auth, no
|
|
10
|
+
install-time build — for consumers that prefer that.
|
|
11
|
+
|
|
12
|
+
> Never hard-code a hex or pixel value that exists as a token.
|
|
13
|
+
|
|
14
|
+
## Exports
|
|
15
|
+
|
|
16
|
+
| Import | What you get |
|
|
17
|
+
|---|---|
|
|
18
|
+
| `@cupped/tokens` | React Native theme object (`tokens`), literal-typed, unitless dp numbers, dual-shape shadows, Reanimated spring params |
|
|
19
|
+
| `@cupped/tokens/css` | CSS custom properties (`--ink`, `--space-base`…), alias `var()` chains preserved, `prefers-reduced-motion` / `prefers-reduced-transparency` blocks built in |
|
|
20
|
+
| `@cupped/tokens/css/components` | Canonical web component classes (`.btn`, `.input`, `.chip-flavor`, `.banner`, `.chrome`…) — optional reference styles |
|
|
21
|
+
| `@cupped/tokens/tailwind` | Tailwind v4 `@theme` file → utilities (`bg-canvas`, `text-ink-secondary`, `rounded-lg`, `shadow-primary`, `p-base`, `text-card-title`…) |
|
|
22
|
+
| `@cupped/tokens/json` | Flat resolved map keyed by CSS names |
|
|
23
|
+
| `@cupped/tokens/json/dtcg` | The merged DTCG source tree |
|
|
24
|
+
|
|
25
|
+
No components, no icons, no font binaries — components stay app-specific;
|
|
26
|
+
fonts are self-hosted per platform (documented).
|
|
27
|
+
|
|
28
|
+
## Consuming
|
|
29
|
+
|
|
30
|
+
- **Phoenix LiveView (Tailwind v4):** [docs/phoenix.md](./docs/phoenix.md) —
|
|
31
|
+
pinned CSS from the GitHub Release, npm git-dep, or zero-npm vendor mode;
|
|
32
|
+
fonts, lint recipe.
|
|
33
|
+
- **Expo / React Native (SDK 53+):** [docs/expo.md](./docs/expo.md) — the
|
|
34
|
+
`theme.ts` pattern, expo-font, ESLint recipe.
|
|
35
|
+
- **Brand & a11y invariants:** [docs/rules.md](./docs/rules.md).
|
|
36
|
+
|
|
37
|
+
Complete copy-paste examples live in [`examples/`](./examples).
|
|
38
|
+
|
|
39
|
+
## Architecture
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
tokens/primitive/*.tokens.json raw palettes & scales (never consumed directly)
|
|
43
|
+
tokens/semantic/*.tokens.json the public API — every token aliases a primitive
|
|
44
|
+
│
|
|
45
|
+
▼ Style Dictionary v5 + custom formats (build/)
|
|
46
|
+
dist/css/tokens.css var() chains preserved (--xp: var(--sweet))
|
|
47
|
+
dist/tailwind/theme.css @theme namespaces, fully resolved
|
|
48
|
+
dist/native/index.{js,cjs,d.ts} resolved literals, as-const types
|
|
49
|
+
dist/json/tokens.{flat,dtcg}.json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Aliases use DTCG `{dot.path}` references; the build fails on unresolved or
|
|
53
|
+
circular references. Accessibility requirements are encoded as data
|
|
54
|
+
(`$extensions["app.cupped"].contrast`) and machine-checked in CI, alongside
|
|
55
|
+
name-collision checks and a parity test against the frozen
|
|
56
|
+
[`source-export/`](./source-export) (the refreshed design-system export this
|
|
57
|
+
package mirrors — kept as reference, never edited).
|
|
58
|
+
|
|
59
|
+
## Developing
|
|
60
|
+
|
|
61
|
+
Building requires **Node 22+** (the build uses `node:fs/promises` `glob`).
|
|
62
|
+
Consuming the published package has no Node version requirement.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm install
|
|
66
|
+
npm run build # tokens/ → dist/ (dist is committed)
|
|
67
|
+
npm test # parity + contrast + collisions + snapshots + type-checks
|
|
68
|
+
npm run check # build, fail on dist/ drift, then test — what CI runs
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Releasing & versioning
|
|
72
|
+
|
|
73
|
+
Releases are automated with [Changesets](https://github.com/changesets/changesets)
|
|
74
|
+
and published to GitHub Packages; each release also attaches version-pinned CSS
|
|
75
|
+
to its GitHub Release. Add a changeset with `npx changeset` in any PR that
|
|
76
|
+
changes tokens.
|
|
77
|
+
|
|
78
|
+
- **Release mechanics & first-publish runbook:** [docs/releasing.md](./docs/releasing.md).
|
|
79
|
+
- **What's a major/minor/patch (the token contract):** [docs/versioning.md](./docs/versioning.md).
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════
|
|
2
|
+
CUPPED COMPONENTS · v0.4
|
|
3
|
+
Canonical component classes. Load AFTER tokens.css:
|
|
4
|
+
<link rel="stylesheet" href="tokens.css">
|
|
5
|
+
<link rel="stylesheet" href="components.css">
|
|
6
|
+
|
|
7
|
+
These are the real design-system components — a prototype's button
|
|
8
|
+
IS this button, not a lookalike. Colors, type, spacing and elevation
|
|
9
|
+
reference tokens (var(--…)); a few structural primitives (hairline
|
|
10
|
+
borders, icon box sizes) stay as raw px where no token exists.
|
|
11
|
+
|
|
12
|
+
Hand-maintained web reference (src/css/components.css in
|
|
13
|
+
@cupped/tokens); shipped via the "/css/components" export.
|
|
14
|
+
════════════════════════════════════════════════════════════════ */
|
|
15
|
+
|
|
16
|
+
/* ——— Buttons ——— */
|
|
17
|
+
.btn {
|
|
18
|
+
display: inline-flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
gap: var(--space-sm);
|
|
22
|
+
font-family: var(--ff-sans);
|
|
23
|
+
font-size: 15px;
|
|
24
|
+
font-weight: 600;
|
|
25
|
+
letter-spacing: -0.005em;
|
|
26
|
+
border-radius: var(--radius-md);
|
|
27
|
+
border: none;
|
|
28
|
+
cursor: pointer;
|
|
29
|
+
padding: 12px 20px;
|
|
30
|
+
min-height: var(--hit-target-min);
|
|
31
|
+
transition: transform .12s, background .15s, box-shadow .2s;
|
|
32
|
+
}
|
|
33
|
+
.btn:active { transform: scale(0.95); opacity: 0.8; }
|
|
34
|
+
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
|
|
35
|
+
.btn[disabled] { background: var(--canvas-border-subtle); color: var(--ink-muted); box-shadow: none; cursor: not-allowed; transform: none; }
|
|
36
|
+
.btn-primary {
|
|
37
|
+
background: var(--primary-strong);
|
|
38
|
+
color: var(--ink-inverse);
|
|
39
|
+
box-shadow: var(--shadow-primary);
|
|
40
|
+
}
|
|
41
|
+
.btn-primary:hover { background: var(--primary-strong-hover); }
|
|
42
|
+
.btn-secondary {
|
|
43
|
+
background: var(--card);
|
|
44
|
+
color: var(--ink);
|
|
45
|
+
border: 1px solid var(--canvas-border);
|
|
46
|
+
}
|
|
47
|
+
.btn-secondary:hover { border-color: var(--ink); }
|
|
48
|
+
.btn-ghost {
|
|
49
|
+
background: transparent;
|
|
50
|
+
color: var(--primary-strong);
|
|
51
|
+
}
|
|
52
|
+
.btn-ghost:hover { background: var(--primary-light); }
|
|
53
|
+
.btn-full { width: 100%; }
|
|
54
|
+
|
|
55
|
+
.btn-stack { display: flex; flex-direction: column; gap: var(--space-sm); align-items: flex-start; }
|
|
56
|
+
.btn-stack .btn { align-self: stretch; }
|
|
57
|
+
.btn-row { display: flex; gap: var(--space-sm); flex-wrap: wrap; }
|
|
58
|
+
|
|
59
|
+
/* ——— Flavor chips (light · text on white) ———
|
|
60
|
+
Set --flavor to a flavor TEXT-band token, e.g.
|
|
61
|
+
style="--flavor: var(--floral-accessible)" */
|
|
62
|
+
.chip-flavor {
|
|
63
|
+
display: inline-flex;
|
|
64
|
+
align-items: center;
|
|
65
|
+
gap: 6px;
|
|
66
|
+
padding: 6px 12px;
|
|
67
|
+
border-radius: var(--radius-full);
|
|
68
|
+
font-size: 13px;
|
|
69
|
+
font-weight: 500;
|
|
70
|
+
background: color-mix(in srgb, var(--flavor) 10%, white);
|
|
71
|
+
color: var(--flavor);
|
|
72
|
+
border: 1px solid color-mix(in srgb, var(--flavor) 25%, white);
|
|
73
|
+
}
|
|
74
|
+
.chip-flavor .dot {
|
|
75
|
+
width: 8px; height: 8px;
|
|
76
|
+
border-radius: 50%;
|
|
77
|
+
background: var(--flavor);
|
|
78
|
+
}
|
|
79
|
+
.chip-stack { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
80
|
+
|
|
81
|
+
/* ——— Flavor tags (solid · on photos/cards) ———
|
|
82
|
+
Set background to a flavor FILL token; the Espresso band
|
|
83
|
+
guarantees white text passes AA for every flavor. */
|
|
84
|
+
.tag-flavor {
|
|
85
|
+
display: inline-flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
font-size: 12px;
|
|
88
|
+
font-weight: 500;
|
|
89
|
+
padding: 4px 8px;
|
|
90
|
+
border-radius: var(--radius-full);
|
|
91
|
+
color: #fff;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* ——— Inputs ——— */
|
|
95
|
+
.input {
|
|
96
|
+
width: 100%;
|
|
97
|
+
padding: 12px 14px;
|
|
98
|
+
border: 1px solid var(--canvas-border);
|
|
99
|
+
border-radius: var(--radius-md);
|
|
100
|
+
background: var(--card);
|
|
101
|
+
font-family: var(--ff-sans);
|
|
102
|
+
font-size: 15px;
|
|
103
|
+
color: var(--ink);
|
|
104
|
+
transition: border-color .15s, box-shadow .15s;
|
|
105
|
+
}
|
|
106
|
+
.input::placeholder { color: var(--ink-muted); }
|
|
107
|
+
.input:focus {
|
|
108
|
+
outline: none;
|
|
109
|
+
border-color: var(--primary);
|
|
110
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 18%, transparent);
|
|
111
|
+
}
|
|
112
|
+
.input.error {
|
|
113
|
+
border-color: var(--error);
|
|
114
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--error) 12%, transparent);
|
|
115
|
+
}
|
|
116
|
+
.input[disabled] { background: var(--canvas); color: var(--ink-muted); cursor: not-allowed; }
|
|
117
|
+
.input-row { display: flex; flex-direction: column; gap: 6px; }
|
|
118
|
+
.input-label { font-size: 12px; font-weight: 500; color: var(--ink-secondary); }
|
|
119
|
+
.input-hint { font-size: 12px; color: var(--ink-secondary); }
|
|
120
|
+
.input-hint.error { color: var(--error-ink); }
|
|
121
|
+
|
|
122
|
+
/* ——— Cards ——— */
|
|
123
|
+
.card {
|
|
124
|
+
background: var(--card);
|
|
125
|
+
border: 1px solid var(--canvas-border);
|
|
126
|
+
border-radius: var(--radius-lg);
|
|
127
|
+
box-shadow: var(--shadow-sm);
|
|
128
|
+
}
|
|
129
|
+
.card-pad { padding: var(--space-lg); }
|
|
130
|
+
|
|
131
|
+
/* ——— Rating stars ——— */
|
|
132
|
+
.rating { display: inline-flex; gap: 4px; color: var(--xp); }
|
|
133
|
+
.rating svg { width: 20px; height: 20px; }
|
|
134
|
+
.rating .empty { color: var(--canvas-border); }
|
|
135
|
+
|
|
136
|
+
/* ——— Feedback banners ———
|
|
137
|
+
The -ink variant tints the icon (≥3:1); the fill tints the border;
|
|
138
|
+
words stay ink / ink-secondary. */
|
|
139
|
+
.banner {
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: flex-start;
|
|
142
|
+
gap: var(--space-md);
|
|
143
|
+
padding: var(--space-md) var(--space-base);
|
|
144
|
+
border-radius: var(--radius-md);
|
|
145
|
+
border: 1px solid;
|
|
146
|
+
margin-bottom: var(--space-sm);
|
|
147
|
+
}
|
|
148
|
+
.banner .icon { width: 20px; height: 20px; flex-shrink: 0; margin-top: 1px; }
|
|
149
|
+
.banner .body { font-size: 14px; }
|
|
150
|
+
.banner .title { font-weight: 600; margin-bottom: 2px; }
|
|
151
|
+
.banner.success { background: var(--success-light); border-color: color-mix(in srgb, var(--success) 25%, transparent); color: var(--success-ink); }
|
|
152
|
+
.banner.error { background: var(--error-light); border-color: color-mix(in srgb, var(--error) 25%, transparent); color: var(--error-ink); }
|
|
153
|
+
.banner.warning { background: var(--warning-light); border-color: color-mix(in srgb, var(--warning) 25%, transparent); color: var(--warning-ink); }
|
|
154
|
+
.banner.info { background: var(--info-light); border-color: color-mix(in srgb, var(--info) 25%, transparent); color: var(--info-ink); }
|
|
155
|
+
.banner .body .title { color: var(--ink); }
|
|
156
|
+
.banner .body p { margin: 0; color: var(--ink-secondary); font-size: 13px; }
|
|
157
|
+
|
|
158
|
+
/* ——— Chrome (floating bar/header material) ———
|
|
159
|
+
The sole sanctioned translucent surface — tab bar and sticky screen
|
|
160
|
+
headers only, one chrome layer per screen. Content surfaces are
|
|
161
|
+
always opaque. prefers-reduced-transparency collapses this to an
|
|
162
|
+
opaque card via the material tokens. */
|
|
163
|
+
.chrome {
|
|
164
|
+
background: var(--material-chrome-bg);
|
|
165
|
+
-webkit-backdrop-filter: var(--material-chrome-blur);
|
|
166
|
+
backdrop-filter: var(--material-chrome-blur);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* ——— Spinner (button loading state) ——— */
|
|
170
|
+
.spinner {
|
|
171
|
+
width: 14px; height: 14px;
|
|
172
|
+
border: 2px solid rgba(255,255,255,0.35);
|
|
173
|
+
border-top-color: #fff;
|
|
174
|
+
border-radius: 50%;
|
|
175
|
+
animation: cupped-spin 0.8s linear infinite;
|
|
176
|
+
flex-shrink: 0;
|
|
177
|
+
}
|
|
178
|
+
@keyframes cupped-spin { to { transform: rotate(360deg); } }
|
|
179
|
+
|
|
180
|
+
@media (prefers-reduced-motion: reduce) {
|
|
181
|
+
.btn { transition: none; }
|
|
182
|
+
.spinner { animation: none; }
|
|
183
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════
|
|
2
|
+
CUPPED · DESIGN TOKENS
|
|
3
|
+
GENERATED FILE — do not edit. Canonical source: the DTCG token files
|
|
4
|
+
under tokens/ (npm run build in @cupped/tokens).
|
|
5
|
+
|
|
6
|
+
· Components reference semantic tokens, never raw hexes.
|
|
7
|
+
· --primary (#E07A5F) is ~3.0:1 on white. It NEVER carries text
|
|
8
|
+
below 24px. Small colored text + text-bearing fills use
|
|
9
|
+
--primary-strong (4.6:1, WCAG AA).
|
|
10
|
+
· Aliases stay live var() chains — change the source, every
|
|
11
|
+
alias follows.
|
|
12
|
+
════════════════════════════════════════════════════════════════ */
|
|
13
|
+
|
|
14
|
+
:root {
|
|
15
|
+
/* ── Color ── */
|
|
16
|
+
--canvas: #F8FAFC;
|
|
17
|
+
--card: #FFFFFF;
|
|
18
|
+
--canvas-border: #E2E8F0;
|
|
19
|
+
--canvas-border-subtle: #F1F5F9;
|
|
20
|
+
--ink: #0F172A;
|
|
21
|
+
--ink-secondary: #475569;
|
|
22
|
+
--ink-muted: #94A3B8;
|
|
23
|
+
--ink-inverse: #F8FAFC;
|
|
24
|
+
--primary: #E07A5F;
|
|
25
|
+
--primary-strong: #C05539;
|
|
26
|
+
--primary-strong-hover: #AD4A30;
|
|
27
|
+
--primary-hover: #D16A4F;
|
|
28
|
+
--primary-light: #FDF2F0;
|
|
29
|
+
--primary-muted: rgba(224, 122, 95, 0.12);
|
|
30
|
+
--success: #22C55E;
|
|
31
|
+
--success-light: #F0FDF4;
|
|
32
|
+
--success-ink: #15803D;
|
|
33
|
+
--error: #EF4444;
|
|
34
|
+
--error-light: #FEF2F2;
|
|
35
|
+
--error-ink: #B91C1C;
|
|
36
|
+
--warning: #F59E0B;
|
|
37
|
+
--warning-light: #FFFBEB;
|
|
38
|
+
--warning-ink: #B45309;
|
|
39
|
+
--info: #3B82F6;
|
|
40
|
+
--info-light: #EFF6FF;
|
|
41
|
+
--info-ink: #1D4ED8;
|
|
42
|
+
--fruity: #B44C54;
|
|
43
|
+
--floral: #865CB2;
|
|
44
|
+
--nutty: #876F49;
|
|
45
|
+
--chocolate: #916951;
|
|
46
|
+
--spice: #B4503A;
|
|
47
|
+
--sweet: #8E6E09;
|
|
48
|
+
--citrus: #A65F02;
|
|
49
|
+
--green: #4E8429;
|
|
50
|
+
--berry: #AC4D7B;
|
|
51
|
+
--roasted: #896B5E;
|
|
52
|
+
--fruity-accessible: #9B494E;
|
|
53
|
+
--berry-accessible: #94496D;
|
|
54
|
+
--citrus-accessible: #925512;
|
|
55
|
+
--sweet-accessible: #7E6207;
|
|
56
|
+
--floral-accessible: #755498;
|
|
57
|
+
--green-accessible: #49742E;
|
|
58
|
+
--spice-accessible: #9B4C3A;
|
|
59
|
+
--nutty-accessible: #79623E;
|
|
60
|
+
--chocolate-accessible: #825C46;
|
|
61
|
+
--roasted-accessible: #7B5F52;
|
|
62
|
+
--on-flavor: #FFFFFF;
|
|
63
|
+
--xp: var(--sweet);
|
|
64
|
+
--xp-accessible: var(--sweet-accessible);
|
|
65
|
+
--ember: #F97316;
|
|
66
|
+
--ember-accessible: #C2410C;
|
|
67
|
+
--streak: var(--ember);
|
|
68
|
+
--streak-accessible: var(--ember-accessible);
|
|
69
|
+
--badge: var(--floral);
|
|
70
|
+
--badge-accessible: var(--floral-accessible);
|
|
71
|
+
--zone-ideal: var(--success);
|
|
72
|
+
--zone-under: var(--info);
|
|
73
|
+
--zone-over: var(--error);
|
|
74
|
+
--zone-strong: var(--warning);
|
|
75
|
+
--zone-weak: var(--ink-muted);
|
|
76
|
+
--chart-sca: var(--primary);
|
|
77
|
+
--chart-ucdavis: var(--floral);
|
|
78
|
+
--chart-grid: var(--canvas-border);
|
|
79
|
+
|
|
80
|
+
/* ── Typography ── */
|
|
81
|
+
--ff-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
82
|
+
--ff-serif: 'Instrument Serif', Georgia, serif;
|
|
83
|
+
--ff-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
|
|
84
|
+
--text-screen-title: 32px;
|
|
85
|
+
--text-sheet-title: 24px;
|
|
86
|
+
--text-card-title: 20px;
|
|
87
|
+
--text-body: 16px;
|
|
88
|
+
--text-body-sm: 14px;
|
|
89
|
+
--text-caption: 12px;
|
|
90
|
+
|
|
91
|
+
/* ── Spacing ── */
|
|
92
|
+
--space-xs: 4px;
|
|
93
|
+
--space-sm: 8px;
|
|
94
|
+
--space-md: 12px;
|
|
95
|
+
--space-base: 16px;
|
|
96
|
+
--space-lg: 20px;
|
|
97
|
+
--space-xl: 24px;
|
|
98
|
+
--space-xxl: 32px;
|
|
99
|
+
|
|
100
|
+
/* ── Radii ── */
|
|
101
|
+
--radius-sm: 8px;
|
|
102
|
+
--radius-md: 12px;
|
|
103
|
+
--radius-lg: 16px;
|
|
104
|
+
--radius-xl: 24px;
|
|
105
|
+
--radius-full: 9999px;
|
|
106
|
+
|
|
107
|
+
/* ── Elevation ── */
|
|
108
|
+
--shadow-sm: 0 1px 2px rgba(15,23,42,0.04), 0 1px 1px rgba(15,23,42,0.03);
|
|
109
|
+
--shadow-md: 0 4px 12px rgba(15,23,42,0.06), 0 1px 3px rgba(15,23,42,0.04);
|
|
110
|
+
--shadow-lg: 0 12px 32px rgba(15,23,42,0.08), 0 4px 8px rgba(15,23,42,0.04);
|
|
111
|
+
--shadow-primary: 0 12px 28px rgba(224,122,95,0.28), 0 4px 10px rgba(224,122,95,0.18);
|
|
112
|
+
|
|
113
|
+
/* ── Motion & interaction ── */
|
|
114
|
+
--spring-response: 0.55s;
|
|
115
|
+
--spring-damping: 0.75;
|
|
116
|
+
--tap-scale: 0.95;
|
|
117
|
+
--tap-opacity: 0.8;
|
|
118
|
+
--stagger-delay: 0.08s;
|
|
119
|
+
--shimmer-duration: 1.5s;
|
|
120
|
+
--motion-reduced: 120ms;
|
|
121
|
+
--focus-ring: 0 0 0 2px var(--card), 0 0 0 4px var(--primary-strong);
|
|
122
|
+
--hit-target-min: 44px;
|
|
123
|
+
|
|
124
|
+
/* ── Materials ── */
|
|
125
|
+
--material-chrome-bg: color-mix(in srgb, var(--card) 95%, transparent);
|
|
126
|
+
--material-chrome-blur: saturate(1.4) blur(20px);
|
|
127
|
+
--scrim: rgba(15, 23, 42, 0.45);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* Motion respects user preference: keep the state change, drop travel. */
|
|
131
|
+
@media (prefers-reduced-motion: reduce) {
|
|
132
|
+
:root {
|
|
133
|
+
--spring-response: var(--motion-reduced);
|
|
134
|
+
--stagger-delay: 0s;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* Transparency respects user preference: chrome collapses to opaque card. */
|
|
139
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
140
|
+
:root {
|
|
141
|
+
--material-chrome-bg: var(--card);
|
|
142
|
+
--material-chrome-blur: none;
|
|
143
|
+
}
|
|
144
|
+
}
|