7k-design-system 1.1.0 → 1.2.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/CONSUMER_GUIDE.md +109 -50
  3. package/DESIGN.md +631 -439
  4. package/README.md +76 -75
  5. package/SKILL.md +107 -78
  6. package/build/icons/icon-7kgroup-light.svg +10 -0
  7. package/build/icons/icon-7kgroup.svg +10 -0
  8. package/build/icons/icon-7kminato-light.svg +10 -0
  9. package/build/icons/icon-7kminato.svg +10 -0
  10. package/build/icons/icon-base.svg +10 -0
  11. package/build/icons/icon-inari-light.svg +10 -0
  12. package/build/icons/icon-inari.svg +10 -0
  13. package/dist/7k-design-system.css +1 -1
  14. package/dist/animations.css +1 -1
  15. package/dist/build/icons/icon-7kgroup-light.svg +10 -0
  16. package/dist/build/icons/icon-7kgroup.svg +10 -0
  17. package/dist/build/icons/icon-7kminato-light.svg +10 -0
  18. package/dist/build/icons/icon-7kminato.svg +10 -0
  19. package/dist/build/icons/icon-base.svg +10 -0
  20. package/dist/build/icons/icon-inari-light.svg +10 -0
  21. package/dist/build/icons/icon-inari.svg +10 -0
  22. package/dist/components.css +1 -1
  23. package/dist/mockServiceWorker.js +361 -0
  24. package/dist/projects.css +1 -0
  25. package/dist/react/components/Alert.d.ts +2 -0
  26. package/dist/react/components/Avatar.d.ts +2 -0
  27. package/dist/react/{react/components → components}/Badge.d.ts +0 -1
  28. package/dist/react/{react/components → components}/Button.d.ts +0 -1
  29. package/dist/react/components/Card.d.ts +4 -0
  30. package/dist/react/components/Checkbox.d.ts +2 -0
  31. package/dist/react/components/Drawer.d.ts +2 -0
  32. package/dist/react/components/Icon.d.ts +2 -0
  33. package/dist/react/{react/components → components}/Input.d.ts +0 -1
  34. package/dist/react/components/IsometricBackground.d.ts +2 -0
  35. package/dist/react/components/Listbox.d.ts +2 -0
  36. package/dist/react/components/Modal.d.ts +4 -0
  37. package/dist/react/components/Nav.d.ts +3 -0
  38. package/dist/react/components/Progress.d.ts +2 -0
  39. package/dist/react/components/ProjectIcon.d.ts +6 -0
  40. package/dist/react/components/Radio.d.ts +2 -0
  41. package/dist/react/components/Select.d.ts +3 -0
  42. package/dist/react/components/Skeleton.d.ts +2 -0
  43. package/dist/react/components/Spinner.d.ts +2 -0
  44. package/dist/react/components/Tabs.d.ts +8 -0
  45. package/dist/react/components/TextureOverlay.d.ts +2 -0
  46. package/dist/react/components/Toast.d.ts +2 -0
  47. package/dist/react/components/Toggle.d.ts +2 -0
  48. package/dist/react/components/Tooltip.d.ts +2 -0
  49. package/dist/react/index.cjs +1 -1
  50. package/dist/react/index.d.ts +32 -0
  51. package/dist/react/index.js +1188 -128
  52. package/dist/react/mockServiceWorker.js +361 -0
  53. package/dist/react/theme/ProjectProvider.d.ts +14 -0
  54. package/dist/react/{react/theme → theme}/ThemeContext.d.ts +0 -1
  55. package/dist/react/{react/theme → theme}/ThemeProvider.d.ts +0 -1
  56. package/dist/react/theme/projects.d.ts +4 -0
  57. package/dist/react/theme/useProject.d.ts +2 -0
  58. package/dist/react/{react/theme → theme}/useTheme.d.ts +0 -1
  59. package/dist/react/types.d.ts +160 -0
  60. package/dist/textures.css +1 -1
  61. package/dist/tokens.css +1 -1
  62. package/package.json +49 -35
  63. package/dist/preview/brand-assets.html +0 -83
  64. package/dist/preview/colors-primary.html +0 -101
  65. package/dist/preview/components-buttons.html +0 -84
  66. package/dist/preview/spacing-tokens.html +0 -79
  67. package/dist/preview/textures-backgrounds.html +0 -102
  68. package/dist/preview/typography-specimens.html +0 -73
  69. package/dist/react/react/components/Badge.stories.d.ts +0 -12
  70. package/dist/react/react/components/Button.stories.d.ts +0 -16
  71. package/dist/react/react/components/Input.stories.d.ts +0 -11
  72. package/dist/react/react/components/ThemeToggle.stories.d.ts +0 -7
  73. package/dist/react/react/index.d.ts +0 -8
  74. package/dist/react/react/types.d.ts +0 -33
  75. package/dist/react/stories/Components.stories.d.ts +0 -10
  76. package/dist/react/stories/Textures.stories.d.ts +0 -11
  77. package/preview/brand-assets.html +0 -83
  78. package/preview/colors-primary.html +0 -101
  79. package/preview/components-buttons.html +0 -84
  80. package/preview/spacing-tokens.html +0 -79
  81. package/preview/textures-backgrounds.html +0 -102
  82. package/preview/typography-specimens.html +0 -73
  83. /package/build/{icon.svg → icons/icon.svg} +0 -0
  84. /package/build/{logo-7k-light.svg → logos/logo-7k-light.svg} +0 -0
  85. /package/build/{logo-7k.svg → logos/logo-7k.svg} +0 -0
  86. /package/dist/build/{icon.svg → icons/icon.svg} +0 -0
  87. /package/dist/build/{logo-7k-light.svg → logos/logo-7k-light.svg} +0 -0
  88. /package/dist/build/{logo-7k.svg → logos/logo-7k.svg} +0 -0
  89. /package/dist/react/{react/components → components}/ThemeToggle.d.ts +0 -0
package/DESIGN.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  > Version: 1.0.0-alpha.1 (production-ready)
4
4
  > Category: Custom · Surface: web, mobile, desktop
5
- > Font: Geist + Geist Mono + Geist Pixel · Brand color: #FF0FF · Logo: 7K · Theme: Dark-first
5
+ > Font: Geist + Geist Mono + Geist Pixel · Major neon: #FF0FF · Secondary neon: cyan (thematic per project) · Logo: 7K · Theme: Dark-first
6
6
  > 1-bit textures: 10 patterns · 1-bit components: 40+ · 1-bit animations: 20+ keyframes
7
- > React UI kit: Button, Input, Badge, ThemeToggle, ThemeProvider, useTheme
7
+ > React UI kit: Button, Input, Badge, Card, Modal, Drawer, Toast, Tooltip, Alert, Tabs, Nav, Checkbox, Radio, Toggle, Select, Textarea, ThemeToggle, ThemeProvider, ProjectProvider, useTheme, useProject
8
8
  > Build: Vite + PostCSS + TypeScript · Test: Vitest + Testing Library · Docs: Storybook
9
9
 
10
10
  ## Source context
@@ -14,16 +14,18 @@ Dark-first dual-theme design system for a tech holding. One parent brand (7K ·
14
14
  The brand brief specifies: "We only have 1 font and it's Geist. Our logo is just '7K' and our main brand color is #FF0FF. We are a tech company with different projects and we're open on an approach to differentiate brand wise the 'main company' with the other projects. We want to use inspiration from Tokyo's neon atmosphere and Manga-influenced 1-bit using black and white as well as abstract 1-bit animations. We're using a dark theme for websites."
15
15
 
16
16
  Key constraints derived from the source:
17
+
17
18
  - **Three-font system** → Geist (sans-serif) for body and headings, Geist Mono for labels, code, and tabular data, Geist Pixel (5 geometric variants: Square, Circle, Grid, Line, Triangle) for ornamental and pixel-constrained display use.
18
- - **Single brand color** → #FF0FF (vivid magenta) as the sole brand accent. No secondary brand color.
19
- - **Logo** → Star-burst pattern logo in `build/logo-7k.svg`: a geometric radial pattern with #FF0FF brand accent tones. Light variant at `build/logo-7k-light.svg` (black polygons for light backgrounds). App icon at `build/icon.svg`.
19
+ - **Major neon accent** → #FF0FF (vivid magenta) as the primary brand accent.
20
+ - **Secondary neon accent** → Cyan by default (`--brand-secondary`), dynamically themable per project via `data-project` or `ProjectProvider`.
21
+ - **Logo** → Star-burst pattern logo in `build/logos/logo-7k.svg`: a geometric radial pattern with #FF0FF brand accent tones. Light variant at `build/logos/logo-7k-light.svg` (black polygons for light backgrounds). App icon at `build/icons/icon.svg`.
20
22
  - **Dark theme** → All surfaces start from near-black. Light theme is opt-in only.
21
- - **Project differentiation** → Child projects get their own accent (solar, cyan, acid, ember) on the same dark base. Parent 7K retains magenta. Each Geist Pixel geometric variant pairs with one accent: Square=magenta, Circle=cyan, Grid=acid, Line=ember, Triangle=solar.
23
+ - **Project differentiation** → Each project gets its own secondary accent on the same dark base: **magenta = 7KGroup** (parent, also `--brand-primary`), **cyan = 7KMinato**, **inari (burnt orange) = Inari**. Projects theme `--brand-secondary` to their hue via `data-project` or `ProjectProvider`.
22
24
  - **Tokyo neon** → High contrast, nocturnal canvas, electric accents, no warm/beige tones.
23
25
  - **1-bit manga influence** → 10-texture background pattern library (scanline, halftone, dot matrix, stripes, crosshatch, checkerboard, noise, vignette). All textures are CSS gradients — no images, no SVG humans.
24
26
  - **Abstract 1-bit animations** → 20+ animation keyframes organized as ambient (continuous) and trigger (burst) categories. Step timing for retro feel, reduced-motion collapse.
25
27
  - **1-bit component system** → 40+ components with zero radius, 2px white borders, invert hover state. Unified black/white visual language with thin accent layer modifiers for color moments.
26
- - **React UI kit** → TypeScript React components (Button, Input, Badge, ThemeToggle) with ThemeProvider + useTheme hook for theme management.
28
+ - **React UI kit** → TypeScript React components (Button, Input, Badge, Card, Modal, Drawer, Toast, Tooltip, Alert, Tabs, Nav, Checkbox, Radio, Toggle, Select, Textarea, ThemeToggle) with ThemeProvider, ProjectProvider, useTheme, and useProject hooks.
27
29
  - **Modular CSS** → 10 source files in `src/css/` compiled into `dist/7k-design-system.css`.
28
30
 
29
31
  ## Package Structure
@@ -69,13 +71,6 @@ The design system is distributed as an npm package with dual entry points: CSS-o
69
71
  │ ├── ThemeProvider.test.tsx
70
72
  │ ├── ThemeToggle.test.tsx
71
73
  │ └── a11y.test.tsx
72
- ├── preview/ # 6 HTML review cards
73
- │ ├── colors-primary.html
74
- │ ├── typography-specimens.html
75
- │ ├── spacing-tokens.html
76
- │ ├── components-buttons.html
77
- │ ├── textures-backgrounds.html
78
- │ └── brand-assets.html
79
74
  ├── build/ # Brand assets
80
75
  │ ├── logo-7k.svg
81
76
  │ ├── logo-7k-light.svg
@@ -124,15 +119,17 @@ The design system is distributed as an npm package with dual entry points: CSS-o
124
119
  ```
125
120
 
126
121
  **CSS-only usage:**
122
+
127
123
  ```typescript
128
- import '7k-design-system/css'; // Full bundle
129
- import '7k-design-system/css/tokens'; // Tokens only
124
+ import '7k-design-system/css'; // Full bundle
125
+ import '7k-design-system/css/tokens'; // Tokens only
130
126
  import '7k-design-system/css/components'; // Components only
131
- import '7k-design-system/css/textures'; // Textures only
127
+ import '7k-design-system/css/textures'; // Textures only
132
128
  import '7k-design-system/css/animations'; // Animations only
133
129
  ```
134
130
 
135
131
  **React usage:**
132
+
136
133
  ```typescript
137
134
  import { Button, Input, Badge, ThemeToggle, ThemeProvider, useTheme } from '7k-design-system/react';
138
135
  import '7k-design-system/css';
@@ -142,7 +139,7 @@ import '7k-design-system/css';
142
139
 
143
140
  - **CSS build:** `vite build --config vite.css.config.ts` — compiles `src/css/index.css` into `dist/7k-design-system.css` with PostCSS pipeline (postcss-import, postcss-nesting, autoprefixer, cssnano)
144
141
  - **React build:** `vite build --config vite.react.config.ts` — compiles TypeScript React components into ESM + CJS bundles with `.d.ts` declarations via vite-plugin-dts
145
- - **Asset copy:** `node scripts/copy-assets.js` — copies preview/, fonts/, build/ to dist/
142
+ - **Asset copy:** `node scripts/copy-assets.js` — copies fonts/ and build/ to dist/
146
143
  - **Development:** `npm run dev` — Vite dev server; `npm run storybook` — Storybook at port 6006
147
144
  - **Testing:** `npm test` — Vitest + jsdom + @testing-library/react; `npm run test:a11y` — axe-core accessibility tests
148
145
  - **Linting:** `npm run lint` — ESLint (TS/TSX) + Stylelint (CSS); `npm run typecheck` — `tsc --noEmit`
@@ -153,11 +150,12 @@ import '7k-design-system/css';
153
150
 
154
151
  Tokyo neon meets manga-influenced 1-bit. The canvas is deep near-black, with sharp white text, electric magenta (`#FF0FF`) as the primary brand accent, and cyan as a secondary project accent. Black-and-white 1-bit textures — scanline overlays, halftone dot noise, glitch keyframes — provide rhythm and atmosphere. The mood is nocturnal, high-contrast, and unapologetically digital.
155
152
 
156
- Company/project differentiation: the parent 7K brand uses vivid magenta (`--brand-primary`). Child projects adopt their own accent (solar, cyan, acid, ember) on the same dark base. Same system, distinct at a glance.
153
+ Company/project differentiation: 7KGroup (parent) uses vivid magenta (`--brand-primary` baseline). Inside a project scope the project accent becomes dominant, overriding the full `--brand-primary` chain: 7KMinato runs cyan, Inari runs burnt orange (Fushimi Inari palette). Same system, distinct at a glance.
157
154
 
158
- **Logo:** Star-burst pattern logo in `build/logo-7k.svg` — a geometric radial pattern with #FF0FF brand accent tones. Light variant at `build/logo-7k-light.svg` (light backgrounds). App icon at `build/icon.svg`.
155
+ **Logo:** Star-burst pattern logo in `build/logos/logo-7k.svg` — a geometric radial pattern with #FF0FF brand accent tones. Light variant at `build/logos/logo-7k-light.svg` (light backgrounds). App icon at `build/icons/icon.svg`.
159
156
 
160
157
  **1-bit texture primitives (background patterns):**
158
+
161
159
  - **Scanline**: `repeating-linear-gradient(0deg, transparent 2px, rgba(255,255,255,0.03) 2px)` — horizontal scan lines, scroll-animated. Two speeds: slow (8s) and fast (3s).
162
160
  - **Halftone dots**: `radial-gradient(color 1px, transparent 1px)` at 4px/6px/10px spacing — manga screentone at three densities (sm/md/lg). Accent-tinted variant uses magenta dots.
163
161
  - **Dot matrix**: Uniform dot grid at 3px (dense), 6px (standard), or 12px (sparse) spacing for texture depth.
@@ -169,6 +167,7 @@ Company/project differentiation: the parent 7K brand uses vivid magenta (`--bran
169
167
  - **Vignette**: Radial gradient from transparent center to black edge. Sharp variant clips tighter for manga panel corner fade.
170
168
 
171
169
  **Glitch primitives:**
170
+
172
171
  - Basic glitch: 5-frame translate jitter, 0.3s, 3 iterations
173
172
  - Complex glitch: multi-axis + skew + clip-path splits, 0.8s, 2 iterations
174
173
  - Invert flash: full-screen filter inversion, 0.15s burst
@@ -179,25 +178,25 @@ Company/project differentiation: the parent 7K brand uses vivid magenta (`--bran
179
178
 
180
179
  ### Texture categories
181
180
 
182
- | Category | Classes | Density variants | Use case |
183
- |----------|---------|------------------|----------|
184
- | Scanline | `.scanline`, `.scanline-fast` | slow (8s), fast (3s) | Hero sections, full-bleed walls |
185
- | Halftone dots | `.halftone-sm`, `.halftone-md`, `.halftone-lg`, `.halftone-accent` | 4px/6px/10px grid, accent-tinted | Manga panel backgrounds, card surfaces |
186
- | Dot matrix | `.dot-matrix-dense`, `.dot-matrix`, `.dot-matrix-sparse` | 3px/6px/12px grid | Texture depth behind text, dividers |
187
- | Diagonal stripes | `.diagonal-stripes`, `.diagonal-stripes-dense`, `.diagonal-stripes-negative` | 7px/4px pitch, pure B/W | Directional cues, loading areas |
188
- | Horizontal stripes | `.stripes-h`, `.stripes-h-dense` | 9px/5px pitch | Section rhythm, horizontal dividers |
189
- | Vertical stripes | `.stripes-v`, `.stripes-v-dense` | 9px/5px pitch | Sidebar textures, column dividers |
190
- | Crosshatch | `.crosshatch`, `.crosshatch-dense` | 7px/4px dual-angle | Dense manga shading, error states |
191
- | Checkerboard | `.checkerboard`, `.checkerboard-onebit` | 12px/16px grid, pure B/W | Retro sections, QR motifs |
192
- | Noise | `.noise`, `.noise-heavy`, `.noise-animated` | 4%/12% opacity, SVG fractal | CRT grain, analog texture |
193
- | Vignette | `.vignette-onebit`, `.vignette-onebit-sharp` | Soft/sharp radial fade | Panel corner fade, hero-edge vignette |
181
+ | Category | Classes | Density variants | Use case |
182
+ | ------------------ | ---------------------------------------------------------------------------- | -------------------------------- | -------------------------------------- |
183
+ | Scanline | `.scanline`, `.scanline-fast` | slow (8s), fast (3s) | Hero sections, full-bleed walls |
184
+ | Halftone dots | `.halftone-sm`, `.halftone-md`, `.halftone-lg`, `.halftone-accent` | 4px/6px/10px grid, accent-tinted | Manga panel backgrounds, card surfaces |
185
+ | Dot matrix | `.dot-matrix-dense`, `.dot-matrix`, `.dot-matrix-sparse` | 3px/6px/12px grid | Texture depth behind text, dividers |
186
+ | Diagonal stripes | `.diagonal-stripes`, `.diagonal-stripes-dense`, `.diagonal-stripes-negative` | 7px/4px pitch, pure B/W | Directional cues, loading areas |
187
+ | Horizontal stripes | `.stripes-h`, `.stripes-h-dense` | 9px/5px pitch | Section rhythm, horizontal dividers |
188
+ | Vertical stripes | `.stripes-v`, `.stripes-v-dense` | 9px/5px pitch | Sidebar textures, column dividers |
189
+ | Crosshatch | `.crosshatch`, `.crosshatch-dense` | 7px/4px dual-angle | Dense manga shading, error states |
190
+ | Checkerboard | `.checkerboard`, `.checkerboard-contrast` | 12px/16px grid, pure B/W | Retro sections, QR motifs |
191
+ | Noise | `.noise`, `.noise-heavy`, `.noise-animated` | 4%/12% opacity, SVG fractal | CRT grain, analog texture |
192
+ | Vignette | `.vignette-ink`, `.vignette-ink-sharp` | Soft/sharp radial fade | Panel corner fade, hero-edge vignette |
194
193
 
195
194
  ### Texture composition rules
196
195
 
197
196
  1. **One texture per section layer.** Apply at most one texture on the background layer and one on the overlay layer (`::after`). Scanline + halftone is the default pair for hero sections.
198
197
  2. **Opacity scales with section density.** Hero/landing sections use lighter textures (5–10% opacity). Data-dense utility sections use stronger textures (10–15% opacity) or none.
199
- 3. **No texture on interactive surfaces.** Cards, buttons, inputs, and form controls must not carry background textures that interfere with legibility. Use solid `--bg-elevated` instead.
200
- 4. **Texture as section separator.** When transitioning between full-bleed sections, add a `.separator-onebit` or `.stripes-h` band (40–80px tall) as a visual break — never use shadow or blur transitions.
198
+ 3. **Texture on components is allowed with restraint.** Cards, panels, modals, drawers, and buttons can carry low-opacity texture overlays (`::before`, `pointer-events: none`) as long as the texture sits behind content and does not reduce contrast. Inputs and form controls should remain solid to preserve legibility. Use `.card-halftone`, `.surface-scanline`, `.btn-halftone`, `.modal-noise`, etc.
199
+ 4. **Texture as section separator.** When transitioning between full-bleed sections, add a `.separator-solid` or `.stripes-h` band (40–80px tall) as a visual break — never use shadow or blur transitions.
201
200
  5. **Layering order:** Base color → texture background → content container → optional scanline overlay. The overlay must have `pointer-events: none` and `z-index: 1` so it does not block interaction.
202
201
  6. **Full-bleed hero walls** use scanline + vignette simultaneously: scanline on `::after` for the line pattern, vignette on `::before` for the edge fade. Both get `pointer-events: none`.
203
202
 
@@ -205,21 +204,21 @@ Company/project differentiation: the parent 7K brand uses vivid magenta (`--bran
205
204
 
206
205
  ```
207
206
  Section 1 (hero) — Scanline overlay + noise grain, full-bleed
208
- ↓ separator-onebit
207
+ ↓ separator-solid
209
208
  Section 2 (content) — Solid surface, no texture (reading zone)
210
- ↓ separator-onebit
209
+ ↓ separator-solid
211
210
  Section 3 (stats) — Halftone-md background with accent tint
212
- ↓ separator-onebit
211
+ ↓ separator-solid
213
212
  Section 4 (cta) — Scanline-fast overlay, invert section if 1-bit
214
213
  ```
215
214
 
216
215
  ### 1-bit section variants
217
216
 
218
- - **Full invert section**: swap `--bg-base` with `--onebit-white`, `--text-primary` with `--onebit-black`. Used for CTAs, callout panels, or manga-style splash panels. Add `.diagonal-stripes-negative` for max contrast.
217
+ - **Full invert section**: swap `--bg-base` with `--color-paper`, `--text-primary` with `--color-ink`. Used for CTAs, callout panels, or manga-style splash panels. Add `.diagonal-stripes-negative` for max contrast.
219
218
  - **Scanline hero**: dark canvas, scanline overlay, accent headline with glow. The scanline `::after` sits above the background but below all content (`z-index: 1`). Content gets `position: relative; z-index: 2`.
220
219
  - **Halftone card wall**: grid of cards with `.halftone-sm` or `.halftone-md` on the section container. Each card has solid `.card` background that breaks the texture — texture only lives between cards.
221
220
  - **Noise backdrop**: `.noise` on full-page backgrounds for analog feel. Use `.noise-heavy` only on splash/loading screens where content density is low.
222
- - **Vignette frame**: `.vignette-onebit` on slide/scene containers to draw the eye center. Used in intro animations and splash panels.
221
+ - **Vignette frame**: `.vignette-ink` on slide/scene containers to draw the eye center. Used in intro animations and splash panels.
223
222
 
224
223
  ## 1c. Isometric Backgrounds — CSS-only 3D Perspective Patterns
225
224
 
@@ -227,192 +226,187 @@ Section 4 (cta) — Scanline-fast overlay, invert section if 1-bit
227
226
 
228
227
  ### Isometric pattern library
229
228
 
230
- | Class | Description | Technique |
231
- |-------|-------------|-----------|
232
- | `.isometric-grid` | Diamond tiling from dual 30°/-30° hatch lines at 24px pitch | `repeating-linear-gradient(30deg)` + `(-30deg)` |
233
- | `.isometric-grid-dense` | Tighter 12px diamond grid | Same technique, denser pitch |
234
- | `.isometric-grid-accent` | Magenta-tinted 24px diamond grid | Same, with `--magenta-500 / 0.12` stroke |
235
- | `.isometric-cubes` | 3-face cube wall: right (150°), top (-30°), left (30°) faces at 40px | 3 `repeating-linear-gradient` layers with face-specific opacity |
236
- | `.isometric-cubes-dense` | 20px cube wall | Same, finer resolution |
237
- | `.isometric-cubes-accent` | Magenta-tinted cube wall | Same, with accent hue fills |
238
- | `.isometric-pyramid` | Ascending zigzag steps: 150° + -30° gradients | Dual gradient with offset phase |
239
- | `.isometric-hex` | Honeycomb hex grid from 60°/-60°/0° overlapping | 3 `repeating-linear-gradient` layers |
240
- | `.isometric-pipes` | Converging tunnel perspective: left/right walls (30°/-30°) + floor (0°) | 3-gradient tunnel simulation |
241
- | `.isometric-pipes-fast` | Denser tunnel, 8px walls | Same, tighter spacing |
242
- | `.isometric-terrain` | Multi-layer depth: horizontal + 30° + -30° zigzag | 3-layer parallax-ready composition |
229
+ | Class | Description | Technique |
230
+ | ------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------- |
231
+ | `.isometric-grid` | Diamond tiling from dual 30°/-30° hatch lines at 24px pitch | `repeating-linear-gradient(30deg)` + `(-30deg)` |
232
+ | `.isometric-grid-dense` | Tighter 12px diamond grid | Same technique, denser pitch |
233
+ | `.isometric-grid-accent` | Magenta-tinted 24px diamond grid | Same, with `--magenta-500 / 0.12` stroke |
234
+ | `.isometric-cubes` | 3-face cube wall: right (150°), top (-30°), left (30°) faces at 40px | 3 `repeating-linear-gradient` layers with face-specific opacity |
235
+ | `.isometric-cubes-dense` | 20px cube wall | Same, finer resolution |
236
+ | `.isometric-cubes-accent` | Magenta-tinted cube wall | Same, with accent hue fills |
237
+ | `.isometric-pyramid` | Ascending zigzag steps: 150° + -30° gradients | Dual gradient with offset phase |
238
+ | `.isometric-hex` | Honeycomb hex grid from 60°/-60°/0° overlapping | 3 `repeating-linear-gradient` layers |
239
+ | `.isometric-pipes` | Converging tunnel perspective: left/right walls (30°/-30°) + floor (0°) | 3-gradient tunnel simulation |
240
+ | `.isometric-pipes-fast` | Denser tunnel, 8px walls | Same, tighter spacing |
241
+ | `.isometric-terrain` | Multi-layer depth: horizontal + 30° + -30° zigzag | 3-layer parallax-ready composition |
243
242
 
244
243
  ### Composition rules
245
244
 
246
245
  1. **One isometric pattern per section.** Apply at most one isometric gradient per container. Stack with scanline overlay via class stacking.
247
- 2. **No texture on interactive surfaces.** Cards, buttons, inputs, and form controls must not carry isometric backgrounds — use solid `--bg-elevated` instead.
246
+ 2. **No isometric background on interactive surfaces.** Cards, buttons, inputs, and form controls must not carry isometric backgrounds — use solid `--bg-elevated` instead. Isometric patterns are for section backgrounds only.
248
247
  3. **Animate with animation classes.** Combine with `.iso-grid-scroll` for diagonal grid movement, `.iso-terrain-shift` for parallax depth layers.
249
248
  4. **Reduced motion:** All isometric animations collapse at `prefers-reduced-motion: reduce`.
250
249
 
251
250
  ## 2. Color
252
251
 
253
- **Source context reference:** The brand hex #FF0FF is the single brand color. All color tokens use hex values mapped through CSS custom properties.
252
+ **Source context reference:** The brand hex #FF0FF is the major neon accent. A secondary neon accent (cyan by default) is used for complementary actions and can be themed per project. All color tokens use hex values mapped through CSS custom properties.
254
253
 
255
254
  The color system has three strict layers:
256
255
 
257
- 1. **Raw ramps** — 11-step scales (50–950) for Neutral, Magenta, Solar, Cyan, Acid, Ember, plus extended below-ramp values (1000, void) and 4 semantic ramps (Success, Warning, Danger, Info). Never reference these directly in components.
256
+ 1. **Raw ramps** — 11-step scales (50–950) for Neutral, Magenta (7KGroup), Cyan (7KMinato), Inari (Inari), plus extended below-ramp values (1000, void) and 4 semantic ramps (Success, Warning, Danger, Info). Never reference these directly in components.
258
257
  2. **Theme role mapping** — `--bg-*`, `--text-*`, `--border-*`, `--brand-*`, `--status-*`, `--accent-*` tokens that map ramp values to functional roles. Remap per dark/light theme. This is the only layer components touch.
259
258
  3. **Semantic colors** — `--status-success/warning/danger/info` tokens bound by **meaning, not decoration**. Use only for actual machine-state indication (badges, toasts, validation). Never use for decorative borders, accent accents, or non-status backgrounds.
260
259
 
261
- > See `preview/colors-theme-dark.html` for the default theme or `preview/colors-theme-light.html` for the opt-in light theme.
260
+ > See Storybook for live color swatches of the default dark theme and the opt-in light theme.
262
261
 
263
262
  ---
263
+
264
264
  ### Layer 1 — Raw Color Ramps
265
265
 
266
266
  All ramps follow the same 11-step pattern (50 = lightest, 950 = darkest). Two extra steps exist below the ramp for true backgrounds.
267
267
 
268
268
  #### Neutral ramp (slight cool cast, hue ~330)
269
269
 
270
- | Token | Hex | Dark role | Light role |
271
- |-------|-----|-----------|------------|
272
- | `--neutral-50` | `#FAFAFB` | — | `--bg-base`, `--bg-void` |
273
- | `--neutral-100` | `#EEEEF1` | — | `--bg-elevated` |
274
- | `--neutral-200` | `#D7D7DC` | — | `--bg-raised`, `--status-neutral-bg` |
275
- | `--neutral-300` | `#B0B0B8` | `--text-secondary` | `--bg-overlay`, `--text-disabled`, `--status-neutral-fg` |
276
- | `--neutral-400` | `#82828A` | `--status-neutral` | `--bg-pressed`, `--text-tertiary`, `--text-placeholder` |
277
- | `--neutral-500` | `#6B6B72` | `--text-tertiary`, `--text-placeholder` | `--text-secondary` |
278
- | `--neutral-600` | `#50505A` | `--text-disabled` | — |
279
- | `--neutral-700` | `#3A3A42` | `--bg-pressed` | — |
280
- | `--neutral-800` | `#26262B` | `--bg-overlay`, `--status-neutral-bg` | — |
281
- | `--neutral-900` | `#1C1C22` | `--bg-raised` | `--text-primary` |
282
- | `--neutral-950` | `#131318` | `--bg-elevated` | — |
283
- | `--neutral-1000` | `#0A0A0D` | `--bg-base` | — |
284
- | `--neutral-void` | `#000000` | `--bg-void`, `--text-on-brand`, `--text-inverse` | — |
285
-
286
- **Usage rule:** Components reference the *role* tokens (e.g. `var(--bg-elevated)`), never the raw ramp tokens (e.g. `var(--neutral-950)`). The ramp table above documents what each step maps to — not what you should write.
270
+ | Token | Hex | Dark role | Light role |
271
+ | ---------------- | --------- | ------------------------------------------------ | -------------------------------------------------------- |
272
+ | `--neutral-50` | `#FAFAFB` | — | `--bg-base`, `--bg-void` |
273
+ | `--neutral-100` | `#EEEEF1` | — | `--bg-elevated` |
274
+ | `--neutral-200` | `#D7D7DC` | — | `--bg-raised`, `--status-neutral-bg` |
275
+ | `--neutral-300` | `#B0B0B8` | `--text-secondary` | `--bg-overlay`, `--text-disabled`, `--status-neutral-fg` |
276
+ | `--neutral-400` | `#82828A` | `--text-tertiary`, `--status-neutral` | `--bg-pressed`, `--text-placeholder` |
277
+ | `--neutral-500` | `#6B6B72` | `--text-placeholder` | `--text-secondary` |
278
+ | `--neutral-600` | `#50505A` | `--text-disabled` | — |
279
+ | `--neutral-700` | `#3A3A42` | `--bg-pressed` | — |
280
+ | `--neutral-800` | `#26262B` | `--bg-overlay`, `--status-neutral-bg` | — |
281
+ | `--neutral-900` | `#1C1C22` | `--bg-raised` | `--text-primary` |
282
+ | `--neutral-950` | `#131318` | `--bg-elevated` | — |
283
+ | `--neutral-1000` | `#0A0A0D` | `--bg-base` | — |
284
+ | `--neutral-void` | `#000000` | `--bg-void`, `--text-on-brand`, `--text-inverse` | — |
285
+
286
+ **Usage rule:** Components reference the _role_ tokens (e.g. `var(--bg-elevated)`), never the raw ramp tokens (e.g. `var(--neutral-950)`). The ramp table above documents what each step maps to — not what you should write.
287
287
 
288
288
  #### Brand ramp — Magenta (hue ~330)
289
289
 
290
- | Token | Hex | Dark role | Light role |
291
- |-------|-----|-----------|------------|
292
- | `--magenta-50` | `#FFE5FF` | `--brand-primary-subtle` (dark) | — |
293
- | `--magenta-100` | `#FFC2FF` | — | `--brand-primary-subtle` (light) |
294
- | `--magenta-200` | `#FF99FF` | — | `--brand-primary-muted` (light) |
295
- | `--magenta-300` | `#FF66FF` | — | — |
296
- | `--magenta-400` | `#FF33FF` | `--brand-primary-hover` (dark) | — |
297
- | `--magenta-500` | `#FF00FF` | `--brand-primary` · `--border-focus` · `--border-brand` · `--accent-square` | same across themes |
298
- | `--magenta-600` | `#D600D6` | `--brand-primary-active` (dark) | `--brand-primary-hover` (light) |
299
- | `--magenta-700` | `#A800A8` | — | `--brand-primary-active` (light) |
300
- | `--magenta-800` | `#800080` | `--brand-primary-muted` (dark) | — |
301
- | `--magenta-900` | `#570057` | — | — |
302
- | `--magenta-950` | `#330033` | `--brand-primary-subtle` (dark) | — |
303
-
304
- #### Project accent ramps — Solar / Cyan / Acid / Ember
290
+ | Token | Hex | Dark role | Light role |
291
+ | --------------- | --------- | --------------------------------------------------------------------------- | -------------------------------- |
292
+ | `--magenta-50` | `#FFE5FF` | `--brand-primary-subtle` (dark) | — |
293
+ | `--magenta-100` | `#FFC2FF` | — | `--brand-primary-subtle` (light) |
294
+ | `--magenta-200` | `#FF99FF` | — | `--brand-primary-muted` (light) |
295
+ | `--magenta-300` | `#FF66FF` | — | — |
296
+ | `--magenta-400` | `#FF33FF` | `--brand-primary-hover` (dark) | — |
297
+ | `--magenta-500` | `#FF00FF` | `--brand-primary` · `--border-focus` · `--border-brand` · `--accent-square` | same across themes |
298
+ | `--magenta-600` | `#D600D6` | `--brand-primary-active` (dark) | `--brand-primary-hover` (light) |
299
+ | `--magenta-700` | `#A800A8` | — | `--brand-primary-active` (light) |
300
+ | `--magenta-800` | `#800080` | `--brand-primary-muted` (dark) | — |
301
+ | `--magenta-900` | `#570057` | — | — |
302
+ | `--magenta-950` | `#330033` | `--brand-primary-subtle` (dark) | — |
305
303
 
306
- Each child project gets a single accent hue. Same 11-step structure; only the base (--500) and the theme-mapped hover (--600 in light) differ.
304
+ #### Project accent ramps — 7KMinato (Cyan) / Inari
307
305
 
308
- **Solar — Triangle (hue ~50)**
306
+ Each project gets a single accent hue. Same 11-step structure; only the base (--500) and the theme-mapped hover (--600 in light) differ. (7KGroup's accent is the magenta primary ramp above.)
309
307
 
310
- `--solar-50: #FFFCE5` → `--solar-500: #FFD60A` → `--solar-950: #332B02`.
311
- Accent token: `--accent-triangle`. Dark: `var(--solar-500)`, Light: `var(--solar-600)`.
312
-
313
- **Cyan — Circle (hue ~190)**
308
+ **Cyan — 7KMinato (hue ~190)**
314
309
 
315
310
  `--cyan-50: #E5FBFF` → `--cyan-500: #00E5FF` → `--cyan-950: #002A2E`.
316
- Accent token: `--accent-circle`. Dark: `var(--cyan-500)`, Light: `var(--cyan-600)`.
317
-
318
- **Acid — Grid (hue ~105)**
311
+ Accent token: `--accent-7kminato`. Dark: `var(--cyan-500)`, Light: `var(--cyan-600)`.
319
312
 
320
- `--acid-50: #F2FFE5` → `--acid-500: #7CFF00` → `--acid-950: #172E00`.
321
- Accent token: `--accent-grid`. Dark: `var(--acid-500)`, Light: `var(--acid-600)`.
313
+ **Inari — Inari project (hue ~18, Fushimi Inari palette)**
322
314
 
323
- **Ember — Line (hue ~15)**
324
-
325
- `--ember-50: #FFEEE5` → `--ember-500: #FF6B35` → `--ember-950: #331205`.
326
- Accent token: `--accent-line`. Dark: `var(--ember-500)`, Light: `var(--ember-600)`.
315
+ `--inari-50: #FDEEE7` → `--inari-500: #EE560D` (Orangealicious) → `--inari-950: #2B1C17` (Tetsu-Guro Black).
316
+ Named stops: `--inari-400` Knockout Orange `#E56F3F`, `--inari-600` Red Panda `#C44813`, `--inari-800` Rogan Josh `#8B310D`.
317
+ Accent token: `--accent-inari`. Dark: `var(--inari-500)`, Light: `var(--inari-600)`.
327
318
 
328
319
  #### Semantic ramps (raw)
329
320
 
330
321
  Each has a full 11-step scale (50–950). Never use directly — always go through `--status-{name}`, `--status-{name}-bg`, or `--status-{name}-fg`.
331
322
 
332
- | Ramp | 50 | 100 | 300 | 500 (base) | 700 | 950 |
333
- |------|----|-----|-----|------------|-----|-----|
334
- | Success | `#E5FCEF` | `#B8F5D2` | `#5CE69A` | `#00E676` | `#008A46` | `#002915` |
335
- | Warning | `#FFF8E5` | `#FFEAB8` | `#FFCE5C` | `#FFB300` | `#A87600` | `#332400` |
336
- | Danger | `#FFE5EB` | `#FFB8C5` | `#FF5C7A` | `#FF3B5C` | `#A82338` | `#330A10` |
337
- | Info | `#E5EFFF` | `#B8D2FF` | `#5C99FF` | `#3F8EFF` | `#1F58A8` | `#091A33` |
323
+ | Ramp | 50 | 100 | 300 | 500 (base) | 700 | 950 |
324
+ | ------- | --------- | --------- | --------- | ---------- | --------- | --------- |
325
+ | Success | `#E5FCEF` | `#B8F5D2` | `#5CE69A` | `#00E676` | `#008A46` | `#002915` |
326
+ | Warning | `#FFF8E5` | `#FFEAB8` | `#FFCE5C` | `#FFB300` | `#A87600` | `#332400` |
327
+ | Danger | `#FFE5EB` | `#FFB8C5` | `#FF5C7A` | `#FF3B5C` | `#A82338` | `#330A10` |
328
+ | Info | `#E5EFFF` | `#B8D2FF` | `#5C99FF` | `#3F8EFF` | `#1F58A8` | `#091A33` |
338
329
 
339
330
  #### 1-bit primitives
340
331
 
341
- - `--onebit-black: #000000` (`oklch(0% 0 0)`)
342
- - `--onebit-white: #FFFFFF` (`oklch(100% 0 0)`)
332
+ - `--color-ink: #000000` (`oklch(0% 0 0)`)
333
+ - `--color-paper: #FFFFFF` (`oklch(100% 0 0)`)
343
334
 
344
335
  ---
336
+
345
337
  ### Layer 2 — Theme Role Mapping
346
338
 
347
339
  **Dark is the default.** Light is opt-in via `@media (prefers-color-scheme: light)` or `html[data-theme="light"` (set by `ThemeToggle` component in `src/react/components/ThemeToggle.tsx`). The same ramp primitives are used by both themes — only the role-to-ramp mapping changes.
348
340
 
349
341
  #### Surface ladder — backgrounds
350
342
 
351
- | Token | Dark value | Light value | Usage rule |
352
- |-------|-----------|-------------|------------|
353
- | `--bg-void` | `--neutral-void` | `--neutral-50` | Page background only. Outermost canvas. |
354
- | `--bg-base` | `--neutral-1000` | `--neutral-50` | Default surface. Most common container. |
355
- | `--bg-elevated` | `--neutral-950` | `--neutral-100` | Cards, panels, section backgrounds. |
356
- | `--bg-raised` | `--neutral-900` | `--neutral-200` | Modals, dropdowns, popovers, inputs. |
357
- | `--bg-overlay` | `--neutral-800` | `--neutral-300` | Hover surfaces, tooltip backgrounds. |
358
- | `--bg-pressed` | `--neutral-700` | `--neutral-400` | Active/pressed state. |
359
- | `--bg-translucent` | `rgba(255,255,255,0.04)` | `rgba(0,0,0,0.04)` | Subtle backdrop overlay. |
343
+ | Token | Dark value | Light value | Usage rule |
344
+ | ------------------ | ------------------------ | ------------------ | --------------------------------------- |
345
+ | `--bg-void` | `--neutral-void` | `--neutral-50` | Page background only. Outermost canvas. |
346
+ | `--bg-base` | `--neutral-1000` | `--neutral-50` | Default surface. Most common container. |
347
+ | `--bg-elevated` | `--neutral-950` | `--neutral-100` | Cards, panels, section backgrounds. |
348
+ | `--bg-raised` | `--neutral-900` | `--neutral-200` | Modals, dropdowns, popovers, inputs. |
349
+ | `--bg-overlay` | `--neutral-800` | `--neutral-300` | Hover surfaces, tooltip backgrounds. |
350
+ | `--bg-pressed` | `--neutral-700` | `--neutral-400` | Active/pressed state. |
351
+ | `--bg-translucent` | `rgba(255,255,255,0.04)` | `rgba(0,0,0,0.04)` | Subtle backdrop overlay. |
360
352
 
361
353
  **Ladder rule:** Step one level for each layer of depth. Never skip from `--bg-void` to `--bg-raised`.
362
354
  `void → base → elevated → raised → overlay → pressed`
363
355
 
364
356
  #### Text ladder
365
357
 
366
- | Token | Dark value | Light value | Usage rule |
367
- |-------|-----------|-------------|------------|
368
- | `--text-primary` | `--neutral-50` | `--neutral-900` | Headlines, body paragraphs, labels. |
369
- | `--text-secondary` | `--neutral-300` | `--neutral-500` | Lede, card body, subtle headings. |
370
- | `--text-tertiary` | `--neutral-500` | `--neutral-400` | Captions, mono labels, metadata. |
371
- | `--text-placeholder` | `--neutral-500` | `--neutral-400` | Form field hints and placeholders. |
372
- | `--text-disabled` | `--neutral-600` | `--neutral-300` | Truly inactive elements. |
373
- | `--text-inverse` | `--neutral-void` | `--neutral-50` | Text on inverted/dark surfaces. |
358
+ | Token | Dark value | Light value | Usage rule |
359
+ | -------------------- | ---------------- | --------------- | ----------------------------------- |
360
+ | `--text-primary` | `--neutral-50` | `--neutral-900` | Headlines, body paragraphs, labels. |
361
+ | `--text-secondary` | `--neutral-300` | `--neutral-500` | Lede, card body, subtle headings. |
362
+ | `--text-tertiary` | `--neutral-500` | `--neutral-400` | Captions, mono labels, metadata. |
363
+ | `--text-placeholder` | `--neutral-500` | `--neutral-400` | Form field hints and placeholders. |
364
+ | `--text-disabled` | `--neutral-600` | `--neutral-300` | Truly inactive elements. |
365
+ | `--text-inverse` | `--neutral-void` | `--neutral-50` | Text on inverted/dark surfaces. |
374
366
 
375
367
  #### Border ladder
376
368
 
377
- | Token | Dark value | Light value | Usage rule |
378
- |-------|-----------|-------------|------------|
379
- | `--border-subtle` | `rgba(255,255,255,0.06)` | `rgba(0,0,0,0.06)` | Internal dividers, hr rules. |
369
+ | Token | Dark value | Light value | Usage rule |
370
+ | ------------------ | ------------------------ | ------------------ | --------------------------------- |
371
+ | `--border-subtle` | `rgba(255,255,255,0.06)` | `rgba(0,0,0,0.06)` | Internal dividers, hr rules. |
380
372
  | `--border-default` | `rgba(255,255,255,0.10)` | `rgba(0,0,0,0.10)` | Cards, inputs, container strokes. |
381
- | `--border-strong` | `rgba(255,255,255,0.18)` | `rgba(0,0,0,0.18)` | Hover emphasis, focus rings. |
382
- | `--border-focus` | `--magenta-500` | `--magenta-500` | Form focus rings (brand). |
383
- | `--border-brand` | `--magenta-500` | `--magenta-500` | Decorative brand border. |
373
+ | `--border-strong` | `rgba(255,255,255,0.18)` | `rgba(0,0,0,0.18)` | Hover emphasis, focus rings. |
374
+ | `--border-focus` | `--magenta-500` | `--magenta-500` | Form focus rings (brand). |
375
+ | `--border-brand` | `--magenta-500` | `--magenta-500` | Decorative brand border. |
384
376
 
385
377
  **Ladder rule:** `subtle → default → strong → focus/brand`. Use `--border-subtle` for separators, `--border-default` for card outlines.
386
378
 
387
379
  #### Brand tokens
388
380
 
389
- | Token | Dark value | Light value | Usage rule |
390
- |-------|-----------|-------------|------------|
391
- | `--brand-primary` | `--magenta-500` | `--magenta-500` | CTAs, focus rings, active nav, brand text. |
392
- | `--brand-primary-hover` | `--magenta-400` | `--magenta-600` | Accent hover state. |
393
- | `--brand-primary-active` | `--magenta-600` | `--magenta-700` | Accent pressed state. |
394
- | `--brand-primary-muted` | `--magenta-800` | `--magenta-200` | Muted brand backgrounds. |
395
- | `--brand-primary-subtle` | `--magenta-950` | `--magenta-100` | Subtle brand surfaces. |
396
- | `--brand-primary-glow` | `color-mix(in srgb, var(--magenta-500) 25%, transparent)` | `color-mix(in srgb, var(--magenta-500) 15%, transparent)` | Glow shadow source. |
397
- | `--text-on-brand` | `--neutral-void` | `--neutral-void` | Text on brand-colored fills. |
381
+ | Token | Dark value | Light value | Usage rule |
382
+ | ------------------------- | --------------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------ |
383
+ | `--brand-primary` | `--magenta-500` | `--magenta-500` | CTAs, focus rings, active nav, brand text. |
384
+ | `--brand-primary-hover` | `--magenta-400` | `--magenta-600` | Accent hover state. |
385
+ | `--brand-primary-active` | `--magenta-600` | `--magenta-700` | Accent pressed state. |
386
+ | `--brand-primary-muted` | `--magenta-800` | `--magenta-200` | Muted brand backgrounds. |
387
+ | `--brand-primary-subtle` | `--magenta-950` | `--magenta-100` | Subtle brand surfaces. |
388
+ | `--brand-primary-glow` | `color-mix(in srgb, var(--magenta-500) 25%, transparent)` | `color-mix(in srgb, var(--magenta-500) 15%, transparent)` | Glow shadow source. |
389
+ | `--brand-secondary` | `--cyan-500` (thematic per project) | `--cyan-600` (thematic per project) | Secondary CTAs, project accents. |
390
+ | `--brand-secondary-hover` | `--cyan-400` | `--cyan-500` | Secondary hover state. |
391
+ | `--text-on-brand` | `--neutral-void` | `--neutral-void` | Text on brand-colored fills. |
398
392
 
399
393
  #### Status tokens
400
394
 
401
- | Token | Dark value | Light value | Usage rule |
402
- |-------|-----------|-------------|------------|
403
- | `--status-success` | `--success-500` | `--success-500` | Positive outcome / online. |
395
+ | Token | Dark value | Light value | Usage rule |
396
+ | --------------------- | --------------- | --------------- | ------------------------------ |
397
+ | `--status-success` | `--success-500` | `--success-500` | Positive outcome / online. |
404
398
  | `--status-success-bg` | `--success-950` | `--success-100` | Background for success badges. |
405
399
  | `--status-success-fg` | `--success-300` | `--success-700` | Foreground for success badges. |
406
- | `--status-warning` | `--warning-500` | `--warning-500` | Attention needed. |
400
+ | `--status-warning` | `--warning-500` | `--warning-500` | Attention needed. |
407
401
  | `--status-warning-bg` | `--warning-950` | `--warning-100` | Background for warning badges. |
408
402
  | `--status-warning-fg` | `--warning-300` | `--warning-700` | Foreground for warning badges. |
409
- | `--status-danger` | `--danger-500` | `--danger-500` | Error / destructive. |
410
- | `--status-danger-bg` | `--danger-950` | `--danger-100` | Background for danger badges. |
411
- | `--status-danger-fg` | `--danger-300` | `--danger-700` | Foreground for danger badges. |
412
- | `--status-info` | `--info-500` | `--info-500` | Informational. |
413
- | `--status-info-bg` | `--info-950` | `--info-100` | Background for info badges. |
414
- | `--status-info-fg` | `--info-300` | `--info-700` | Foreground for info badges. |
415
- | `--status-neutral` | `--neutral-400` | `--neutral-400` | Default / inactive. |
403
+ | `--status-danger` | `--danger-500` | `--danger-500` | Error / destructive. |
404
+ | `--status-danger-bg` | `--danger-950` | `--danger-100` | Background for danger badges. |
405
+ | `--status-danger-fg` | `--danger-300` | `--danger-700` | Foreground for danger badges. |
406
+ | `--status-info` | `--info-500` | `--info-500` | Informational. |
407
+ | `--status-info-bg` | `--info-950` | `--info-100` | Background for info badges. |
408
+ | `--status-info-fg` | `--info-300` | `--info-700` | Foreground for info badges. |
409
+ | `--status-neutral` | `--neutral-400` | `--neutral-400` | Default / inactive. |
416
410
  | `--status-neutral-bg` | `--neutral-900` | `--neutral-200` | Background for neutral badges. |
417
411
  | `--status-neutral-fg` | `--neutral-300` | `--neutral-700` | Foreground for neutral badges. |
418
412
 
@@ -420,43 +414,44 @@ Each has a full 11-step scale (50–950). Never use directly — always go throu
420
414
 
421
415
  #### Project accent tokens
422
416
 
423
- | Token | Dark base | Light base | Project |
424
- |-------|-----------|------------|---------|
425
- | `--accent-square` | `--magenta-500` | `--magenta-500` | 7K parent |
426
- | `--accent-triangle` | `--solar-500` | `--solar-600` | Triangle |
427
- | `--accent-circle` | `--cyan-500` | `--cyan-600` | Circle |
428
- | `--accent-grid` | `--acid-500` | `--acid-600` | Grid |
429
- | `--accent-line` | `--ember-500` | `--ember-600` | Line |
417
+ | Token | Dark base | Light base | Project |
418
+ | ------------------ | --------------- | --------------- | ---------------- |
419
+ | `--accent-7kgroup` | `--magenta-500` | `--magenta-500` | 7KGroup (parent) |
420
+ | `--accent-7kminato` | `--cyan-500` | `--cyan-600` | 7KMinato |
421
+ | `--accent-inari` | `--inari-500` | `--inari-600` | Inari |
430
422
 
431
- Light theme shifts project accents one step darker (500→600) to maintain contrast against the brighter background.
423
+ These tokens are the canonical hue for each project. They also feed `--brand-secondary` when a project scope is applied via `data-project` or `ProjectProvider`. Light theme shifts project accents one step darker (500→600) to maintain contrast against the brighter background.
432
424
 
433
425
  ---
426
+
434
427
  ### Layer 3 — Semantic Colors: Meaning, Not Decoration
435
428
 
436
429
  Semantic colors exist **only** for status indication. Each maps to exactly one meaning.
437
430
 
438
- | Match | Token | Example |
439
- |-------|-------|---------|
440
- | Positive outcome / online | `--status-success` + `--status-success-bg` | Badge: "Online" in green |
441
- | Attention needed | `--status-warning` + `--status-warning-bg` | Badge: "Pending" in amber |
442
- | Error / destructive | `--status-danger` + `--status-danger-bg` | Badge: "Error" in red |
443
- | Informational | `--status-info` + `--status-info-bg` | Badge: "Info" in blue |
444
- | Default / inactive | `--status-neutral` + `--status-neutral-bg` | Badge: "Offline" in grey |
431
+ | Match | Token | Example |
432
+ | ------------------------- | ------------------------------------------ | ------------------------- |
433
+ | Positive outcome / online | `--status-success` + `--status-success-bg` | Badge: "Online" in green |
434
+ | Attention needed | `--status-warning` + `--status-warning-bg` | Badge: "Pending" in amber |
435
+ | Error / destructive | `--status-danger` + `--status-danger-bg` | Badge: "Error" in red |
436
+ | Informational | `--status-info` + `--status-info-bg` | Badge: "Info" in blue |
437
+ | Default / inactive | `--status-neutral` + `--status-neutral-bg` | Badge: "Offline" in grey |
445
438
 
446
439
  **Do not use semantic colors for:**
440
+
447
441
  - Decorative borders on cards
448
442
  - Accent accent headers
449
443
  - Non-status icon fills
450
444
  - Background washes for sections
451
445
 
452
446
  ---
447
+
453
448
  ### Usage rules
454
449
 
455
450
  1. **Neutral ladder** — Step one surface layer per depth level: `void → base → elevated → raised → overlay → pressed`. Never skip a level for visual emphasis.
456
451
  2. **Accent on action, not surface** — Brand appears on primary CTAs, focus rings, active borders, brand typography. Never as a full surface background fill.
457
452
  3. **Semantic = meaning only** — Status hues exist for machine-state communication (badge bg, toast icon, validation message, online/offline dot). If it doesn't communicate a machine state, use the raw ramps instead.
458
453
  4. **Status bg uses `--*-bg`** — Status badges and pills use the `--status-*-bg` token, never the solid `--*-500` as a fill.
459
- 5. **Project scoping** — Parent 7K uses `--accent-square` (magenta). Child projects swap `--accent-*` for their own hue. The neutral ramp stays unchanged.
454
+ 5. **Project scoping** — 7KGroup uses magenta, 7KMinato cyan, Inari burnt orange. Within a project scope (`data-project` or `ProjectProvider`), the project accent takes over the **entire brand chain** — `--brand-primary` and `--brand-secondary` (primary/glow buttons, focus rings, brand borders) — making the project hue more prevalent than the 7KGroup baseline. Magenta only persists in constant identity marks (`--accent-7kgroup`, logo/icon strokes). Semantic status colors and the neutral ramp stay unchanged.
460
455
  6. **No raw ramp references in components** — Always reference role tokens (`--bg-elevated`, `--text-primary`, `--border-default`), never raw ramp tokens (`--neutral-950`, `--neutral-50`, etc.). This is how theme switching works.
461
456
  7. **Dark is default, light is opt-in** — `:root` holds dark token mappings. `@media (prefers-color-scheme: light)` overrides only the role tokens. Primitive ramps are shared and unchanged.
462
457
 
@@ -466,23 +461,24 @@ Semantic colors exist **only** for status indication. Each maps to exactly one m
466
461
 
467
462
  ### Three-font system
468
463
 
469
- | Family | Role | Weight range | Source |
470
- |--------|------|-------------|--------|
471
- | **Geist** (sans) | Display, headings, body, UI text | 100–900 | CDN (`geist` npm package) |
472
- | **Geist Mono** | Labels, code, tabular data, metadata | 400, 500 | CDN (`geist` npm package) |
473
- | **Geist Pixel** (5 variants) | Ornamental display, pixel-constrained surfaces, hero wordmarks | 400–800 (one per variant) | Local `fonts/` TTFs |
464
+ | Family | Role | Weight range | Source |
465
+ | ---------------------------- | -------------------------------------------------------------- | ------------------------- | ------------------------- |
466
+ | **Geist** (sans) | Display, headings, body, UI text | 100–900 | CDN (`geist` npm package) |
467
+ | **Geist Mono** | Labels, code, tabular data, metadata | 400, 500 | CDN (`geist` npm package) |
468
+ | **Geist Pixel** (5 variants) | Ornamental display, pixel-constrained surfaces, hero wordmarks | 400–800 (one per variant) | Local `fonts/` TTFs |
474
469
 
475
470
  ### Geist Pixel variant → project accent pairing
476
471
 
477
- | Variant | Weight | Pairs with | Best for |
478
- |---------|--------|------------|----------|
479
- | **Square** | 400 (Regular) | Magenta (7K parent) | Body-sized pixel text, data displays |
480
- | **Circle** | 500 (Medium) | Cyan | Buttons, badges, navigation |
481
- | **Grid** | 600 (SemiBold) | Acid (Grid project) | Section titles, stat values |
482
- | **Line** | 700 (Bold) | Ember (Line project) | Display headlines, hero text |
483
- | **Triangle** | 800 (ExtraBold) | Solar (Triangle project) | Hero wordmarks, giant headlines |
472
+ | Variant | Weight | Pairs with | Best for |
473
+ | ------------ | --------------- | ------------------------ | ------------------------------------ |
474
+ | **Square** | 400 (Regular) | Magenta (7KGroup) | Body-sized pixel text, data displays |
475
+ | **Circle** | 500 (Medium) | Cyan (7KMinato) | Buttons, badges, navigation |
476
+ | **Grid** | 600 (SemiBold) | Neutral | Section titles, stat values |
477
+ | **Line** | 700 (Bold) | Neutral | Display headlines, hero text |
478
+ | **Triangle** | 800 (ExtraBold) | Inari (Inari project) | Hero wordmarks, giant headlines |
484
479
 
485
480
  ### Font stacks
481
+
486
482
  ```
487
483
  --font-sans: 'Geist', system-ui, -apple-system, sans-serif;
488
484
  --font-mono: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace;
@@ -491,21 +487,22 @@ Semantic colors exist **only** for status indication. Each maps to exactly one m
491
487
 
492
488
  ### Type scale — engineering blueprint
493
489
 
494
- | Token | Size | Family / Weight | Usage |
495
- |-------|------|----------------|-------|
496
- | `--text-display` | `clamp(48px, 8vw, 160px)` | Geist 900 -0.04em | Hero numerals, giant headlines |
497
- | `--text-h1` | 4rem (64px) | Geist 700 -0.04em | Page titles |
498
- | `--text-h2` | 3rem (48px) | Geist 700 -0.03em | Section titles |
499
- | `--text-h3` | 2rem (32px) | Geist 600 -0.02em | Sub-section headers |
500
- | `--text-h4` | 1.5rem (24px) | Geist 600 -0.02em | Card titles |
501
- | `--text-body-lg` | 1.125rem (18px) | Geist 400 -0.01em | Larger body / lede |
502
- | `--text-body` | 1rem (16px) | Geist 400 -0.01em | Body paragraphs |
503
- | `--text-body-sm` | 0.875rem (14px) | Geist 400 -0.01em | Secondary text |
504
- | `--text-caption` | 0.75rem (12px) | Geist 500 | Metadata, timestamps |
505
- | `--text-mono-label` | 0.6875rem (11px) | Geist Mono 500 0.12em uppercase | Labels, badges, form labels — the "connective tissue" |
506
- | `--text-mono-body` | 0.8125rem (13px) | Geist Mono 400 | Code blocks, tabular data |
490
+ | Token | Size | Family / Weight | Usage |
491
+ | ------------------- | ------------------------- | ------------------------------- | ----------------------------------------------------- |
492
+ | `--text-display` | `clamp(48px, 8vw, 160px)` | Geist 900 -0.04em | Hero numerals, giant headlines |
493
+ | `--text-h1` | 4rem (64px) | Geist 700 -0.04em | Page titles |
494
+ | `--text-h2` | 3rem (48px) | Geist 700 -0.03em | Section titles |
495
+ | `--text-h3` | 2rem (32px) | Geist 600 -0.02em | Sub-section headers |
496
+ | `--text-h4` | 1.5rem (24px) | Geist 600 -0.02em | Card titles |
497
+ | `--text-body-lg` | 1.125rem (18px) | Geist 400 -0.01em | Larger body / lede |
498
+ | `--text-body` | 1rem (16px) | Geist 400 -0.01em | Body paragraphs |
499
+ | `--text-body-sm` | 0.875rem (14px) | Geist 400 -0.01em | Secondary text |
500
+ | `--text-caption` | 0.75rem (12px) | Geist 500 | Metadata, timestamps |
501
+ | `--text-mono-label` | 0.6875rem (11px) | Geist Mono 500 0.12em uppercase | Labels, badges, form labels — the "connective tissue" |
502
+ | `--text-mono-body` | 0.8125rem (13px) | Geist Mono 400 | Code blocks, tabular data |
507
503
 
508
504
  ### Legacy alignment tokens (deprecated but kept for compatibility)
505
+
509
506
  ```
510
507
  --text-7xl 7.5rem (120px) --text-6xl 5.5rem (88px)
511
508
  --text-5xl 4rem (64px) --text-4xl 3rem (48px)
@@ -516,6 +513,7 @@ Semantic colors exist **only** for status indication. Each maps to exactly one m
516
513
  ```
517
514
 
518
515
  ### Weight scale
516
+
519
517
  ```
520
518
  --weight-thin: 100 --weight-extralight: 200 --weight-light: 300
521
519
  --weight-regular: 400 --weight-medium: 500 --weight-semibold: 600
@@ -523,6 +521,7 @@ Semantic colors exist **only** for status indication. Each maps to exactly one m
523
521
  ```
524
522
 
525
523
  ### Line heights
524
+
526
525
  ```
527
526
  --leading-none: 1 --leading-tight: 1.15
528
527
  --leading-snug: 1.3 --leading-normal: 1.5
@@ -530,6 +529,7 @@ Semantic colors exist **only** for status indication. Each maps to exactly one m
530
529
  ```
531
530
 
532
531
  ### Letter spacing
532
+
533
533
  ```
534
534
  --tracking-tightest: -0.04em --tracking-tighter: -0.02em
535
535
  --tracking-tight: -0.01em --tracking-normal: 0
@@ -538,9 +538,11 @@ Semantic colors exist **only** for status indication. Each maps to exactly one m
538
538
  ```
539
539
 
540
540
  ### Mono-label language — "connective tissue"
541
+
541
542
  Every label, badge, form label, tab, breadcrumb, and status indicator uses `--text-mono-label` (Geist Mono, 11px, 500 weight, 0.12em uppercase). This creates the engineering-blueprint aesthetic: the reader always knows which layer they are looking at because the meta-information reads like a schematic.
542
543
 
543
544
  ### Numerics
545
+
544
546
  - All data / metrics use `font-family: var(--font-mono)` with `font-variant-numeric: tabular-nums`
545
547
  - Display: -0.04em, h1: -0.04em, h2: -0.03em, h3: -0.02em, h4: -0.02em
546
548
 
@@ -597,6 +599,7 @@ Sharp (0px) and subtle (2–4px) are preferred for 1-bit elements. 8–12px for
597
599
  **Source context reference:** The brief's "tech company with different projects" suggests a dashboard/app-shell layout pattern. The 12-column grid supports both marketing pages and data-dense project dashboards.
598
600
 
599
601
  ### Container widths
602
+
600
603
  ```
601
604
  --container-sm: 640px
602
605
  --container-md: 960px
@@ -606,6 +609,7 @@ Sharp (0px) and subtle (2–4px) are preferred for 1-bit elements. 8–12px for
606
609
  ```
607
610
 
608
611
  ### Z-index scale
612
+
609
613
  ```
610
614
  --z-base: 0
611
615
  --z-raised: 10
@@ -617,23 +621,27 @@ Sharp (0px) and subtle (2–4px) are preferred for 1-bit elements. 8–12px for
617
621
  ```
618
622
 
619
623
  ### Grid
624
+
620
625
  - 12-column responsive grid, `--grid-gutter` (24px) gutter
621
626
  - Breakpoints: 480px (mobile), 768px (tablet), 1024px (desktop), 1440px (wide)
622
627
  - Max content width: 1280px, centered
623
628
 
624
629
  ### Navigation
630
+
625
631
  - Sticky top nav (frosted glass) on dark bg
626
632
  - Bottom tab bar on mobile, side nav for app shells
627
633
  - Active nav item: accent dot indicator
628
634
 
629
635
  ### 1-bit section rhythm
636
+
630
637
  - Scanline overlay on hero / full-bleed sections
631
638
  - Halftone dot separators between content blocks
632
- - Full-bleed sections use `.separator-onebit` (2px white line at 25% opacity) as rhythm breaks
639
+ - Full-bleed sections use `.separator-solid` (2px white line at 25% opacity) as rhythm breaks
633
640
  - Texture shift between sections: scanline → solid → halftone → solid → scanline. Never two textured sections adjacent.
634
- - Manga panel composition: content is the "panel" (solid black border), background is the "page" (noise or scanline). Each panel gets a `.vignette-onebit` edge fade.
641
+ - Manga panel composition: content is the "panel" (solid black border), background is the "page" (noise or scanline). Each panel gets a `.vignette-ink` edge fade.
635
642
 
636
643
  ### Product shell layout
644
+
637
645
  ```
638
646
  ┌──────────────────────────────────────────┐
639
647
  │ Sidebar (240px) │ Main content area │
@@ -658,156 +666,161 @@ Sharp (0px) and subtle (2–4px) are preferred for 1-bit elements. 8–12px for
658
666
 
659
667
  **Modern neon** — the only button system. All buttons use `mono-label` typography (Geist Mono, 11px, 500 weight, 0.12em uppercase) and 4px border-radius. Accent fills use the brand-primary ramp (500→hover:400→active:600). Button groups, split buttons, and loading state are built on the same base.
660
668
 
661
- | Class | Description |
662
- |-------|-------------|
663
- | `.btn-modern` | Base: mono-label typography, 12px/20px padding, `rounded.sm` (4px) |
664
- | `.btn-modern-primary` | `--brand-primary` (`--magenta-500`) fill, `--brand-primary-hover` on hover + glow shadow |
665
- | `.btn-modern-secondary` | `--bg-raised` fill, `--bg-overlay` on hover |
666
- | `.btn-modern-ghost` | Transparent, `--text-secondary` text, subtle bg on hover |
667
- | `.btn-modern-glow` | `--magenta-500` fill + neon glow, `--magenta-400` on hover |
668
- | `.btn-modern-glow-cyan` | `--cyan-500` fill + cyan glow, `--cyan-400` on hover |
669
- | `.btn-modern-glow-grid` | `--acid-500` fill + acid glow, `--acid-400` on hover |
670
- | `.btn-modern-danger` | Transparent + danger border, danger fill on hover |
671
- | `.btn-modern-sm/lg` | Size variants (8px/16px small, 16px/28px large) |
672
- | `.btn-modern-icon` | 40×40 square icon button |
673
- | `.btn-modern-lg-icon` | 52×52 large icon button |
674
- | `.btn-modern-loading` | Loading state — `onebit-spin` replaces icon |
675
- | `.btn-group` | Inline flex container for grouped buttons (adjacent borders merge) |
676
- | `.btn-split` | Split button trigger — last child gets narrower padding + left border |
669
+ | Class | Description |
670
+ | --------------------------- | ------------------------------------------------------------------------------------------ |
671
+ | `.btn` | Base: mono-label typography, 12px/20px padding, `rounded.sm` (4px) |
672
+ | `.btn-primary` | Magenta outline, `--brand-primary-subtle` fill tint on hover, white text when active |
673
+ | `.btn-secondary` | `--bg-raised` fill, `--bg-overlay` on hover |
674
+ | `.btn-ghost` | Transparent, `--text-secondary` text, subtle bg on hover |
675
+ | `.btn-glow` | Magenta outline + persistent neon glow, intensifies on hover |
676
+ | `.btn-accent` | Dynamic `--brand-secondary` outline + fill tint on hover (per-project accent) |
677
+ | `.btn-glow-accent` | `--brand-secondary` fill + glow (the filled "neon" button; magenta for the parent brand) |
678
+ | `.btn-glow-secondary`| Cyan/`--brand-secondary` outline + glow variant of `.btn-glow` |
679
+ | `.btn-danger` | Transparent + danger border, danger fill on hover |
680
+ | `.btn-sm/lg` | Size variants (8px/16px small, 16px/28px large) |
681
+ | `.btn-icon` | 40×40 square icon button |
682
+ | `.btn-lg-icon` | 52×52 large icon button |
683
+ | `.btn-loading` | Loading state — `spin-steps` replaces icon |
684
+ | `.btn:disabled` | 40% opacity, no pointer events, glow removed — applies to every variant |
685
+ | `.btn-group` | Inline flex container for grouped buttons (adjacent borders merge) |
686
+ | `.btn-split` | Split button trigger — last child gets narrower padding + left border |
677
687
 
678
688
  All variants use standard CSS transitions for interaction states:
679
- - **`:hover`** → fill shifts to `--brand-primary-hover` (`--magenta-400`), optional glow shadow intensifies
689
+
690
+ - **`:hover`** → border/fill shifts to the `-hover` step of the variant's ramp, optional glow shadow intensifies
680
691
  - **`:focus-visible`** → outline ring
681
- - **`:active`** → fill shifts to `--brand-primary-active` (`--magenta-600`)
682
- - **`Loading`** → `onebit-spin` (0.6s steps(4) infinite — square frame rotation)
692
+ - **`:active`** → fill shifts to the `-muted` step with `--color-paper` text (keeps contrast ≥ 7:1)
693
+ - **`:disabled`** → 40% opacity, `not-allowed` cursor, no glow
694
+ - **`Loading`** → `spin-steps` (0.6s steps(4) infinite — square frame rotation)
683
695
 
684
696
  ### 6b. Form controls
685
697
 
686
- | Class | Description |
687
- |-------|-------------|
688
- | `.input` | Text input: black bg, 2px white border, accent glow on focus |
689
- | `.textarea` | Multi-line input, same tokens |
690
- | `.select-native` | Custom dropdown, SVG chevron |
691
- | `.checkbox` | 16px square, checked fills white (`.checkbox-accent`: fills magenta) |
692
- | `.radio` | 16px square, selected fills white (`.radio-accent`: fills magenta) |
693
- | `.toggle` | 36x18 switch, on state fills white (`.toggle-accent`: fills magenta) |
694
- | `.range` | 6px track, 16px square thumb |
695
- | `.form-group` | Flex column with gap |
696
- | `.form-label` | Mono uppercase label, 11px |
697
- | `.field-error` | Red mono error text |
698
- | `.input-group` | Inline input + addon |
699
- | `.input-addon` | Prefix/suffix decoration |
700
- | `.color-swatch` | 32px square, accent shadow on selected |
698
+ | Class | Description |
699
+ | ---------------- | -------------------------------------------------------------------- |
700
+ | `.input` | Text input: black bg, 2px white border, accent glow on focus |
701
+ | `.textarea` | Multi-line input, same tokens |
702
+ | `.select-native` | Custom dropdown, SVG chevron |
703
+ | `.checkbox` | 16px square, checked fills white (`.checkbox-accent`: fills `--brand-secondary`) |
704
+ | `.radio` | 16px square, selected fills white (`.radio-accent`: fills `--brand-secondary`) |
705
+ | `.toggle` | 36x18 switch, on state fills white (`.toggle-accent`: fills `--brand-secondary`) |
706
+ | `.range` | 6px track, 16px square thumb |
707
+ | `.form-group` | Flex column with gap |
708
+ | `.form-label` | Mono uppercase label, 11px |
709
+ | `.field-error` | Red mono error text |
710
+ | `.input-group` | Inline input + addon |
711
+ | `.input-addon` | Prefix/suffix decoration |
712
+ | `.color-swatch` | 32px square, accent shadow on selected |
701
713
 
702
714
  ### 6c. Navigation
703
715
 
704
- | Class | Description |
705
- |-------|-------------|
706
- | `.nav` | Vertical nav container |
707
- | `.nav-item` | Nav link with optional bullet, invert on active |
708
- | `.nav-item-accent` | Magenta border on active |
709
- | `.tabs` | Horizontal tab bar, 2px bottom border |
710
- | `.tab` | Mono uppercase tab, white underline on active |
711
- | `.tab-accent` | Magenta underline on active |
712
- | `.pagination` | Inline page button group |
713
- | `.page-btn` | 32px square, invert on active |
714
- | `.breadcrumb` | Mono slash-separated trail |
715
- | `.stepper` | Numbered step indicator with connecting line |
716
+ | Class | Description |
717
+ | ------------------ | ----------------------------------------------- |
718
+ | `.nav` | Vertical nav container |
719
+ | `.nav-item` | Nav link with optional bullet, invert on active |
720
+ | `.nav-item-accent` | Magenta border on active |
721
+ | `.tabs` | Horizontal tab bar, 2px bottom border |
722
+ | `.tab` | Mono uppercase tab, white underline on active |
723
+ | `.tab-accent` | Magenta underline on active |
724
+ | `.pagination` | Inline page button group |
725
+ | `.page-btn` | 32px square, invert on active |
726
+ | `.breadcrumb` | Mono slash-separated trail |
727
+ | `.stepper` | Numbered step indicator with connecting line |
716
728
 
717
729
  ### 6d. Data display
718
730
 
719
- | Class | Description |
720
- |-------|-------------|
721
- | `.table` | Collapsed table, 2px header border, mono uppercase headers |
722
- | `.badge` | Inline uppercase label, 11px, 1px border |
723
- | `.badge-inverted` | White bg, black text |
724
- | `.badge-accent` / `.badge-success` / `.badge-warning` / `.badge-danger` | Colored border variants |
725
- | `.tag` | 11px uppercase inline, 3 variants (default, outlined, inverted) |
726
- | `.chip` | Removable inline tag with close button |
727
- | `.chip-accent` | Magenta border variant |
728
- | `.avatar` | 32x32 square, 2px border, mono initial |
729
- | `.avatar-sm` / `.avatar-lg` / `.avatar-group` | Size + overlap group |
730
- | `.stat` | Value + label vertical pair |
731
- | `.stat-accent` | Magenta value color |
732
- | `.kbd` | Keyboard key with 3px bottom border weight |
733
- | `.code-block` | Pre block, 2px border, 13px mono |
734
- | `.code-inline` | Inline code snippet |
735
- | `.link` | Underlined white text, thicker hover |
736
- | `.link-accent` | Magenta colored link |
737
- | `.list` | Bordered list group with 2px border |
738
- | `.list-item` | 13px item with hover/active states |
739
- | `.tree` | Nested tree with lines |
740
- | `.tree-item` | Indented with left border, accent on active |
731
+ | Class | Description |
732
+ | ----------------------------------------------------------------------- | --------------------------------------------------------------- |
733
+ | `.table` | Collapsed table, 2px header border, mono uppercase headers |
734
+ | `.badge` | Inline uppercase label, 11px, 1px border |
735
+ | `.badge-inverted` | White bg, black text |
736
+ | `.badge-accent` / `.badge-success` / `.badge-warning` / `.badge-danger` | Colored border variants |
737
+ | `.tag` | 11px uppercase inline, 3 variants (default, outlined, inverted) |
738
+ | `.chip` | Removable inline tag with close button |
739
+ | `.chip-accent` | Magenta border variant |
740
+ | `.avatar` | 32x32 square, 2px border, mono initial |
741
+ | `.avatar-sm` / `.avatar-lg` / `.avatar-group` | Size + overlap group |
742
+ | `.stat` | Value + label vertical pair |
743
+ | `.stat-accent` | Magenta value color |
744
+ | `.kbd` | Keyboard key with 3px bottom border weight |
745
+ | `.code-block` | Pre block, 2px border, 13px mono |
746
+ | `.code-inline` | Inline code snippet |
747
+ | `.link` | Underlined white text, thicker hover |
748
+ | `.link-accent` | Magenta colored link |
749
+ | `.list` | Bordered list group with 2px border |
750
+ | `.list-item` | 13px item with hover/active states |
751
+ | `.tree` | Nested tree with lines |
752
+ | `.tree-item` | Indented with left border, accent on active |
741
753
 
742
754
  ### 6e. Overlays
743
755
 
744
- | Class | Description |
745
- |-------|-------------|
746
- | `.modal` | Black bg, 2px border, 8px hard offset shadow |
747
- | `.drawer` | Side panel, 300-480px width |
748
- | `.toast` | Notification with 4px hard offset shadow, slide-up animation |
749
- | `.toast-success` / `.toast-error` / `.toast-warning` | Colored icon variants |
750
- | `.tooltip` | Positioned label on hover |
751
- | `.alert` | Inline message with icon |
752
- | `.alert-success` / `.alert-error` / `.alert-warning` | Colored border variants |
756
+ | Class | Description |
757
+ | ---------------------------------------------------- | ------------------------------------------------------------ |
758
+ | `.modal` | Black bg, 2px border, 8px hard offset shadow |
759
+ | `.drawer` | Side panel, 300-480px width |
760
+ | `.toast` | Notification with 4px hard offset shadow, slide-up animation |
761
+ | `.toast-success` / `.toast-error` / `.toast-warning` | Colored icon variants |
762
+ | `.tooltip` | Positioned label on hover |
763
+ | `.alert` | Inline message with icon |
764
+ | `.alert-success` / `.alert-error` / `.alert-warning` | Colored border variants |
753
765
 
754
766
  ### 6f. Feedback
755
767
 
756
- | Class | Description |
757
- |-------|-------------|
758
- | `.progress` | 12px bar, 2px border |
759
- | `.progress-accent` | Magenta fill |
760
- | `.progress-indeterminate` | Scanning bar animation |
761
- | `.progress-striped` | Striped fill overlay |
762
- | `.spinner` | 20px square rotating frame, 90° steps |
763
- | `.spinner-accent` / `.spinner-cyan` | Colored border variants |
764
- | `.skeleton` | Loading placeholder, opacity pulse |
765
- | `.empty` | Dashed border placeholder, centered content |
766
- | `.loading-screen` | Full block loading with blinking label |
767
- | `.banner` | Full-width colored message bar |
768
+ | Class | Description |
769
+ | ----------------------------------- | ------------------------------------------- |
770
+ | `.progress` | 12px bar, 2px border |
771
+ | `.progress-accent` | `--brand-secondary` (project accent) fill |
772
+ | `.progress-indeterminate` | Scanning bar animation |
773
+ | `.progress-striped` | Striped fill overlay |
774
+ | `.spinner` | 20px square rotating frame, 90° steps |
775
+ | `.spinner-accent` / `.spinner-cyan` | Colored border variants |
776
+ | `.skeleton` | Loading placeholder, opacity pulse |
777
+ | `.empty` | Dashed border placeholder, centered content |
778
+ | `.loading-screen` | Full block loading with blinking label |
779
+ | `.banner` | Full-width colored message bar |
768
780
 
769
781
  ### 6g. Media & Layout
770
782
 
771
- | Class | Description |
772
- |-------|-------------|
773
- | `.image-frame` | 2px border placeholder |
774
- | `.video-frame` | 16:9 frame with play button + timeline |
775
- | `.icon-box` | 40x40 square icon container |
776
- | `.icon-box-sm` / `.icon-box-lg` / `.icon-box-accent` / `.icon-box-cyan` | Variants |
777
- | `.container` | 1280px centered max-width |
778
- | `.grid` / `.grid-2` / `.grid-3` / `.grid-4` | Grid with 24px gap |
779
- | `.hr` / `.hr-thick` | Horizontal rules |
783
+ | Class | Description |
784
+ | ----------------------------------------------------------------------- | -------------------------------------- |
785
+ | `.image-frame` | 2px border placeholder |
786
+ | `.video-frame` | 16:9 frame with play button + timeline |
787
+ | `.icon-box` | 40x40 square icon container |
788
+ | `.icon-box-sm` / `.icon-box-lg` / `.icon-box-accent` / `.icon-box-cyan` | Variants |
789
+ | `.container` | 1280px centered max-width |
790
+ | `.grid` / `.grid-2` / `.grid-3` / `.grid-4` | Grid with 24px gap |
791
+ | `.hr` / `.hr-thick` | Horizontal rules |
780
792
 
781
793
  ### 6h. Misc
782
794
 
783
- | Class | Description |
784
- |-------|-------------|
785
- | `.menu` | Dropdown menu list |
786
- | `.menu-item` | Menu entry with divider support |
787
- | `.toolbar` | Icon button row with separators |
788
- | `.status-dot` | 8px square dot (live/away/busy/offline) |
789
- | `.timeline` | Vertical timeline with dots + lines |
790
- | `.countdown` | Tabular numeric countdown with labels |
791
- | `.rating` | 5-star rating, 20px squares, accent on hover |
792
- | `.combobox` | Searchable select with dropdown menu |
793
- | `.date-input` | Date field with segmented parts |
795
+ | Class | Description |
796
+ | ------------- | -------------------------------------------- |
797
+ | `.menu` | Dropdown menu list |
798
+ | `.menu-item` | Menu entry with divider support |
799
+ | `.toolbar` | Icon button row with separators |
800
+ | `.status-dot` | 8px square dot (live/away/busy/offline) |
801
+ | `.timeline` | Vertical timeline with dots + lines |
802
+ | `.countdown` | Tabular numeric countdown with labels |
803
+ | `.rating` | 5-star rating, 20px squares, accent on hover |
804
+ | `.combobox` | Searchable select with dropdown menu |
805
+ | `.date-input` | Date field with segmented parts |
794
806
 
795
807
  ### 6i. Accent layer modifiers
796
808
 
797
809
  These classes add thin color to any 1-bit component without breaking the black/white base. Apply alongside the component class.
798
810
 
799
- | Class | Effect |
800
- |-------|--------|
801
- | `.accent-border-top` / `.accent-border-left` / `.accent-border-bottom` | 3px magenta border on one edge |
802
- | `.cyan-border-top` / `.grid-border-top` / `.line-border-top` | 3px colored top border |
803
- | `.accent-underline` / `.cyan-underline` | Colored underline on text |
804
- | `.accent-dot` / `.cyan-dot` / `.grid-dot` | Small colored dot after element |
805
- | `.accent-bar` / `.cyan-bar` / `.grid-bar` / `.line-bar` | Thin colored bar across top |
806
- | `.glow-mod` / `.glow-mod-cyan` | Colored glow shadow |
807
- | `.border-mod-accent` / `.border-mod-cyan` | Border color override |
808
- | `.accent-corner` / `.cyan-corner` | Small colored corner badge |
811
+ | Class | Effect |
812
+ | -------------------------------------------------------------------------------------- | ------------------------------------------------- |
813
+ | `.accent-border-top` / `.accent-border-left` / `.accent-border-bottom` | 3px `--brand-primary` (magenta) border on one edge |
814
+ | `.accent-secondary-border-top` / `-left` / `-bottom` | 3px `--brand-secondary` (per-project) border |
815
+ | `.accent-underline` / `.accent-secondary-underline` | Colored underline on text |
816
+ | `.accent-dot` / `.accent-secondary-dot` | Small colored dot after element |
817
+ | `.accent-bar` / `.accent-secondary-bar` | Thin colored bar across top |
818
+ | `.glow-mod` / `.glow-mod-secondary` | Colored glow shadow |
819
+ | `.border-mod-accent` / `.border-mod-secondary` | Border color override |
820
+ | `.accent-corner` / `.accent-secondary-corner` | Small colored corner badge |
809
821
 
810
822
  ### 1-bit composition rules
823
+
811
824
  - **No radii.** Every 1-bit component uses `border-radius: 0`. Sharp corners are part of the identity.
812
825
  - **No blur shadows.** Only hard offset shadows (`box-shadow: 8px 8px 0 #FFFFFF`) on modal and toast.
813
826
  - **2px borders.** All bordered 1-bit components use 2px `solid` white borders unless specified.
@@ -822,6 +835,7 @@ These classes add thin color to any 1-bit component without breaking the black/w
822
835
  **Source context reference:** The brief's "abstract 1-bit animations" directly motivates the scanline-scroll, glitch, and halftone keyframe primitives. Reduced-motion support is a standard accessibility requirement.
823
836
 
824
837
  ### Durations & easing
838
+
825
839
  ```
826
840
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1)
827
841
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1)
@@ -835,43 +849,43 @@ These classes add thin color to any 1-bit component without breaking the black/w
835
849
 
836
850
  ### Full 1-bit Animation Library
837
851
 
838
- | Animation | Class | Duration | Type | Description |
839
- |-----------|-------|----------|------|-------------|
840
- | Scanline scroll | `.scanline` (::after) | 8s linear infinite | Ambient | Horizontal lines scroll down — signature 7K texture |
841
- | Scanline fast | `.scanline-fast` (::after) | 3s linear infinite | Ambient | Faster variant for high-energy sections |
842
- | Basic glitch | `.glitch` | 0.3s, 3 iterations | Trigger | Translate jitter on 5 random frames |
843
- | Complex glitch | `.glitch-complex` | 0.8s, 2 iterations | Trigger | Multi-axis + skew + clip-path splits |
844
- | Glitch accent | `.glitch-accent` | 0.4s, 2 iterations | Trigger | Glitch with magenta glow trail |
845
- | CRT flicker | `.flicker` / `.flicker-fast` | 4s / 1.5s infinite | Ambient | Opacity stutter at irregular intervals |
846
- | Binary blink | `.blink` / `.blink-fast` | 1s / 0.4s step-end | Ambient | Sharp on/off toggle |
847
- | Typewriter | `.typewriter` | 1.5s (30 steps) | Trigger | Text reveal from left |
848
- | Neon pulse | `.neon-pulse` / `.neon-pulse-cyan` | 2s ease-in-out | Ambient | Accent glow oscillation |
849
- | Noise shift | `.noise-animated` | 0.5s, steps(5) | Ambient | SVG noise translates in discrete positions |
850
- | Scan reveal | `.scan-reveal` | 2s, 1 iteration | Trigger | White bar sweeps down |
851
- | Pixel fade-in | `.pixel-fade-in` | 0.6s, steps(8) | Trigger | Left-to-right reveal in pixel steps |
852
- | Invert flash | `.invert-flash` | 0.15s, 2 iterations | Trigger | Full filter inversion burst |
853
- | Pixel dots | `.pixel-dots` / `.pixel-dots-fast` | 0.3s, steps(4), 2 iterations | Trigger | Small black squares scatter at random positions — 1-bit corruption effect |
854
- | Progress scan | `.progress-indeterminate` | 1.5s | Loading | Bar sweeps left-to-right |
855
- | Skeleton pulse | `.skeleton` | 1.2s ease-in-out | Loading | Opacity pulse |
856
- | Slide-up reveal | `.slide-up-reveal` | 0.5s ease-out | Trigger | Content rises with clip-path |
857
- | Shimmer sweep | `.shimmer` | 2s linear infinite | Loading | Horizontal gradient sweep |
858
- | Frame step | `.frame-step` (::after) | 0.8s steps(1) | Ambient | Binary character cycle (▌▐█▀) |
859
- | One-bit spin | `.spinner` | 0.6s linear | Loading | Square frame in 90° increments |
860
- | Matrix rain | `.matrix-rain-char` | 2s linear infinite | Ambient | Falling character column |
861
- | Accent flicker | `.accent-flicker` | 1.8s step-end infinite | Ambient | Blinking accent color text |
852
+ | Animation | Class | Duration | Type | Description |
853
+ | --------------- | ---------------------------------- | ---------------------------- | ------- | ------------------------------------------------------------------------- |
854
+ | Scanline scroll | `.scanline` (::after) | 8s linear infinite | Ambient | Horizontal lines scroll down — signature 7K texture |
855
+ | Scanline fast | `.scanline-fast` (::after) | 3s linear infinite | Ambient | Faster variant for high-energy sections |
856
+ | Basic glitch | `.glitch` | 0.3s, 3 iterations | Trigger | Translate jitter on 5 random frames |
857
+ | Complex glitch | `.glitch-complex` | 0.8s, 2 iterations | Trigger | Multi-axis + skew + clip-path splits |
858
+ | Glitch accent | `.glitch-accent` | 0.4s, 2 iterations | Trigger | Glitch with magenta glow trail |
859
+ | CRT flicker | `.flicker` / `.flicker-fast` | 4s / 1.5s infinite | Ambient | Opacity stutter at irregular intervals |
860
+ | Binary blink | `.blink` / `.blink-fast` | 1s / 0.4s step-end | Ambient | Sharp on/off toggle |
861
+ | Typewriter | `.typewriter` | 1.5s (30 steps) | Trigger | Text reveal from left |
862
+ | Neon pulse | `.neon-pulse` / `.neon-pulse-cyan` | 2s ease-in-out | Ambient | Accent glow oscillation |
863
+ | Noise shift | `.noise-animated` | 0.5s, steps(5) | Ambient | SVG noise translates in discrete positions |
864
+ | Scan reveal | `.scan-reveal` | 2s, 1 iteration | Trigger | White bar sweeps down |
865
+ | Pixel fade-in | `.pixel-fade-in` | 0.6s, steps(8) | Trigger | Left-to-right reveal in pixel steps |
866
+ | Invert flash | `.invert-flash` | 0.15s, 2 iterations | Trigger | Full filter inversion burst |
867
+ | Pixel dots | `.pixel-dots` / `.pixel-dots-fast` | 0.3s, steps(4), 2 iterations | Trigger | Small black squares scatter at random positions — 1-bit corruption effect |
868
+ | Progress scan | `.progress-indeterminate` | 1.5s | Loading | Bar sweeps left-to-right |
869
+ | Skeleton pulse | `.skeleton` | 1.2s ease-in-out | Loading | Opacity pulse |
870
+ | Slide-up reveal | `.slide-up-reveal` | 0.5s ease-out | Trigger | Content rises with clip-path |
871
+ | Shimmer sweep | `.shimmer` | 2s linear infinite | Loading | Horizontal gradient sweep |
872
+ | Frame step | `.frame-step` (::after) | 0.8s steps(1) | Ambient | Binary character cycle (▌▐█▀) |
873
+ | One-bit spin | `.spinner` | 0.6s linear | Loading | Square frame in 90° increments |
874
+ | Matrix rain | `.matrix-rain-char` | 2s linear infinite | Ambient | Falling character column |
875
+ | Accent flicker | `.accent-flicker` | 1.8s step-end infinite | Ambient | Blinking accent color text |
862
876
 
863
877
  ### Isometric Animation Library
864
878
 
865
- | Animation | Class | Duration | Type | Description |
866
- |-----------|-------|----------|------|-------------|
867
- | Isometric float | `.iso-float` | 3s ease-in-out infinite | Ambient | Block bobs up/down with subtle scale depth shift |
868
- | Float + spin | `.iso-float-spin` | 4s ease-in-out infinite | Ambient | Float + slow Y-axis rotation (90° steps) |
869
- | Grid scroll | `.iso-grid-scroll` | 4s linear infinite | Ambient | Isometric diamond grid scrolls diagonally |
870
- | Terrain shift | `.iso-terrain-shift` | 6s linear infinite | Ambient | 3 parallax layers move at different speeds |
871
- | Rotate cube | `.iso-rotate-cube` | 6s linear infinite | Ambient | Full 3D cube rotation in isometric space |
872
- | Assemble blocks | `.iso-assemble` | 0.8s ease-out forwards | Trigger | Blocks rise from below into position (5 delay variants: `.iso-assemble-2` through `-5`) |
873
- | Perspective dolly | `.iso-perspective-dolly` | 1s ease-out forwards | Trigger | Content zooms toward viewer with blur-in |
874
- | Step build | `.iso-step-build` | 0.4s steps(6) forwards | Trigger | Square reveals in pixel-step sequence |
879
+ | Animation | Class | Duration | Type | Description |
880
+ | ----------------- | ------------------------ | ----------------------- | ------- | --------------------------------------------------------------------------------------- |
881
+ | Isometric float | `.iso-float` | 3s ease-in-out infinite | Ambient | Block bobs up/down with subtle scale depth shift |
882
+ | Float + spin | `.iso-float-spin` | 4s ease-in-out infinite | Ambient | Float + slow Y-axis rotation (90° steps) |
883
+ | Grid scroll | `.iso-grid-scroll` | 4s linear infinite | Ambient | Isometric diamond grid scrolls diagonally |
884
+ | Terrain shift | `.iso-terrain-shift` | 6s linear infinite | Ambient | 3 parallax layers move at different speeds |
885
+ | Rotate cube | `.iso-rotate-cube` | 6s linear infinite | Ambient | Full 3D cube rotation in isometric space |
886
+ | Assemble blocks | `.iso-assemble` | 0.8s ease-out forwards | Trigger | Blocks rise from below into position (5 delay variants: `.iso-assemble-2` through `-5`) |
887
+ | Perspective dolly | `.iso-perspective-dolly` | 1s ease-out forwards | Trigger | Content zooms toward viewer with blur-in |
888
+ | Step build | `.iso-step-build` | 0.4s steps(6) forwards | Trigger | Square reveals in pixel-step sequence |
875
889
 
876
890
  ### Animation composition rules
877
891
 
@@ -884,16 +898,16 @@ These classes add thin color to any 1-bit component without breaking the black/w
884
898
 
885
899
  ### Animation timing — when 1-bit animations apply
886
900
 
887
- | Surface | Ambient animation | Trigger animation |
888
- |---------|-------------------|-------------------|
889
- | Landing / marketing hero | `.scanline` (8s) | `.scan-reveal` on load |
890
- | Dashboard / app shell | None | `.glitch` on filter change |
891
- | Loading state | `.skeleton` or `.shimmer` | None |
892
- | Error state | None | `.glitch-complex` on container |
893
- | 1-bit splash / manga panel | `.scanline-fast` (3s) | `.invert-flash` on page enter |
894
- | Toast / notification | None | `.slide-up-reveal` on mount |
895
- | Button (accent) | None | Color transition on hover |
896
- | Accent text | `.accent-flicker` | None |
901
+ | Surface | Ambient animation | Trigger animation |
902
+ | -------------------------- | ------------------------- | ------------------------------ |
903
+ | Landing / marketing hero | `.scanline` (8s) | `.scan-reveal` on load |
904
+ | Dashboard / app shell | None | `.glitch` on filter change |
905
+ | Loading state | `.skeleton` or `.shimmer` | None |
906
+ | Error state | None | `.glitch-complex` on container |
907
+ | 1-bit splash / manga panel | `.scanline-fast` (3s) | `.invert-flash` on page enter |
908
+ | Toast / notification | None | `.slide-up-reveal` on mount |
909
+ | Button (accent) | None | Color transition on hover |
910
+ | Accent text | `.accent-flicker` | None |
897
911
 
898
912
  ## 8. React UI Kit
899
913
 
@@ -908,12 +922,14 @@ npm install 7k-design-system
908
922
  ```typescript
909
923
  // App entry point
910
924
  import '7k-design-system/css';
911
- import { ThemeProvider } from '7k-design-system/react';
925
+ import { ThemeProvider, ProjectProvider } from '7k-design-system/react';
912
926
 
913
927
  function App() {
914
928
  return (
915
929
  <ThemeProvider defaultTheme="dark">
916
- <YourApp />
930
+ <ProjectProvider defaultProject="7k">
931
+ <YourApp />
932
+ </ProjectProvider>
917
933
  </ThemeProvider>
918
934
  );
919
935
  }
@@ -925,9 +941,10 @@ function App() {
925
941
  import { Button } from '7k-design-system/react';
926
942
 
927
943
  <Button
928
- variant="primary" // 'primary' | 'secondary' | 'ghost' | 'glow' | 'glow-cyan' | 'glow-grid' | 'danger'
944
+ variant="primary" // 'primary' | 'secondary' | 'ghost' | 'glow' | 'accent' | 'glow-accent' | 'glow-secondary' | 'danger'
929
945
  size="md" // 'sm' | 'md' | 'lg'
930
946
  disabled={false}
947
+ loading={false}
931
948
  onClick={() => {}}
932
949
  type="button" // 'button' | 'submit' | 'reset'
933
950
  className=""
@@ -937,11 +954,13 @@ import { Button } from '7k-design-system/react';
937
954
  ```
938
955
 
939
956
  **CSS classes applied:**
940
- - Base: `.btn-modern`
941
- - Variant: `.btn-modern-{variant}` (e.g., `.btn-modern-primary`)
942
- - Size: `.btn-modern-sm` | `.btn-modern-lg` (md applies no extra class)
943
957
 
944
- **Behavior:** Forwards ref to `<button>`. Combines `className` prop with generated classes.
958
+ - Base: `.btn`
959
+ - Variant: `.btn-{variant}` (e.g., `.btn-primary`)
960
+ - Size: `.btn-sm` | `.btn-lg` (md applies no extra class)
961
+ - Loading: `.btn-loading` when `loading={true}`
962
+
963
+ **Behavior:** Forwards ref to `<button>`. Combines `className` prop with generated classes. Sets `aria-busy` when loading.
945
964
 
946
965
  ### Input
947
966
 
@@ -954,29 +973,194 @@ import { Input } from '7k-design-system/react';
954
973
  disabled={false}
955
974
  value={value}
956
975
  onChange={(value) => setValue(value)} // string callback, not event
976
+ label="Email"
977
+ error="Required"
957
978
  className=""
958
979
  />
959
980
  ```
960
981
 
961
- **CSS class applied:** `.input`
982
+ **CSS classes applied:** `.input`, `.form-group`, `.form-label`, `.field-error`
962
983
 
963
- **Behavior:** Forwards ref to `<input>`. `onChange` receives the raw string value (not an event). All standard HTML input props pass through.
984
+ **Behavior:** Forwards ref to `<input>`. `onChange` receives the raw string value. Renders an associated `<label>` when `label` is provided and wires error text via `aria-describedby`.
964
985
 
965
986
  ### Badge
966
987
 
967
988
  ```typescript
968
989
  import { Badge } from '7k-design-system/react';
969
990
 
970
- <Badge variant="default"> // 'default' | 'success' | 'warning' | 'danger' | 'info' | 'neutral'
991
+ <Badge variant="default" role="status"> // 'default' | 'accent' | 'success' | 'warning' | 'danger' | 'info' | 'neutral'
971
992
  Status
972
993
  </Badge>
973
994
  ```
974
995
 
975
996
  **CSS classes applied:**
997
+
976
998
  - Base: `.badge`
977
999
  - Variant: `.badge-{variant}` (e.g., `.badge-success`)
978
1000
 
979
- **Behavior:** Forwards ref to `<span>`. Children render as text content.
1001
+ **Behavior:** Forwards ref to `<span>`. Renders with `role="status"` by default for accessibility.
1002
+
1003
+ ### Card
1004
+
1005
+ ```typescript
1006
+ import { Card, CardHeader, CardBody } from '7k-design-system/react';
1007
+
1008
+ <Card texture="halftone" hover={true}>
1009
+ <CardHeader>Title</CardHeader>
1010
+ <CardBody>Content</CardBody>
1011
+ </Card>
1012
+ ```
1013
+
1014
+ **CSS classes applied:** `.card`, `.card-halftone` | `.card-scanline` | `.card-noise` | `.card-dots` | `.card-crosshatch`, `.card-header`, `.card-body`
1015
+
1016
+ ### Modal
1017
+
1018
+ ```typescript
1019
+ import { Modal, ModalHeader, ModalFooter } from '7k-design-system/react';
1020
+
1021
+ <Modal open={isOpen} onClose={close} texture="noise" aria-labelledby="modal-title">
1022
+ <ModalHeader>
1023
+ <h2 id="modal-title">Modal Title</h2>
1024
+ </ModalHeader>
1025
+ <p>Modal content</p>
1026
+ <ModalFooter>
1027
+ <Button onClick={close}>Close</Button>
1028
+ </ModalFooter>
1029
+ </Modal>
1030
+ ```
1031
+
1032
+ **CSS classes applied:** `.modal`, `.modal-backdrop`, `.modal-header`, `.modal-footer`, texture variants
1033
+
1034
+ **Behavior:** Renders a fixed backdrop with `role="dialog"`, `aria-modal="true"`, and focus management. Body scroll is locked while open.
1035
+
1036
+ ### Drawer
1037
+
1038
+ ```typescript
1039
+ import { Drawer } from '7k-design-system/react';
1040
+
1041
+ <Drawer open={isOpen} onClose={close} side="right" texture="scanline">
1042
+ Drawer content
1043
+ </Drawer>
1044
+ ```
1045
+
1046
+ **CSS classes applied:** `.drawer`, `.drawer-backdrop`, texture variants
1047
+
1048
+ ### Toast
1049
+
1050
+ ```typescript
1051
+ import { Toast } from '7k-design-system/react';
1052
+
1053
+ <Toast variant="success" onDismiss={dismiss} role="status">
1054
+ Operation completed
1055
+ </Toast>
1056
+ ```
1057
+
1058
+ **CSS classes applied:** `.toast`, `.toast-success` | `.toast-error` | `.toast-warning`, `.toast-icon`, `.toast-dismiss`
1059
+
1060
+ ### Tooltip
1061
+
1062
+ ```typescript
1063
+ import { Tooltip } from '7k-design-system/react';
1064
+
1065
+ <Tooltip content="Helper text" position="top">
1066
+ <Button>Hover me</Button>
1067
+ </Tooltip>
1068
+ ```
1069
+
1070
+ **CSS classes applied:** `.tooltip`, `.tooltip-trigger`
1071
+
1072
+ ### Alert
1073
+
1074
+ ```typescript
1075
+ import { Alert } from '7k-design-system/react';
1076
+
1077
+ <Alert variant="warning" onClose={close}>
1078
+ Please review your settings
1079
+ </Alert>
1080
+ ```
1081
+
1082
+ **CSS classes applied:** `.alert`, `.alert-success` | `.alert-warning` | `.alert-danger` | `.alert-info`
1083
+
1084
+ ### Tabs
1085
+
1086
+ ```typescript
1087
+ import { Tabs, TabList, Tab, TabPanel } from '7k-design-system/react';
1088
+
1089
+ <Tabs defaultIndex={0}>
1090
+ <TabList>
1091
+ <Tab index={0}>First</Tab>
1092
+ <Tab index={1}>Second</Tab>
1093
+ </TabList>
1094
+ <TabPanel index={0}>Panel 1</TabPanel>
1095
+ <TabPanel index={1}>Panel 2</TabPanel>
1096
+ </Tabs>
1097
+ ```
1098
+
1099
+ **CSS classes applied:** `.tabs`, `.tab-list`, `.tab`, `.tab-panel`
1100
+
1101
+ ### Nav
1102
+
1103
+ ```typescript
1104
+ import { Nav, NavItem } from '7k-design-system/react';
1105
+
1106
+ <Nav orientation="horizontal">
1107
+ <NavItem href="/" active>Home</NavItem>
1108
+ <NavItem href="/about">About</NavItem>
1109
+ </Nav>
1110
+ ```
1111
+
1112
+ **CSS classes applied:** `.nav`, `.nav-horizontal` | `.nav-vertical`, `.nav-item`
1113
+
1114
+ ### Checkbox, Radio, Toggle
1115
+
1116
+ ```typescript
1117
+ import { Checkbox, Radio, Toggle } from '7k-design-system/react';
1118
+
1119
+ <Checkbox label="Accept terms" />
1120
+ <Radio label="Option A" name="group" />
1121
+ <Toggle label="Enable notifications" checked={on} onChange={setOn} />
1122
+ ```
1123
+
1124
+ **CSS classes applied:** `.checkbox`, `.radio`, `.toggle`
1125
+
1126
+ ### Select & Textarea
1127
+
1128
+ ```typescript
1129
+ import { Select, Textarea } from '7k-design-system/react';
1130
+
1131
+ <Select>
1132
+ <option>One</option>
1133
+ <option>Two</option>
1134
+ </Select>
1135
+
1136
+ <Textarea rows={4} />
1137
+ ```
1138
+
1139
+ **CSS classes applied:** `.select-native`, `.textarea`
1140
+
1141
+ ### TextureOverlay
1142
+
1143
+ ```typescript
1144
+ import { TextureOverlay } from '7k-design-system/react';
1145
+
1146
+ <TextureOverlay texture="halftone" animate>
1147
+ <section>Content</section>
1148
+ </TextureOverlay>
1149
+ ```
1150
+
1151
+ **CSS classes applied:** `.texture-halftone`, `.texture-animated`
1152
+
1153
+ ### IsometricBackground
1154
+
1155
+ ```typescript
1156
+ import { IsometricBackground } from '7k-design-system/react';
1157
+
1158
+ <IsometricBackground pattern="grid" animated>
1159
+ <section>Hero content</section>
1160
+ </IsometricBackground>
1161
+ ```
1162
+
1163
+ **CSS classes applied:** `.isometric-grid`, `.isometric-grid-animated`
980
1164
 
981
1165
  ### ThemeToggle
982
1166
 
@@ -986,7 +1170,7 @@ import { ThemeToggle } from '7k-design-system/react';
986
1170
  <ThemeToggle className="" />
987
1171
  ```
988
1172
 
989
- **Behavior:** Renders a 32×32 square button with `☀` / `☾` icon. Uses `useTheme()` internally. Calls `toggleTheme()` on click. Sets `data-theme` attribute on `<html>` and persists to `localStorage` under key `7k-theme`.
1173
+ **Behavior:** Renders a 32×32 square button with sun/moon icon. Uses `useTheme()` internally. Calls `toggleTheme()` on click. Sets `data-theme` attribute on `<html>` and persists to `localStorage` under key `7k-theme`.
990
1174
 
991
1175
  ### ThemeProvider
992
1176
 
@@ -1002,6 +1186,7 @@ import { ThemeProvider } from '7k-design-system/react';
1002
1186
  ```
1003
1187
 
1004
1188
  **Behavior:**
1189
+
1005
1190
  - On mount: reads `localStorage` for stored theme, falls back to `defaultTheme`
1006
1191
  - On theme change: sets `document.documentElement.setAttribute('data-theme', theme)` and writes to `localStorage`
1007
1192
  - Exposes context value: `{ theme, toggleTheme, setTheme }`
@@ -1015,6 +1200,7 @@ const { theme, toggleTheme, setTheme } = useTheme();
1015
1200
  ```
1016
1201
 
1017
1202
  **Returns:**
1203
+
1018
1204
  - `theme: 'dark' | 'light'` — current active theme
1019
1205
  - `toggleTheme: () => void` — flips dark ↔ light
1020
1206
  - `setTheme: (theme: 'dark' | 'light') => void` — sets explicit theme
@@ -1031,7 +1217,14 @@ interface BaseProps {
1031
1217
  children?: ReactNode;
1032
1218
  }
1033
1219
 
1034
- type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'glow' | 'glow-cyan' | 'glow-grid' | 'danger';
1220
+ type ButtonVariant =
1221
+ | 'primary'
1222
+ | 'secondary'
1223
+ | 'ghost'
1224
+ | 'glow'
1225
+ | 'glow-cyan'
1226
+ | 'glow-grid'
1227
+ | 'danger';
1035
1228
  type ButtonSize = 'sm' | 'md' | 'lg';
1036
1229
  interface ButtonProps extends BaseProps {
1037
1230
  variant?: ButtonVariant;
@@ -1066,18 +1259,18 @@ interface ThemeContextValue {
1066
1259
 
1067
1260
  The CSS is split into 10 source files under `src/css/`, compiled into `dist/7k-design-system.css`. Each file has a single responsibility. Import `src/css/index.css` to load all modules, or import individual modules for tree-shaking.
1068
1261
 
1069
- | File | Size | Responsibility |
1070
- |------|------|---------------|
1071
- | `fonts.css` | ~1.7KB | `@font-face` for Geist Pixel 5 variants; CDN imports for Geist Sans/Mono |
1072
- | `tokens.css` | ~12.5KB | All design tokens: color ramps, semantic roles, typography, spacing, radii, shadows, motion, layout, z-index |
1073
- | `themes.css` | ~7.2KB | Dark default in `:root`; light overrides in `@media (prefers-color-scheme: light)` and `html[data-theme="light"]` |
1074
- | `base.css` | ~7.6KB | CSS reset, body/html base styles, `.mono-label` utility, `.display`/`.h1`–`.h4`/`.body` type utilities |
1075
- | `textures.css` | ~12.4KB | 10 texture categories: scanline, halftone, dot matrix, stripes, crosshatch, checkerboard, noise, vignette |
1076
- | `isometric.css` | ~12.5KB | 11 isometric patterns: grid, cubes, pyramid, hex, pipes, terrain + animation variants |
1077
- | `components.css` | ~36KB | 40+ component classes: buttons, forms, nav, data display, overlays, feedback, media, misc |
1078
- | `modifiers.css` | ~2.2KB | Accent layer modifiers: border-top, underline, dot, bar, glow, corner |
1079
- | `animations.css` | ~15.8KB | 20+ keyframe animations: glitch, flicker, blink, typewriter, neon-pulse, scan-reveal, pixel-fade, iso-float |
1080
- | `accessibility.css` | ~0.6KB | `prefers-reduced-motion` collapse, `:focus-visible` rings, `prefers-contrast` support, screen-reader utilities |
1262
+ | File | Size | Responsibility |
1263
+ | ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
1264
+ | `fonts.css` | ~1.7KB | `@font-face` for Geist Pixel 5 variants; CDN imports for Geist Sans/Mono |
1265
+ | `tokens.css` | ~12.5KB | All design tokens: color ramps, semantic roles, typography, spacing, radii, shadows, motion, layout, z-index |
1266
+ | `themes.css` | ~7.2KB | Dark default in `:root`; light overrides in `@media (prefers-color-scheme: light)` and `html[data-theme="light"]` |
1267
+ | `base.css` | ~7.6KB | CSS reset, body/html base styles, `.mono-label` utility, `.display`/`.h1`–`.h4`/`.body` type utilities |
1268
+ | `textures.css` | ~12.4KB | 10 texture categories: scanline, halftone, dot matrix, stripes, crosshatch, checkerboard, noise, vignette |
1269
+ | `isometric.css` | ~12.5KB | 11 isometric patterns: grid, cubes, pyramid, hex, pipes, terrain + animation variants |
1270
+ | `components.css` | ~36KB | 40+ component classes: buttons, forms, nav, data display, overlays, feedback, media, misc |
1271
+ | `modifiers.css` | ~2.2KB | Accent layer modifiers: border-top, underline, dot, bar, glow, corner |
1272
+ | `animations.css` | ~15.8KB | 20+ keyframe animations: glitch, flicker, blink, typewriter, neon-pulse, scan-reveal, pixel-fade, iso-float |
1273
+ | `accessibility.css` | ~0.6KB | `prefers-reduced-motion` collapse, `:focus-visible` rings, `prefers-contrast` support, screen-reader utilities |
1081
1274
 
1082
1275
  ### PostCSS Pipeline
1083
1276
 
@@ -1093,10 +1286,10 @@ src/css/index.css
1093
1286
  ### Standalone CSS Exports
1094
1287
 
1095
1288
  ```typescript
1096
- import '7k-design-system/css'; // Full bundle (~115KB)
1097
- import '7k-design-system/css/tokens'; // Tokens only (~12KB)
1289
+ import '7k-design-system/css'; // Full bundle (~115KB)
1290
+ import '7k-design-system/css/tokens'; // Tokens only (~12KB)
1098
1291
  import '7k-design-system/css/components'; // Components only (~36KB)
1099
- import '7k-design-system/css/textures'; // Textures only (~12KB)
1292
+ import '7k-design-system/css/textures'; // Textures only (~12KB)
1100
1293
  import '7k-design-system/css/animations'; // Animations only (~16KB)
1101
1294
  ```
1102
1295
 
@@ -1105,7 +1298,7 @@ import '7k-design-system/css/animations'; // Animations only (~16KB)
1105
1298
  ```bash
1106
1299
  npm run build:css # Compile CSS bundle + standalone modules
1107
1300
  npm run build:react # Compile React ESM + CJS + .d.ts
1108
- npm run build:copy-assets # Copy preview/, fonts/, build/ to dist/
1301
+ npm run build:copy-assets # Copy fonts/ and build/ to dist/
1109
1302
  npm run build # Run all three build steps
1110
1303
  ```
1111
1304
 
@@ -1116,16 +1309,17 @@ npm run build # Run all three build steps
1116
1309
  Location: `tests/`
1117
1310
  Runner: Vitest + jsdom + @testing-library/react + jest-axe
1118
1311
 
1119
- | File | Coverage |
1120
- |------|----------|
1121
- | `Button.test.tsx` | Rendering, variant/size classes, click handler, disabled state |
1122
- | `Input.test.tsx` | Rendering, value/onChange callback, disabled state, placeholder |
1123
- | `Badge.test.tsx` | Rendering, variant classes, children content |
1312
+ | File | Coverage |
1313
+ | ------------------------ | --------------------------------------------------------------- |
1314
+ | `Button.test.tsx` | Rendering, variant/size classes, click handler, disabled state |
1315
+ | `Input.test.tsx` | Rendering, value/onChange callback, disabled state, placeholder |
1316
+ | `Badge.test.tsx` | Rendering, variant classes, children content |
1124
1317
  | `ThemeProvider.test.tsx` | Default theme, localStorage persistence, `data-theme` attribute |
1125
- | `ThemeToggle.test.tsx` | Click toggles theme, icon changes, aria-label updates |
1126
- | `a11y.test.tsx` | axe-core accessibility checks on Button, Input, Badge |
1318
+ | `ThemeToggle.test.tsx` | Click toggles theme, icon changes, aria-label updates |
1319
+ | `a11y.test.tsx` | axe-core accessibility checks on Button, Input, Badge |
1127
1320
 
1128
1321
  **Run tests:**
1322
+
1129
1323
  ```bash
1130
1324
  npm test # Unit tests
1131
1325
  npm run test:a11y # Accessibility tests
@@ -1137,36 +1331,34 @@ npm run test:watch # Watch mode
1137
1331
  Location: `src/stories/`
1138
1332
  Port: 6006
1139
1333
 
1140
- | Story | Content |
1141
- |-------|---------|
1142
- | `Design System/Overview` (`Overview.mdx`) | Design principles, color palette, usage examples |
1143
- | `Design System/Tokens` (`Tokens.mdx`) | Token reference tables |
1144
- | `Components/Button` (`Components.stories.tsx`) | All Button variants and sizes |
1145
- | `Components/Input` (`Components.stories.tsx`) | Input states |
1146
- | `Components/Badge` (`Components.stories.tsx`) | Badge variants |
1147
- | `Components/ThemeToggle` (`Components.stories.tsx`) | Theme toggle button |
1148
- | `Textures/All` (`Textures.stories.tsx`) | All 10 texture patterns |
1149
- | `Textures/Isometric` (`Textures.stories.tsx`) | All 11 isometric patterns |
1334
+ | Story | Content |
1335
+ | ---------------------------------------------------- | ------------------------------------------------ |
1336
+ | `Design System/Overview` (`Overview.mdx`) | Design principles, color palette, usage examples |
1337
+ | `Design System/Tokens` (`Tokens.mdx`) | Token reference tables |
1338
+ | `Components/Button` (`Components.stories.tsx`) | All Button variants and sizes |
1339
+ | `Components/TexturedButtons` | Textured button variants |
1340
+ | `Components/Inputs` (`Components.stories.tsx`) | Input states |
1341
+ | `Components/Badges` (`Components.stories.tsx`) | Badge variants |
1342
+ | `Components/Cards` (`Components.stories.tsx`) | Card styles and textures |
1343
+ | `Components/TexturedCards` | Textured card variants |
1344
+ | `Components/Navigation` (`Components.stories.tsx`) | Nav patterns |
1345
+ | `Components/Alerts` (`Components.stories.tsx`) | Alert variants |
1346
+ | `Components/Toasts` (`Components.stories.tsx`) | Toast variants |
1347
+ | `Components/FormControls` (`Components.stories.tsx`) | Checkbox, radio, toggle |
1348
+ | `Components/ThemeToggle` (`Components.stories.tsx`) | Theme toggle button |
1349
+ | `Textures/All` (`Textures.stories.tsx`) | All texture patterns |
1350
+ | `Textures/Isometric` (`Textures.stories.tsx`) | Isometric patterns |
1351
+ | `Textures/IsometricAnimated` | Animated isometric backgrounds |
1150
1352
 
1151
1353
  **Run Storybook:**
1354
+
1152
1355
  ```bash
1153
1356
  npm run storybook # Dev server at http://localhost:6006
1154
1357
  npm run build-storybook # Static build for deployment
1155
1358
  npm run chromatic # Visual regression testing
1156
1359
  ```
1157
1360
 
1158
- ### Preview HTML Cards
1159
-
1160
- Location: `preview/` (copied to `dist/preview/` on build)
1161
-
1162
- | File | Purpose |
1163
- |------|---------|
1164
- | `colors-primary.html` | Accent swatches, ramps, project overrides |
1165
- | `typography-specimens.html` | Type scale + weights + pixel variants |
1166
- | `spacing-tokens.html` | 4px grid, radii, shadows |
1167
- | `components-buttons.html` | Product component states |
1168
- | `textures-backgrounds.html` | 10 background texture categories with composition demos |
1169
- | `brand-assets.html` | Logo variants + brand in context |
1361
+ > **Note:** Preview HTML cards were removed in favor of Storybook as the canonical preview surface.
1170
1362
 
1171
1363
  ## 11. Voice & Brand
1172
1364
 
@@ -1175,7 +1367,7 @@ Location: `preview/` (copied to `dist/preview/` on build)
1175
1367
  - **Tone**: Direct, technical, slightly playful. "Built for midnight."
1176
1368
  - **Capitalization**: Sentence case for headings, uppercase only for kickers/labels
1177
1369
  - **Company**: 7K (always uppercase with the numeral). Child projects: "7K Project Neon"
1178
- - **Logo**: Star-burst pattern SVG in `build/logo-7k.svg` with #FF0FF brand accent tones. Light variant at `build/logo-7k-light.svg` (black polygons for light backgrounds). App icon at `build/icon.svg`.
1370
+ - **Logo**: Star-burst pattern SVG in `build/logos/logo-7k.svg` with #FF0FF brand accent tones. Light variant at `build/logos/logo-7k-light.svg` (black polygons for light backgrounds). App icon at `build/icons/icon.svg`.
1179
1371
  - **Terminology**: "Surface" for pages, "module" for components, "canvas" for background
1180
1372
  - **No filler**: never use "streamlined", "innovative", "leveraging" unless literal
1181
1373
  - **Error messages**: direct, no "oops". "Connection failed. Retry." not "Something went wrong."
@@ -1184,24 +1376,24 @@ Location: `preview/` (copied to `dist/preview/` on build)
1184
1376
 
1185
1377
  **Source context reference:** Each anti-pattern below derives from a specific brief constraint: dark theme (no warm backgrounds), three-font system kept to Geist family only, 1-bit influence (no rounded corners on 1-bit elements), neon Tokyo (no generic purple gradients), brand-color-only accent (no color proliferation).
1186
1378
 
1187
- | Anti-pattern | Why |
1188
- |---|---|
1189
- | Warm beige/cream/peach backgrounds | System is dark-first; light theme is precise white |
1190
- | Multiple font families outside the system | Three fonts only: Geist (sans), Geist Mono, Geist Pixel (5 variants). No other families. |
1191
- | Over-rounded everything | Sharp 0px or subtle 4px preferred |
1192
- | Gradient overload | Max one gradient per page; no full-page gradient backgrounds |
1193
- | Emoji iconography | Use CSS/SVG instead |
1194
- | Drop shadows on text | Use high-contrast fg instead |
1195
- | Stock photography | Use 1-bit halftone texture library |
1196
- | Generic purple/violet gradients | Accent is magenta (#FF0FF), not purple |
1197
- | Invented metrics/fake stats | Use real data or grey stubs |
1198
- | Circular spinners on 1-bit elements | Spinner is square — never mix circular |
1199
- | Rounded checkboxes/radios | One-bit form controls are square |
1200
- | Blurred drop shadows on 1-bit components | Shadow is a hard offset, not a blur |
1201
- | SVG humans / scenery / illustrations | 1-bit means abstract texture, not hand-drawn |
1202
- | Glitch as a continuous loop | Glitch is a 2–3 iteration burst |
1203
- | Warm/beige tones anywhere | System is nocturnal dark + neon |
1204
- | Multiple textures on the same section layer | Max one background + one overlay per section |
1205
- | Continuous animation on UI surfaces | Ambient animations are for hero/landing sections only |
1206
- | Isometric animation on interactive UI | Isometric bg + motion is for hero/splash sections only; never on cards, buttons, or form controls |
1207
- | Mixing 1-bit button patterns into product surfaces | Use the modern button system (.btn-modern*) for all product surfaces. 1-bit button classes (.btn, .btn-primary, .btn-accent) are removed — do not reintroduce raw invert-hover buttons in place of modern neon buttons. |
1379
+ | Anti-pattern | Why |
1380
+ | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
1381
+ | Warm beige/cream/peach backgrounds | System is dark-first; light theme is precise white |
1382
+ | Multiple font families outside the system | Three fonts only: Geist (sans), Geist Mono, Geist Pixel (5 variants). No other families. |
1383
+ | Over-rounded everything | Sharp 0px or subtle 4px preferred |
1384
+ | Gradient overload | Max one gradient per page; no full-page gradient backgrounds |
1385
+ | Emoji iconography | Use CSS/SVG instead |
1386
+ | Drop shadows on text | Use high-contrast fg instead |
1387
+ | Stock photography | Use 1-bit halftone texture library |
1388
+ | Generic purple/violet gradients | Accent is magenta (#FF0FF), not purple |
1389
+ | Invented metrics/fake stats | Use real data or grey stubs |
1390
+ | Circular spinners on 1-bit elements | Spinner is square — never mix circular |
1391
+ | Rounded checkboxes/radios | One-bit form controls are square |
1392
+ | Blurred drop shadows on 1-bit components | Shadow is a hard offset, not a blur |
1393
+ | SVG humans / scenery / illustrations | 1-bit means abstract texture, not hand-drawn |
1394
+ | Glitch as a continuous loop | Glitch is a 2–3 iteration burst |
1395
+ | Warm/beige tones anywhere | System is nocturnal dark + neon |
1396
+ | Multiple textures on the same section layer | Max one background + one overlay per section |
1397
+ | Continuous animation on UI surfaces | Ambient animations are for hero/landing sections only |
1398
+ | Isometric animation on interactive UI | Isometric bg + motion is for hero/splash sections only; never on cards, buttons, or form controls |
1399
+ | Mixing 1-bit button patterns into product surfaces | Use the modern button system (.btn\*) for all product surfaces. 1-bit button classes (.btn, .btn-primary, .btn-accent) are removed — do not reintroduce raw invert-hover buttons in place of modern neon buttons. |