@nadicodeai/design-system 0.5.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -14,7 +14,7 @@ Plain imperatives are the default. The few hard prohibitions below use `never`/`
14
14
  - Preserve approved `DESIGN.md` token and component families unless the user explicitly approves a palette/component migration. Website/kernel CSS is implementation evidence, not the complete palette authority; never delete tokens because current prototypes do not use them or because `@google/design.md lint` reports them as unused.
15
15
  - Name implemented grids, components, modules, and page elements as NadicodeAI-owned primitives; source brands such as Vercel or Attio may appear only in reference notes, never in component names, CSS comments, `data-module` values, or public-facing contracts.
16
16
  - Calculate page grids, module spans, seams, borders, and element placement from explicit grid math; never hand-place visual structure by eye.
17
- - Author CSS-bundle work as a reusable design-system component architecture first, not as showcase/page-specific code. The design-system CSS lives in `src/css/` (`tokens.generated` [built from `DESIGN.md`] + `tokens.local` [hand-authored] / `reset`/`foundation`/`motion`/`layout`/`primitives` + `components/*`, mirrored to `dist/css/` and exported as `@nadicodeai/design-system/css`). Since the Tailwind+shadcn migration (ADR 0007) the bundle ships only framework-agnostic brand/display CSS components: the cascade is `@layer tokens, reset, foundation, motion, layout, primitives, components;` (no `sections` layer), and `components/*` holds the agent-chat CSS component family, the run-state `state-tag` family, and `image` — the generic marketing/SaaS component CSS and the whole `sections/*` layer retired to React shadcn components in `@nadicodeai/ui`. The delivery tiers map to real authoring homes: tokens → `tokens.generated`/`tokens.local`; page grammar → `layout.css`; CSS primitives/components → `primitives.css` + `components/*`; specimens → `examples/`. Contracted CSS components are paired with `DESIGN.md components:` entries; the three named CSS-internal components are deliberate no-token exceptions. Pages, site-specific page assemblies, and the standard/interactive/section UI belong to consuming surfaces (`../website/`, `../portal/`, sibling Nadia apps) and to the React package (`@nadicodeai/ui`), not this package. Study current source HTML/CSS for approved external references before implementing similar NadicodeAI primitives, then adapt the structure into NadicodeAI-owned tokens, primitives, and components. Specimen HTML demonstrates only already-defined primitives/components; it never invents component geometry, seams, borders, fillers, heights, or responsive behavior inline. The generated token layer (`tokens.generated.css`) and the Tailwind adapter (`nadicode.theme.css`) are emitted by Style Dictionary (`scripts/sd/`, driven from `scripts/build.ts`) as a complete projection of the `@google/design.md` export — never an allowlist or subset; responsive `@media` switching and composed/`calc` vars live in `layout.css`/`tokens.local.css` and reference emitted `--nc-*` tokens only, while the `.nc-type-*` utility classes live in `foundation.css`. Emitted-but-unreferenced tokens are intentional (the contract drives emission, not consumption), and the generated Tailwind adapter owns standard shadcn role maps for both `:root` and `.dark` using generated `--color-*`/`--radius-*` references, plus a small set of `--nc-*` remaps in the `.dark` block (the `state-*`, `selection-*`, and `cross` families → their `--nc-dark-*` counterparts) so design-system CSS components that read those raw brand tokens directly flip on the dark console; `@nadicodeai/ui/globals.css` keeps the Tailwind role bridge plus UI-local product aliases. Correctness is enforced by export-derived structural parity (`tests/token-structural-parity.test.ts` for the `--nc-*` layer; the per-token `@theme` value loops and light/dark role-integrity checks in `tests/tailwind-v4-theme.test.ts` for the adapter), the narrowed two-way parity between `DESIGN.md` component YAML/prose and the retained CSS component surface (`tests/components-yaml-matches-css.test.ts`, ADR 0007 D4), plus consumer discipline (`tests/consumer-css-discipline.test.ts`), not a byte snapshot (ADR 0006 supersedes ADR 0005 D1–D3/D5; ADR 0008 supersedes ADR 0005 D4).
17
+ - Author CSS-bundle work as a reusable design-system component architecture first, not as showcase/page-specific code. The design-system CSS lives in `src/css/` (`tokens.generated` [built from `DESIGN.md`] + `tokens.local` [hand-authored] / `reset`/`foundation`/`motion`/`layout`/`primitives` + `components/*`, mirrored to `dist/css/` and exported as `@nadicodeai/design-system/css`). Since the Tailwind+shadcn migration (ADR 0007) the bundle ships only framework-agnostic brand/display CSS components: the cascade is `@layer tokens, reset, foundation, motion, layout, primitives, components;` (no `sections` layer), and `components/*` holds the agent-chat CSS component family, the run-state `state-tag` family, and `image` — the generic marketing/SaaS component CSS and the whole `sections/*` layer retired to React shadcn components in `@nadicodeai/ui`. The delivery tiers map to real authoring homes: tokens → `tokens.generated`/`tokens.local`; page grammar → `layout.css`; CSS primitives/components → `primitives.css` + `components/*`; specimens → `examples/`. Contracted CSS components are paired with `DESIGN.md components:` entries; the three named CSS-internal components are deliberate no-token exceptions. Pages, site-specific page assemblies, and the standard/interactive/section UI belong to consuming surfaces (`../website/`, `../portal/`, sibling Nadia apps) and to the React package (`@nadicodeai/ui`), not this package. Study current source HTML/CSS for approved external references before implementing similar NadicodeAI primitives, then adapt the structure into NadicodeAI-owned tokens, primitives, and components. Specimen HTML demonstrates only already-defined primitives/components; it never invents component geometry, seams, borders, fillers, heights, or responsive behavior inline. The generated token layer (`tokens.generated.css`) and the Tailwind adapter (`nadicode.theme.css`) are emitted by Style Dictionary (`scripts/sd/`, driven from `scripts/build.ts`) as a complete projection of the `@google/design.md` export — never an allowlist or subset; responsive `@media` switching and composed/`calc` vars live in `layout.css`/`tokens.local.css` and reference emitted `--nc-*` tokens only, while the `.nc-type-*` utility classes live in `foundation.css`. Emitted-but-unreferenced tokens are intentional (the contract drives emission, not consumption), and the generated Tailwind adapter owns standard shadcn role maps for both `:root` and `.dark` using generated `--color-*`/`--radius-*` references, plus a small set of `--nc-*` remaps in the `.dark` block (the `state-*`, `selection-*`, and `cross` families → their `--nc-dark-*` counterparts) so design-system CSS components that read those raw brand tokens directly flip on the dark console; `@nadicodeai/ui/globals.css` keeps the Tailwind role bridge plus UI-local product aliases. Correctness is enforced by export-derived structural parity (`tests/guards/token-structural-parity.test.ts` for the `--nc-*` layer; the per-token `@theme` value loops and light/dark role-integrity checks in `tests/guards/tailwind-v4-theme.test.ts` for the adapter), the narrowed two-way parity between `DESIGN.md` component YAML/prose and the retained CSS component surface (`tests/guards/components-yaml-matches-css.test.ts`, ADR 0007 D4), plus consumer discipline (`tests/guards/consumer-css-discipline.test.ts`), not a byte snapshot (ADR 0006 supersedes ADR 0005 D1–D3/D5; ADR 0008 supersedes ADR 0005 D4).
18
18
  - Follow a source-first reference workflow for external visual references: inspect live/source DOM, stylesheet/CSSOM rules, inline styles, custom properties, computed styles, grid tracks, spans, seam ownership, colors, heights, and breakpoints before writing NadicodeAI code. Screenshots are verification evidence only after implementation; never use them as the source for authoring structure, geometry, or CSS.
19
19
  - Never derive reusable kernel geometry from screenshots, eyeballing, one-off browser coordinates, or local patch experiments. Browser measurements may verify an implementation after the source CSS/DOM model is understood, but they do not replace reading the source rules that create the behavior.
20
20
  - Map every imported visual behavior to either `DESIGN.md`, an existing kernel token/primitive, or an explicit user-approved change before implementation. If the reference leaves a required decision open, or if `DESIGN.md` does not decide it, ask before coding the missing decision, including height/row span, surface color, visual payload, content slots, crosshair placement, and responsive behavior.
@@ -32,21 +32,21 @@ Generated-artifact and runtime-JS prohibitions live in the Forbidden Patterns ta
32
32
  - Treat `dist/tokens/nadicode.dtcg.json` and `dist/tailwind/nadicode.tailwind.json` as generated, tracked consumer artifacts.
33
33
  - Treat `src/assets/` as the source for exported brand SVG assets.
34
34
  - Treat `dist/icons/` as a generated icon set baked from the pinned `lucide-static` dependency by `npm run generate:icons` (also run inside `npm run build`) and exported via `./icons/*`; regenerate by bumping `lucide-static`, never hand-edit.
35
- - Treat `../docs/experiments/**` as the archived `design-canvas/` prototype source-of-record (the chat-motion/component prototypes that `src/css/motion.css`, `src/js/chat-autoplay.js`, and `tests/chat-showcase.test.ts` re-express); never treat it as the package build, runtime component surface, or normative brand contract.
35
+ - The `design-canvas/` prototypes that `src/css/motion.css`, `src/js/chat-autoplay.js`, and `tests/guards/chat-showcase.test.ts` re-express are deleted from the tree; git history retains them under docs/experiments/design-canvas/. The kernel CSS and its tests are the living expression — never reconstruct the prototypes as a build, runtime component surface, or normative brand contract.
36
36
  - Any change to package-consumed output (`DESIGN.md`, generated tokens, CSS bundle, Tailwind theme output, package exports, assets, package docs, or agent instructions) must end with an explicit npm release decision before handoff — enforced by the pre-push release gate: bump the version (merge then auto-publishes; see `../docs/agents/npm-publishing.md`) or mark a commit `[no-publish]`. If the change should reach external consumers, bump `@nadicodeai/design-system` and run `npm pack --dry-run -w @nadicodeai/design-system`. When `@nadicodeai/ui` consumes the changed output, publish `@nadicodeai/design-system` first, then bump/update/publish `@nadicodeai/ui`. Never claim the package is shipped to npm until `npm view @nadicodeai/design-system version` reports the intended version.
37
37
 
38
38
  ## Task Routing
39
39
 
40
40
  | Task | Read first | Then read | Verify |
41
41
  | --- | --- | --- | --- |
42
- | Design token, contract, or token-pipeline change | `DESIGN.md`, `scripts/sd/config.ts`, `scripts/sd/transforms.ts`, `scripts/sd/format-token-layer.ts`, `scripts/sd/format-tailwind-v4-theme.ts` | `npm exec -- design.md spec`, `scripts/build.ts`, `tests/token-structural-parity.test.ts`, `tests/consumer-css-discipline.test.ts`, `tests/tailwind-v4-theme.test.ts` | `npm run lint:design && npm run build && npm run test` |
43
- | Kernel geometry or component work | `DESIGN.md` Layout and Components | `src/css/index.css`, `src/css/layout.css`, `src/css/primitives.css`, `src/css/components/*.css`, `src/css/motion.css`, `tests/kernel-css-architecture.test.ts`, `tests/kernel-rendered-geometry.test.ts` | from design-system/: `npx vitest run tests/kernel-css-architecture.test.ts tests/kernel-rendered-geometry.test.ts` |
44
- | CSS component or `examples/` specimen work | `DESIGN.md` Layout and Components | `src/css/components/`, `examples/`, `../skills/nadicodeai-brand-copy/SKILL.md`, `../skills/nadicodeai-brand-copy/references/writing-craft.md`, `../skills/nadicodeai-brand-copy/references/brand-voice-profile.md`, `../skills/nadicodeai-brand-copy/references/voice-examples.md` | `npm run test -- tests/examples-package-coherence.test.ts` |
45
- | Package consumption or export surface | `README.md` | `package.json`, `scripts/build.ts`, `dist/tailwind/`, `dist/tokens/` | `npm run build && npm run test -- tests/build-produces-exports.test.ts tests/tailwind-v4-theme.test.ts` |
42
+ | Design token, contract, or token-pipeline change | `DESIGN.md`, `scripts/sd/config.ts`, `scripts/sd/transforms.ts`, `scripts/sd/format-token-layer.ts`, `scripts/sd/format-tailwind-v4-theme.ts` | `npm exec --package=@google/design.md -- design.md spec`, `scripts/build.ts`, `tests/guards/token-structural-parity.test.ts`, `tests/guards/consumer-css-discipline.test.ts`, `tests/guards/tailwind-v4-theme.test.ts` | `npm run lint:design && npm run build && npm run test` |
43
+ | Kernel geometry or component work | `DESIGN.md` Layout and Components | `src/css/index.css`, `src/css/layout.css`, `src/css/primitives.css`, `src/css/components/*.css`, `src/css/motion.css`, `tests/guards/kernel-css-architecture.test.ts`, `tests/guards/kernel-rendered-geometry.test.ts` | from design-system/: `npx vitest run tests/guards/kernel-css-architecture.test.ts tests/guards/kernel-rendered-geometry.test.ts` |
44
+ | CSS component or `examples/` specimen work | `DESIGN.md` Layout and Components | `src/css/components/`, `examples/`, `../skills/nadicodeai-brand-copy/SKILL.md`, `../skills/nadicodeai-brand-copy/references/writing-craft.md`, `../skills/nadicodeai-brand-copy/references/brand-voice-profile.md`, `../skills/nadicodeai-brand-copy/references/voice-examples.md` | `npm run test -- tests/guards/examples-package-coherence.test.ts` |
45
+ | Package consumption or export surface | `README.md` | `package.json`, `scripts/build.ts`, `dist/tailwind/`, `dist/tokens/` | `npm run build && npm run test -- tests/guards/build-produces-exports.test.ts tests/guards/tailwind-v4-theme.test.ts` |
46
46
 
47
47
  ## DESIGN.md Authoring
48
48
 
49
- - Check `npm exec -- design.md spec` before adding or changing YAML front matter fields.
49
+ - Check `npm exec --package=@google/design.md -- design.md spec` before adding or changing YAML front matter fields.
50
50
  - Put exact reusable values in YAML when they should export through `npm run build`: colors, typography, rounded, spacing, and component fields listed by the current spec.
51
51
  - Put application guidance in prose when it describes how to use values: borders, gradients, grid placement, motion, state behavior, responsive composition, markup shape, and accessibility.
52
52
  - Keep component identity paired inside `## Components`: every named YAML `components:` entry needs a matching Markdown `**\`component-name\`**` entry in the Components section, and every Markdown component entry in that section needs a matching YAML `components:` entry. YAML carries machine-readable component style hooks; Markdown carries usage, variants, constraints, and judgment.
@@ -89,7 +89,7 @@ Before claiming work complete (from this directory, or with `-w design-system` f
89
89
  npm run lint:design && npm run build && npm run test
90
90
  ```
91
91
 
92
- `npm run test` MUST stay browser-free: browser-driven tests live in `tests/**/*.visual.ts` (outside the default `*.test.ts` glob) and run only via `npm run test:visual`. Never add a browser test to the default suite — parallel headless sessions inside the gate are what orphaned Chrome and hung it; that is the real constraint, not `agent-browser` itself.
92
+ `npm run test` MUST stay browser-free: browser-driven tests live in `tests/visual/*.visual.ts` (outside the default `*.test.ts` glob) and run only via `npm run test:visual`. Never add a browser test to the default suite — parallel headless sessions inside the gate are what orphaned Chrome and hung it; that is the real constraint, not `agent-browser` itself.
93
93
 
94
94
  For a visual check, agents use the workspace-local `agent-browser` package (`npm exec -w design-system -- agent-browser ...` from the repo root, or `npm exec -- agent-browser ...` from this directory): open the rendered page, save a screenshot into the ignored evidence folder (`../tmp/visual-evidence/`), inspect it, confirm it looks right, and **close the session** so no Chrome daemon is left running. Run these checks **sequentially, one page at a time** — never as a parallel suite. The repo-level `agent-browser.json` and this directory's `agent-browser.json` set the idle timeout for ad hoc commands, but explicit close is still required. The screenshots persist in `../tmp/visual-evidence/` as evidence for the operator to review.
95
95
 
@@ -104,11 +104,10 @@ For a visual check, agents use the workspace-local `agent-browser` package (`npm
104
104
  | `scripts/build.ts` | Exports DTCG + Tailwind tokens from `DESIGN.md`, runs the Style Dictionary build for the CSS token layer + Tailwind v4 theme, generates the icon set, then mirrors `dist/css` |
105
105
  | `scripts/sd/` | Style Dictionary build: `config.ts` (entrypoints), `transforms.ts` (`name/nc`/`color/nc-hex`/`dimension/nc-px` + FORK-A line-height), `format-token-layer.ts` (OUTPUT 1), `format-tailwind-v4-theme.ts` (OUTPUT 2). See ADR 0006 |
106
106
  | `scripts/generate-icons.ts` | Bakes the NadicodeAI icon set into `dist/icons/` from the pinned `lucide-static` dependency |
107
- | `tests/` | Vitest gate for design lint, build exports, and accepted repo-local validators |
107
+ | `tests/` | Vitest suites, foldered per ADR 0011: `guards/` (the package-spanning gate design lint, build exports, accepted repo-local validators), `visual/` (opt-in browser suite), `global-setup.ts`. Unit tests for build modules sit beside them in `scripts/` |
108
108
  | `agent-browser.json` | Project-level timeout defaults for workspace-local `agent-browser` visual checks |
109
109
  | `src/assets/` | Package logo SVG exports |
110
110
  | `dist/` | Generated token exports tracked for package consumers |
111
111
  | `dist/icons/` | Generated Lucide-derived icon set, exported via `./icons/*` |
112
112
  | `../docs/adr/` | Decision records (ADR 0005/0006 govern the token pipeline) |
113
- | `../docs/experiments/` | Archived `design-canvas/` prototype source-of-record for the kernel chat motion and CSS components |
114
113
  | `src/css/motion.css` | The brand motion contract: register, the four moves, craft rules, banned moves — read before any animation work |
package/DESIGN.md CHANGED
@@ -3,13 +3,17 @@ version: alpha
3
3
  name: NadicodeAI Design System
4
4
  description: >-
5
5
  Reusable design-system contract for NadicodeAI: engineered page geometry,
6
- neutral high-contrast surfaces, AI-agent work artifacts, and strict
7
- 12-column/10-column composition rules for the public website and package
8
- token exports.
6
+ neutral high-contrast product surfaces, AI-agent work artifacts, strict
7
+ 12-column/10-column public-page composition, and the package token exports
8
+ shared by every NadicodeAI interface.
9
9
 
10
10
  colors:
11
11
  primary: "#008c45"
12
12
  on-primary: "#ffffff"
13
+ action: "#007a3c"
14
+ action-foreground: "#ffffff"
15
+ action-hover: "#00602f"
16
+ action-active: "#00301a"
13
17
  ink: "#171717"
14
18
  body: "#4d4d4d"
15
19
  muted: "#888888"
@@ -17,8 +21,11 @@ colors:
17
21
  canvas-soft: "#fafafa"
18
22
  canvas-soft-2: "#f5f5f5"
19
23
  line: "#e5e5e5"
24
+ input: "#8f8f8f"
20
25
  seam: "#e4e7ec"
21
26
  cross: "#a1a1a1"
27
+ focus-ring: "#007a3c"
28
+ scrim: "#171717"
22
29
  link: "#007a3c"
23
30
  link-deep: "#00602f"
24
31
  link-bg-soft: "#d9f6e4"
@@ -123,9 +130,15 @@ colors:
123
130
  dark-seam: "#1f1f1f"
124
131
  dark-primary: "#ededed"
125
132
  dark-on-primary: "#0a0a0a"
133
+ dark-action: "#ededed"
134
+ dark-action-foreground: "#0a0a0a"
135
+ dark-action-hover: "#d4d4d4"
136
+ dark-action-active: "#a3a3a3"
126
137
  dark-link: "#9fe6bc"
127
138
  dark-link-deep: "#c3f0d4"
128
139
  dark-link-bg-soft: "#00301a"
140
+ dark-focus-ring: "#9fe6bc"
141
+ dark-scrim: "#f5f5f5"
129
142
  dark-error: "#f7b3b5"
130
143
  dark-error-soft: "#4a000e"
131
144
  dark-error-deep: "#fad3d4"
@@ -270,6 +283,8 @@ rounded:
270
283
  md: 6px
271
284
  lg: 8px
272
285
  xl: 10px
286
+ 2xl: 12px
287
+ 3xl: 16px
273
288
  pill-sm: 64px
274
289
  pill: 100px
275
290
  full: 9999px
@@ -289,6 +304,10 @@ spacing:
289
304
  6xl: 128px
290
305
  section: 192px
291
306
  guide: 1px
307
+ focus-ring-width: 3px
308
+ control-height: 32px
309
+ control-padding-inline: 10px
310
+ touch-target: 44px
292
311
  page-pad: 24px
293
312
  page-max-mobile: 448px
294
313
  page-max-tablet: 624px
@@ -369,7 +388,7 @@ components:
369
388
  backgroundColor: "{colors.canvas-soft}"
370
389
  textColor: "{colors.body}"
371
390
  typography: "{typography.caption}"
372
- rounded: "{rounded.full}"
391
+ rounded: "{rounded.md}"
373
392
  padding: "0px {spacing.xs}"
374
393
  filter-chip:
375
394
  backgroundColor: "{colors.canvas-soft}"
@@ -502,9 +521,12 @@ Backgrounds are `{colors.background-100}` (page default, white) and `{colors.bac
502
521
 
503
522
  ### Semantic roles (functional tier)
504
523
 
505
- - **Primary** (`{colors.primary}` = `green-italia-700`): primary actions and primary buttons, always with `{colors.on-primary}` (white) text. Green, not near-black, is now the primary weight; `{colors.ink}` becomes the neutral/secondary button treatment.
506
- - **Canvas / Line / Cross / Seam** (`{colors.canvas}`, `{colors.line}`, `{colors.cross}`, `{colors.seam}`): white content cells, the universal 1 px divider/seam color, the stronger gray for marks and crosshair markers, and the dashed connector guide. `{colors.line}` is the only token used to tune ordinary seam visibility; do not darken borders, gaps, or dividers locally.
507
- - **Body / Muted** (`{colors.body}`, `{colors.muted}`): secondary copy and low-priority labels.
524
+ - **Primary brand anchor** (`{colors.primary}` = `green-italia-700`): identity marks and non-text brand accents. It is not the text-bearing action surface; normal-size white text on this green does not clear AA.
525
+ - **Action** (`{colors.action}`, `{colors.action-foreground}`, `{colors.action-hover}`, `{colors.action-active}`): the text-bearing primary-control family. Shadcn `primary` roles map here rather than to the brand anchor. Dark mode uses the corresponding `dark-action-*` roles.
526
+ - **Canvas / Line / Input / Cross / Seam** (`{colors.canvas}`, `{colors.line}`, `{colors.input}`, `{colors.cross}`, `{colors.seam}`): white content cells, the universal decorative 1 px divider, the stronger resting-control boundary, the stronger gray for marks and crosshair markers, and the dashed connector guide. `{colors.line}` owns ordinary seams; `{colors.input}` owns fields and other interactive boundaries that must clear the 3:1 non-text contrast floor. Never darken a decorative border locally to make it behave like a control.
527
+ - **Body / Muted** (`{colors.body}`, `{colors.muted}`): `{colors.body}` is readable supporting copy; `{colors.muted}` is restricted to disabled, inactive, and placeholder content. Do not use muted text for ordinary descriptions, labels, or help text.
528
+ - **Focus ring** (`{colors.focus-ring}` / `{colors.dark-focus-ring}`): the full-opacity `{spacing.focus-ring-width}` keyboard-focus indicator with no offset. It is independent of the resting border and clears the 3:1 non-text contrast floor against the adjacent canvas.
529
+ - **Scrim** (`{colors.scrim}` / `{colors.dark-scrim}`): the semantic modal-overlay foreground. Its opacity is the generated material token declared in `Elevation & Depth`; it is never combined with backdrop blur.
508
530
  - **Link** (`{colors.link}` = `green-italia-800`, `{colors.link-deep}` = `green-italia-900`, `{colors.link-bg-soft}` = `green-italia-200`): inline links, navigational accents, and approved/example proof states. Intentionally green, keeping the Italian signal without turning the interface into flag decoration.
509
531
  - **Semantic feedback** (`{colors.success}`, `{colors.error}` + `{colors.error-soft}`/`{colors.error-deep}`, `{colors.warning}` + `{colors.warning-soft}`/`{colors.warning-deep}`, `{colors.info}`): validation, caution, approval, and operational feedback. `success` uses `green-italia-700`; `error` uses `red-italia-800` with soft/deep on `red-italia-200`/`red-italia-900`; `warning` uses `amber-600` with soft/deep on `amber-200`/`amber-900`; `info` (`blue-cobalto-700`) is the new informational role.
510
532
  - **Accent** (`{colors.accent}` = `red-italia-700`): UI highlights, badges, and selected markers. Flag red is now an active accent — the former "decoration-only" restriction on flag red is retired. Do not conflate this functional Italia `accent` with the identically-named shadcn surface role `accent`: the latter is a neutral (mapped to `{colors.canvas-soft-2}` in light and `{colors.dark-canvas-soft-2}` in dark) and carries no flag-red hue despite the shared word.
@@ -533,7 +555,7 @@ Four campo rules govern their use:
533
555
 
534
556
  ### Dark primitives
535
557
 
536
- **Dark Primitives** (`{colors.dark-canvas}`, `{colors.dark-ink}`, `{colors.dark-line}`, and siblings) are the source tokens for the generated shadcn `.dark` role map — mode-bearing primitives, not a separate palette; consuming apps opt in by applying a `.dark` ancestor through their runtime theme provider. The dark neutrals (`dark-canvas`, `dark-canvas-soft`, `dark-canvas-soft-2`, `dark-ink`, `dark-body`, `dark-muted`, `dark-line`, `dark-input`, `dark-seam`, `dark-primary`, `dark-on-primary`) are true neutrals: each is a pure gray (equal channels) so the interface carries no ambient tint, and they step in clear elevation planes (`dark-canvas` → `dark-canvas-soft` → `dark-canvas-soft-2`). `dark-input` is the resting text-input boundary, held one gray brighter than the decorative `dark-line` border so a field edge clears non-text contrast before the focus ring appears. Chroma lives only in the intentional accents: the dark semantic ramps ride the same Italia scales as their light counterparts, moved to lighter steps where they are text-bearing — `dark-link`/`dark-link-deep` on `green-italia-400`/`green-italia-300`, `dark-error`/`dark-error-deep` on `red-italia-400`/`red-italia-300`, `dark-warning`/`dark-warning-deep` on `amber-400`/`amber-300`, with the `*-soft` tinted grounds on each scale's `1000` step, plus `dark-success` on `green-italia-500` for the positive-feedback green. The `dark-state-*` workflow family is not a text role; it preserves the matching ready/running/review/blocked/complete rail colors for 3 px state accents while text stays on neutral foreground roles. The remaining dark-ramp members stay true-neutral: `dark-selection-bg`/`dark-selection-fg` invert the light selection (a bright neutral ground with dark text) and `dark-cross` is the visible mark gray, brighter than the decorative `dark-line`. Never reintroduce hue into the neutral set.
558
+ **Dark Primitives** (`{colors.dark-canvas}`, `{colors.dark-ink}`, `{colors.dark-line}`, and siblings) are the source tokens for the generated shadcn `.dark` role map — mode-bearing primitives, not a separate palette; consuming apps opt in by applying a `.dark` ancestor through their runtime theme provider. The dark neutrals (`dark-canvas`, `dark-canvas-soft`, `dark-canvas-soft-2`, `dark-ink`, `dark-body`, `dark-muted`, `dark-line`, `dark-input`, `dark-seam`, `dark-primary`, `dark-on-primary`, `dark-action`, `dark-action-foreground`, `dark-action-hover`, `dark-action-active`, and `dark-scrim`) are true neutrals: each is a pure gray (equal channels) so the interface carries no ambient tint, and they step in clear elevation planes (`dark-canvas` → `dark-canvas-soft` → `dark-canvas-soft-2`). `dark-input` is the resting-control boundary, held one gray brighter than the decorative `dark-line` border so a field edge clears non-text contrast before `{colors.dark-focus-ring}` appears. Chroma lives only in the intentional accents: the dark semantic ramps ride the same Italia scales as their light counterparts, moved to lighter steps where they are text-bearing — `dark-link`/`dark-link-deep` on `green-italia-400`/`green-italia-300`, `dark-error`/`dark-error-deep` on `red-italia-400`/`red-italia-300`, `dark-warning`/`dark-warning-deep` on `amber-400`/`amber-300`, with the `*-soft` tinted grounds on each scale's `1000` step, plus `dark-success` on `green-italia-500` for the positive-feedback green. The `dark-state-*` workflow family is not a text role; it preserves the matching ready/running/review/blocked/complete rail colors for 3 px state accents while text stays on neutral foreground roles. The remaining dark-ramp members stay true-neutral: `dark-selection-bg`/`dark-selection-fg` invert the light selection, `dark-scrim` supplies the modal foreground, and `dark-cross` is the visible mark gray, brighter than the decorative `dark-line`. Never reintroduce hue into the neutral set.
537
559
 
538
560
  This grayscale-only discipline is not dark-specific: it governs the whole generated shadcn surface-role bridge in both the light `:root` and dark `.dark` maps. The surface-role family — `background`, `card`, `popover`, `muted`, `secondary`, the `sidebar` roles and their `-foreground`/`-border` variants, plus `border` and `input` — resolves only to pure grays (equal channels) in both themes; hue in the role bridge is reserved for `primary`, `destructive`, and the focus rings (`ring`/`sidebar-ring`). In dark product shells, `background`, `card`, `popover`, and `sidebar` share `{colors.dark-canvas}` so page chrome, cards, tables, overlays, and nav rails read as one black console. `muted`, `secondary`, and `accent` retain the `dark-canvas-soft` steps for small interaction states such as hover, selected rows, keycaps, and inline controls. Large product surfaces never take a tinted or soft-panel fill by default.
539
561
 
@@ -681,19 +703,46 @@ These live helpers are part of the kept page-grammar layout layer. They are not
681
703
 
682
704
  ## Elevation & Depth
683
705
 
684
- NadicodeAI website depth is flat and architectural. Hairlines, contrast, dotted fields, diagonal fills, and dark action bands create hierarchy. Shadows are optional for small artifact cards only and must stay subtle.
706
+ NadicodeAI website depth is flat and architectural. Hairlines, contrast, dotted fields, diagonal fills, and dark action bands create hierarchy. The public website does not use floating card stacks as its main structure; the page frame and row grid remain dominant.
707
+
708
+ Product UI uses explicit material roles. Resting content surfaces use no shadow; hierarchy comes from one owned border, spacing, and surface contrast. Shadows identify genuinely floating UI only. The same low-opacity black shadow stacks are used in light and dark themes so elevation does not change character between modes.
709
+
710
+ The Google design schema does not define elevation or opacity groups. These declarations are therefore the authored material-token source inside this contract. The build reads this block strictly, emits generated `--nc-*` hooks, and maps Tailwind's named opacity and shadow utilities to them; consumers never repeat these values.
711
+
712
+ ```css material-tokens
713
+ --nc-material-scrim-opacity: 10%;
714
+ --nc-material-shadow-tooltip: 0 1px 1px rgb(0 0 0 / 2%), 0 4px 8px rgb(0 0 0 / 4%);
715
+ --nc-material-shadow-menu: 0 1px 1px rgb(0 0 0 / 2%), 0 4px 8px -4px rgb(0 0 0 / 4%), 0 16px 24px -8px rgb(0 0 0 / 6%);
716
+ --nc-material-shadow-dialog: 0 1px 1px rgb(0 0 0 / 2%), 0 8px 16px -4px rgb(0 0 0 / 4%), 0 24px 32px -8px rgb(0 0 0 / 6%);
717
+ --nc-material-shadow-sheet: 0 2px 2px rgb(0 0 0 / 4%), 0 8px 16px -4px rgb(0 0 0 / 4%);
718
+ ```
719
+
720
+ | Material role | Border / radius | Elevation | Internal spacing |
721
+ | --- | --- | --- | --- |
722
+ | Resting content surface | 1 px `{colors.line}` / `{colors.dark-line}`; `{rounded.md}` (6 px) | none | 24 px, or 16 px only for an explicitly compact surface |
723
+ | Resting control | 1 px `{colors.input}` / `{colors.dark-input}`; `{rounded.md}` (6 px) | none | `{spacing.control-padding-inline}` inline; `{spacing.xs}` block for textareas; minimum height `{spacing.control-height}` |
724
+ | Tooltip | 1 px `{colors.line}` / `{colors.dark-line}`; `{rounded.md}` (6 px) | tooltip shadow | 6 px block / 12 px inline |
725
+ | Menu | 1 px `{colors.line}` / `{colors.dark-line}`; `{rounded.2xl}` (12 px) | menu shadow | 4 px |
726
+ | Popover | 1 px `{colors.line}` / `{colors.dark-line}`; `{rounded.2xl}` (12 px) | menu shadow | 10 px |
727
+ | Dialog | 1 px `{colors.line}` / `{colors.dark-line}`; `{rounded.2xl}` (12 px) | dialog shadow | 24 px body / 16 px footer |
728
+ | Inset sheet | 1 px `{colors.line}` / `{colors.dark-line}`; `{rounded.3xl}` (16 px) | sheet shadow | 12 px outer inset / 24 px sections |
729
+ | Takeover | 1 px `{colors.line}` / `{colors.dark-line}`; `{rounded.3xl}` (16 px) | dialog shadow | 24 px |
730
+
731
+ Modal overlays use `{colors.scrim}` / `{colors.dark-scrim}` at the generated `scrim` opacity with no blur. Focus is not elevation: controls use a full-opacity `{spacing.focus-ring-width}` `{colors.focus-ring}` / `{colors.dark-focus-ring}` ring with no offset. Avoid nested decorative borders: one container owns containment, while child groups use spacing, headings, or dividers only when those dividers clarify structure.
685
732
 
686
- The public website should not rely on floating card stacks as the main structure. Cards may exist inside a cell as an artifact, but the page frame and row grid must remain the dominant structure.
733
+ On coarse or non-hover input capability, every interactive target is at least 44 × 44 px at every viewport width. A compact visual mark such as a checkbox or radio stays compact while its label or hit area supplies the target size. Fine, hover-capable pointers may use the compact control scale.
687
734
 
688
735
  ## Shapes
689
736
 
690
- Corners are restrained.
737
+ Corners are restrained and assigned by material role.
691
738
 
692
739
  - Use `{rounded.none}` for page rows, frame edges, grid cells, and structural modules.
693
- - Use `{rounded.sm}` to `{rounded.lg}` for buttons, chips, status tags, chat bubbles, and small artifacts.
694
- - Use `{rounded.full}` only for truly circular identity or avatar chrome.
740
+ - Use `{rounded.md}` (6 px) for resting content surfaces, controls, buttons, chips, status tags, tooltips, chat bubbles, and small artifacts.
741
+ - Use `{rounded.2xl}` (12 px) for menus, popovers, and dialogs.
742
+ - Use `{rounded.3xl}` (16 px) for inset sheets and takeovers.
743
+ - Use `{rounded.full}` only for intrinsically circular identity/avatar chrome and compact control marks whose geometry is inherently round or pill-shaped. It never turns a content surface, button, badge, or navigation item into a pill by default.
695
744
 
696
- Cards are not rounded by default. A cell is usually square because its parent frame supplies the visual system.
745
+ Public page-grammar cells are not cards and remain square because their parent frame supplies the visual system. Product cards are resting content surfaces and use the 6 px role above; they do not gain thicker borders, nested frames, or a shadow merely because they contain grouped settings.
697
746
 
698
747
  ## Components
699
748
 
@@ -703,7 +752,7 @@ Component entries are grouped by design-system family so the decision model stay
703
752
 
704
753
  Interface CSS components provide small metadata, label, and link chrome. They inherit NadicodeAI tokens and stay subordinate to the page grammar; they must not create independent layout systems or repair structural seams. The generic interactive controls (navigation, buttons, inputs, footer chrome, the marketing card/code/pricing/proof surfaces, the standard sections) ship as React shadcn components from `@nadicodeai/ui`; this contract keeps only the brand/display CSS components and primitives that belong in the framework-agnostic package.
705
754
 
706
- Interactive CSS components must expose a visible `:focus-visible` state using the NadicodeAI link/accent family or a contrast-safe inverse on dark surfaces. Do not remove outlines without an equivalent replacement.
755
+ Interactive CSS components must expose a visible `:focus-visible` state using the `{spacing.focus-ring-width}` full-opacity `{colors.focus-ring}` / `{colors.dark-focus-ring}` role with no offset. Do not remove outlines without that contrast-safe equivalent.
707
756
 
708
757
  **`label-mono`** — mono eyebrow/label text for section labels and low-priority metadata.
709
758
 
@@ -737,7 +786,7 @@ Agentic work surfaces are the NadicodeAI-specific layer. They show people and ag
737
786
 
738
787
  **`tool-call-trace`** — compact code/trace row. Use only when tool use is relevant to the explanation.
739
788
 
740
- State-tag variants share the same shape — a compact rectangular pill at `{typography.caption-mono}` and differentiate by a 3 px colored `border-left` consuming the matching `{colors.state-*}` token. Shape carries meaning; color carries variant. State is never conveyed through swatches, dots, pulses, breathing animations, or loading spinners.
789
+ State-tag variants share the same compact rectangular shape at `{typography.caption-mono}` and differentiate by a 3 px colored `border-left` consuming the matching `{colors.state-*}` token. Shape carries meaning; color carries variant. State is never conveyed through swatches, dots, pulses, breathing animations, or loading spinners.
741
790
 
742
791
  **`state-tag-ready`** — workflow state tag for work that is ready or waiting to start. Uses `{colors.state-ready}` for the left edge.
743
792
 
@@ -769,6 +818,8 @@ State-tag variants share the same shape — a compact rectangular pill at `{typo
769
818
  - Do keep centered content in the 10-column `active-lane` while preserving visible ownership of columns 1 and 12.
770
819
  - Do use `side-fill`, guide strips, or component-owned fillers whenever content does not occupy the outer columns.
771
820
  - Do use `{spacing.guide}` and `{colors.line}` for ordinary seams.
821
+ - Do use `{colors.input}` / `{colors.dark-input}` for resting control boundaries and the dedicated focus-ring roles for keyboard focus.
822
+ - Do use exactly one material role per container: resting surfaces are border-only; menus, popovers, dialogs, sheets, and takeovers use their specified floating treatment.
772
823
  - Do tune line visibility by changing `{colors.line}` at the token contract, then rebuilding generated exports.
773
824
  - Do use `{colors.cross}` for crosshair color while keeping crosshair weight equal to `{spacing.guide}`.
774
825
  - Do use fixed height tokens for default component/specimen height and let content grow only when required.
@@ -783,6 +834,8 @@ State-tag variants share the same shape — a compact rectangular pill at `{typo
783
834
  - Don't create naked centered 10-column sections without visible ownership of columns 1 and 12.
784
835
  - Don't draw the same seam from two adjacent elements.
785
836
  - Don't add borders inside cells to fix visual seams; fix the owner layer.
837
+ - Don't use a 1 px decorative line as an input boundary, or locally increase card border weight to manufacture hierarchy.
838
+ - Don't stack borders around nested groups, add shadows to resting cards, or blur modal scrims.
786
839
  - Don't tune seam contrast with local opacity, raw colors, or component-specific border colors.
787
840
  - Don't use viewport-scaled typography.
788
841
  - Don't use negative letter spacing in the website kernel.
package/README.md CHANGED
@@ -120,4 +120,4 @@ For motion, the package ships exactly one optional, vanilla, dependency-free enh
120
120
 
121
121
  Use the monorepo's `brand/brand-book/` for NadicodeAI story, positioning, buyer, promise, method, use cases, technology story, trust doctrine, identity, voice, visual direction, sales behavior, language, and boundaries.
122
122
 
123
- The archived `design-canvas/` prototype source-of-record (the chat motion and component prototypes the kernel re-expresses) lives in the monorepo's `docs/experiments` and is not package runtime or current brand canon.
123
+ The `design-canvas/` prototypes the kernel re-expresses (chat motion and component prototypes) are deleted from the tree; git history retains them under `docs/experiments/design-canvas/`. They are not package runtime or current brand canon.
@@ -96,6 +96,6 @@
96
96
  }
97
97
 
98
98
  .nc-approval-gate-actions button:focus-visible {
99
- outline: var(--nc-guide) solid var(--nc-link);
100
- outline-offset: 2px;
99
+ outline: var(--nc-focus-ring-width) solid var(--nc-focus-ring);
100
+ outline-offset: 0;
101
101
  }
@@ -305,8 +305,8 @@
305
305
  }
306
306
 
307
307
  .nc-filter-chip:focus-visible {
308
- outline: 2px solid var(--nc-link);
309
- outline-offset: 2px;
308
+ outline: var(--nc-focus-ring-width) solid var(--nc-focus-ring);
309
+ outline-offset: 0;
310
310
  }
311
311
 
312
312
  /* nc-link-inline — the inline body link style (DESIGN.md link-inline). It reads
@@ -332,9 +332,9 @@
332
332
  }
333
333
 
334
334
  .nc-link-inline:focus-visible {
335
- outline: 2px solid var(--nc-link);
336
- outline-offset: 2px;
337
- border-radius: var(--nc-rounded-xs);
335
+ outline: var(--nc-focus-ring-width) solid var(--nc-focus-ring);
336
+ outline-offset: 0;
337
+ border-radius: var(--nc-rounded-md);
338
338
  }
339
339
 
340
340
  /* nc-label-mono — the mono eyebrow/kicker for section labels and low-priority
@@ -7,6 +7,10 @@
7
7
  /* Colors */
8
8
  --nc-primary: #008c45;
9
9
  --nc-on-primary: #ffffff;
10
+ --nc-action: #007a3c;
11
+ --nc-action-foreground: #ffffff;
12
+ --nc-action-hover: #00602f;
13
+ --nc-action-active: #00301a;
10
14
  --nc-ink: #171717;
11
15
  --nc-body: #4d4d4d;
12
16
  --nc-muted: #888888;
@@ -14,8 +18,11 @@
14
18
  --nc-canvas-soft: #fafafa;
15
19
  --nc-canvas-soft-2: #f5f5f5;
16
20
  --nc-line: #e5e5e5;
21
+ --nc-input: #8f8f8f;
17
22
  --nc-seam: #e4e7ec;
18
23
  --nc-cross: #a1a1a1;
24
+ --nc-focus-ring: #007a3c;
25
+ --nc-scrim: #171717;
19
26
  --nc-link: #007a3c;
20
27
  --nc-link-deep: #00602f;
21
28
  --nc-link-bg-soft: #d9f6e4;
@@ -120,9 +127,15 @@
120
127
  --nc-dark-seam: #1f1f1f;
121
128
  --nc-dark-primary: #ededed;
122
129
  --nc-dark-on-primary: #0a0a0a;
130
+ --nc-dark-action: #ededed;
131
+ --nc-dark-action-foreground: #0a0a0a;
132
+ --nc-dark-action-hover: #d4d4d4;
133
+ --nc-dark-action-active: #a3a3a3;
123
134
  --nc-dark-link: #9fe6bc;
124
135
  --nc-dark-link-deep: #c3f0d4;
125
136
  --nc-dark-link-bg-soft: #00301a;
137
+ --nc-dark-focus-ring: #9fe6bc;
138
+ --nc-dark-scrim: #f5f5f5;
126
139
  --nc-dark-error: #f7b3b5;
127
140
  --nc-dark-error-soft: #4a000e;
128
141
  --nc-dark-error-deep: #fad3d4;
@@ -171,6 +184,10 @@
171
184
  --nc-6xl: 128px;
172
185
  --nc-section: 192px;
173
186
  --nc-guide: 1px;
187
+ --nc-focus-ring-width: 3px;
188
+ --nc-control-height: 32px;
189
+ --nc-control-padding-inline: 10px;
190
+ --nc-touch-target: 44px;
174
191
  --nc-page-pad: 24px;
175
192
  --nc-page-max-mobile: 448px;
176
193
  --nc-page-max-tablet: 624px;
@@ -225,6 +242,8 @@
225
242
  --nc-rounded-md: 6px;
226
243
  --nc-rounded-lg: 8px;
227
244
  --nc-rounded-xl: 10px;
245
+ --nc-rounded-2xl: 12px;
246
+ --nc-rounded-3xl: 16px;
228
247
  --nc-rounded-pill-sm: 64px;
229
248
  --nc-rounded-pill: 100px;
230
249
  --nc-rounded-full: 9999px;
@@ -315,4 +334,11 @@
315
334
  --nc-type-button-lg-font-weight: 500;
316
335
  --nc-type-button-lg-line-height: 24px;
317
336
  --nc-type-button-lg-letter-spacing: 0px;
337
+
338
+ /* Material opacity and shadows (strictly parsed from DESIGN.md prose) */
339
+ --nc-material-scrim-opacity: 10%;
340
+ --nc-material-shadow-tooltip: 0 1px 1px rgb(0 0 0 / 2%), 0 4px 8px rgb(0 0 0 / 4%);
341
+ --nc-material-shadow-menu: 0 1px 1px rgb(0 0 0 / 2%), 0 4px 8px -4px rgb(0 0 0 / 4%), 0 16px 24px -8px rgb(0 0 0 / 6%);
342
+ --nc-material-shadow-dialog: 0 1px 1px rgb(0 0 0 / 2%), 0 8px 16px -4px rgb(0 0 0 / 4%), 0 24px 32px -8px rgb(0 0 0 / 6%);
343
+ --nc-material-shadow-sheet: 0 2px 2px rgb(0 0 0 / 4%), 0 8px 16px -4px rgb(0 0 0 / 4%);
318
344
  }
@@ -4,6 +4,10 @@
4
4
  "colors": {
5
5
  "primary": "#008c45",
6
6
  "on-primary": "#ffffff",
7
+ "action": "#007a3c",
8
+ "action-foreground": "#ffffff",
9
+ "action-hover": "#00602f",
10
+ "action-active": "#00301a",
7
11
  "ink": "#171717",
8
12
  "body": "#4d4d4d",
9
13
  "muted": "#888888",
@@ -11,8 +15,11 @@
11
15
  "canvas-soft": "#fafafa",
12
16
  "canvas-soft-2": "#f5f5f5",
13
17
  "line": "#e5e5e5",
18
+ "input": "#8f8f8f",
14
19
  "seam": "#e4e7ec",
15
20
  "cross": "#a1a1a1",
21
+ "focus-ring": "#007a3c",
22
+ "scrim": "#171717",
16
23
  "link": "#007a3c",
17
24
  "link-deep": "#00602f",
18
25
  "link-bg-soft": "#d9f6e4",
@@ -117,9 +124,15 @@
117
124
  "dark-seam": "#1f1f1f",
118
125
  "dark-primary": "#ededed",
119
126
  "dark-on-primary": "#0a0a0a",
127
+ "dark-action": "#ededed",
128
+ "dark-action-foreground": "#0a0a0a",
129
+ "dark-action-hover": "#d4d4d4",
130
+ "dark-action-active": "#a3a3a3",
120
131
  "dark-link": "#9fe6bc",
121
132
  "dark-link-deep": "#c3f0d4",
122
133
  "dark-link-bg-soft": "#00301a",
134
+ "dark-focus-ring": "#9fe6bc",
135
+ "dark-scrim": "#f5f5f5",
123
136
  "dark-error": "#f7b3b5",
124
137
  "dark-error-soft": "#4a000e",
125
138
  "dark-error-deep": "#fad3d4",
@@ -351,6 +364,8 @@
351
364
  "md": "6px",
352
365
  "lg": "8px",
353
366
  "xl": "10px",
367
+ "2xl": "12px",
368
+ "3xl": "16px",
354
369
  "pill-sm": "64px",
355
370
  "pill": "100px",
356
371
  "full": "9999px"
@@ -370,6 +385,10 @@
370
385
  "6xl": "128px",
371
386
  "section": "192px",
372
387
  "guide": "1px",
388
+ "focus-ring-width": "3px",
389
+ "control-height": "32px",
390
+ "control-padding-inline": "10px",
391
+ "touch-target": "44px",
373
392
  "page-pad": "24px",
374
393
  "page-max-mobile": "448px",
375
394
  "page-max-tablet": "624px",
@@ -10,19 +10,22 @@
10
10
  --card-foreground: var(--color-ink);
11
11
  --popover: var(--color-canvas);
12
12
  --popover-foreground: var(--color-ink);
13
- --primary: var(--color-nadicode-primary);
14
- --primary-foreground: var(--color-on-primary);
13
+ --primary: var(--color-action);
14
+ --primary-foreground: var(--color-action-foreground);
15
+ --primary-hover: var(--color-action-hover);
16
+ --primary-active: var(--color-action-active);
15
17
  --secondary: var(--color-canvas-soft);
16
18
  --secondary-foreground: var(--color-ink);
17
19
  --muted: var(--color-canvas-soft);
18
- --muted-foreground: var(--color-nadicode-muted);
20
+ --muted-foreground: var(--color-body);
19
21
  --accent: var(--color-canvas-soft-2);
20
22
  --accent-foreground: var(--color-ink);
21
23
  --destructive: var(--color-error);
22
24
  --destructive-foreground: var(--color-on-primary);
23
25
  --border: var(--color-line);
24
- --input: var(--color-line);
25
- --ring: var(--color-link);
26
+ --input: var(--color-nadicode-input);
27
+ --ring: var(--color-focus-ring);
28
+ --scrim: var(--color-nadicode-scrim);
26
29
  --chart-1: var(--color-nadicode-chart-1);
27
30
  --chart-2: var(--color-nadicode-chart-2);
28
31
  --chart-3: var(--color-nadicode-chart-3);
@@ -35,7 +38,7 @@
35
38
  --sidebar-accent: var(--color-canvas-soft-2);
36
39
  --sidebar-accent-foreground: var(--color-ink);
37
40
  --sidebar-border: var(--color-line);
38
- --sidebar-ring: var(--color-link);
41
+ --sidebar-ring: var(--color-focus-ring);
39
42
  }
40
43
 
41
44
  .dark {
@@ -46,19 +49,22 @@
46
49
  --card-foreground: var(--color-dark-ink);
47
50
  --popover: var(--color-dark-canvas);
48
51
  --popover-foreground: var(--color-dark-ink);
49
- --primary: var(--color-dark-primary);
50
- --primary-foreground: var(--color-dark-on-primary);
52
+ --primary: var(--color-dark-action);
53
+ --primary-foreground: var(--color-dark-action-foreground);
54
+ --primary-hover: var(--color-dark-action-hover);
55
+ --primary-active: var(--color-dark-action-active);
51
56
  --secondary: var(--color-dark-canvas-soft);
52
57
  --secondary-foreground: var(--color-dark-ink);
53
58
  --muted: var(--color-dark-canvas-soft);
54
- --muted-foreground: var(--color-dark-muted);
59
+ --muted-foreground: var(--color-dark-body);
55
60
  --accent: var(--color-dark-canvas-soft-2);
56
61
  --accent-foreground: var(--color-dark-ink);
57
62
  --destructive: var(--color-dark-error);
58
63
  --destructive-foreground: var(--color-dark-on-primary);
59
64
  --border: var(--color-dark-line);
60
65
  --input: var(--color-dark-input);
61
- --ring: var(--color-dark-link);
66
+ --ring: var(--color-dark-focus-ring);
67
+ --scrim: var(--color-dark-scrim);
62
68
  --chart-1: var(--color-dark-chart-1);
63
69
  --chart-2: var(--color-dark-chart-2);
64
70
  --chart-3: var(--color-dark-chart-3);
@@ -71,10 +77,17 @@
71
77
  --sidebar-accent: var(--color-dark-canvas-soft-2);
72
78
  --sidebar-accent-foreground: var(--color-dark-ink);
73
79
  --sidebar-border: var(--color-dark-line);
74
- --sidebar-ring: var(--color-dark-link);
80
+ --sidebar-ring: var(--color-dark-focus-ring);
75
81
  }
76
82
 
77
83
  :root.dark {
84
+ --nc-action: var(--nc-dark-action);
85
+ --nc-action-foreground: var(--nc-dark-action-foreground);
86
+ --nc-action-hover: var(--nc-dark-action-hover);
87
+ --nc-action-active: var(--nc-dark-action-active);
88
+ --nc-input: var(--nc-dark-input);
89
+ --nc-focus-ring: var(--nc-dark-focus-ring);
90
+ --nc-scrim: var(--nc-dark-scrim);
78
91
  --nc-state-ready: var(--nc-dark-state-ready);
79
92
  --nc-state-running: var(--nc-dark-state-running);
80
93
  --nc-state-review: var(--nc-dark-state-review);
@@ -114,6 +127,10 @@
114
127
  --nadicode-spacing-6xl: var(--spacing-nadicode-6xl);
115
128
  --nadicode-spacing-section: var(--spacing-nadicode-section);
116
129
  --nadicode-spacing-guide: var(--spacing-nadicode-guide);
130
+ --nadicode-spacing-focus-ring-width: var(--spacing-nadicode-focus-ring-width);
131
+ --nadicode-spacing-control-height: var(--spacing-nadicode-control-height);
132
+ --nadicode-spacing-control-padding-inline: var(--spacing-nadicode-control-padding-inline);
133
+ --nadicode-spacing-touch-target: var(--spacing-nadicode-touch-target);
117
134
  --nadicode-spacing-page-pad: var(--spacing-nadicode-page-pad);
118
135
  --nadicode-spacing-page-max-mobile: var(--spacing-nadicode-page-max-mobile);
119
136
  --nadicode-spacing-page-max-tablet: var(--spacing-nadicode-page-max-tablet);
@@ -166,6 +183,10 @@
166
183
  @theme {
167
184
  --color-primary: #008c45;
168
185
  --color-on-primary: #ffffff;
186
+ --color-action: #007a3c;
187
+ --color-action-foreground: #ffffff;
188
+ --color-action-hover: #00602f;
189
+ --color-action-active: #00301a;
169
190
  --color-ink: #171717;
170
191
  --color-body: #4d4d4d;
171
192
  --color-muted: #888888;
@@ -173,8 +194,11 @@
173
194
  --color-canvas-soft: #fafafa;
174
195
  --color-canvas-soft-2: #f5f5f5;
175
196
  --color-line: #e5e5e5;
197
+ --color-input: #8f8f8f;
176
198
  --color-seam: #e4e7ec;
177
199
  --color-cross: #a1a1a1;
200
+ --color-focus-ring: #007a3c;
201
+ --color-scrim: #171717;
178
202
  --color-link: #007a3c;
179
203
  --color-link-deep: #00602f;
180
204
  --color-link-bg-soft: #d9f6e4;
@@ -279,9 +303,15 @@
279
303
  --color-dark-seam: #1f1f1f;
280
304
  --color-dark-primary: #ededed;
281
305
  --color-dark-on-primary: #0a0a0a;
306
+ --color-dark-action: #ededed;
307
+ --color-dark-action-foreground: #0a0a0a;
308
+ --color-dark-action-hover: #d4d4d4;
309
+ --color-dark-action-active: #a3a3a3;
282
310
  --color-dark-link: #9fe6bc;
283
311
  --color-dark-link-deep: #c3f0d4;
284
312
  --color-dark-link-bg-soft: #00301a;
313
+ --color-dark-focus-ring: #9fe6bc;
314
+ --color-dark-scrim: #f5f5f5;
285
315
  --color-dark-error: #f7b3b5;
286
316
  --color-dark-error-soft: #4a000e;
287
317
  --color-dark-error-deep: #fad3d4;
@@ -314,8 +344,10 @@
314
344
  --color-dark-chart-div-warm: #ffd97d;
315
345
  --color-dark-chart-div-mid: #e6e6e6;
316
346
  --color-dark-chart-div-cool: #cdd9fd;
347
+ --color-nadicode-input: #8f8f8f;
317
348
  --color-nadicode-muted: #888888;
318
349
  --color-nadicode-primary: #008c45;
350
+ --color-nadicode-scrim: #171717;
319
351
  --color-nadicode-chart-1: #2743d8;
320
352
  --color-nadicode-chart-2: #008c45;
321
353
  --color-nadicode-chart-3: #f5a623;
@@ -463,9 +495,17 @@
463
495
  --radius-md: 6px;
464
496
  --radius-lg: 8px;
465
497
  --radius-xl: 10px;
498
+ --radius-2xl: 12px;
499
+ --radius-3xl: 16px;
466
500
  --radius-pill-sm: 64px;
467
501
  --radius-pill: 100px;
468
502
  --radius-full: 9999px;
503
+ --ring-width-focus: var(--spacing-nadicode-focus-ring-width);
504
+ --opacity-scrim: var(--nc-material-scrim-opacity);
505
+ --shadow-tooltip: var(--nc-material-shadow-tooltip);
506
+ --shadow-menu: var(--nc-material-shadow-menu);
507
+ --shadow-dialog: var(--nc-material-shadow-dialog);
508
+ --shadow-sheet: var(--nc-material-shadow-sheet);
469
509
  --spacing-nadicode-xxs: 4px;
470
510
  --spacing-nadicode-filter-chip-gap: 6px;
471
511
  --spacing-nadicode-xs: 8px;
@@ -480,6 +520,10 @@
480
520
  --spacing-nadicode-6xl: 128px;
481
521
  --spacing-nadicode-section: 192px;
482
522
  --spacing-nadicode-guide: 1px;
523
+ --spacing-nadicode-focus-ring-width: 3px;
524
+ --spacing-nadicode-control-height: 32px;
525
+ --spacing-nadicode-control-padding-inline: 10px;
526
+ --spacing-nadicode-touch-target: 44px;
483
527
  --spacing-nadicode-page-pad: 24px;
484
528
  --spacing-nadicode-page-max-mobile: 448px;
485
529
  --spacing-nadicode-page-max-tablet: 624px;
@@ -526,4 +570,7 @@
526
570
  --spacing-nadicode-h-bento-strip: 20px;
527
571
  --spacing-nadicode-filter-chip-height: 28px;
528
572
  --spacing-nadicode-filter-chip-icon: 14px;
573
+ --spacing-control-height: var(--spacing-nadicode-control-height);
574
+ --spacing-control-padding-inline: var(--spacing-nadicode-control-padding-inline);
575
+ --spacing-touch-target: var(--spacing-nadicode-touch-target);
529
576
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://www.designtokens.org/schemas/2025.10/format.json",
3
- "$description": "Reusable design-system contract for NadicodeAI: engineered page geometry, neutral high-contrast surfaces, AI-agent work artifacts, and strict 12-column/10-column composition rules for the public website and package token exports.",
3
+ "$description": "Reusable design-system contract for NadicodeAI: engineered page geometry, neutral high-contrast product surfaces, AI-agent work artifacts, strict 12-column/10-column public-page composition, and the package token exports shared by every NadicodeAI interface.",
4
4
  "nadicode": {
5
5
  "color": {
6
6
  "$type": "color",
@@ -26,6 +26,50 @@
26
26
  "hex": "#ffffff"
27
27
  }
28
28
  },
29
+ "action": {
30
+ "$value": {
31
+ "colorSpace": "srgb",
32
+ "components": [
33
+ 0,
34
+ 0.478,
35
+ 0.235
36
+ ],
37
+ "hex": "#007a3c"
38
+ }
39
+ },
40
+ "action-foreground": {
41
+ "$value": {
42
+ "colorSpace": "srgb",
43
+ "components": [
44
+ 1,
45
+ 1,
46
+ 1
47
+ ],
48
+ "hex": "#ffffff"
49
+ }
50
+ },
51
+ "action-hover": {
52
+ "$value": {
53
+ "colorSpace": "srgb",
54
+ "components": [
55
+ 0,
56
+ 0.376,
57
+ 0.184
58
+ ],
59
+ "hex": "#00602f"
60
+ }
61
+ },
62
+ "action-active": {
63
+ "$value": {
64
+ "colorSpace": "srgb",
65
+ "components": [
66
+ 0,
67
+ 0.188,
68
+ 0.102
69
+ ],
70
+ "hex": "#00301a"
71
+ }
72
+ },
29
73
  "ink": {
30
74
  "$value": {
31
75
  "colorSpace": "srgb",
@@ -103,6 +147,17 @@
103
147
  "hex": "#e5e5e5"
104
148
  }
105
149
  },
150
+ "input": {
151
+ "$value": {
152
+ "colorSpace": "srgb",
153
+ "components": [
154
+ 0.561,
155
+ 0.561,
156
+ 0.561
157
+ ],
158
+ "hex": "#8f8f8f"
159
+ }
160
+ },
106
161
  "seam": {
107
162
  "$value": {
108
163
  "colorSpace": "srgb",
@@ -125,6 +180,28 @@
125
180
  "hex": "#a1a1a1"
126
181
  }
127
182
  },
183
+ "focus-ring": {
184
+ "$value": {
185
+ "colorSpace": "srgb",
186
+ "components": [
187
+ 0,
188
+ 0.478,
189
+ 0.235
190
+ ],
191
+ "hex": "#007a3c"
192
+ }
193
+ },
194
+ "scrim": {
195
+ "$value": {
196
+ "colorSpace": "srgb",
197
+ "components": [
198
+ 0.09,
199
+ 0.09,
200
+ 0.09
201
+ ],
202
+ "hex": "#171717"
203
+ }
204
+ },
128
205
  "link": {
129
206
  "$value": {
130
207
  "colorSpace": "srgb",
@@ -1269,6 +1346,50 @@
1269
1346
  "hex": "#0a0a0a"
1270
1347
  }
1271
1348
  },
1349
+ "dark-action": {
1350
+ "$value": {
1351
+ "colorSpace": "srgb",
1352
+ "components": [
1353
+ 0.929,
1354
+ 0.929,
1355
+ 0.929
1356
+ ],
1357
+ "hex": "#ededed"
1358
+ }
1359
+ },
1360
+ "dark-action-foreground": {
1361
+ "$value": {
1362
+ "colorSpace": "srgb",
1363
+ "components": [
1364
+ 0.039,
1365
+ 0.039,
1366
+ 0.039
1367
+ ],
1368
+ "hex": "#0a0a0a"
1369
+ }
1370
+ },
1371
+ "dark-action-hover": {
1372
+ "$value": {
1373
+ "colorSpace": "srgb",
1374
+ "components": [
1375
+ 0.831,
1376
+ 0.831,
1377
+ 0.831
1378
+ ],
1379
+ "hex": "#d4d4d4"
1380
+ }
1381
+ },
1382
+ "dark-action-active": {
1383
+ "$value": {
1384
+ "colorSpace": "srgb",
1385
+ "components": [
1386
+ 0.639,
1387
+ 0.639,
1388
+ 0.639
1389
+ ],
1390
+ "hex": "#a3a3a3"
1391
+ }
1392
+ },
1272
1393
  "dark-link": {
1273
1394
  "$value": {
1274
1395
  "colorSpace": "srgb",
@@ -1302,6 +1423,28 @@
1302
1423
  "hex": "#00301a"
1303
1424
  }
1304
1425
  },
1426
+ "dark-focus-ring": {
1427
+ "$value": {
1428
+ "colorSpace": "srgb",
1429
+ "components": [
1430
+ 0.624,
1431
+ 0.902,
1432
+ 0.737
1433
+ ],
1434
+ "hex": "#9fe6bc"
1435
+ }
1436
+ },
1437
+ "dark-scrim": {
1438
+ "$value": {
1439
+ "colorSpace": "srgb",
1440
+ "components": [
1441
+ 0.961,
1442
+ 0.961,
1443
+ 0.961
1444
+ ],
1445
+ "hex": "#f5f5f5"
1446
+ }
1447
+ },
1305
1448
  "dark-error": {
1306
1449
  "$value": {
1307
1450
  "colorSpace": "srgb",
@@ -1741,6 +1884,30 @@
1741
1884
  "unit": "px"
1742
1885
  }
1743
1886
  },
1887
+ "focus-ring-width": {
1888
+ "$value": {
1889
+ "value": 3,
1890
+ "unit": "px"
1891
+ }
1892
+ },
1893
+ "control-height": {
1894
+ "$value": {
1895
+ "value": 32,
1896
+ "unit": "px"
1897
+ }
1898
+ },
1899
+ "control-padding-inline": {
1900
+ "$value": {
1901
+ "value": 10,
1902
+ "unit": "px"
1903
+ }
1904
+ },
1905
+ "touch-target": {
1906
+ "$value": {
1907
+ "value": 44,
1908
+ "unit": "px"
1909
+ }
1910
+ },
1744
1911
  "page-pad": {
1745
1912
  "$value": {
1746
1913
  "value": 24,
@@ -2056,6 +2223,18 @@
2056
2223
  "unit": "px"
2057
2224
  }
2058
2225
  },
2226
+ "2xl": {
2227
+ "$value": {
2228
+ "value": 12,
2229
+ "unit": "px"
2230
+ }
2231
+ },
2232
+ "3xl": {
2233
+ "$value": {
2234
+ "value": 16,
2235
+ "unit": "px"
2236
+ }
2237
+ },
2059
2238
  "pill-sm": {
2060
2239
  "$value": {
2061
2240
  "value": 64,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nadicodeai/design-system",
3
- "version": "0.5.3",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -45,7 +45,7 @@
45
45
  "build": "tsx scripts/build.ts",
46
46
  "generate:icons": "tsx scripts/generate-icons.ts",
47
47
  "generate:favicons": "tsx scripts/generate-favicons.ts",
48
- "lint:design": "npm exec -- design.md lint DESIGN.md",
48
+ "lint:design": "design.md lint DESIGN.md",
49
49
  "test": "vitest run",
50
50
  "test:visual": "vitest run --config vitest.visual.config.ts",
51
51
  "prepublishOnly": "npm run build"