trdr-ds-install 1.6.0 β†’ 1.6.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trdr-ds-install",
3
- "version": "1.6.0",
3
+ "version": "1.6.5",
4
4
  "description": "Installs the TRDR Design System skill for Claude Code",
5
5
  "bin": {
6
6
  "trdr-ds-install": "./bin/install.js"
@@ -6,7 +6,7 @@ argument-hint: "[analyze|apply|foundation|violations|components|final|resume|sta
6
6
  allowed-tools: [Read, Glob, Grep, Edit, Write, Bash, WebFetch]
7
7
  ---
8
8
 
9
- **Skill version:** 1.6.0
9
+ **Skill version:** 1.6.5
10
10
  **npm package:** trdr-ds-install
11
11
 
12
12
  You are implementing the **TRDR Design System** in a developer's project. The Design Hub is the single source of truth and lives at **https://trdr.mrocontent.com.br**.
@@ -53,13 +53,13 @@ Run this command silently via Bash:
53
53
  npm show trdr-ds-install version 2>/dev/null
54
54
  ```
55
55
 
56
- Compare the result with the **Skill version** constant at the top of this file (`1.6.0`).
56
+ Compare the result with the **Skill version** constant at the top of this file (`1.6.5`).
57
57
 
58
58
  - If the command fails or returns empty (no internet / npm unavailable): skip silently, continue.
59
59
  - If registry version == local version: skip silently, continue.
60
60
  - If registry version > local version:
61
61
  ```
62
- πŸ”„ Nova versΓ£o da skill disponΓ­vel: trdr-ds-install@[registry-version] (instalada: 1.6.0)
62
+ πŸ”„ Nova versΓ£o da skill disponΓ­vel: trdr-ds-install@[registry-version] (instalada: 1.6.5)
63
63
 
64
64
  Responda:
65
65
  - `"atualizar"` / `"update"` β€” instalar a nova versΓ£o agora (requer reiniciar /trdr-ds apΓ³s)
@@ -114,6 +114,18 @@ Read `package.json` at the project root. Identify:
114
114
 
115
115
  Save `stylingMode` β€” it must be referenced throughout Phase 2 wherever the output format differs by framework.
116
116
 
117
+ **Dual stylingMode β€” tailwind + styled-components simultaneously:**
118
+ If `package.json` contains BOTH `tailwindcss` AND `styled-components` (or `@emotion/*`):
119
+ - Set `stylingMode: 'tailwind'` (dominant β€” utility classes in className)
120
+ - Set `hasStyledComponents: true` to activate additional scan
121
+ - In Step 3, add a styled-components scan alongside the normal CSS scan:
122
+ - Pattern in `*.tsx, *.ts, *.jsx, *.js`: `` styled\.\w+`[^`]*(?:#[0-9A-Fa-f]{3,8}|font-family|rgba\()[^`]*` ``
123
+ - For each template literal matched: run A, B, F violation checks against its content (even though it's not a `.css` file)
124
+ - Fix: replace hardcoded values inside template literals with CSS var tokens:
125
+ `background: #00A8CC` β†’ `background: var(--action-brand-default);`
126
+ `font-family: 'Inter'` β†’ `font-family: var(--font-secondary);`
127
+ - Document in `CLAUDE.md` of the project: "This project uses styled-components AND Tailwind. New components: prefer Tailwind + DS classes. Existing styled-components: use DS tokens via CSS vars in template literals."
128
+
117
129
  ### Step 2 β€” Map style structure
118
130
 
119
131
  Search for all style files:
@@ -133,6 +145,14 @@ Determine the best directory for new CSS files:
133
145
  - React CRA/Vite with `src/`: β†’ `src/styles/` or `src/assets/`
134
146
  - Plain HTML: β†’ `css/` or `styles/`
135
147
 
148
+ **For `tailwind` stylingMode β€” additional scan:**
149
+ Read `tailwind.config.js` (or `tailwind.config.ts`) and check `theme.colors` and `theme.extend.colors`:
150
+ - If any color value is a hardcoded `#hex` that matches a TRDR DS token, flag it
151
+ - Add `tailwind.config.js` to "FILES TO MODIFY" in the plan
152
+ - Fix during Sub-fase B: replace each `'#hex'` with `'var(--semantic-token)'`
153
+ - Example: `brand: '#00A8CC'` β†’ `brand: 'var(--content-brand)'`
154
+ - This allows Tailwind classes like `text-brand` to use the DS token automatically
155
+
136
156
  ### Step 3 β€” Find violations
137
157
 
138
158
  Search for TRDR rule violations across all source files (*.css, *.scss, *.tsx, *.jsx, *.ts, *.js, *.vue, *.html):
@@ -140,15 +160,30 @@ Search for TRDR rule violations across all source files (*.css, *.scss, *.tsx, *
140
160
  **A β€” Hardcoded colors** (should be CSS vars):
141
161
  Search pattern: `#[0-9A-Fa-f]{3,8}` in CSS/SCSS files; `#[0-9A-Fa-f]{3,8}` in component files within style props or className strings.
142
162
 
163
+ **Special case β€” SVG attribute colors** (`stroke=`, `fill=`, `stop-color=` in HTML/JSX/Vue):
164
+ When `#hex` is found inside an SVG attribute (not a CSS property), the fix is different β€” CSS variables do NOT work in SVG attributes. Instead:
165
+ - If the SVG is a simple icon with a single solid color β†’ replace with `stroke="currentColor"` / `fill="currentColor"` and control color via a CSS class (e.g., `.icon-brand { color: var(--content-brand); }`)
166
+ - If the SVG has multiple distinct colors (multi-tone icon) β†’ it should be replaced as a Category J violation (inline SVG β†’ icon library)
167
+ - Do NOT write `stroke="var(--token)"` β€” it is invalid in HTML SVG attributes
168
+
169
+ Track SVG attribute color violations separately as **A\*** in DS_ANALYSIS.md with the note "SVG attribute β€” requires currentColor + CSS class approach, not var()."
170
+
143
171
  **B β€” Hardcoded font-family** (should be var(--font-primary/secondary/mono)):
144
172
  Search: `font-family.*Inter|font-family.*JetBrains Mono|font-family.*Space Grotesk|font-family.*Roboto Mono`
145
173
 
174
+ **Note β€” JSX camelCase:** In React/Next.js files, font-family appears as `fontFamily` inside `style={{}}` objects. These are NOT detected by Category B (which scans CSS). They are captured by Category I (inline styles with `font` keyword). Do NOT double-count them in Category B; address them in Category I fix instead.
175
+
146
176
  **C β€” Hardcoded px spacing** (should be var(--spacing-*)):
147
177
  Search: `(margin|padding|gap):\s*\d+px` in CSS/SCSS
148
178
 
149
179
  **D β€” Primitive token usage** (should be semantic):
150
180
  Search: `var\(--color-|var\(--space-` in CSS/SCSS/component files
151
181
 
182
+ Also search for **custom CSS variable definitions with primitive naming** in `:root {}` blocks:
183
+ - Pattern: `--color-[a-z]|--space-[0-9]|--font-size-[0-9]` inside `:root {`
184
+ - Flag as: "Custom CSS variable using primitive-style name: `--color-brand`. This duplicates DS token naming. Remove and replace all `var(--color-brand)` usages with the appropriate semantic token."
185
+ - Do NOT auto-remove β€” flag for manual review in DS_MIGRATION.md
186
+
152
187
  **E β€” Missing tokens.css**:
153
188
  Check if `tokens.css` already exists in the project and if it's imported in the global CSS.
154
189
 
@@ -159,10 +194,29 @@ Search: `rgba\(` in CSS/SCSS/HTML files (excluding node_modules, vendor)
159
194
  Search: `linear-gradient|radial-gradient` in CSS/SCSS/HTML files
160
195
  Flag any gradient that doesn't reference a TRDR gradient token (`var(--gradient-*)`)
161
196
 
197
+ **Gradients with hex stops:** Compare against TRDR gradient token approximate values:
198
+ - `--gradient-bg-hero` β‰ˆ `linear-gradient(180deg, #0E0E0E 0%, #141519 100%)`
199
+ - `--gradient-bg-surface` β‰ˆ `linear-gradient(180deg, #141519 0%, #0E0E0E 100%)`
200
+ - `--gradient-brand` β‰ˆ `linear-gradient(90deg, #00A8CC 0%, #00D4FF 100%)`
201
+ If a gradient closely matches one of these: replace with `var(--gradient-name)`.
202
+ If no match: flag in DS_MIGRATION.md as "Custom gradient β€” no DS token available."
203
+ Non-DS colors in gradient stops (e.g. `#0a1520`) are also A violations β€” flag separately.
204
+
205
+ **Gradients with rgba stops:** When gradient stops use `rgba()` instead of hex:
206
+ 1. Extract the base color from each rgba stop and identify it in the TRDR color mapping table.
207
+ 2. If the base color has a DS token: recommend `rgba(var(--token-rgb), opacity)` if the DS exposes RGB variables, otherwise flag in DS_MIGRATION.md.
208
+ 3. **Fade-to-transparent** pattern (e.g. `rgba(0,212,255,0.04) 0%, transparent 100%`):
209
+ - This is a glow/haze effect. Very unlikely to have a DS token.
210
+ - Flag as: "Glow effect gradient β€” no DS token. Consider converting to `box-shadow: 0 0 Xpx var(--token)` or remove if purely decorative."
211
+ 4. **Overlay gradient** (e.g. `rgba(255,204,64,0.1) 0%, rgba(255,204,64,0.05) 100%`):
212
+ - Flag as: "Tinted overlay gradient β€” no DS equivalent. Map rgba base color to token; keep gradient as-is or convert to a solid rgba with semantic token."
213
+
162
214
  **H β€” Hardcoded font-size in px** (should use .trdr-h* / .trdr-body-* text style classes):
163
215
  Search: `font-size:\s*\d+px` in CSS/SCSS files (skip tokens.css itself)
164
216
 
165
217
  **I β€” Inline styles with design properties** (should be CSS classes with tokens):
218
+
219
+ **I.1 β€” JSX/HTML style attribute** (standard inline styles):
166
220
  Search in `*.html, *.tsx, *.jsx, *.vue, *.svelte`:
167
221
  - HTML/Vue: `style="[^"]*(?:color|background|font|padding|margin|gap|border)[^"]*"`
168
222
  - React/JSX: `style=\{\{[^}]*(?:color|background|font|padding|margin|gap|border)[^}]*\}\}`
@@ -173,20 +227,85 @@ Do NOT flag (these are acceptable exceptions):
173
227
  - `style="--custom-prop: value"` β€” CSS custom property passing a dynamic value to CSS (e.g. `style="--card-delay:0.1s"`)
174
228
  - `style={{ '--custom-prop': value }}` β€” same in JSX
175
229
 
230
+ **I.2 β€” Dynamic DOM style assignment** (imperative JS manipulation, NOT covered by I.1):
231
+ Search in `*.tsx, *.jsx, *.js, *.ts`:
232
+ - Pattern: `\.style\.[a-zA-Z]+\s*=\s*['"]`
233
+ - Example: `e.currentTarget.style.background = 'rgba(255,255,255,0.03)'`
234
+ - Example: `ref.current.style.color = '#00D4FF'`
235
+
236
+ This pattern is common in hover handlers (`onMouseEnter/onMouseLeave`) and imperative animations. The assigned value is a hardcoded design value that must be replaced.
237
+
238
+ **I.2 fix procedure:**
239
+
240
+ *CASE 1 β€” onMouseEnter/onMouseLeave hover effect:*
241
+ This is the most common case. Convert to a CSS `:hover` rule:
242
+ ```css
243
+ /* Before: onMouseEnter sets background imperatively */
244
+ .item { transition: background 0.15s; }
245
+ .item:hover { background: var(--surface-hover); }
246
+ ```
247
+ Remove the `onMouseEnter` and `onMouseLeave` handlers. Add `className="item"` to the element.
248
+
249
+ *CASE 2 β€” State-driven imperative style (non-hover):*
250
+ If the DOM assignment is driven by JS logic beyond simple hover, replace the hardcoded value only:
251
+ ```tsx
252
+ // Before
253
+ el.style.background = 'rgba(255,255,255,0.03)';
254
+ // After
255
+ el.style.background = 'var(--surface-hover)';
256
+ ```
257
+ Document in DS_PROGRESS.md as "I.2 fix β€” dynamic style value replaced with token."
258
+
259
+ PRIORITY: Always prefer CASE 1 (CSS pseudo-class) β€” it's more performant and idiomatic than CASE 2.
260
+
176
261
  **J β€” SVG icons inline** (should use an icon library):
177
262
  Search in `*.html, *.tsx, *.jsx, *.vue`:
178
263
  - Pattern: `<svg` in source files (NOT in logo files, NOT in `node_modules/`, `references/`, `assets/icons/`)
179
264
  - Do NOT flag: `<svg` in known logo files (those with the official TRDR fingerprint)
180
265
  - Count distinct files with inline SVGs, not total occurrences
181
266
 
267
+ **Severity sub-classification:**
268
+ - **J.high**: `<svg>` with hardcoded `stroke="#hex"` or `fill="#hex"` β€” both a J and A* violation; replace with icon library ASAP
269
+ - **J.medium**: `<svg>` with dynamic JSX fill/stroke expression (e.g. `fill={isActive ? 'currentColor' : 'none'}`) β€” no hex hardcoded, but state-driven SVG attribute that must be preserved during migration; replace with icon library using conditional CSS class
270
+ - **J.low**: `<svg>` using ONLY `currentColor` / `inherit` (no hardcoded colors) β€” still prefer icon library, but lower priority; note in plan: "SVG uses currentColor (color is CSS-controlled). Migration to Material Icons recommended but non-urgent."
271
+
272
+ **J.medium fix procedure β€” dynamic SVG attributes:**
273
+ When an SVG has `fill={condition ? 'currentColor' : 'none'}` or `stroke={value}` (JSX expression):
274
+ 1. Identify the two visual states (filled/outlined, active/inactive)
275
+ 2. Create CSS classes for each state:
276
+ ```css
277
+ .icon-star { color: var(--content-tertiary); }
278
+ .icon-star.active { color: var(--context-trading-signal); }
279
+ ```
280
+ 3. Replace the SVG with a Material Icon (or equivalent DS icon) using a conditional className:
281
+ ```tsx
282
+ <span className={`material-icons icon-star ${isWatching ? 'active' : ''}`}>star</span>
283
+ ```
284
+ 4. The `fill`/`stroke` logic is handled entirely by CSS β€” never pass state to icon attributes.
285
+
182
286
  **K β€” Logo missing or incorrect in HTML/JSX** (should use official logo-trdr.svg):
183
- Search in `*.html, *.tsx, *.jsx, *.vue`:
184
- - `<img[^>]*(?:logo|brand|mark)[^>]*src="(?!.*logo-trdr)[^"]*"` β€” img tag with non-official logo src
185
- - `<span[^>]*>[^<]*TRDR[^<]*</span>` β€” text "TRDR" in a span used as logo replacement
186
- - `import\s+\w+\s+from\s+['"][^'"]*logo(?!-trdr)[^'"]*['"]` β€” logo import that isn't logo-trdr
287
+ Search in `*.html, *.tsx, *.jsx, *.vue` using **two separate Grep calls** (the combined pattern is unreliable in ripgrep):
288
+
289
+ Call 1 β€” Non-official img logo (HTML):
290
+ - Pattern: `src="[^"]*logo(?!-trdr)[^"]*"` β€” img/Image with logo in the src value itself (covers JSX where src is first attribute)
291
+ - Secondary: `<img[^>]*(?:logo|brand|mark)[^>]*src="(?!.*logo-trdr)[^"]*"` β€” catches cases where logo/brand/mark appears in alt= or class= before src=
292
+
293
+ Call 1b β€” Next.js `<Image>` component (Next.js projects only):
294
+ - Pattern: `<Image[^>]*src="[^"]*logo(?!-trdr)[^"]*"` β€” next/image component with non-official logo
295
+ - Also flag `<Image[^>]*src=\{[^}]*logo(?!Trdr)[^}]*\}` for dynamic src with variable name not matching logoTrdr
296
+
297
+ Call 2 β€” Text span as logo (use this pattern, NOT the combined version):
298
+ - Pattern: `>\s*TRDR\s*<` β€” finds any element with text content "TRDR"
299
+ - Then check if the surrounding element is `<span>` or `<div>` (not `<img alt="TRDR">`)
300
+ - Simpler alternative: `class="[^"]*logo[^"]*"` + check if no `<img` tag on the same line
301
+
302
+ Call 3 β€” Wrong logo import:
303
+ - Pattern: `import\s+\w+\s+from\s+['"][^'"]*logo(?!-trdr)[^'"]*['"]` β€” logo import that isn't logo-trdr
187
304
 
188
305
  Do NOT flag: `logo-trdr.svg` references β€” those are correct.
189
306
 
307
+ **Note:** The pattern `<span[^>]*>[^<]*TRDR[^<]*</span>` is known to fail in ripgrep β€” do NOT use it.
308
+
190
309
  Track:
191
310
  - `total_violations` = sum of all A–H occurrences
192
311
  - `total_files_with_violations` = count of unique files with β‰₯ 1 violation
@@ -829,10 +948,12 @@ For each batch listed as PENDING in `DS_PROGRESS.md` Β§ Sub-fase B:
829
948
  **Font mapping:**
830
949
  | Hardcoded | Replace with |
831
950
  |-----------|-------------|
832
- | `font-family: 'Inter'` | `font-family: var(--font-secondary)` |
833
- | `font-family: 'JetBrains Mono'` | `font-family: var(--font-primary)` |
951
+ | `font-family: 'Inter'` or `font-family: 'Inter', -apple-system, ...` | `font-family: var(--font-secondary)` |
952
+ | `font-family: 'JetBrains Mono'` or `font-family: 'JetBrains Mono', monospace` | `font-family: var(--font-primary)` |
834
953
  | `font-family: 'Space Grotesk'` | `font-family: var(--font-primary)` |
835
- | `font-family: 'Roboto Mono'` | `font-family: var(--font-mono)` |
954
+ | `font-family: 'Roboto Mono'` or `font-family: 'Roboto Mono', monospace` | `font-family: var(--font-mono)` |
955
+
956
+ **Note:** System font fallbacks (`-apple-system`, `BlinkMacSystemFont`, `sans-serif`) are removed when replacing with a DS token. The token's value in tokens.css already defines the complete font stack including fallbacks β€” no manual fallback needed.
836
957
 
837
958
  **Spacing mapping:**
838
959
  | Hardcoded | Replace with |
@@ -844,26 +965,102 @@ For each batch listed as PENDING in `DS_PROGRESS.md` Β§ Sub-fase B:
844
965
  | `20px` | `var(--spacing-xl)` |
845
966
  | `24px` | `var(--spacing-2xl)` |
846
967
  | `32px` | `var(--spacing-3xl)` |
968
+ | `0` / `0px` | Keep as `0` (no token needed) |
969
+ | Any other value (48px, 64px, 96px, etc.) | **Keep the value as-is** β€” no DS token exists for it. Flag in DS_MIGRATION.md as "Custom spacing value: [Npx] in [file:line] β€” consider refactoring or proposing a new token in the Hub." Do NOT invent a `--spacing-4xl` or similar that doesn't exist in tokens.css. |
970
+
971
+ **Multi-value spacing shorthands** (`padding: 16px 32px`, `margin: 12px 0 8px`):
972
+ - Replace each value independently using the mapping above
973
+ - Example: `padding: 16px 32px` β†’ `padding: var(--spacing-lg) var(--spacing-3xl)`
974
+ - Example: `margin: 12px 0 8px` β†’ `margin: var(--spacing-md) 0 var(--spacing-sm)`
975
+ - If one value has no token: replace only the mappable ones; keep the others as-is and flag
976
+
977
+ **Ambiguous colors:** Use property context to decide β€” `background-color` β†’ bg/surface token, `color` β†’ content token, `border-color` β†’ border token, `accent-color` β†’ action token.
978
+
979
+ **Tailwind arbitrary value colors** (only when `stylingMode: tailwind`):
980
+
981
+ Detect in `*.tsx, *.jsx, *.html, *.vue`:
982
+ - Pattern: `(?:bg|text|border|ring|from|to|via|outline|fill|stroke)-\[#[0-9A-Fa-f]{3,8}\]`
983
+ - Also detect `hover:`, `focus:`, `active:`, `dark:` prefixed variants
984
+
985
+ Fix strategy β€” apply in order of preference:
847
986
 
848
- **Ambiguous colors:** Use property context to decide β€” `background-color` β†’ bg/surface token, `color` β†’ content token, `border-color` β†’ border token.
987
+ 1. **DS class exists for element role β†’ OpΓ§Γ£o A (DS class):**
988
+ Replace the arbitrary Tailwind classes with the DS class, keeping non-color utilities:
989
+ ```jsx
990
+ // Before
991
+ className="bg-[#005266] text-white px-4 py-2 rounded cursor-pointer"
992
+ // After
993
+ className="trdr-btn trdr-btn-primary px-4 rounded"
994
+ ```
995
+
996
+ 2. **No DS class, but color maps to DS token β†’ OpΓ§Γ£o B (CSS var arbitrary):**
997
+ ```jsx
998
+ // Before
999
+ className="bg-[#1A1A1A] border border-[#222222]"
1000
+ // After
1001
+ className="bg-[var(--bg-tertiary)] border border-[var(--border-subtle)]"
1002
+ ```
1003
+ Token mapping (use same color β†’ semantic table as CSS):
1004
+ - `bg-[#0E0E0E]` β†’ `bg-[var(--bg-primary)]`
1005
+ - `bg-[#141519]` β†’ `bg-[var(--bg-secondary)]`
1006
+ - `bg-[#1A1A1A]` β†’ `bg-[var(--bg-tertiary)]`
1007
+ - `text-[#FFFFFF]` β†’ `text-[var(--content-primary)]`
1008
+ - `text-[#A4A4A4]` β†’ `text-[var(--content-tertiary)]`
1009
+ - `border-[#222222]` β†’ `border-[var(--border-subtle)]`
1010
+ - `border-[#4A4A4A]` β†’ `border-[var(--border-default)]`
1011
+ - `focus:border-[#00D4FF]` β†’ `focus:border-[var(--border-focus)]`
1012
+ - `text-[#4FE290]` β†’ `text-[var(--context-trading-up)]`
1013
+ - `text-[#F34F45]` β†’ `text-[var(--context-trading-down)]`
1014
+
1015
+ 3. **Color has no DS token (e.g. `hover:bg-[#3DD980]`, `hover:bg-[#E03D3A]`):**
1016
+ - Flag in DS_MIGRATION.md: "Custom hover color `#hex` β€” no DS token equivalent"
1017
+ - Suggestion: replace with CSS hover effect: `hover:[filter:brightness(1.15)]` or use a utility class
1018
+ - Do NOT invent a token or leave the hardcoded color silently
1019
+
1020
+ **`accent-color` property:** Controls native checkbox/radio/range styling.
1021
+ - `accent-color: #00A8CC` β†’ `accent-color: var(--action-brand-default)`
1022
+ - `accent-color: #4FE290` β†’ `accent-color: var(--content-success)`
849
1023
 
850
1024
  **rgba() mapping:**
851
1025
  | Hardcoded pattern | Context | Replace with |
852
1026
  |-------------------|---------|-------------|
853
1027
  | `rgba(0,0,0,*)` | box-shadow | No TRDR shadow token exists β†’ flag in DS_PROGRESS.md / DS_MIGRATION.md as "Missing shadow token" |
1028
+ | `rgba(255,255,255,0.03–0.08)` | border / subtle divider | `var(--border-subtle)` if token exists, otherwise flag |
1029
+ | `rgba(255,255,255,0.10–0.20)` | hover/hover overlay | `var(--surface-hover)` if token exists, otherwise flag |
854
1030
  | `rgba(255,255,255,.29)` approx | overlay/backdrop | `var(--bg-overlay)` |
855
1031
  | `rgba(255,255,255,*)` other | overlay | flag |
1032
+ | `rgba(0,212,255,*)` | focus glow/shadow | No alpha token exists for `--border-focus` β†’ flag as "Missing focus-alpha token" |
1033
+ | `rgba(0,168,204,*)` | brand alpha bg | Use `var(--surface-brand)` if available, otherwise flag |
1034
+ | `rgba(79,226,144,*)` | success alpha bg | Use `var(--surface-success)` if available, otherwise flag |
1035
+ | `rgba(243,79,69,*)` | error alpha bg | Use `var(--surface-error)` if available, otherwise flag |
1036
+ | `rgba(255,204,64,*)` | warning alpha bg | Use `var(--surface-warning)` if available, otherwise flag |
856
1037
  | Any other `rgba(N,N,N,*)` | various | Map to nearest semantic alpha token (--surface-brand, --surface-info, --action-*-alpha, etc.) or flag |
857
1038
 
858
1039
  **Gradient mapping:**
1040
+
1041
+ Known TRDR gradient token values (use to match):
1042
+ | Token | Approximate value |
1043
+ |-------|------------------|
1044
+ | `--gradient-text-brand` | `linear-gradient(90deg, var(--content-brand), var(--border-focus))` β€” cyan to bright-cyan, horizontal |
1045
+ | `--gradient-bg-hero` | `linear-gradient(180deg, var(--bg-secondary), var(--bg-primary))` β€” dark vertical fade |
1046
+ | `--gradient-bg-fade` | `linear-gradient(180deg, var(--bg-tertiary) 0%, transparent 100%)` β€” surface to transparent |
1047
+
859
1048
  | Pattern | Replace with |
860
1049
  |---------|-------------|
861
- | `linear-gradient(...)` using only TRDR brand colors | `var(--gradient-text-brand)`, `var(--gradient-bg-hero)`, or `var(--gradient-bg-fade)` as appropriate |
1050
+ | Gradient whose colors map to `--content-brand` + `--border-focus` (horizontal) | `var(--gradient-text-brand)` |
1051
+ | Gradient whose colors map to `--bg-secondary` β†’ `--bg-primary` (vertical fade) | `var(--gradient-bg-hero)` |
1052
+ | Gradient whose colors map to `--bg-tertiary` β†’ transparent | `var(--gradient-bg-fade)` |
1053
+ | Gradient using only TRDR bg colors but not matching any token above | Flag β€” add comment `/* gradient-bg-custom: consider adding to Hub */` |
862
1054
  | `linear-gradient(...)` using any non-DS colors | Flag β€” developer must decide: remove, replace with TRDR gradient token, or add new token to Hub |
863
1055
  | Gradient inside SVG data URI embedded in CSS | Flag |
864
1056
 
865
1057
  **Font-size mapping (bidirectional β€” CSS + HTML/JSX/Vue):**
866
1058
 
1059
+ **Exception for global selectors:** If `font-size: Npx` is inside a `body {}`, `html {}`, `:root {}`, or `* {}` rule:
1060
+ - **Remove the `font-size` property entirely** β€” do NOT add a DS class to the element
1061
+ - Document in DS_MIGRATION.md: "Global font-size reset removed β€” TRDR DS typography classes manage sizes per-element"
1062
+ - Do NOT apply DS text class to `<body>` or `<html>` tags
1063
+
867
1064
  When a CSS class has a `font-size` that maps to a DS text style, the fix is **two-part**:
868
1065
 
869
1066
  **Part 1 β€” In the CSS file**: remove the properties already provided by the DS class:
@@ -879,6 +1076,12 @@ When a CSS class has a `font-size` that maps to a DS text style, the fix is **tw
879
1076
  | Vue | `<h1 class="hero-title trdr-h2">` or `:class="['hero-title', 'trdr-h2']"` |
880
1077
  | `css-modules` | Add `composes: trdr-h2 from global;` inside `.hero-title` in the `.module.css` |
881
1078
 
1079
+ **CSS Modules local composition:** If a class uses `composes: AnotherClass` (without `from global`), it inherits styles from that class within the same file. When fixing:
1080
+ - Add `composes: trdr-X from global` to the **base class** (AnotherClass)
1081
+ - Do NOT add `composes: trdr-X from global` to the **inheriting class** β€” it inherits the token transitively
1082
+ - Example: `.select { composes: input; }` β€” add `composes: trdr-text-input from global` only to `.input`, not to `.select`
1083
+ - Adding `composes: trdr-X from global` to both would apply DS styles twice, causing doubled specificity
1084
+
882
1085
  **font-size β†’ DS class table:**
883
1086
  | font-size | DS Class | Notes |
884
1087
  |-----------|----------|-------|
@@ -1214,6 +1417,35 @@ Vue:
1214
1417
  <!-- Keep :style only if the value is truly dynamic (changes at runtime based on data) -->
1215
1418
  ```
1216
1419
 
1420
+ **Conditional / ternary values in `style={{}}`** (common in React):
1421
+ When a style value is a ternary expression or computed value:
1422
+ ```jsx
1423
+ // Before β€” conditional style object
1424
+ style={{
1425
+ background: isActive ? '#4A4A4A' : 'transparent',
1426
+ color: isActive ? '#FFFFFF' : '#A4A4A4',
1427
+ }}
1428
+ // After β€” state classes
1429
+ className={isActive ? 'tab-active' : 'tab-inactive'}
1430
+ // + CSS:
1431
+ // .tab-active { background: var(--surface-primary); color: var(--content-primary); }
1432
+ // .tab-inactive { background: transparent; color: var(--content-tertiary); }
1433
+ ```
1434
+ Steps:
1435
+ 1. Identify the boolean condition controlling the state
1436
+ 2. Create two CSS classes (active/inactive) with semantic token values
1437
+ 3. Replace `style={{...}}` with `className={condition ? 'active-class' : 'inactive-class'}`
1438
+ 4. Keep all business logic intact β€” only change how styles are applied
1439
+ 5. Document in DS_PROGRESS.md: "Ternary style at [file:line] converted to state classes"
1440
+
1441
+ **Special: trading up/down ternary** β€” when the two values are `#4FE290`/`#F34F45` (or any trading up/down pair):
1442
+ ```css
1443
+ /* Use context.trading tokens, NOT content.success/error */
1444
+ .price-up { color: var(--context-trading-up); }
1445
+ .price-down { color: var(--context-trading-down); }
1446
+ /* WRONG: .price-up { color: var(--content-success); } β€” success is for non-trading contexts */
1447
+ ```
1448
+
1217
1449
  **Add new utility classes to the project's main CSS** (not to components.css or tokens.css β€” those are skill-managed):
1218
1450
  Group new classes in a clearly labelled block at the bottom of the project's CSS, e.g.:
1219
1451
  ```css