@mediaradar/design-tokens 2.0.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 ADDED
@@ -0,0 +1,50 @@
1
+ # Design Tokens — MediaRadar Design System
2
+
3
+ Style Dictionary build for the MediaRadar Design System. This package reads the token source files in `packages/tokens/` (one level up) and transforms them into CSS custom properties, Tailwind v4 integration files, and JS/TS token values — deployed to a CDN consumed directly by URL, no npm package required.
4
+
5
+ See the root `CLAUDE.md` for the full token pipeline architecture and consuming-app setup. This file covers only building this package locally.
6
+
7
+ ---
8
+
9
+ ## Building locally
10
+
11
+ ```bash
12
+ cd packages/design-tokens
13
+ npm ci
14
+ npm run build # runs scripts/build-tokens.js → writes dist/
15
+ ```
16
+
17
+ `dist/` is gitignored and never committed — it's a pure CI build artifact, deployed straight to the CDN by `.github/workflows/tokens.yml` on push to `main`. Do not edit anything under `dist/` by hand; it's regenerated from `packages/tokens/*.json` on every build and any local edit is silently overwritten.
18
+
19
+ ## Build config
20
+
21
+ Style Dictionary config lives in `sd.config.mjs`. The custom `name/prefix-mr-strip-layer` transform strips the leading layer segment (`ref`/`sys`/`component`) from each token path and adds an `mr-` prefix — see root `CLAUDE.md`'s "Name transform" section for the full mapping rules.
22
+
23
+ ## Output
24
+
25
+ ```
26
+ dist/
27
+ css/ ← tokens.css (entry point), ref.css, sys.css, spacing.css, typography.css, component.css, dark.css
28
+ tailwind/ ← theme.css (@theme block), typography.css (@utility text-style-* classes)
29
+ js/ ← tokens.js, tokens.d.ts
30
+ DESIGN.md ← LLM-optimized design spec, auto-generated
31
+ patterns.json ← NOT built here — published by the ux-design repo; do not create or edit
32
+ index.html, scss/utilities/ ← copied as-is from static/, unwired legacy leftovers
33
+ ```
34
+
35
+ ## Consuming this package
36
+
37
+ Downstream projects don't install anything from this package — they `@import` the deployed CSS directly by URL:
38
+
39
+ ```css
40
+ @import "https://lemon-cliff-091e8ef0f.7.azurestaticapps.net/css/tokens.css";
41
+ @import "https://lemon-cliff-091e8ef0f.7.azurestaticapps.net/css/dark.css";
42
+ ```
43
+
44
+ See root `CLAUDE.md`'s "Consuming in a React + Tailwind app" section for the full Tailwind v4 wiring, the CDN asset reference table, and MCP server tool list.
45
+
46
+ ## Contributing
47
+
48
+ 1. Edit token source files under `packages/tokens/*.json` — never `dist/`.
49
+ 2. `npm run build` locally to verify output.
50
+ 3. Open a PR against `main`. Changes deploy automatically on merge.
package/dist/DESIGN.md ADDED
@@ -0,0 +1,370 @@
1
+ # MediaRadar Design System
2
+
3
+ > LLM context file for `@mediaradar/design-tokens`. Provides brand rules, semantic guides, and component patterns for AI-assisted UI development. Import via `@node_modules/@mediaradar/design-tokens/DESIGN.md` in Claude Code. The token reference section below is auto-generated — rebuild the package to update resolved values.
4
+ >
5
+ > This is the authoritative resolved-values reference — if any other doc
6
+ > disagrees with it, this one wins. Two other places document the same
7
+ > system from a different angle: `design-site`'s live `/stylesheet` route
8
+ > (real components, real variants — the visual reference) and
9
+ > `mr-clientapps-insights-studio`'s local `frontend/DESIGN.md` (app-specific
10
+ > component usage).
11
+
12
+ ## Brand
13
+
14
+ MediaRadar is a B2B media intelligence platform — enterprise software for advertising analytics, market research, and competitive intelligence. The UI is professional, information-dense, and analytical. It is never playful or decorative. Palette is warm-cream, not the cool-gray/blue look common to SaaS dashboards.
15
+
16
+ **Two brand colors, strictly separated by role — do not conflate them:**
17
+ - **Coral** — `sys.color.brand.primary` (`#f05323` light / `#ff7548` dark) — **identity only**: logo, AI-surface accents (sparkle icons, AI gradient endpoint), brand moments. Never a button fill, never a link, never used for "interactive" anything.
18
+ - **Warm royal blue** — `sys.color.brand.primaryAction` (`#2747c4` light / `#5b73dd` dark) — **the only interactive color**: primary CTA fills, links, focus rings, active/selected nav states.
19
+ - **Neutral "black":** `sys.color.text.primary` (`#1f1b16` light / `#f4f2ee` dark) — a warm near-black, not a cool blue-black. The whole neutral ramp (canvas/surface/subtle/borders) is warm-toned; never substitute cool grays.
20
+ - **Typography:** Instrument Sans (UI/body) + Instrument Serif (display — used italic for editorial/greeting moments). Not Roboto Flex.
21
+
22
+ ## Token semantics
23
+
24
+ **Rule:** Always consume `sys.*` tokens in component styles. `ref.*` tokens bypass dark mode and semantic intent — they are raw primitives, not design decisions.
25
+
26
+ ### Color roles
27
+
28
+ | Tailwind key | Use for |
29
+ |---|---|
30
+ | `canvas` | Outermost page background |
31
+ | `surface` | Cards, panels, dialogs, drawers |
32
+ | `subtle` | Secondary areas, sidebars, striped table rows |
33
+ | `text-primary` | Body copy, headings, form values |
34
+ | `text-secondary` | Supporting text, metadata, timestamps |
35
+ | `text-inverse` | Text/icons on dark or brand-colored backgrounds |
36
+ | `text-warning` | Caution states |
37
+ | `brand-primary` | Logo, AI-surface accents, brand identity moments ONLY — never buttons/links |
38
+ | `brand-primaryAction` | CTAs, links, focus rings, active/selected nav — the actual interactive color |
39
+ | `brand-onprimary` | Text/icons placed directly on brand-primary backgrounds |
40
+ | `border-default` | Dividers, input outlines, card borders |
41
+ | `border-focus` | Keyboard focus rings |
42
+ | `status-success` | Positive values, confirmations |
43
+ | `status-danger` | Errors, destructive actions |
44
+ | `status-onstatus` | Text/icons on status-colored backgrounds |
45
+
46
+ ### Typography hierarchy
47
+
48
+ Prefer `text-style-*` composite classes — they set size, weight, line-height, letter-spacing, and color in one class and support all Tailwind variants (`hover:`, `md:`, etc.).
49
+
50
+ | Role | Class | Use for |
51
+ |---|---|---|
52
+ | Page title | `text-style-heading-1` | h1, page-level titles |
53
+ | Section heading | `text-style-heading-2` | h2, major section headers |
54
+ | Sub-heading | `text-style-heading-3` | h3, card titles, panel headers |
55
+ | Large body | `text-style-body-lg` | Intro or featured paragraphs |
56
+ | Body | `text-style-body` | Standard paragraphs, descriptions |
57
+ | Small body | `text-style-body-sm` | Secondary content, sidebar text |
58
+ | XS body | `text-style-body-xs` | Fine print, helper text |
59
+ | Label | `text-style-label` | Form labels, key–value metadata |
60
+ | Label strong | `text-style-label-strong` | Bold labels, selected state labels |
61
+ | Label small | `text-style-label-sm` | Compact labels, tag text |
62
+ | Label XS | `text-style-label-xs` | Dense table headers, badge text |
63
+ | Caption | `text-style-caption` | Tooltips, image captions, timestamps |
64
+ | Link | `text-style-link` | Anchor text |
65
+ | Link strong | `text-style-link-strong` | Prominent / bold links |
66
+ | Link XS | `text-style-link-xs` | Inline small links |
67
+
68
+ ## Component patterns
69
+
70
+ ### Card
71
+ ```tsx
72
+ <div className="bg-surface rounded-card shadow-raised border border-border-default p-6">
73
+ <h2 className="text-style-heading-3">Title</h2>
74
+ <p className="text-style-body text-text-secondary mt-2">Description</p>
75
+ </div>
76
+ ```
77
+
78
+ ### Form input
79
+ ```tsx
80
+ <label className="text-style-label text-text-primary">
81
+ Field label
82
+ <input
83
+ className="mt-1 block w-full bg-surface rounded-control border border-border-default
84
+ px-3 py-2 text-style-body text-text-primary
85
+ focus:border-border-focus focus:outline-none"
86
+ />
87
+ </label>
88
+ ```
89
+
90
+ ### Primary button
91
+ ```tsx
92
+ <button className="inline-flex items-center gap-2 bg-brand-primaryAction text-brand-onprimary
93
+ rounded-control px-4 py-2 text-style-label-strong
94
+ hover:opacity-90 disabled:opacity-disabled">
95
+ Action
96
+ </button>
97
+ ```
98
+ Note: `bg-brand-primary` (coral) is reserved for identity/AI-accent moments — never a button fill.
99
+
100
+ ### Dialog / modal
101
+ ```tsx
102
+ <div className="fixed inset-0 z-modal flex items-center justify-center">
103
+ <div className="bg-surface rounded-card shadow-overlay p-8 w-full max-w-lg">
104
+ <h2 className="text-style-heading-2">Dialog title</h2>
105
+ <p className="text-style-body text-text-secondary mt-3">Content goes here.</p>
106
+ </div>
107
+ </div>
108
+ ```
109
+
110
+ ### Data table row
111
+ ```tsx
112
+ <tr className="border-b border-border-default hover:bg-subtle
113
+ transition-colors duration-interactive ease-interactive">
114
+ <td className="px-4 py-3 text-style-body text-text-primary">{value}</td>
115
+ <td className="px-4 py-3 text-style-body-sm text-text-secondary">{meta}</td>
116
+ </tr>
117
+ ```
118
+
119
+ ### Status badge
120
+ ```tsx
121
+ <span className="inline-flex items-center gap-1 rounded-control px-2 py-1
122
+ text-style-label-xs bg-status-success text-status-onstatus">
123
+ Active
124
+ </span>
125
+ ```
126
+
127
+ ### Dropdown / tooltip overlay
128
+ ```tsx
129
+ <div className="bg-surface rounded-card shadow-overlay border border-border-default
130
+ z-dropdown p-1">
131
+ {items}
132
+ </div>
133
+ ```
134
+
135
+ ## Dark mode
136
+
137
+ Set `data-theme="dark"` on any ancestor element. All `sys.*` tokens adapt automatically — no `dark:` Tailwind variants needed.
138
+
139
+ ```ts
140
+ document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light')
141
+ ```
142
+
143
+ **Diagnostic:** If a color is not adapting to dark mode, verify you're using a `sys.color.*` token (e.g., `bg-canvas`) rather than a `ref.color.*` primitive (e.g., `--mr-ref-color-shadow-universal-2`). Only sys tokens have dark overrides.
144
+
145
+ ## Decision guide
146
+
147
+ When building UI, follow this order:
148
+
149
+ 1. **Text:** Is there a `text-style-*` that matches the typographic role? Use it — do not manually compose font-size + weight + line-height.
150
+ 2. **Color:** Is there a `sys.color.*` semantic name describing the element's intent? Use it — `bg-{key}`, `text-{key}`, `border-{key}`, etc.
151
+ 3. **Spacing:** Is there a spacing scale value that fits? Use the discrete scale (`p-4`, `gap-3`, `mt-8`). Avoid arbitrary values. Use pixel values (`p-1px`) only for sub-pixel tuning.
152
+ 4. **Shape/elevation:** Use `rounded-control` for interactive elements, `rounded-card` for containers. Use `shadow-raised` for resting cards, `shadow-overlay` for floating surfaces.
153
+ 5. **Primitives:** Reach into `ref.*` only when no semantic token fits. If the pattern recurs, propose a new `sys.*` token.
154
+
155
+ ---
156
+
157
+ ## Token reference
158
+
159
+ > Auto-generated from Style Dictionary. All values are resolved — no aliases. Rebuild to update.
160
+
161
+ ### Colors
162
+
163
+ Key is the suffix for any Tailwind color utility: `bg-{key}`, `text-{key}`, `border-{key}`, `ring-{key}`, `fill-{key}`, etc. Dark values activate when `data-theme="dark"` is set on any ancestor.
164
+
165
+ | Key | Light | Dark |
166
+ | --- | --- | --- |
167
+ | canvas | #f4f2ee | #1c1814 |
168
+ | surface | #fbfaf7 | #26211b |
169
+ | subtle | #ebe7e0 | #322c24 |
170
+ | text-primary | #1f1b16 | #f4f2ee |
171
+ | text-secondary | #6b6358 | #b5aea1 |
172
+ | text-tertiary | #5f574b | #a39b8c |
173
+ | text-inverse | #fbfaf7 | #1c1814 |
174
+ | text-warning | #5c4118 | #e8c285 |
175
+ | text-danger | #8b1018 | #ff7068 |
176
+ | text-success | #1d4d2a | #7fc28f |
177
+ | text-link | #2747c4 | #8aa0ff |
178
+ | brand-primary | #f05323 | #ff7548 |
179
+ | brand-primaryAction | #2747c4 | #5b73dd |
180
+ | brand-onprimary | #ffffff | — |
181
+ | brand-primarySoft | #ebe3d5 | #3a322a |
182
+ | status-success | #1d7a3b | #3a9555 |
183
+ | status-warning | #b8843a | #d9a655 |
184
+ | status-danger | #c53030 | #e84a4a |
185
+ | status-onstatus | #ffffff | — |
186
+ | status-on-status | #ffffff | — |
187
+ | border-default | #dcd6cb | #3a3329 |
188
+ | border-interactive | #6b6358 | — |
189
+ | border-focus | #2747c4 | #8aa0ff |
190
+ | border-focusSoft | rgba(39, 71, 196, 0.28) | rgba(138, 160, 255, 0.35) |
191
+ | ai-tint | #e4e2f5 | #2b2e48 |
192
+ | ai-ontint | #2747c4 | #8aa0ff |
193
+ | ai-gradient | linear-gradient(135deg, #2747c4 0%, #f05323 60%, #f99d20 100%) | linear-gradient(135deg, #5b73dd 0%, #ff7548 60%, #ffb878 100%) |
194
+
195
+ ### Typography
196
+
197
+ **Font sizes** — Tailwind: `text-{key}`
198
+
199
+ | Key | Value |
200
+ | --- | --- |
201
+ | xs | 0.75rem |
202
+ | sm | 0.875rem |
203
+ | base | 1rem |
204
+ | md | 1.125rem |
205
+ | lg | 1.25rem |
206
+ | xl | 1.5rem |
207
+ | h1 | 1.875rem |
208
+
209
+ **Font weights** — Tailwind: `font-{key}`
210
+
211
+ | Key | Value |
212
+ | --- | --- |
213
+ | regular | 400 |
214
+ | medium | 500 |
215
+ | semibold | 600 |
216
+ | bold | 700 |
217
+
218
+ **Line heights** — Tailwind: `leading-{key}`
219
+
220
+ | Key | Value |
221
+ | --- | --- |
222
+ | tight | 1.2 |
223
+ | base | 1.5 |
224
+ | head | 1.5 |
225
+
226
+ **Letter spacing** — Tailwind: `tracking-{key}`
227
+
228
+ | Key | Value |
229
+ | --- | --- |
230
+ | normal | 0em |
231
+ | tight | -0.01em |
232
+
233
+ **Text styles** — Tailwind: `text-style-{name}`. One class sets font-size, font-weight, line-height, letter-spacing, and color. Supports all Tailwind variants.
234
+
235
+ | Style | Size | Weight | Leading | Tracking | Color |
236
+ | --- | --- | --- | --- | --- | --- |
237
+ | text-style-heading-1 | 1.875rem | 600 | 1.5 | 0em | #363233 |
238
+ | text-style-heading-2 | 1.25rem | 600 | 1.2 | 0em | #1f1b16 |
239
+ | text-style-heading-3 | 0.875rem | 600 | 1.2 | 0em | #1f1b16 |
240
+ | text-style-body-lg | 1.25rem | 700 | 1.2 | 0em | #1f1b16 |
241
+ | text-style-body | 1.125rem | 400 | 1.5 | 0em | #1f1b16 |
242
+ | text-style-body-sm | 0.875rem | 400 | 1.5 | 0em | #1f1b16 |
243
+ | text-style-body-xs | 0.75rem | 400 | 1.5 | 0em | #1f1b16 |
244
+ | text-style-label | 1rem | 400 | 1.2 | 0em | #1f1b16 |
245
+ | text-style-label-strong | 1rem | 600 | 1.2 | 0em | #1f1b16 |
246
+ | text-style-label-sm | 0.875rem | 700 | 1.2 | 0em | #6b6358 |
247
+ | text-style-label-xs | 0.75rem | 600 | 1.2 | 0em | #6b6358 |
248
+ | text-style-caption | 0.75rem | 400 | 1.5 | 0em | #6b6358 |
249
+ | text-style-link | 0.875rem | 400 | 1.5 | 0em | #2747c4 |
250
+ | text-style-link-strong | 0.875rem | 600 | 1.5 | 0em | #2747c4 |
251
+ | text-style-link-xs | 0.75rem | 400 | 1.5 | 0em | #2747c4 |
252
+
253
+ ### Spacing
254
+
255
+ Tailwind: `p-{key}`, `m-{key}`, `gap-{key}`, `w-{key}`, `h-{key}`, etc. Integer scale: 1 step = 0.25rem (4px) — so `p-4` = 1rem = 16px. Half-steps (e.g. `p-1_5`) and pixel values (e.g. `p-1px`) are available.
256
+
257
+ **rem scale:**
258
+
259
+ | Key | Value |
260
+ | --- | --- |
261
+ | 0 | 0rem |
262
+ | 1 | 0.25rem |
263
+ | 2 | 0.5rem |
264
+ | 3 | 0.75rem |
265
+ | 4 | 1rem |
266
+ | 5 | 1.25rem |
267
+ | 6 | 1.5rem |
268
+ | 7 | 1.75rem |
269
+ | 8 | 2rem |
270
+ | 9 | 2.25rem |
271
+ | 10 | 2.5rem |
272
+ | 11 | 2.75rem |
273
+ | 12 | 3rem |
274
+ | 13 | 3.25rem |
275
+ | 14 | 3.5rem |
276
+ | 15 | 3.75rem |
277
+ | 16 | 4rem |
278
+ | 17 | 4.25rem |
279
+ | 18 | 4.5rem |
280
+ | 19 | 4.75rem |
281
+ | 20 | 5rem |
282
+ | 21 | 5.25rem |
283
+ | 22 | 5.5rem |
284
+ | 23 | 5.75rem |
285
+ | 24 | 6rem |
286
+ | 25 | 7rem |
287
+ | 26 | 8rem |
288
+ | 27 | 9rem |
289
+ | 28 | 10rem |
290
+ | 29 | 11rem |
291
+ | 30 | 12rem |
292
+ | 1_5 | 0.375rem |
293
+ | 2_5 | 0.625rem |
294
+ | 3_5 | 0.875rem |
295
+ | 4_5 | 1.125rem |
296
+ | 5_5 | 1.375rem |
297
+ | 6_5 | 1.625rem |
298
+ | 7_5 | 1.875rem |
299
+
300
+ **pixel values:**
301
+
302
+ | Key | Value |
303
+ | --- | --- |
304
+ | 0px | 0px |
305
+ | 1px | 1px |
306
+ | 2px | 2px |
307
+ | 3px | 3px |
308
+ | 5px | 5px |
309
+ | 6px | 6px |
310
+ | 7px | 7px |
311
+ | 8px | 8px |
312
+ | 9px | 9px |
313
+ | 10px | 10px |
314
+
315
+ **Semantic spacing** — no Tailwind utility; use `var(--mr-spacing-{key})` in CSS directly.
316
+
317
+ | Token | Value |
318
+ | --- | --- |
319
+ | control-padding-x | 0.75rem |
320
+ | control-padding-y | 0.5rem |
321
+ | layout-xs | 0.5rem |
322
+ | layout-sm | 0.75rem |
323
+ | layout-md | 1rem |
324
+ | layout-lg | 1.5rem |
325
+ | layout-xl | 2rem |
326
+ | card-padding | 1.25rem |
327
+ | dialog-padding | 1.5rem |
328
+
329
+ ### Shape
330
+
331
+ **Border radius** — Tailwind: `rounded-{key}`
332
+
333
+ | Key | Value |
334
+ | --- | --- |
335
+ | control | 8px |
336
+ | card | 12px |
337
+
338
+ ### Elevation
339
+
340
+ **Box shadows** — Tailwind: `shadow-{key}`
341
+
342
+ | Key | Value |
343
+ | --- | --- |
344
+ | raised | #000bec |
345
+ | overlay | #000bec |
346
+
347
+ ### Motion
348
+
349
+ | Type | Key | Tailwind | Value |
350
+ | --- | --- | --- | --- |
351
+ | duration | interactive | duration-interactive | 200ms |
352
+ | easing | interactive | ease-interactive | cubic-bezier(0.2, 0, 0, 1) |
353
+
354
+ ### Opacity
355
+
356
+ Tailwind: `opacity-{key}`
357
+
358
+ | Key | Value |
359
+ | --- | --- |
360
+ | disabled | 0.4 |
361
+
362
+ ### Z-index
363
+
364
+ Tailwind: `z-{key}`
365
+
366
+ | Key | Value |
367
+ | --- | --- |
368
+ | dropdown | 1000 |
369
+ | modal | 1100 |
370
+ | tooltip | 1200 |
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Do not edit directly, this file was auto-generated.
3
+ */
4
+
5
+ :root {
6
+ --mr-button-border: #dcd6cb;
7
+ --mr-button-typography-fontfamily: 'Roboto Flex', sans-serif;
8
+ }
@@ -0,0 +1,27 @@
1
+ [data-theme="dark"] {
2
+ --mr-color-canvas: var(--mr-ref-color-brand-warm-canvas-dark);
3
+ --mr-color-surface: var(--mr-ref-color-brand-warm-surface-dark);
4
+ --mr-color-subtle: var(--mr-ref-color-brand-warm-subtle-dark);
5
+ --mr-color-text-primary: var(--mr-ref-color-brand-warm-text-primary-dark);
6
+ --mr-color-text-secondary: var(--mr-ref-color-brand-warm-text-secondary-dark);
7
+ --mr-color-text-tertiary: var(--mr-ref-color-brand-warm-text-tertiary-dark);
8
+ --mr-color-text-inverse: var(--mr-ref-color-brand-warm-text-inverse-dark);
9
+ --mr-color-text-warning: var(--mr-ref-color-brand-warm-text-warning-dark);
10
+ --mr-color-text-danger: var(--mr-ref-color-brand-warm-text-danger-dark);
11
+ --mr-color-text-success: var(--mr-ref-color-brand-warm-text-success-dark);
12
+ --mr-color-text-link: var(--mr-ref-color-brand-warm-text-link-dark);
13
+ --mr-color-brand-primary: var(--mr-ref-color-brand-warm-brand-primary-dark);
14
+ --mr-color-brand-primary-action: var(--mr-ref-color-brand-warm-brand-primary-action-dark);
15
+ --mr-color-brand-primary-soft: var(--mr-ref-color-brand-warm-brand-primary-soft-dark);
16
+ --mr-color-status-success: var(--mr-ref-color-brand-warm-status-success-dark);
17
+ --mr-color-status-warning: var(--mr-ref-color-brand-warm-status-warning-dark);
18
+ --mr-color-status-danger: var(--mr-ref-color-brand-warm-status-danger-dark);
19
+ --mr-color-border-default: var(--mr-ref-color-brand-warm-border-default-dark);
20
+ --mr-color-border-focus: var(--mr-ref-color-brand-warm-border-focus-dark);
21
+ --mr-color-border-focus-soft: var(--mr-ref-color-brand-warm-border-focus-soft-dark);
22
+ --mr-color-ai-tint: var(--mr-ref-color-brand-warm-ai-tint-dark);
23
+ --mr-color-ai-ontint: var(--mr-ref-color-brand-warm-ai-ontint-dark);
24
+ --mr-color-ai-gradient: var(--mr-ref-color-brand-warm-ai-gradient-dark);
25
+ --mr-text-style-heading-1-color: var(--mr-ref-color-secondary-light-10);
26
+ --mr-typography-line-height-head: var(--mr-ref-typography-line-height-sm);
27
+ }