@path58/tokens 1.0.0-rc.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Path58
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # @path58/tokens
2
+
3
+ Design tokens for the Path58 design system. Single source of truth for color, type, spacing, motion, z-index.
4
+
5
+ **Status:** ๐Ÿšง Stub โ€” populated in DSGN-1.1.2 (Day 2, 2026-06-03) when `colors_and_type.css` migrates from `_path58-brand/tokens/`.
6
+
7
+ ## Exports
8
+
9
+ - `@path58/tokens/css` โ€” the canonical `tokens.css` (CSS variables)
10
+ - `@path58/tokens` โ€” TS exports of the same values (for non-CSS consumers)
11
+
12
+ ## Token naming
13
+
14
+ All tokens use the `--p58-*` namespace. Example:
15
+
16
+ ```css
17
+ :root {
18
+ --p58-bg: #0a0a1a;
19
+ --p58-accent: #00d4aa;
20
+ --p58-font-display: 'Space Grotesk', ui-sans-serif, sans-serif;
21
+ }
22
+ ```
23
+
24
+ ## See also
25
+
26
+ - `@path58/themes` โ€” theme files that override these tokens
27
+ - `@path58/ui` โ€” components that read these tokens at runtime
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@path58/tokens",
3
+ "version": "1.0.0-rc.1",
4
+ "description": "Path58 design tokens โ€” CSS variables and TS exports for color, type, spacing, motion, z-index. Single source of truth consumed by @path58/themes and @path58/ui.",
5
+ "type": "module",
6
+ "main": "./src/tokens.ts",
7
+ "types": "./src/tokens.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./src/tokens.ts",
11
+ "types": "./src/tokens.ts"
12
+ },
13
+ "./css": "./src/tokens.css",
14
+ "./tokens.css": "./src/tokens.css"
15
+ },
16
+ "files": [
17
+ "src",
18
+ "README.md"
19
+ ],
20
+ "license": "MIT",
21
+ "author": "Path58",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/tsvika58/path58-design.git",
25
+ "directory": "packages/tokens"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "scripts": {
31
+ "build": "echo 'tokens: no build step โ€” ship src directly' && exit 0",
32
+ "lint": "echo 'tokens: lint TBD' && exit 0"
33
+ }
34
+ }
package/src/tokens.css ADDED
@@ -0,0 +1,419 @@
1
+ /* =========================================================================
2
+ Path58 โ€” Design Tokens
3
+ Dark terminal aesthetic. Serious infrastructure, not startup-cute.
4
+ ========================================================================= */
5
+
6
+ /* NOTE: Font-face rules live in @path58/brand-assets/fonts/fonts.css
7
+ (split out in DSGN-1.1.2). Import that file to load the actual woff2 files. */
8
+
9
+ :root {
10
+ /* -------------------------------------------------------------------
11
+ COLOR โ€” BASE SURFACES
12
+ ------------------------------------------------------------------- */
13
+ --p58-bg: #0a0a1a; /* canvas / deep background */
14
+ --p58-surface: #0e0e24; /* cards, panels, elevated surfaces */
15
+ --p58-surface-2: #14142e; /* inputs, nested panels */
16
+ --p58-surface-3: #1b1b3a; /* hover / selected row */
17
+
18
+ /* -------------------------------------------------------------------
19
+ COLOR โ€” FOREGROUND (on dark surfaces)
20
+ ------------------------------------------------------------------- */
21
+ --p58-fg-1: #f5f6fb; /* primary text, headings */
22
+ --p58-fg-2: #b8bad0; /* secondary body text */
23
+ --p58-fg-3: #7b7e9c; /* tertiary / labels / meta */
24
+ --p58-fg-4: #4a4d6b; /* disabled / placeholder */
25
+
26
+ /* -------------------------------------------------------------------
27
+ COLOR โ€” BORDERS & DIVIDERS
28
+ ------------------------------------------------------------------- */
29
+ --p58-border: rgba(255, 255, 255, 0.08);
30
+ --p58-border-strong: rgba(255, 255, 255, 0.14);
31
+ --p58-border-subtle: rgba(255, 255, 255, 0.04);
32
+
33
+ /* -------------------------------------------------------------------
34
+ COLOR โ€” ACCENT (terminal teal / brand)
35
+ `--p58-teal-*` is the canonical p58 accent (data / dev / proof moments),
36
+ per BRAND_STRATEGY_v2 ยง Type system implications. `--p58-accent-*` is now
37
+ an ALIAS of teal โ€” preserved for backwards compatibility. PREFER
38
+ `--p58-teal-*` in new code; `--p58-accent-*` resolves to the same values.
39
+ ------------------------------------------------------------------- */
40
+ --p58-teal: #00d4aa; /* primary accent โ€” teal */
41
+ --p58-teal-hover: #1ee5bd; /* hover state */
42
+ --p58-teal-press: #00b892; /* press state */
43
+ --p58-teal-dim: #00d4aa22;/* subtle tint fill */
44
+ --p58-teal-glow: #00d4aa44;/* glow / ring */
45
+
46
+ /* Darker teal text-shift for teal-as-FOREGROUND (text / small UI) on LIGHT
47
+ surfaces. #00d4aa is only 1.77:1 on the p58-light canvas; this variant is
48
+ 4.90:1 on #f4f6fa (AA body). Mirrors --p58-lime-text-on-light. Components
49
+ consume it under [data-theme="p58-light"] (per REQ-2026-06-02-007, Option A
50
+ PM-approved 2026-06-02 โ€” component swap is the follow-on task). */
51
+ --p58-teal-text-on-light: #007a63;
52
+
53
+ /* Text / icon color sitting ON a solid teal fill (e.g. P58Button primary).
54
+ Dark brand ink, theme-independent โ€” 8.46:1 on teal in ALL themes. Replaces
55
+ the former `var(--p58-bg)` pattern, which inverted to near-white (1.77:1)
56
+ on p58-light. Per REQ-2026-06-02-007 (Decision #3 resolution, Option A). */
57
+ --p58-on-accent: #0d1d4d;
58
+
59
+ /* Theme-dispatched accent foreground. In p58-dark: bright teal. In p58-light:
60
+ darker teal-text-on-light (REQ-007 Class B / DSGN-1.1.5a). Components consume
61
+ this for accent text/icons/focus borders so the foreground darkens per theme
62
+ WITHOUT overriding the brand-locked --p58-teal (AC9/AC11). Tints that use teal
63
+ inside color-mix() stay on --p58-teal โ€” they are translucent fills, not text. */
64
+ --p58-accent-fg: var(--p58-teal);
65
+
66
+ --p58-accent: var(--p58-teal); /* alias โ†’ --p58-teal */
67
+ --p58-accent-hover: var(--p58-teal-hover); /* alias โ†’ --p58-teal-hover */
68
+ --p58-accent-press: var(--p58-teal-press); /* alias โ†’ --p58-teal-press */
69
+ --p58-accent-dim: var(--p58-teal-dim); /* alias โ†’ --p58-teal-dim */
70
+ --p58-accent-glow: var(--p58-teal-glow); /* alias โ†’ --p58-teal-glow */
71
+
72
+ --p58-icon-accent-soft: color-mix(in srgb, var(--p58-teal) 70%, transparent);
73
+ /* Soft-icon foreground (IconContainer default variant). On dark, 70%-opacity teal reads as
74
+ muted cyan glyph โ€” preserves the "soft icon" aesthetic. On p58-light it dispatches to a
75
+ fully opaque darker teal (see p58-light.css). Per REQ-2026-06-02-008 Option A. */
76
+
77
+ /* -------------------------------------------------------------------
78
+ BRAND COLOR FAMILIES (per BRAND_STRATEGY_v2 ยง Visual identity)
79
+ Three secondary accent families woven across the two sub-brands:
80
+ --p58-blue-* shared anchor (Path58 + p58). Navy DNA. Surface depth.
81
+ --p58-lime-* Path58-only accent โ€” money / revenue moments (rare).
82
+ --p58-teal-* p58-only accent โ€” data / dev / proof (defined above).
83
+ ------------------------------------------------------------------- */
84
+
85
+ /* --- BLUE (shared anchor) -------------------------------------------
86
+ Anchor: --p58-blue-900 = #0d1d4d (Path58 primary text/action navy).
87
+ Derivation: sRGB linear interpolation from the #0d1d4d anchor toward
88
+ #ffffff at perceptually-spaced ratios (900=0% โ†’ 50=97% white). Light
89
+ stops are intentionally low-saturation cool-grays with a navy undertone
90
+ (suits surfaces/borders); a hue-preserving OKLCH ramp is a future option.
91
+ Method + exact values: evidence/token-extension.md. */
92
+ --p58-blue-50: #f8f8fa;
93
+ --p58-blue-100: #eeeff3;
94
+ --p58-blue-200: #e0e2e8;
95
+ --p58-blue-300: #c7cbd6;
96
+ --p58-blue-400: #adb2c2;
97
+ --p58-blue-500: #9097ad;
98
+ --p58-blue-600: #6e7794;
99
+ --p58-blue-700: #4c587b;
100
+ --p58-blue-800: #2c3a64;
101
+ --p58-blue-900: #0d1d4d; /* anchor โ€” Path58 navy (locked, BRAND_STRATEGY_v2) */
102
+
103
+ /* --- LIME (Path58 money/revenue accent โ€” use sparingly, 5-10% by volume) -
104
+ Locked values from BRAND_STRATEGY_v2 + TASTE_NOTES ยง Money moments.
105
+ โš  A11Y: --p58-lime-text-on-light (#5e8a23) on #f6f4ee cream = 3.72:1 โ€”
106
+ passes WCAG AA *large* (โ‰ฅ3:1) but FAILS AA *body* (โ‰ฅ4.5:1). Value is
107
+ brand-locked; do NOT darken without sign-off. See REQ-2026-06-02-005
108
+ and evidence/token-extension.md ยง WCAG. Prefer the wash for body $-figures. */
109
+ --p58-lime: #9ab64a; /* anchor โ€” muted citrus (fills/data series) */
110
+ --p58-lime-text-on-light: #5e8a23; /* darker text variant (AA-large only โ€” see REQ-005) */
111
+ --p58-lime-wash: rgba(154, 182, 74, 0.32);/* highlight wash under money figures */
112
+ --p58-lime-300: #c7d79b; /* optional โ€” light tint (backgrounds) */
113
+ --p58-lime-700: #6c7f34; /* optional โ€” deep lime */
114
+
115
+ /* -------------------------------------------------------------------
116
+ COLOR โ€” SEMANTIC
117
+ ------------------------------------------------------------------- */
118
+ --p58-success: #00d4aa;
119
+ --p58-success-dim: #00d4aa1a;
120
+ --p58-warning: #f5a623;
121
+ --p58-warning-dim: #f5a6231a;
122
+ --p58-danger: #ff4757;
123
+ --p58-danger-dim: #ff47571a;
124
+ --p58-info: #5aa9ff;
125
+ --p58-info-dim: #5aa9ff1a;
126
+
127
+ /* -------------------------------------------------------------------
128
+ COLOR โ€” TREND / DELTA
129
+ Teal is the brand accent โ€” do NOT use it as generic "up = good".
130
+ Most movement is reported neutrally; the number and arrow carry the
131
+ direction. Red is reserved for unambiguous regressions. Teal is only
132
+ used when a metric EXPLICITLY beats a baseline (benchmark wins,
133
+ SLO-over-target).
134
+ Consumers pick a class based on *context*, not just sign:
135
+ cost โ†“ -> .p58-trend-neutral (good, but expected)
136
+ error-rate โ†‘ -> .p58-trend-negative (red)
137
+ pass-rate beats baseline -> .p58-trend-positive (teal, sparingly)
138
+ ------------------------------------------------------------------- */
139
+ --p58-trend-neutral: var(--p58-fg-2); /* default movement โ€” no value judgement */
140
+ --p58-trend-muted: var(--p58-fg-3); /* meta / "vs baseline" label */
141
+ --p58-trend-negative: #ff4757; /* regression โ€” SLO breach, cost spike, error rate up */
142
+ --p58-trend-positive: var(--p58-accent);/* beats baseline โ€” use sparingly, for wins only */
143
+
144
+ /* Additional data-viz accents (harmonized with teal primary) */
145
+ --p58-viz-1: #00d4aa;
146
+ --p58-viz-2: #5aa9ff;
147
+ --p58-viz-3: #c084fc;
148
+ --p58-viz-4: #f5a623;
149
+ --p58-viz-5: #ff4757;
150
+ --p58-viz-6: #7b7e9c;
151
+
152
+ /* -------------------------------------------------------------------
153
+ TYPOGRAPHY โ€” FAMILIES
154
+ ------------------------------------------------------------------- */
155
+ --p58-font-display: 'Space Grotesk', ui-sans-serif, system-ui, sans-serif;
156
+ --p58-font-ui: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;
157
+ --p58-font-mono: 'JetBrains Mono', ui-monospace, 'Menlo', 'Monaco', monospace;
158
+
159
+ /* -------------------------------------------------------------------
160
+ TYPOGRAPHY โ€” SCALE (UI-focused; dense)
161
+ ------------------------------------------------------------------- */
162
+ --p58-text-2xs: 10px;
163
+ --p58-text-xs: 11px;
164
+ --p58-text-sm: 12px;
165
+ --p58-text-md: 13px; /* default body */
166
+ --p58-text-base:14px;
167
+ --p58-text-lg: 16px;
168
+ --p58-text-xl: 20px;
169
+ --p58-text-2xl: 24px;
170
+ --p58-text-3xl: 32px;
171
+ --p58-text-4xl: 40px;
172
+ --p58-text-5xl: 56px;
173
+ --p58-text-6xl: 72px;
174
+
175
+ /* -------------------------------------------------------------------
176
+ TYPOGRAPHY โ€” WEIGHTS & LINE HEIGHTS
177
+ ------------------------------------------------------------------- */
178
+ --p58-weight-light: 300;
179
+ --p58-weight-regular: 400;
180
+ --p58-weight-medium: 500;
181
+ --p58-weight-semibold:600;
182
+ --p58-weight-bold: 700;
183
+
184
+ --p58-leading-tight: 1.15;
185
+ --p58-leading-snug: 1.3;
186
+ --p58-leading-normal: 1.5;
187
+ --p58-leading-loose: 1.7;
188
+
189
+ --p58-tracking-tight: -0.02em;
190
+ --p58-tracking-normal: 0;
191
+ --p58-tracking-wide: 0.04em;
192
+ --p58-tracking-caps: 0.12em; /* for uppercase labels */
193
+
194
+ /* -------------------------------------------------------------------
195
+ SPACING (4px baseline)
196
+ ------------------------------------------------------------------- */
197
+ --p58-space-0: 0;
198
+ --p58-space-1: 4px;
199
+ --p58-space-2: 8px;
200
+ --p58-space-3: 12px;
201
+ --p58-space-4: 16px;
202
+ --p58-space-5: 20px;
203
+ --p58-space-6: 24px;
204
+ --p58-space-8: 32px;
205
+ --p58-space-10: 40px;
206
+ --p58-space-12: 48px;
207
+ --p58-space-16: 64px;
208
+ --p58-space-20: 80px;
209
+ --p58-space-24: 96px;
210
+
211
+ /* -------------------------------------------------------------------
212
+ RADII โ€” minimal, intentional. Infrastructure โ‰  bubbly.
213
+ ------------------------------------------------------------------- */
214
+ --p58-radius-none: 0;
215
+ --p58-radius-sm: 2px; /* inputs, chips */
216
+ --p58-radius-md: 4px; /* buttons, small cards */
217
+ --p58-radius-lg: 6px; /* cards, panels */
218
+ --p58-radius-xl: 10px; /* modals */
219
+ --p58-radius-full: 999px; /* pills, avatars */
220
+
221
+ /* -------------------------------------------------------------------
222
+ ELEVATION
223
+ Dark-on-dark drop shadows disappear. We lift surfaces instead with
224
+ a color ramp + brighter border. Apply elevation as a pair:
225
+ background + border. Keep shadow-inset as the shared highlight.
226
+ ------------------------------------------------------------------- */
227
+ --p58-elev-1-bg: #0e0e24; /* base โ€” no lift */
228
+ --p58-elev-1-border: rgba(255, 255, 255, 0.08);
229
+ --p58-elev-2-bg: #13132f; /* hover / lifted */
230
+ --p58-elev-2-border: rgba(255, 255, 255, 0.15);
231
+ --p58-elev-3-bg: #16163a; /* modal / menu */
232
+ --p58-elev-3-border: rgba(255, 255, 255, 0.22);
233
+
234
+ --p58-shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.03);
235
+ --p58-glow-accent: 0 0 0 1px var(--p58-accent), 0 0 16px var(--p58-accent-glow);
236
+ --p58-ring-focus: 0 0 0 2px var(--p58-bg), 0 0 0 4px var(--p58-accent);
237
+
238
+ /* -------------------------------------------------------------------
239
+ MOTION
240
+ ------------------------------------------------------------------- */
241
+ --p58-ease: cubic-bezier(0.2, 0.6, 0.2, 1);
242
+ --p58-ease-in: cubic-bezier(0.4, 0, 1, 1);
243
+ --p58-duration-fast: 120ms;
244
+ --p58-duration-base: 180ms;
245
+ --p58-duration-slow: 260ms;
246
+
247
+ /* -------------------------------------------------------------------
248
+ Z-INDEX
249
+ ------------------------------------------------------------------- */
250
+ --p58-z-base: 1;
251
+ --p58-z-sticky: 10;
252
+ --p58-z-dropdown:100;
253
+ --p58-z-modal: 1000;
254
+ --p58-z-toast: 2000;
255
+
256
+ /* โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
257
+ * Third-party brand identity colors
258
+ * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
259
+ * These are upstream tech-logo identity colors used in iconography.
260
+ * They are NOT Path58 design tokens โ€” they must render as the
261
+ * upstream brands specify regardless of active theme.
262
+ *
263
+ * DO NOT theme-swap these (no light-theme variants, no marketing-
264
+ * theme variants). DO NOT use them for any element that is not an
265
+ * official representation of the upstream brand's logo or mark.
266
+ *
267
+ * Adding a new third-party brand color: file a REQ documenting
268
+ * the upstream source (e.g., brand guidelines URL) and the
269
+ * components that consume it.
270
+ * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
271
+ */
272
+ --p58-brand-3p-react: #61DAFB;
273
+ --p58-brand-3p-react-hover: #4DD0E1;
274
+ --p58-brand-3p-html5: #E34F26;
275
+ --p58-brand-3p-html5-hover: #F06529;
276
+ }
277
+
278
+ /* =========================================================================
279
+ SEMANTIC ELEMENT STYLES
280
+ Apply these by using the class or by attaching to real elements.
281
+ ========================================================================= */
282
+
283
+ html, body {
284
+ background: var(--p58-bg);
285
+ color: var(--p58-fg-1);
286
+ font-family: var(--p58-font-ui);
287
+ font-size: var(--p58-text-md);
288
+ line-height: var(--p58-leading-normal);
289
+ -webkit-font-smoothing: antialiased;
290
+ -moz-osx-font-smoothing: grayscale;
291
+ }
292
+
293
+ /* Headings โ€” Space Grotesk, tight tracking, tight leading */
294
+ .p58-h1, h1.p58 {
295
+ font-family: var(--p58-font-display);
296
+ font-size: var(--p58-text-5xl);
297
+ font-weight: var(--p58-weight-semibold);
298
+ line-height: var(--p58-leading-tight);
299
+ letter-spacing: var(--p58-tracking-tight);
300
+ color: var(--p58-fg-1);
301
+ }
302
+ .p58-h2, h2.p58 {
303
+ font-family: var(--p58-font-display);
304
+ font-size: var(--p58-text-3xl);
305
+ font-weight: var(--p58-weight-semibold);
306
+ line-height: var(--p58-leading-tight);
307
+ letter-spacing: var(--p58-tracking-tight);
308
+ color: var(--p58-fg-1);
309
+ }
310
+ .p58-h3, h3.p58 {
311
+ font-family: var(--p58-font-display);
312
+ font-size: var(--p58-text-2xl);
313
+ font-weight: var(--p58-weight-medium);
314
+ line-height: var(--p58-leading-snug);
315
+ color: var(--p58-fg-1);
316
+ }
317
+ .p58-h4, h4.p58 {
318
+ font-family: var(--p58-font-display);
319
+ font-size: var(--p58-text-xl);
320
+ font-weight: var(--p58-weight-medium);
321
+ line-height: var(--p58-leading-snug);
322
+ color: var(--p58-fg-1);
323
+ }
324
+
325
+ /* Body */
326
+ .p58-body {
327
+ font-family: var(--p58-font-ui);
328
+ font-size: var(--p58-text-md);
329
+ font-weight: var(--p58-weight-regular);
330
+ line-height: var(--p58-leading-normal);
331
+ color: var(--p58-fg-2);
332
+ }
333
+ .p58-body-lg {
334
+ font-family: var(--p58-font-ui);
335
+ font-size: var(--p58-text-lg);
336
+ line-height: var(--p58-leading-normal);
337
+ color: var(--p58-fg-2);
338
+ }
339
+ .p58-small {
340
+ font-size: var(--p58-text-sm);
341
+ color: var(--p58-fg-3);
342
+ }
343
+
344
+ /* Eyebrow / label โ€” uppercase, wide tracking, mono. Classic ops dashboard. */
345
+ .p58-eyebrow {
346
+ font-family: var(--p58-font-mono);
347
+ font-size: var(--p58-text-xs);
348
+ font-weight: var(--p58-weight-medium);
349
+ text-transform: uppercase;
350
+ letter-spacing: var(--p58-tracking-caps);
351
+ color: var(--p58-fg-3);
352
+ }
353
+
354
+ /* Code / data โ€” JetBrains Mono */
355
+ .p58-code, code.p58, kbd.p58 {
356
+ font-family: var(--p58-font-mono);
357
+ font-size: 0.92em;
358
+ color: var(--p58-fg-1);
359
+ background: var(--p58-surface-2);
360
+ border: 1px solid var(--p58-border);
361
+ border-radius: var(--p58-radius-sm);
362
+ padding: 1px 5px;
363
+ }
364
+
365
+ /* Metric โ€” big display number, mono */
366
+ .p58-metric {
367
+ font-family: var(--p58-font-mono);
368
+ font-size: var(--p58-text-4xl);
369
+ font-weight: var(--p58-weight-medium);
370
+ line-height: 1;
371
+ letter-spacing: -0.01em;
372
+ color: var(--p58-fg-1);
373
+ font-variant-numeric: tabular-nums;
374
+ }
375
+ .p58-metric-sm {
376
+ font-family: var(--p58-font-mono);
377
+ font-size: var(--p58-text-xl);
378
+ font-weight: var(--p58-weight-medium);
379
+ line-height: 1;
380
+ color: var(--p58-fg-1);
381
+ font-variant-numeric: tabular-nums;
382
+ }
383
+
384
+ /* Scrollbars โ€” thin, unobtrusive */
385
+ .p58-scroll::-webkit-scrollbar { width: 10px; height: 10px; }
386
+ .p58-scroll::-webkit-scrollbar-track { background: transparent; }
387
+ .p58-scroll::-webkit-scrollbar-thumb {
388
+ background: var(--p58-border-strong);
389
+ border-radius: var(--p58-radius-full);
390
+ border: 2px solid var(--p58-bg);
391
+ }
392
+ .p58-scroll::-webkit-scrollbar-thumb:hover { background: var(--p58-fg-4); }
393
+
394
+ /* Selection */
395
+ ::selection { background: var(--p58-accent-dim); color: var(--p58-fg-1); }
396
+
397
+ /* =========================================================================
398
+ TREND / DELTA โ€” semantic classes for metric movement.
399
+ Pick by CONTEXT (is this change good/bad/just movement?), not by sign.
400
+ All are mono + tabular-nums so arrows and digits align in stacks.
401
+ ========================================================================= */
402
+ .p58-trend,
403
+ .p58-trend-neutral,
404
+ .p58-trend-negative,
405
+ .p58-trend-positive {
406
+ font-family: var(--p58-font-mono);
407
+ font-size: var(--p58-text-xs);
408
+ font-variant-numeric: tabular-nums;
409
+ display: inline-flex;
410
+ align-items: center;
411
+ gap: 4px;
412
+ line-height: 1;
413
+ }
414
+ .p58-trend,
415
+ .p58-trend-neutral { color: var(--p58-trend-neutral); } /* default โ€” no value judgement */
416
+ .p58-trend-negative { color: var(--p58-trend-negative); } /* red โ€” regression */
417
+ .p58-trend-positive { color: var(--p58-trend-positive); } /* teal โ€” explicit win vs baseline */
418
+ .p58-trend-muted { color: var(--p58-trend-muted); font-family: var(--p58-font-mono); font-size: var(--p58-text-xs); }
419
+ .p58-trend-baseline { color: var(--p58-trend-muted); font-family: var(--p58-font-mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.1em; margin-left: 2px; }
package/src/tokens.ts ADDED
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Path58 Design Tokens โ€” TypeScript mirror of tokens.css.
3
+ *
4
+ * The CANONICAL source of values is `tokens.css` (CSS custom properties on
5
+ * `:root`). This file mirrors those values as a deeply-frozen const so TS/JS
6
+ * consumers (build scripts, JS-driven styling, docs) can read the same numbers
7
+ * without parsing CSS. Keys map to `--p58-<group>-<name>` in the CSS.
8
+ *
9
+ * Parity for the sample keys (bg, accent, border) is asserted in
10
+ * `evidence/token-parity.md` (AC6). When you change a value here, change it in
11
+ * `tokens.css` too โ€” they must not drift.
12
+ *
13
+ * Brand color families (BRAND_STRATEGY_v2 ยง Visual identity): `color.teal`
14
+ * (p58 accent), `color.blue` (shared navy anchor, stops 50-900), `color.lime`
15
+ * (Path58 money accent). The `accent*` keys are documented ALIASES of `teal*`
16
+ * (back-compat) โ€” the canonical TS names are the `teal*` group; prefer those.
17
+ *
18
+ * Theme-DISPATCHED tokens โ€” `color.accentFg` and `color.iconAccentSoft` โ€” are the
19
+ * exception to value-mirroring: their value is the self-referencing CSS var
20
+ * (e.g. 'var(--p58-accent-fg)'), NOT a baked hex. A JS inline-style consumer emits
21
+ * the var, which the cascade resolves per active theme (bright teal on p58-dark;
22
+ * darker #007a63 on p58-light). Baking a hex would freeze them to one theme and
23
+ * defeat the dispatch. (accentFg: DSGN-1.1.5a / REQ-007; iconAccentSoft: DSGN-1.1.5b / REQ-008.)
24
+ *
25
+ * `color.brand3p` (React/HTML5 tech-logo identity colors) is INTENTIONALLY
26
+ * outside the theme system โ€” these render as the upstream brands specify
27
+ * regardless of active theme. Do NOT theme-swap them. (DSGN-1.1.3, Decision #2.)
28
+ */
29
+
30
+ export const tokens = {
31
+ color: {
32
+ // Base surfaces โ€” maps to --p58-bg / --p58-surface*
33
+ bg: '#0a0a1a',
34
+ surface: '#0e0e24',
35
+ surface2: '#14142e',
36
+ surface3: '#1b1b3a',
37
+
38
+ // Foreground (on dark) โ€” maps to --p58-fg-*
39
+ fg1: '#f5f6fb',
40
+ fg2: '#b8bad0',
41
+ fg3: '#7b7e9c',
42
+ fg4: '#4a4d6b',
43
+
44
+ // Borders & dividers โ€” maps to --p58-border*
45
+ border: 'rgba(255, 255, 255, 0.08)',
46
+ borderStrong: 'rgba(255, 255, 255, 0.14)',
47
+ borderSubtle: 'rgba(255, 255, 255, 0.04)',
48
+
49
+ // Teal (p58 accent โ€” data/dev/proof) โ€” maps to --p58-teal* (canonical)
50
+ teal: '#00d4aa',
51
+ tealHover: '#1ee5bd',
52
+ tealPress: '#00b892',
53
+ tealDim: '#00d4aa22',
54
+ tealGlow: '#00d4aa44',
55
+ // tealTextOnLight: darker teal for teal-as-foreground on light (4.90:1 on #f4f6fa) โ€” REQ-007
56
+ tealTextOnLight: '#007a63',
57
+ // onAccent: text/icon on a solid teal fill โ€” dark ink, theme-independent (8.46:1 on teal) โ€” REQ-007
58
+ onAccent: '#0d1d4d',
59
+ // accentFg: theme-DISPATCHED accent foreground (REQ-007 Class B / DSGN-1.1.5a).
60
+ // Unlike the resolved-hex tokens around it, this is CSS-time-resolved: the value
61
+ // is the self-referencing var so a JS inline-style consumer
62
+ // (style={{ color: tokens.color.accentFg }}) emits var(--p58-accent-fg), which
63
+ // the cascade dispatches to bright teal (p58-dark) or #007a63 (p58-light). A
64
+ // baked hex here would freeze it to one theme and defeat the dispatch.
65
+ accentFg: 'var(--p58-accent-fg)',
66
+
67
+ // iconAccentSoft: theme-DISPATCHED soft-icon foreground (REQ-008 Option A / DSGN-1.1.5b).
68
+ // Same CSS-time-resolved dispatch as accentFg above: the self-referencing var emits
69
+ // var(--p58-icon-accent-soft), which the cascade resolves to 70%-opacity teal (p58-dark,
70
+ // "soft icon" aesthetic) or fully-opaque #007a63 (p58-light, AA-body legible). A baked
71
+ // color-mix or hex would freeze it to one theme and reintroduce the on-light contrast fail.
72
+ iconAccentSoft: 'var(--p58-icon-accent-soft)',
73
+
74
+ // Accent โ€” ALIASES of teal* (back-compat; maps to --p58-accent* โ†’ var(--p58-teal*))
75
+ accent: '#00d4aa',
76
+ accentHover: '#1ee5bd',
77
+ accentPress: '#00b892',
78
+ accentDim: '#00d4aa22',
79
+ accentGlow: '#00d4aa44',
80
+
81
+ // Blue (shared navy anchor) โ€” maps to --p58-blue-* (anchor blue900 = #0d1d4d)
82
+ blue50: '#f8f8fa',
83
+ blue100: '#eeeff3',
84
+ blue200: '#e0e2e8',
85
+ blue300: '#c7cbd6',
86
+ blue400: '#adb2c2',
87
+ blue500: '#9097ad',
88
+ blue600: '#6e7794',
89
+ blue700: '#4c587b',
90
+ blue800: '#2c3a64',
91
+ blue900: '#0d1d4d',
92
+
93
+ // Lime (Path58 money accent โ€” rare) โ€” maps to --p58-lime*
94
+ // โš  limeTextOnLight is AA-large only on #f6f4ee (3.72:1) โ€” see REQ-2026-06-02-005
95
+ lime: '#9ab64a',
96
+ limeTextOnLight: '#5e8a23',
97
+ limeWash: 'rgba(154, 182, 74, 0.32)',
98
+ lime300: '#c7d79b',
99
+ lime700: '#6c7f34',
100
+
101
+ // Semantic โ€” maps to --p58-success/warning/danger/info(+dim)
102
+ success: '#00d4aa',
103
+ successDim: '#00d4aa1a',
104
+ warning: '#f5a623',
105
+ warningDim: '#f5a6231a',
106
+ danger: '#ff4757',
107
+ dangerDim: '#ff47571a',
108
+ info: '#5aa9ff',
109
+ infoDim: '#5aa9ff1a',
110
+
111
+ // Trend / delta โ€” maps to --p58-trend-*
112
+ trendNegative: '#ff4757',
113
+
114
+ // Data-viz accents โ€” maps to --p58-viz-*
115
+ viz1: '#00d4aa',
116
+ viz2: '#5aa9ff',
117
+ viz3: '#c084fc',
118
+ viz4: '#f5a623',
119
+ viz5: '#ff4757',
120
+ viz6: '#7b7e9c',
121
+
122
+ // Elevation backgrounds/borders โ€” maps to --p58-elev-*
123
+ elev1Bg: '#0e0e24',
124
+ elev1Border: 'rgba(255, 255, 255, 0.08)',
125
+ elev2Bg: '#13132f',
126
+ elev2Border: 'rgba(255, 255, 255, 0.15)',
127
+ elev3Bg: '#16163a',
128
+ elev3Border: 'rgba(255, 255, 255, 0.22)',
129
+
130
+ // Third-party brand identity โ€” maps to --p58-brand-3p-*
131
+ // โš  INTENTIONALLY OUTSIDE THE THEME SYSTEM. These are upstream tech-logo
132
+ // identity colors (React, HTML5) used in iconography โ€” they must render as
133
+ // the upstream brands specify regardless of active theme. DO NOT theme-swap.
134
+ // Adding a new one: file a REQ documenting the upstream source. See the
135
+ // "Third-party brand identity colors" section in tokens.css.
136
+ brand3p: {
137
+ react: '#61DAFB',
138
+ reactHover: '#4DD0E1',
139
+ html5: '#E34F26',
140
+ html5Hover: '#F06529',
141
+ },
142
+ },
143
+
144
+ font: {
145
+ // Families โ€” maps to --p58-font-*
146
+ display: "'Space Grotesk', ui-sans-serif, system-ui, sans-serif",
147
+ ui: "'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif",
148
+ mono: "'JetBrains Mono', ui-monospace, 'Menlo', 'Monaco', monospace",
149
+ },
150
+
151
+ // Type scale โ€” maps to --p58-text-*
152
+ text: {
153
+ '2xs': '10px',
154
+ xs: '11px',
155
+ sm: '12px',
156
+ md: '13px',
157
+ base: '14px',
158
+ lg: '16px',
159
+ xl: '20px',
160
+ '2xl': '24px',
161
+ '3xl': '32px',
162
+ '4xl': '40px',
163
+ '5xl': '56px',
164
+ '6xl': '72px',
165
+ },
166
+
167
+ // Weights โ€” maps to --p58-weight-*
168
+ weight: {
169
+ light: 300,
170
+ regular: 400,
171
+ medium: 500,
172
+ semibold: 600,
173
+ bold: 700,
174
+ },
175
+
176
+ // Line heights โ€” maps to --p58-leading-*
177
+ leading: {
178
+ tight: 1.15,
179
+ snug: 1.3,
180
+ normal: 1.5,
181
+ loose: 1.7,
182
+ },
183
+
184
+ // Letter spacing โ€” maps to --p58-tracking-*
185
+ tracking: {
186
+ tight: '-0.02em',
187
+ normal: '0',
188
+ wide: '0.04em',
189
+ caps: '0.12em',
190
+ },
191
+
192
+ // Spacing (4px baseline) โ€” maps to --p58-space-*
193
+ space: {
194
+ 0: '0',
195
+ 1: '4px',
196
+ 2: '8px',
197
+ 3: '12px',
198
+ 4: '16px',
199
+ 5: '20px',
200
+ 6: '24px',
201
+ 8: '32px',
202
+ 10: '40px',
203
+ 12: '48px',
204
+ 16: '64px',
205
+ 20: '80px',
206
+ 24: '96px',
207
+ },
208
+
209
+ // Radii โ€” maps to --p58-radius-*
210
+ radius: {
211
+ none: '0',
212
+ sm: '2px',
213
+ md: '4px',
214
+ lg: '6px',
215
+ xl: '10px',
216
+ full: '999px',
217
+ },
218
+
219
+ // Motion โ€” maps to --p58-ease* / --p58-duration-*
220
+ motion: {
221
+ ease: 'cubic-bezier(0.2, 0.6, 0.2, 1)',
222
+ easeIn: 'cubic-bezier(0.4, 0, 1, 1)',
223
+ durationFast: '120ms',
224
+ durationBase: '180ms',
225
+ durationSlow: '260ms',
226
+ },
227
+
228
+ // Z-index โ€” maps to --p58-z-*
229
+ z: {
230
+ base: 1,
231
+ sticky: 10,
232
+ dropdown: 100,
233
+ modal: 1000,
234
+ toast: 2000,
235
+ },
236
+ } as const;
237
+
238
+ export type Tokens = typeof tokens;
239
+
240
+ export default tokens;