@nadicodeai/design-system 9.2.0 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/DESIGN.md +170 -287
- package/GLOSSARY.md +4 -4
- package/README.md +32 -27
- package/dist/assets/app-icon.png +0 -0
- package/dist/assets/app-icon.svg +1 -0
- package/dist/assets/logo-one-ink-white.png +0 -0
- package/dist/assets/logo-one-ink-white.svg +1 -0
- package/dist/assets/logo-one-ink.png +0 -0
- package/dist/assets/logo-one-ink.svg +1 -0
- package/dist/assets/logo-white.png +0 -0
- package/dist/assets/logo-white.svg +1 -0
- package/dist/assets/logo.png +0 -0
- package/dist/assets/logo.svg +1 -0
- package/dist/assets/mark-white.png +0 -0
- package/dist/assets/mark-white.svg +1 -0
- package/dist/assets/mark.png +0 -0
- package/dist/assets/mark.svg +1 -0
- package/dist/css/host.css +45 -150
- package/dist/css/index.css +113 -912
- package/dist/css/tokens.css +44 -149
- package/dist/favicon/apple-touch-icon.png +0 -0
- package/dist/favicon/favicon.ico +0 -0
- package/dist/favicon/favicon.svg +1 -7
- package/dist/favicon/icon-192.png +0 -0
- package/dist/favicon/icon-512.png +0 -0
- package/dist/favicon/site.webmanifest +4 -4
- package/dist/icons/agent.svg +1 -1
- package/dist/icons/approvals.svg +1 -1
- package/dist/icons/arch.svg +1 -1
- package/dist/tailwind/nadicode.tailwind.json +23 -91
- package/dist/tokens/nadicode.dtcg-resolved.json +56 -426
- package/dist/tokens/nadicode.dtcg.json +56 -426
- package/package.json +43 -83
- package/src/assets/logo-geometry.d.ts +10 -7
- package/src/assets/logo-geometry.js +119 -172
- package/dist/assets/logo-lockup-inverse.png +0 -0
- package/dist/assets/logo-lockup-inverse.svg +0 -4
- package/dist/assets/logo-lockup-mono.png +0 -0
- package/dist/assets/logo-lockup-mono.svg +0 -4
- package/dist/assets/logo-lockup-on-verde.png +0 -0
- package/dist/assets/logo-lockup-on-verde.svg +0 -4
- package/dist/assets/logo-lockup.png +0 -0
- package/dist/assets/logo-lockup.svg +0 -4
- package/dist/assets/logo-mark-inverse.png +0 -0
- package/dist/assets/logo-mark-inverse.svg +0 -6
- package/dist/assets/logo-mark-mono.png +0 -0
- package/dist/assets/logo-mark-mono.svg +0 -6
- package/dist/assets/logo-mark-on-verde.png +0 -0
- package/dist/assets/logo-mark-on-verde.svg +0 -6
- package/dist/assets/logo-mark.png +0 -0
- package/dist/assets/logo-mark.svg +0 -6
- package/dist/assets/logo-wordmark-inverse.png +0 -0
- package/dist/assets/logo-wordmark-inverse.svg +0 -4
- package/dist/assets/logo-wordmark-mono.png +0 -0
- package/dist/assets/logo-wordmark-mono.svg +0 -4
- package/dist/assets/logo-wordmark-on-verde.png +0 -0
- package/dist/assets/logo-wordmark-on-verde.svg +0 -4
- package/dist/assets/logo-wordmark.png +0 -0
- package/dist/assets/logo-wordmark.svg +0 -4
- package/src/assets/logo-mark.d.ts +0 -2
- package/src/assets/logo-wordmark.d.ts +0 -2
- /package/src/assets/{logo-lockup.d.ts → logo-asset.d.ts} +0 -0
package/DESIGN.md
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
version: alpha
|
|
3
|
-
name:
|
|
3
|
+
name: nadicode Design System
|
|
4
4
|
description: >-
|
|
5
|
-
Reusable design-system contract for
|
|
5
|
+
Reusable design-system contract for nadicode: one foundation of colour,
|
|
6
6
|
type, spacing, radius, material, elevation, and motion, applied by three
|
|
7
7
|
registers, the website, the Portal, and the Nadia desktop app, plus the
|
|
8
8
|
package token, CSS, and asset exports they consume.
|
|
9
9
|
|
|
10
10
|
colors:
|
|
11
|
-
primary: "#007a3c"
|
|
12
11
|
on-primary: "#ffffff"
|
|
13
12
|
action: "#111111"
|
|
14
13
|
action-foreground: "#ffffff"
|
|
@@ -44,7 +43,6 @@ colors:
|
|
|
44
43
|
warning: "#ffc220"
|
|
45
44
|
warning-soft: "#fff3d1"
|
|
46
45
|
warning-deep: "#7a5800"
|
|
47
|
-
verde-vivo: "#008c45"
|
|
48
46
|
selection-bg: "#111111"
|
|
49
47
|
selection-fg: "#fafafa"
|
|
50
48
|
navigation-selection-bg: "#ededed"
|
|
@@ -63,6 +61,7 @@ colors:
|
|
|
63
61
|
identity-azzurro: "#0f6ee8"
|
|
64
62
|
identity-ink: "#000000"
|
|
65
63
|
identity-white: "#ffffff"
|
|
64
|
+
logo-dot: "#1e3cff"
|
|
66
65
|
chart-1: "#1e3cff"
|
|
67
66
|
chart-2: "#00a85a"
|
|
68
67
|
chart-3: "#ddaa00"
|
|
@@ -88,7 +87,6 @@ colors:
|
|
|
88
87
|
dark-line: "#262626"
|
|
89
88
|
dark-input: "#696969"
|
|
90
89
|
dark-seam: "#1a1a1a"
|
|
91
|
-
dark-primary: "#2fd584"
|
|
92
90
|
dark-on-primary: "#0a0a0a"
|
|
93
91
|
dark-action: "#ffffff"
|
|
94
92
|
dark-action-foreground: "#0a0a0a"
|
|
@@ -116,13 +114,13 @@ colors:
|
|
|
116
114
|
dark-state-review: "#ffc220"
|
|
117
115
|
dark-state-blocked: "#d3302f"
|
|
118
116
|
dark-state-complete: "#00a85a"
|
|
117
|
+
dark-logo-dot: "#4d6bff"
|
|
119
118
|
dark-selection-bg: "#ededed"
|
|
120
119
|
dark-selection-fg: "#0a0a0a"
|
|
121
120
|
dark-navigation-selection-bg: "#1a1a1a"
|
|
122
121
|
dark-navigation-selection-fg: "#ededed"
|
|
123
122
|
dark-navigation-selection-hover: "#262626"
|
|
124
123
|
dark-cross: "#555555"
|
|
125
|
-
dark-verde-vivo: "#62d494"
|
|
126
124
|
dark-chart-1: "#4d6bff"
|
|
127
125
|
dark-chart-2: "#00a85a"
|
|
128
126
|
dark-chart-3: "#ffd866"
|
|
@@ -144,42 +142,36 @@ typography:
|
|
|
144
142
|
fontSize: 72px
|
|
145
143
|
fontWeight: 600
|
|
146
144
|
lineHeight: 74px
|
|
147
|
-
letterSpacing: -
|
|
145
|
+
letterSpacing: -2.52px
|
|
148
146
|
display-lg:
|
|
149
147
|
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
150
148
|
fontSize: 52px
|
|
151
149
|
fontWeight: 600
|
|
152
150
|
lineHeight: 54px
|
|
153
|
-
letterSpacing: -
|
|
151
|
+
letterSpacing: -1.5px
|
|
154
152
|
display-md:
|
|
155
153
|
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
156
|
-
fontSize:
|
|
157
|
-
fontWeight: 600
|
|
158
|
-
lineHeight: 32px
|
|
159
|
-
letterSpacing: 0px
|
|
160
|
-
display-sm:
|
|
161
|
-
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
162
|
-
fontSize: 20px
|
|
154
|
+
fontSize: 40px
|
|
163
155
|
fontWeight: 600
|
|
164
|
-
lineHeight:
|
|
165
|
-
letterSpacing:
|
|
166
|
-
|
|
156
|
+
lineHeight: 42px
|
|
157
|
+
letterSpacing: -1px
|
|
158
|
+
heading-lg:
|
|
167
159
|
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
168
|
-
fontSize:
|
|
160
|
+
fontSize: 30px
|
|
169
161
|
fontWeight: 600
|
|
170
|
-
lineHeight:
|
|
162
|
+
lineHeight: 32px
|
|
171
163
|
letterSpacing: 0px
|
|
172
|
-
|
|
164
|
+
heading-md:
|
|
173
165
|
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
174
|
-
fontSize:
|
|
166
|
+
fontSize: 24px
|
|
175
167
|
fontWeight: 600
|
|
176
168
|
lineHeight: 32px
|
|
177
169
|
letterSpacing: 0px
|
|
178
|
-
|
|
170
|
+
heading-sm:
|
|
179
171
|
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
180
|
-
fontSize:
|
|
172
|
+
fontSize: 20px
|
|
181
173
|
fontWeight: 600
|
|
182
|
-
lineHeight:
|
|
174
|
+
lineHeight: 28px
|
|
183
175
|
letterSpacing: 0px
|
|
184
176
|
body-lg:
|
|
185
177
|
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
@@ -193,59 +185,29 @@ typography:
|
|
|
193
185
|
fontWeight: 400
|
|
194
186
|
lineHeight: 25px
|
|
195
187
|
letterSpacing: 0px
|
|
196
|
-
body-md-strong:
|
|
197
|
-
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
198
|
-
fontSize: 16px
|
|
199
|
-
fontWeight: 500
|
|
200
|
-
lineHeight: 24px
|
|
201
|
-
letterSpacing: 0px
|
|
202
188
|
body-sm:
|
|
203
189
|
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
204
190
|
fontSize: 14px
|
|
205
191
|
fontWeight: 400
|
|
206
192
|
lineHeight: 20px
|
|
207
193
|
letterSpacing: 0px
|
|
208
|
-
body-sm-strong:
|
|
209
|
-
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
210
|
-
fontSize: 14px
|
|
211
|
-
fontWeight: 500
|
|
212
|
-
lineHeight: 20px
|
|
213
|
-
letterSpacing: 0px
|
|
214
194
|
caption:
|
|
215
195
|
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
216
196
|
fontSize: 12px
|
|
217
197
|
fontWeight: 400
|
|
218
198
|
lineHeight: 16px
|
|
219
199
|
letterSpacing: 0px
|
|
220
|
-
caption-strong:
|
|
221
|
-
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
222
|
-
fontSize: 12px
|
|
223
|
-
fontWeight: 500
|
|
224
|
-
lineHeight: 16px
|
|
225
|
-
letterSpacing: 0px
|
|
226
|
-
caption-mono:
|
|
227
|
-
fontFamily: Geist Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, monospace
|
|
228
|
-
fontSize: 12px
|
|
229
|
-
fontWeight: 500
|
|
230
|
-
lineHeight: 16px
|
|
231
|
-
letterSpacing: 0px
|
|
232
200
|
code:
|
|
233
201
|
fontFamily: Geist Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, monospace
|
|
234
202
|
fontSize: 13px
|
|
235
203
|
fontWeight: 400
|
|
236
204
|
lineHeight: 20px
|
|
237
205
|
letterSpacing: 0px
|
|
238
|
-
|
|
239
|
-
fontFamily: Geist
|
|
240
|
-
fontSize:
|
|
241
|
-
fontWeight: 500
|
|
242
|
-
lineHeight: 18px
|
|
243
|
-
letterSpacing: 0px
|
|
244
|
-
button-lg:
|
|
245
|
-
fontFamily: Geist, Inter, system-ui, -apple-system, sans-serif
|
|
246
|
-
fontSize: 16px
|
|
206
|
+
label-mono:
|
|
207
|
+
fontFamily: Geist Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, monospace
|
|
208
|
+
fontSize: 12px
|
|
247
209
|
fontWeight: 500
|
|
248
|
-
lineHeight:
|
|
210
|
+
lineHeight: 16px
|
|
249
211
|
letterSpacing: 0px
|
|
250
212
|
|
|
251
213
|
rounded:
|
|
@@ -286,7 +248,7 @@ spacing:
|
|
|
286
248
|
|
|
287
249
|
## Overview
|
|
288
250
|
|
|
289
|
-
|
|
251
|
+
nadicode is an AI agency for SMBs. The design system makes the website and the shipped product read as one family: a calm, high-contrast monochrome architecture in which the identity layer — the Agent orbs and Nadia's striped ribbon among them — is the expressive element. Structure, chrome, and controls are neutral; a desaturated screen loses nothing structural. The interface helps a pragmatic buyer understand the work: repeated workflows, agents working beside people, inspectable outputs, human approval.
|
|
290
252
|
|
|
291
253
|
One foundation, three registers. The foundation is every `core` value in this contract: the colour roles and their dark pairs, the two type families and the type scale, the spacing ladder and the control geometry, the radius scale, the material values, the four-rung elevation ladder, the motion durations and easings, the icon render, and the brand marks. It is owned by no single product and available to every product; a value stays foundation whether one product renders it or three. A register is one product's way of applying it: its direction, its density, the rungs and steps it reaches for, its dark-mode stance, its structural grammar, its motion budget. The three registers are the website, the Portal, and the Nadia desktop app; `## Registers` names each one's rulebook, its own token families, and its dark-mode stance.
|
|
292
254
|
|
|
@@ -294,9 +256,13 @@ A register decides where a foundation value appears and adds rules of its own. I
|
|
|
294
256
|
|
|
295
257
|
`DESIGN.md` defines the reusable contract and exported scalar tokens; the `@nadicodeai/design-system/css` bundle (`src/css/**`) realises that contract. Homepage copy, page-specific ordering, and temporary prototypes do not belong in this file.
|
|
296
258
|
|
|
259
|
+
The settled target state of this contract is [the nadicode design system ADR](../../docs/adr/2026-09-23-the-nadicode-design-system.md): the brand is still, only Agents move. A section that ADR changes opens with a **Target state** paragraph naming the decision and the issue that ships it; until that issue lands, the rest of the section describes what is built. The issue's change replaces the pointer with the rule as shipped.
|
|
260
|
+
|
|
297
261
|
## Colors
|
|
298
262
|
|
|
299
|
-
|
|
263
|
+
**Two greens, and only two.** `{colors.link}` #00713d, dark `{colors.dark-link}` #4ecf8c, is the green that carries text: links, navigational accents, approval states, and the deep and soft steps the `success` pair reuses. Identity verde `{colors.identity-verde}` #00a85a is the green that carries marks. Nothing else in this contract is green. A third green always turned out to be one of those two at a slightly different lightness, which is why `primary` #007a3c and `verde-vivo` #008c45, with their dark pairs `dark-primary` and `dark-verde-vivo`, no longer exist: the logo is ink with a cobalt dot and needs no brand verde, and the presence mark `verde-vivo` painted is retired with the portrait it sat on. The shadcn `primary` role is unaffected and still maps to the neutral action family.
|
|
264
|
+
|
|
265
|
+
Neutrals carry the interface: grounds, chrome, hierarchy, and every control come from the achromatic spine, and the strongest contrast on any surface lands on the primary action. Chromatic colour appears where it says something a reader already knows how to read: the semantic feedback hues, the two greens in their scoped duties, the chart palettes on data, and the Agent identity palette inside the Agent visuals. Chrome, sections, and controls stay unpainted.
|
|
300
266
|
|
|
301
267
|
Interaction states are material, not meaning: focus, hover, and selection read as contrast steps on the neutral spine. A hover ground is a neutral step; the only change a control hover carries is a step inside its own family, as `{colors.action-hover}` does on the action control. Cobalto stays on info and running.
|
|
302
268
|
|
|
@@ -319,8 +285,7 @@ Every value a role needs is carried by the role token itself; there is no numeri
|
|
|
319
285
|
|
|
320
286
|
### Semantic roles (functional tier)
|
|
321
287
|
|
|
322
|
-
- **Action** (`{colors.action}` = ink `#111111`, `{colors.action-foreground}` = white, `{colors.action-hover}`, `{colors.action-active}`): the primary-control family is neutral — a white label on the ink field in light shells, and in dark shells the `dark-action-*` roles, a white control carrying a near-black label. Maximum contrast belongs to the thing that acts. The shadcn `primary` roles map here.
|
|
323
|
-
- **Brand accent — verde** (`{colors.primary}` = deep verde `#007a3c`, white `{colors.on-primary}` text on its field): identity marks, logo contexts, and brand accents. Verde's working duties are exactly the scoped roles below — links, success, and Nadia's presence — and the brighter verde `#00a85a` stays the imagery-tier anchor, never carrying normal-size white text.
|
|
288
|
+
- **Action** (`{colors.action}` = ink `#111111`, `{colors.action-foreground}` = white, `{colors.action-hover}`, `{colors.action-active}`): the primary-control family is neutral — a white label on the ink field in light shells, and in dark shells the `dark-action-*` roles, a white control carrying a near-black label. Maximum contrast belongs to the thing that acts. The shadcn `primary` roles map here, and `{colors.on-primary}` / `{colors.dark-on-primary}` are the foregrounds that role carries.
|
|
324
289
|
- **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 resting-control boundary, the stronger mark/crosshair gray, and the dashed connector guide. `{colors.line}` owns ordinary seams and is deliberately quiet — a decorative hairline, not held to a non-text contrast floor. `{colors.input}` owns fields and other interactive boundaries and clears the 3:1 non-text floor against its canvas. A labeled filter or search control already identified by readable text and its icon may use the quiet line role for an optional perimeter, configured by its composition owner. Form fields whose boundary identifies the input keep the input role. Focus remains a separate full-contrast state. Never darken a decorative border locally to make it behave like a control.
|
|
325
290
|
- **Body / Muted** (`{colors.body}`, `{colors.muted}`): `{colors.body}` is readable supporting copy and clears AA on canvas; `{colors.muted}` is restricted to disabled, inactive, and placeholder content. Do not use muted text for ordinary descriptions, labels, or help text.
|
|
326
291
|
- **Focus ring** (`{colors.focus-ring}` / `{colors.dark-focus-ring}`): the ink keyboard-focus indicator, a full-opacity `outline` of `{spacing.focus-outline-width}` at `{spacing.focus-outline-offset}` offset, never a box-shadow. Focus is a state of material, so the indicator is the maximum-contrast neutral on each ground rather than a hue; the offset keeps it independent of the resting border, and it clears the 3:1 non-text floor against the adjacent canvas.
|
|
@@ -329,7 +294,6 @@ Every value a role needs is carried by the role token itself; there is no numeri
|
|
|
329
294
|
- **Navigation selection** (`{colors.navigation-selection-bg}`, `{colors.navigation-selection-fg}`, `{colors.navigation-selection-hover}`): the selected destination in persistent product navigation, a neutral selection field. Selection is a place, not a meaning, so it holds by contrast on the neutral spine; cobalto belongs to the semantic info and running roles only. The dark counterparts are tuned independently for the black console. Resting and hover pairs clear AA for text, and the offset focus outline stays visible against both the selection fill and the adjacent canvas.
|
|
330
295
|
- **Semantic feedback** (`{colors.success}` = verde with `{colors.success-soft}`/`{colors.success-deep}`; `{colors.error}` = rosso funzionale `#d3302f` with `{colors.error-soft}`/`{colors.error-deep}`; `{colors.warning}` = giallo `#ffc220` with `{colors.warning-soft}`/`{colors.warning-deep}`; `{colors.info}` = cobalto `#1e3cff` with `{colors.info-soft}`/`{colors.info-deep}`): validation, caution, approval, and operational feedback. In each pair the `-soft` value is the tinted tag/banner ground and the `-deep` value is the AA-clearing text on it. On a solid `error` fill (the shadcn `destructive` role) text is white; on a solid `warning` or `success` fill text is ink. The success pair intentionally reuses the link pair's AA-safe verde values; its feedback meaning remains distinct from inline navigation and entity-status semantics.
|
|
331
296
|
- **Accent** (`{colors.accent}` = arancio `#ff5a1f`): a small emphasis mark for exception flags and highlights; it appears as a mark, carries no text, and paints no fill or background. The identically-named shadcn surface role is a different thing — a neutral (`{colors.canvas-soft-2}` light, `{colors.dark-canvas-soft-2}` dark) with no hue.
|
|
332
|
-
- **Verde vivo** (`{colors.verde-vivo}` = `#008c45`, dark `{colors.dark-verde-vivo}` = `#62d494`): Nadia's presence accent. It paints the marks that say *Nadia herself is here*, such as the success beat over her silhouette on Nadia's entry screen. It is a mark colour, never a control fill, a text colour, a link, or a status; `action`, `link`, and `success` keep their jobs. It clears the 3:1 non-text floor on `{colors.canvas}` (4.3:1) and `{colors.dark-canvas}` (11.4:1) and carries no text of its own. White on it is 4.34:1, below AA for normal text, so a label never sits on a `verde-vivo` fill; the ring, halo, or portrait sits on it and the words sit on the canvas.
|
|
333
297
|
- **Workflow States** (`{colors.state-ready}` neutral, `{colors.state-running}` cobalto, `{colors.state-review}` giallo, `{colors.state-blocked}` rosso, `{colors.state-complete}` verde): the left-border/state vocabulary for agentic work surfaces — cobalto means in motion, verde means done. The dark counterparts (`{colors.dark-state-ready}`, `{colors.dark-state-running}`, `{colors.dark-state-review}`, `{colors.dark-state-blocked}`, `{colors.dark-state-complete}`) keep the same functional identity. These colours are carried by non-text state accents only — meter fills, delta marks, and the brand book's own rails; label text stays on the neutral foreground roles for contrast in both themes. Status is not one of their jobs: every status the product renders is the Badge status vocabulary (see `## Status Vocabulary`), which reads from the semantic feedback and link pairs, and the two token sets never cross.
|
|
334
298
|
|
|
335
299
|
### Chart categoricals (functional tier)
|
|
@@ -343,7 +307,7 @@ Five full-strength hues are the system's expressive chromatic range: verde `{col
|
|
|
343
307
|
|
|
344
308
|
### Dark primitives
|
|
345
309
|
|
|
346
|
-
**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. `dark-canvas` is true black: the only base plane for dark product shells. The remaining dark neutrals (`dark-canvas-soft`, `dark-canvas-soft-2`, `dark-ink`, `dark-body`, `dark-muted`, `dark-line`, `dark-input`, `dark-seam`, `dark-on-primary`, `dark-scrim`, and the neutral `dark-selection`/`dark-cross` marks) are exact equal-channel grays (OKLCH chroma 0), so no hue paints a surface. The soft canvas steps belong only to bounded interaction states such as hover, selection, keycaps, and inline controls; they never replace true black as a page, section, card, popover, sidebar, or large-panel ground. `dark-input` is the resting-control boundary, held brighter than the decorative `dark-line` border so a field edge clears the non-text floor before `{colors.dark-focus-ring}` appears. The `dark-action` family is a white control stepping through light grays, ink-labelled — the primary control stays neutral on black. Chroma lives only in the intentional accents: `dark-
|
|
310
|
+
**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. `dark-canvas` is true black: the only base plane for dark product shells. The remaining dark neutrals (`dark-canvas-soft`, `dark-canvas-soft-2`, `dark-ink`, `dark-body`, `dark-muted`, `dark-line`, `dark-input`, `dark-seam`, `dark-on-primary`, `dark-scrim`, and the neutral `dark-selection`/`dark-cross` marks) are exact equal-channel grays (OKLCH chroma 0), so no hue paints a surface. The soft canvas steps belong only to bounded interaction states such as hover, selection, keycaps, and inline controls; they never replace true black as a page, section, card, popover, sidebar, or large-panel ground. `dark-input` is the resting-control boundary, held brighter than the decorative `dark-line` border so a field edge clears the non-text floor before `{colors.dark-focus-ring}` appears. The `dark-action` family is a white control stepping through light grays, ink-labelled — the primary control stays neutral on black. Chroma lives only in the intentional accents: `dark-link`/`dark-link-deep` a lighter verde for links, and `dark-error`/`dark-error-deep`, `dark-warning`/`dark-warning-deep`, `dark-info`/`dark-info-deep`, `dark-success`/`dark-success-deep` the brightened feedback hues, each `*-soft` a deep tinted ground. `dark-navigation-selection-*` and `dark-focus-ring` sit on the neutral spine: selection and focus are material states, not meanings. The `dark-state-*` workflow family is not a text role; it preserves the matching ready/running/review/blocked/complete rail colours for 3 px state accents while text stays on neutral foreground roles. `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 chroma into the neutral set.
|
|
347
311
|
|
|
348
312
|
This achromatic-neutral discipline is not dark-specific: it governs the generated shadcn surface-role bridge in both the light `:root` and dark `.dark` maps. The neutral surface family — `background`, `card`, `popover`, `muted`, `secondary`, `sidebar`, `sidebar-accent`, their neutral foreground/border variants, plus `border` and `input` — resolves only to exact equal-channel grays (OKLCH chroma 0) in both themes. Hue in the role bridge is reserved for the explicit semantic roles `destructive`, `success`, and `warning`; `primary` resolves to the neutral action family. The focus rings (`ring`/`sidebar-ring`) and the `sidebar-primary*` navigation-selection family resolve to equal-channel grays like the surface family: focus and selection are material states, and no interaction state carries a hue. 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 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.
|
|
349
313
|
|
|
@@ -407,36 +371,34 @@ is never the only explanation.
|
|
|
407
371
|
|
|
408
372
|
## Typography
|
|
409
373
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
|
417
|
-
|
|
|
418
|
-
| `{typography.display-
|
|
419
|
-
| `{typography.display-
|
|
420
|
-
| `{typography.
|
|
421
|
-
| `{typography.
|
|
422
|
-
| `{typography.
|
|
423
|
-
| `{typography.
|
|
424
|
-
| `{typography.body-
|
|
425
|
-
| `{typography.body-md
|
|
426
|
-
| `{typography.body-sm}`
|
|
427
|
-
| `{typography.
|
|
428
|
-
| `{typography.
|
|
429
|
-
| `{typography.
|
|
430
|
-
| `{typography.caption-mono}` | 12px | 500 | 16px | Eyebrows, identifiers and code. |
|
|
431
|
-
| `{typography.code}` | 13px | 400 | 20px | Tool calls, snippets, traces. |
|
|
432
|
-
| `{typography.button-lg}` | 16px | 500 | 24px | Large button labels. |
|
|
433
|
-
| `{typography.button-md}` | 14px | 500 | 18px | Standard button and control labels. |
|
|
374
|
+
**Twelve sizes, named by the role they play.** A token says what a string is — a display line, a heading, body copy, a caption, code, a mono label — never how big it is, so a page that changes its mind about size changes one token and not every call site. Strong is a weight, not a token: a 500 run of body copy is `body-md` with `font-weight: 500`, which is why `body-md-strong`, `body-sm-strong`, `caption-strong` and the two `button-*` tokens are gone.
|
|
375
|
+
|
|
376
|
+
Geist Sans and Geist Mono are the two families, and there is no third. Each token below carries its own — `code` and `label-mono` are Geist Mono, every other token is Geist Sans — and its Use column says what that token is for. The register law that decides which family a given string takes, and what a card, panel, or section title therefore takes, is stated once in `## Components` → **`label-mono`**.
|
|
377
|
+
|
|
378
|
+
Do not use viewport-scaled type (no `vw`/`vh` font sizing): use fixed token sizes stepped by breakpoint-specific rules when a headline must grow. Tracking is a display-tier exception and nothing else: the three display sizes tighten from -0.035em at 72px to -0.025em at 40px so large type reads optically tight, and every heading, body, caption, code and label tier stays at `0px`. The contract authors the result in px, because DTCG dimensions are px or rem.
|
|
379
|
+
|
|
380
|
+
| Token | Size | Weight | Line Height | Tracking | Use |
|
|
381
|
+
| --------------------------- | ---- | ------ | ----------- | ---------- | ---------------------------------------------------------------------- |
|
|
382
|
+
| `{typography.display-xl}` | 72px | 600 | 74px | `-2.52px` | Hero headline at the widest breakpoint. |
|
|
383
|
+
| `{typography.display-lg}` | 52px | 600 | 54px | `-1.5px` | Compact hero and major landing headlines. |
|
|
384
|
+
| `{typography.display-md}` | 40px | 600 | 42px | `-1px` | Major section headings and the smallest display line. |
|
|
385
|
+
| `{typography.heading-lg}` | 30px | 600 | 32px | `0px` | Standard section title. |
|
|
386
|
+
| `{typography.heading-md}` | 24px | 600 | 32px | `0px` | Cell, artifact and panel titles; action bands and plan names. |
|
|
387
|
+
| `{typography.heading-sm}` | 20px | 600 | 28px | `0px` | The smallest heading, inline above a group. |
|
|
388
|
+
| `{typography.body-lg}` | 18px | 400 | 27px | `0px` | Hero and lead paragraphs. |
|
|
389
|
+
| `{typography.body-md}` | 16px | 400 | 25px | `0px` | Default body copy, and large control labels at weight 500. |
|
|
390
|
+
| `{typography.body-sm}` | 14px | 400 | 20px | `0px` | Secondary copy, nav, compact cell copy, control labels at weight 500. |
|
|
391
|
+
| `{typography.caption}` | 12px | 400 | 16px | `0px` | Footer secondary lines, badge labels, compact chrome labels. |
|
|
392
|
+
| `{typography.code}` | 13px | 400 | 20px | `0px` | Tool calls, snippets, traces. Geist Mono. |
|
|
393
|
+
| `{typography.label-mono}` | 12px | 500 | 16px | `0px` | Mono eyebrows, identifiers and low-priority metadata. Geist Mono. |
|
|
434
394
|
|
|
435
395
|
## Layout
|
|
436
396
|
|
|
437
|
-
Layout is mathematical and single-owner in every register: one owner per visible line, every gap
|
|
397
|
+
Layout is mathematical and single-owner in every register: one owner per visible line, every gap from the tokens below, never eyeballed.
|
|
398
|
+
|
|
399
|
+
The website's structure is three kinds of full-bleed section and nothing else: white for reading, black for a scene, and at most one flat, full-strength colour section per page for its single statement. Every section runs edge to edge and centres its content in the one column, `.nc-page`: a single content max-width with side gutters that grow from phone to desktop. Inside a section the content is a single column or a picture-and-text split, and between two sections there is one spacing step. Nothing else on the website sets a page width, and a section adds no frame, no row grid and no gutter texture.
|
|
438
400
|
|
|
439
|
-
The
|
|
401
|
+
The Portal and the Nadia desktop app build their own structure by their rulebooks (`## Registers`) and reach for the spacing ladder and the control geometry, not for the website's column.
|
|
440
402
|
|
|
441
403
|
### Spacing
|
|
442
404
|
|
|
@@ -460,7 +422,7 @@ Control geometry is foundation, so a control has the same physical size and the
|
|
|
460
422
|
|
|
461
423
|
| Token | Value | Owns |
|
|
462
424
|
| --- | --- | --- |
|
|
463
|
-
| `{spacing.guide}` | 1 px | Every ordinary seam
|
|
425
|
+
| `{spacing.guide}` | 1 px | Every ordinary seam |
|
|
464
426
|
| `{spacing.icon-stroke}` | 1.5 px | The house icon line, on screen, at 16, 20 and 24 px |
|
|
465
427
|
| `{spacing.icon-stroke-sm}` | 1.25 px | The same line at 12 px |
|
|
466
428
|
| `{spacing.focus-outline-width}` | 2 px | The one keyboard focus outline |
|
|
@@ -469,99 +431,29 @@ Control geometry is foundation, so a control has the same physical size and the
|
|
|
469
431
|
| `{spacing.control-padding-inline}` | 10 px | Inline padding of a control |
|
|
470
432
|
| `{spacing.touch-target}` | 44 px | Minimum target on coarse or non-hover input |
|
|
471
433
|
|
|
472
|
-
|
|
434
|
+
The website's column and its section rhythm belong to the website register and are authored in `register.website.layout`; the filter-chip sizes belong to the Portal register and are authored in `register.portal.density`. Both emit today's `--nc-*` names, and the values live in the one `json design-tokens` fence ("CSS Architecture & Token Pipeline"). Six tokens are the whole of the website's geometry; a page that needs a seventh is asking for a section kind the register does not have.
|
|
473
435
|
|
|
474
|
-
|
|
|
436
|
+
| Token | Owns | Register |
|
|
475
437
|
| --- | --- | --- |
|
|
476
|
-
|
|
|
477
|
-
|
|
|
478
|
-
|
|
|
479
|
-
|
|
|
480
|
-
|
|
|
481
|
-
|
|
|
482
|
-
|
|
|
483
|
-
| Bento heights | `h-bento-primary`, `h-bento-secondary`, `h-bento-mobile-copy`, `h-bento-mobile-main`, `h-bento-strip` | Website |
|
|
484
|
-
| Filter chip | `filter-chip-gap`, `filter-chip-height`, `filter-chip-icon` | Portal |
|
|
485
|
-
|
|
486
|
-
### Frame System
|
|
487
|
-
|
|
488
|
-
- `page-system` adds `--nc-page-pad` horizontal page padding and `{spacing.4xl}` vertical padding, so the frame floats on clear canvas between the sticky nav chrome and the footer instead of stacking against their hairlines.
|
|
489
|
-
- `page-frame` is centered and capped at `--nc-frame-max`. It owns the outer left/right/top borders.
|
|
490
|
-
- `page-row` is the only direct section unit inside `page-frame`. It owns the bottom border for each row.
|
|
491
|
-
- Desktop rows use 12 equal columns with `--nc-frame-gap` gutters.
|
|
492
|
-
- `active-lane` spans columns 2 through 11 on desktop and all columns on smaller viewports.
|
|
493
|
-
- Full-lane rows span all 12 columns only when the content owns columns 1 and 12 explicitly through the `stage` geometry (`nc-stage-frame`/`nc-stage-fill`/`nc-stage-grid`/`nc-stage-active`).
|
|
494
|
-
- Columns 1 and 12 are the page's quiet margin: empty canvas by default. Their presence is the whitespace itself — the grid sizes them whether or not anything paints there, matching the reference container model where structure lives inside bounded modules and never as page-length gutter texture. The diagonal `side-fill` is a scarce structural accent a row opts into with `data-rails="hatch"`; reserve it for the page's anchor rows (the opening hero, the closing conversion row), never as a default on every row. When present, the fill is bounded on both sides — the frame perimeter outside, the fill's own inner rail inside — so the texture reads as a deliberate panel, not an unbounded wash.
|
|
495
|
-
|
|
496
|
-
### Seam Ownership
|
|
497
|
-
|
|
498
|
-
Every visible line has one owner. Do not draw borders on both adjacent children at the same coordinate. Use a line-colored parent background plus `{spacing.guide}` gaps, or use a single explicit border owned by the parent row/component.
|
|
499
|
-
|
|
500
|
-
On a `blueprint-field` surface the model is draw-all-then-occlude: the texture layer owns every line uniformly and opaque content (`cell-solid` or a content slot) occludes the lines it covers. This is distinct from the parent-plus-gap model used by `cell-grid`; both keep exactly one owner per visible line.
|
|
501
|
-
|
|
502
|
-
The universal guide weight is `{spacing.guide}`. Crosshairs use the same physical weight as the line they mark; they are darker through `{colors.cross}`, not thicker.
|
|
438
|
+
| `content-max` | 1200 px: the widest the reading column ever grows | Website |
|
|
439
|
+
| `gutter-mobile` | 20 px: the side gutter beside that column below 600 px | Website |
|
|
440
|
+
| `gutter-tablet` | 40 px: the same gutter from 600 px | Website |
|
|
441
|
+
| `gutter-desktop` | 64 px: the same gutter from 960 px | Website |
|
|
442
|
+
| `section-step-mobile` | 64 px: the one gap between two sections below 960 px | Website |
|
|
443
|
+
| `section-step-desktop` | 96 px: the same gap from 960 px | Website |
|
|
444
|
+
| `filter-chip-gap`, `filter-chip-height`, `filter-chip-icon` | The Portal's filter chip | Portal |
|
|
503
445
|
|
|
504
446
|
### Responsive Rules
|
|
505
447
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
Height tokens are fixed by component family and breakpoint. Components may grow when real content requires it, but the default specimen height comes from the exported height tokens so repeated rows align predictably.
|
|
509
|
-
|
|
510
|
-
Page shells must prevent horizontal scrollbars when a mathematically aligned full-bleed surface uses viewport width. Clip horizontal overflow at the shell/root level; do not hide overflow on structural cells to mask bad seam math.
|
|
511
|
-
|
|
512
|
-
Compositions arrange approved primitives for a content role. They must not redefine page-frame math, row seams, marker placement, side-fill ownership, active-lane spans, or global guide primitives. If a composition needs new structural geometry, promote that geometry into the page grammar or a real component first.
|
|
513
|
-
|
|
514
|
-
### Delivery Tiers
|
|
515
|
-
|
|
516
|
-
Each reusable concern has one home and one authoring surface, so a member is documented and shipped in exactly one place:
|
|
517
|
-
|
|
518
|
-
- **Tokens** — exact reusable values live in this contract's `colors`, `spacing`, `rounded`, and `typography` front matter, and in the one `json design-tokens` fence for material, elevation, motion, and the register groups; they export to the generated token layer. No component or section may re-encode a token value.
|
|
519
|
-
- **Framework-agnostic CSS components** — the brand/display CSS components that remain in this package (agent-work artifacts, `image`, and the small label/badge/link metadata components). Their names and semantics live once in `## Components`; design-system CSS realises that catalog without a second recipe or component-token hierarchy.
|
|
520
|
-
- **Reusable compositions and sections** — patterns that arrange the page grammar and lower tiers for a content role. They ship as React shadcn compositions from `@nadicodeai/ui`, composed over the kept page grammar; they are not a pure-CSS section layer and do not add a second component catalog here.
|
|
521
|
-
- **Layout grammar** — the page-frame, row, lane, seam, stage, and marker system documented across this `## Layout` section, carried by the layout CSS layer.
|
|
522
|
-
- **Specimens** — static demonstrations of already-defined primitives. They invent no geometry, seams, heights, or responsive behavior; they only assemble shipped tiers for inspection.
|
|
523
|
-
|
|
524
|
-
The page grammar below is the `## Layout` home for the structural names; the section-level compositions that arrange them ship from `@nadicodeai/ui`.
|
|
525
|
-
|
|
526
|
-
### Page Grammar
|
|
527
|
-
|
|
528
|
-
Page grammar is the NadicodeAI structural system. It defines how pages are built before any content surface appears. These names live in this layout section, not in the component catalog. Exact reusable values are exported through `colors`, `spacing`, `rounded`, and `typography`; the structural semantics live here as layout doctrine, not as interface components.
|
|
529
|
-
|
|
530
|
-
**`page-frame`** (`nc-page-frame`) — centered bordered frame capped by `--nc-frame-max`. Owns the outer left/right/top seams.
|
|
448
|
+
The website has two breakpoints, 600 px and 960 px. They live in the application CSS layer, never in the generated token layer: `foundation.css` collapses `gutter-*` into `--nc-gutter` and `section-step-*` into `--nc-section-step` at those widths, so a section reads one name and resolves the value for the viewport it is on. No register adds a third breakpoint to this column.
|
|
531
449
|
|
|
532
|
-
|
|
450
|
+
Page shells must prevent horizontal scrollbars when a full-bleed section uses viewport width. Clip horizontal overflow at the shell or root level; do not hide overflow on an inner surface to mask bad math.
|
|
533
451
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
**`side-fill`** (`nc-side-fill`) — the opt-in owner for columns 1 and 12 when a row uses the active lane. Hidden by default (the quiet-gutter doctrine: the empty margin column is the default treatment); a row enables it with `data-rails="hatch"` on the `page-row`, reserved for the page's anchor rows. When shown, it paints the diagonal filler, expands into the frame gutter so the texture touches the active content edge, and owns its single inner boundary rail (`{colors.line}` on its lane-facing edge) so the hatch is bounded on both sides — frame perimeter outside, fill rail inside.
|
|
537
|
-
|
|
538
|
-
**`cell-grid`** (`nc-row-grid`) — repeated cell math. Uses `{colors.line}` parent background and `{spacing.guide}` gaps so the seam has one owner. Supports 2, 3, 4, 5, and 6 column desktop variants with responsive collapse.
|
|
539
|
-
|
|
540
|
-
**`panel-cell`** — a square structural content cell inside `cell-grid`. Uses `--nc-cell-padding` and no local border.
|
|
541
|
-
|
|
542
|
-
**`marker`** — sparse crosshair marker for major section/frame corners. It marks intersections; it is not decorative chrome for every card. It is placed on a grid-field track intersection and derives its position from the grid, not from a frame-relative offset.
|
|
543
|
-
|
|
544
|
-
**`diagonal-fill`** — structural filler for outer columns and empty side lanes.
|
|
545
|
-
|
|
546
|
-
**`dotted-field`** — artifact/canvas background for conversations, outputs, and diagrams. It indicates a work surface, not generic decoration.
|
|
547
|
-
|
|
548
|
-
**`blueprint-field`** — a feathered structural-pitch background texture that visualizes a grid as graph-paper rather than as load-bearing DOM. Column and row pitch track the meaningful column count so it stays legible; the field is always feathered so it reads as texture, not as paper. On the blueprint surface the lines are drawn once underneath and occluded by opaque content (`cell-solid` or the content slot) — the draw-all-then-occlude model. It is incidental brand texture: if the blueprint field is the first thing you notice, it is too strong.
|
|
549
|
-
|
|
550
|
-
**`rule-svg`** — bounded dashed connector rule. Uses `{colors.seam}` and never overlaps a cell seam.
|
|
551
|
-
|
|
552
|
-
Reusable section compositions ship as React components from `@nadicodeai/ui`, composed over the page grammar above; the page grammar is the framework-agnostic foundation they assemble.
|
|
553
|
-
|
|
554
|
-
### Related Layout Helpers
|
|
555
|
-
|
|
556
|
-
This live helper is part of the kept page-grammar layout layer. It supports index-style page assemblies rather than naming an interface component.
|
|
557
|
-
|
|
558
|
-
**`index-grid`** — layout helper for index-style page assemblies (blog, learn, and case-study rows whose guide layer owns the dividers).
|
|
559
|
-
|
|
560
|
-
`index-card` is the repeated item class inside `index-grid`, not a standalone contract key.
|
|
452
|
+
Compositions arrange approved primitives for a content role. They do not redefine the content max-width, the gutters, or the step between sections. If a composition needs structural geometry this section does not name, promote that geometry here first.
|
|
561
453
|
|
|
562
454
|
## Elevation & Depth
|
|
563
455
|
|
|
564
|
-
Product UI uses one shared material ladder. The workspace is one continuous ground (`{colors.material-workspace}` / `{colors.dark-material-workspace}`); every solid object uses the same fill (`{colors.material-solid}` / `{colors.dark-material-solid}`). In dark mode, both are true black. The workspace remains legible because it carries the existing `dotted-field` texture and solid objects occlude it. Elevation never means progressively greyer cards. Physical distance changes only the falloff of the rung, and the four rungs are the four owned utilities: `nc-elevation-resting` for resting content, then `nc-elevation-raised`, `nc-elevation-floating`, and `nc-elevation-modal` when an object is physically raised, floating, or modal. Each rung is authored per mode, light and dark, and carries its own ring as the recipe's final layer, so an elevated root never adds a border, a second ring, a local ring tint, or an opacity override. Product code chooses only the semantic role.
|
|
456
|
+
Product UI uses one shared material ladder. The workspace is one continuous ground (`{colors.material-workspace}` / `{colors.dark-material-workspace}`); every solid object uses the same fill (`{colors.material-solid}` / `{colors.dark-material-solid}`). In dark mode, both are true black. The workspace remains legible because it carries the existing `dotted-field` texture and solid objects occlude it. Elevation never means progressively greyer cards. Physical distance changes only the falloff of the rung, and the four rungs are the four owned utilities: `nc-elevation-resting` for resting content, then `nc-elevation-raised`, `nc-elevation-floating`, and `nc-elevation-modal` when an object is physically raised, floating, or modal. Each rung is authored per mode, light and dark, and carries its own ring as the recipe's final layer, so an elevated root never adds a border, a second ring, a local ring tint, or an opacity override. In light mode every rung's ring is black at 5%, because the shadow carries the height. On true black the shadows vanish, so the dark ring carries it instead and steps with the rung: resting 12%, raised 16%, floating 22%, modal 28% white. The falloff layers are identical in both modes; only the ring differs. Product code chooses only the semantic role.
|
|
565
457
|
|
|
566
458
|
Glass is a material variant, not an elevation step. Floating chrome may be glass: menus, popovers, selects, comboboxes, the command palette, and bars, the surfaces that stand over the room and show it through themselves. Content surfaces stay solid: cards, KPIs, tables, inspectors, and dialog, sheet, and drawer bodies, because glass floats but never carries content. Inside the window, glass composites only over our own content; a product whose window the operating system composites states its window material in its register. Glass keeps exactly one separator, the integrated edge ring of its elevation falloff, never ring plus shadow plus border stacked. Reduced-transparency mode replaces glass with the same solid material at the same elevation.
|
|
567
459
|
|
|
@@ -591,32 +483,44 @@ On coarse or non-hover input capability, every interactive target is at least 44
|
|
|
591
483
|
One radius rounds every surface. The reference is the search field: `{rounded.md}` (6 px). A surface never earns a larger corner by sitting higher on the elevation ladder, and no register may reintroduce a second surface radius.
|
|
592
484
|
|
|
593
485
|
- Use `{rounded.md}` (6 px) for every surface and every control: resting, raised, outlined, floating, and modal surfaces; cards, KPI cards, chart cards, tables, menus, selects, popovers, dropdowns, dialogs, sheets, drawers, takeovers, tooltips, toasts, inspectors; and buttons, inputs, chips, status tags, and small artifacts.
|
|
594
|
-
- Use `{rounded.none}` for
|
|
486
|
+
- Use `{rounded.none}` for full-bleed sections, structural cells, and structural modules.
|
|
595
487
|
- 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.
|
|
596
488
|
|
|
597
489
|
The radius scale itself is unchanged: `{rounded.xs}` through `{rounded.3xl}` stay exported for inner marks and for geometry a component owns, such as a progress track or a bar end. Only the rung that surfaces take is fixed.
|
|
598
490
|
|
|
599
|
-
|
|
491
|
+
Structural cells on the website are not cards and remain square, because the section around them supplies the visual system. Product cards use the resting material role. A details composition may divide its header and bound individual facts with the outlined role; each edge has one owner and fact cells add no elevation. Grouping does not justify another ring around the same container or a stronger shadow.
|
|
600
492
|
|
|
601
493
|
## Motion
|
|
602
494
|
|
|
603
|
-
|
|
495
|
+
**One motion law.** Only Agents move on their own. The interface answers a person's action, briefly, and stops: motion follows the action, stays under 300 ms, grows from the element that was pressed, and settles. While a person waits for something they asked for, one waiting line moves and nothing else.
|
|
496
|
+
|
|
497
|
+
Only Agents move on their own. An idle orb holds still, and under reduced
|
|
498
|
+
motion a thinking or working orb breathes in opacity, 1.6 s ease-in-out from
|
|
499
|
+
full ink to 0.45, so busy still reads as busy while every other orb is still
|
|
500
|
+
([agent orbs](../ui/docs/agent-orb.md)). Opening an Agent in the Portal is the
|
|
501
|
+
one view transition: the orb travels from the list row into the Agent's page
|
|
502
|
+
on `transition` with `in-out-strong`, over a root crossfade on `close`, and
|
|
503
|
+
reduced motion navigates instantly; the Portal's `portal.css` owns those rules
|
|
504
|
+
because that one navigation is the only place the product moves a page.
|
|
505
|
+
|
|
506
|
+
**One default transition in every product**: `confirm`, 180 ms, `out-strong`. It is set once, on `--default-transition-duration` and `--default-transition-timing-function` in `src/css/motion.css`, so a bounded Tailwind transition utility inherits the cadence and no product declares a default of its own.
|
|
604
507
|
|
|
605
|
-
|
|
508
|
+
**One reduced-motion policy**, stated once in `motion.css` and repeated nowhere: under `prefers-reduced-motion: reduce`, movement stops and paint continues. Transforms and keyframed movement go to their end state; opacity and colour transitions are kept, because a fade or a colour change is the state change itself rather than decoration around it, and an Agent that is thinking or working still has to read as busy. A component never answers reduced motion by turning every transition off.
|
|
509
|
+
|
|
510
|
+
The durations and easings live in `core.motion` of the authored token extension ("CSS Architecture & Token Pipeline"). The build emits every duration as `--nc-duration-*` and every easing as `--nc-ease-*`. `src/css/motion.css` owns the keyframes, the `nc-anim-*` and `nc-transition-*` classes, and the reduced-motion law, and references those names; it declares no duration, easing, or alias of its own. A register decides where motion appears; it never picks a duration outside this list, and `tests/guards/motion-durations.test.ts` fails on a time literal anywhere in the motion layer.
|
|
606
511
|
|
|
607
512
|
| Token | Use |
|
|
608
513
|
| --- | --- |
|
|
609
|
-
| `
|
|
610
|
-
| `
|
|
611
|
-
| `close` / `open` | Floating chrome and overlays leaving and arriving |
|
|
612
|
-
| `
|
|
613
|
-
| `msg-in` | A transcript message arriving |
|
|
614
|
-
| `
|
|
615
|
-
| `
|
|
616
|
-
| `
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
The easings are `emphasized`, `out-strong`, `in-out-strong`, and `drawer`.
|
|
514
|
+
| `stagger` 60 ms | The step between siblings in one arrival |
|
|
515
|
+
| `control` 100 ms | Hover and press on a control in a dense register |
|
|
516
|
+
| `close` 140 ms / `open` 220 ms | Floating chrome and overlays leaving and arriving |
|
|
517
|
+
| `confirm` 180 ms | Confirmation feedback, instant state flips, and the default transition |
|
|
518
|
+
| `msg-in` 240 ms | A transcript message arriving |
|
|
519
|
+
| `transition` 240 ms | Property transitions on a working surface, and the Agent view transition |
|
|
520
|
+
| `drawer-swipe` 400 ms / `drawer` 450 ms | Sheets and drawers, pointer-driven and programmatic |
|
|
521
|
+
| `wait` 1.6 s | The one waiting line, and nothing else |
|
|
522
|
+
|
|
523
|
+
The easings are `emphasized`, `out-strong`, `in-out-strong`, and `drawer`. Every remaining duration has a job these rules allow, which is why `spin`, `typing` and `shimmer` retired with the spinner, the typewriter line and the three shimmer systems: a busy spinner is not an Agent, and ambient decoration is not an answer to anything a person did.
|
|
620
524
|
|
|
621
525
|
## Registers
|
|
622
526
|
|
|
@@ -626,21 +530,31 @@ A register adds rules. It never redefines a foundation value. A value one regist
|
|
|
626
530
|
|
|
627
531
|
| Register | Rulebook | Its own token families | Dark mode |
|
|
628
532
|
| --- | --- | --- | --- |
|
|
629
|
-
| Website | `apps/website/docs/design-doctrine.md` over `## Layout` here | `register.website.layout`: `
|
|
533
|
+
| Website | `apps/website/docs/design-doctrine.md` over `## Layout` here | `register.website.layout`: `content-max`, `gutter-*`, `section-step-*`. It speaks `display-xl`, `display-lg`, and `title-lg` | Light only |
|
|
630
534
|
| Portal | `apps/portal/docs/information-architecture.md` for direction; `apps/portal/docs/design-doctrine.md` for implementation | `register.portal.density`: `filter-chip-gap`, `filter-chip-height`, `filter-chip-icon` | System, light, dark, on the `.dark` class |
|
|
631
535
|
| Nadia desktop app | `apps/nadia/docs/design-doctrine.md` | `register.nadia.*`: colour-role and radius aliases; six deprecated elevation recipes and the legacy overlay border remain as compatibility data. New surfaces consume the foundation's material roles | Follows the operating system, on the `.dark` class |
|
|
632
536
|
|
|
633
|
-
The website
|
|
537
|
+
The website is built from three kinds of full-bleed section and nothing else: white for reading, black for a scene with a marble figure and the live orb, and at most one flat, full-strength colour section per page for its single statement, in the hue of that page's picture. One content max-width with growing side gutters centres the reading content, a section holds a single column or a picture-and-text split, and one spacing step separates two sections (`## Layout`).
|
|
538
|
+
|
|
539
|
+
The website's depth is flat and architectural: the three section grounds, contrast, large Geist headlines and the approved pictures make hierarchy. It has no page frame, no row grid, no diagonal fill and no dotted field; the dotted field is the Portal's work surface. It uses no rung of the material ladder and no floating card stack as page structure, and no negative letter spacing outside the two display tiers.
|
|
634
540
|
|
|
635
541
|
The Portal and the desktop are product shells on the material ladder above, each by its rulebook. The desktop's window material is the operating system's where the OS composites the window; inside the window the foundation's glass law holds.
|
|
636
542
|
|
|
637
543
|
## Components
|
|
638
544
|
|
|
639
|
-
This section is the semantic catalog for framework-agnostic components. Exact reusable values stay in the token maps above; CSS owns component composition.
|
|
545
|
+
This section is the semantic catalog for framework-agnostic components. Exact reusable values stay in the token maps above; CSS owns component composition. The section grammar and the content column live in `## Layout`, while React components and reusable sections live in `@nadicodeai/ui`.
|
|
546
|
+
|
|
547
|
+
### Structural Surfaces
|
|
548
|
+
|
|
549
|
+
Two surfaces carry structure rather than content. Both are square (`{rounded.none}`), both take no rung of the elevation ladder, and neither draws a border of its own.
|
|
550
|
+
|
|
551
|
+
**`panel-cell`** — a structural content cell. It pads its content with `{spacing.lg}` and takes its height from what it holds; the surface around it owns any seam.
|
|
552
|
+
|
|
553
|
+
**`dotted-field`** — the Portal's work surface: the dotted ground behind conversations, outputs, and diagrams, on the material ladder's workspace role ("Elevation & Depth"). It indicates a work surface, never decoration, and the website does not use it.
|
|
640
554
|
|
|
641
555
|
### Interface Atoms
|
|
642
556
|
|
|
643
|
-
Interface CSS components provide small metadata, label, and link chrome. They inherit
|
|
557
|
+
Interface CSS components provide small metadata, label, and link chrome. They inherit nadicode tokens and stay subordinate to the layout; 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.
|
|
644
558
|
|
|
645
559
|
Keyboard focus has one owner: the kit's foundation layer draws the full-opacity `{spacing.focus-outline-width}` `{colors.focus-ring}` / `{colors.dark-focus-ring}` outline at `{spacing.focus-outline-offset}` offset on every `:focus-visible` element. A component never repaints focus with its own ring, hue, or width, and never removes the outline without a contrast-safe equivalent.
|
|
646
560
|
|
|
@@ -654,13 +568,13 @@ Keyboard focus has one owner: the kit's foundation layer draws the full-opacity
|
|
|
654
568
|
|
|
655
569
|
### Content Surfaces
|
|
656
570
|
|
|
657
|
-
Content surfaces display specific content types inside
|
|
571
|
+
Content surfaces display specific content types inside a section. They are valid when the content exists; they do not replace the section, the content column, or the seam rules.
|
|
658
572
|
|
|
659
|
-
**`image`** — editorial media mount, the single home for art-directed imagery inside
|
|
573
|
+
**`image`** — editorial media mount, the single home for art-directed imagery inside a section. A bounded media fill (img, picture, video, or inline SVG) with an optional mono tag chip overlaid on the media and an optional body-tone caption bar below it, both typed by the generated caption utilities applied in markup. Square-cornered (`{rounded.none}`): a mounted print, not a floating card — the parent frame supplies the visual system. With `data-frame="true"` it draws exactly one hairline (its own `{colors.line}` border), so it sits inside a borderless `panel-cell` or a visual slot without repairing or stacking onto any grid seam. The aspect ratio is the per-instance `--nc-image-ratio` knob (default 4 / 3) — set the prop on the element, never re-derive geometry inline. It has one form: there is no divider-strip variant. Use `image` for every illustrated image and every photographic surface. Conversation artifacts render through assistant-ui rather than a design-system CSS family.
|
|
660
574
|
|
|
661
575
|
### Agentic Work Surfaces
|
|
662
576
|
|
|
663
|
-
Agentic work surfaces are the
|
|
577
|
+
Agentic work surfaces are the nadicode-specific display layer outside the conversation renderer. They show concrete work output or workflow state such as memory, state, run progress, identity, and handoffs. Conversation messages, tools, artifacts, approvals, and pending indicators belong to assistant-ui.
|
|
664
578
|
|
|
665
579
|
Agent identity is decorative product identity, not a work artifact or a status signal: the Agent orbs, owned by [`packages/ui/docs/agent-orb.md`](../ui/docs/agent-orb.md).
|
|
666
580
|
|
|
@@ -697,30 +611,41 @@ whole map in one module.
|
|
|
697
611
|
|
|
698
612
|
## System activity
|
|
699
613
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
614
|
+
Who does the work decides how it looks. An Agent's work shows that Agent's orb
|
|
615
|
+
in its state and a sentence saying what it is doing; Nadia connecting is
|
|
616
|
+
Nadia's ribbon, working. Everything below is the system's own work, and an orb
|
|
617
|
+
means an Agent, so no system wait takes one.
|
|
618
|
+
|
|
619
|
+
System work under about a second is a still pending label on the control: its
|
|
620
|
+
own word changes, it holds its place and its icon, and it carries `disabled`
|
|
621
|
+
and `aria-busy`. Past a second, one 2 px waiting line of ink moves beside the
|
|
622
|
+
work, a 32% segment crossing its track linearly on `wait`; nothing else on the
|
|
623
|
+
screen moves while it does. Measurable work is a progress line with a written
|
|
624
|
+
count. A page load shows still placeholders in the shape of the content.
|
|
625
|
+
Reduced motion drops the travel and breathes the whole line in opacity.
|
|
626
|
+
|
|
627
|
+
The colour of a wait is ink: the cobalto info role belonged to the retired
|
|
628
|
+
activity particles and marks no system wait now. Success, warning and error
|
|
629
|
+
keep their meanings; waiting for a person or a failed operation uses the
|
|
630
|
+
feedback treatment, not an activity one.
|
|
631
|
+
|
|
632
|
+
The renderers are `PendingLabel`, `WaitingLine`, `Progress` and `Skeleton` in
|
|
633
|
+
`@nadicodeai/ui`. The one-second delay, the geometry, the ink and the motion
|
|
634
|
+
are owned by [`packages/ui/docs/activity.md`](../ui/docs/activity.md); the
|
|
635
|
+
motion vocabulary owns `.nc-anim-wait` and its reduced-motion law; a consuming
|
|
636
|
+
app chooses the wait and supplies its readable words.
|
|
712
637
|
|
|
713
638
|
## Do's and Don'ts
|
|
714
639
|
|
|
715
640
|
This section states the correct form; a complete positive definition is the whole rule.
|
|
716
641
|
|
|
717
|
-
-
|
|
718
|
-
- Every visible line has one owner: ordinary seams are `{spacing.guide}` at `{colors.line}`, tuned only at the token contract; required control boundaries are `{colors.input}` / `{colors.dark-input}`; named collection controls may use the optional-perimeter rule above; keyboard focus is the dedicated focus-ring roles
|
|
719
|
-
- Page structure is architectural: hairlines, luminance, spacing, and the grammar above. One material role per product container; structural
|
|
720
|
-
- Typography uses fixed token sizes stepped by breakpoint;
|
|
721
|
-
- Agent orbs identify an Agent; conversations, artifacts, review states, and work output belong to assistant-ui and the agentic work surfaces. Text
|
|
722
|
-
- Components are named as
|
|
723
|
-
- Each register keeps its own structure and chrome: the
|
|
642
|
+
- A website page is a sequence of full-bleed sections in three kinds only: white for reading, black for a scene, and at most one flat colour section for one statement. Each one centres its content in the same column, capped at `content-max` with the gutter its viewport gives it, and the sections sit one spacing step apart.
|
|
643
|
+
- Every visible line has one owner: ordinary seams are `{spacing.guide}` at `{colors.line}`, tuned only at the token contract; required control boundaries are `{colors.input}` / `{colors.dark-input}`; named collection controls may use the optional-perimeter rule above; keyboard focus is the dedicated focus-ring roles.
|
|
644
|
+
- Page structure is architectural: hairlines, luminance, spacing, and the section grammar above. One material role per product container; structural cells carry no elevation; the four `nc-elevation-*` rungs are the complete shadow vocabulary; modal scrims stay unblurred.
|
|
645
|
+
- Typography uses fixed token sizes stepped by breakpoint; a component's height comes from its content and the spacing ladder, never from a fixed height of its own.
|
|
646
|
+
- Agent orbs identify an Agent; conversations, artifacts, review states, and work output belong to assistant-ui and the agentic work surfaces. Text sits on the canvas beside an identity mark, never on it.
|
|
647
|
+
- Components are named as nadicode-owned primitives, and this file carries contract only: tokens, semantics, and application rules — component prop APIs, state matrices, screenshots, and page-specific material live with their owners.
|
|
648
|
+
- Each register keeps its own structure and chrome: the three section kinds on the website, the material ladder in the Portal and the desktop, the desktop window following the operating system.
|
|
724
649
|
|
|
725
650
|
## Iconography
|
|
726
651
|
|
|
@@ -729,7 +654,7 @@ discipline below, the sizes, the stroke, and the decorative-versus-named rule,
|
|
|
729
654
|
is foundation and holds in every register.
|
|
730
655
|
|
|
731
656
|
The website, the Portal, and `@nadicodeai/ui` draw from Lucide (ISC). Lucide's
|
|
732
|
-
shapes are never edited; the
|
|
657
|
+
shapes are never edited; the nadicode house render changes only how they are
|
|
733
658
|
drawn: a line of `{spacing.icon-stroke}` on screen at every size, held there by
|
|
734
659
|
`vector-effect: non-scaling-stroke` on each shape, round caps, round joins, no
|
|
735
660
|
fill, and `currentColor` inheritance. A 12 px icon takes
|
|
@@ -758,31 +683,31 @@ carry an accessible name.
|
|
|
758
683
|
|
|
759
684
|
## Brand media authority
|
|
760
685
|
|
|
761
|
-
The
|
|
686
|
+
The company is **nadicode**, lowercase ([ADR](../../docs/adr/2026-09-23-the-nadicode-design-system.md)). Its logo has three approved forms:
|
|
762
687
|
|
|
763
|
-
1. **
|
|
764
|
-
2. **Mark.** The
|
|
765
|
-
3. **
|
|
688
|
+
1. **Wordmark.** nadicode drawn in one geometric line, with one dot over the i. The dot is the only colour in the logo: where an Agent sits. Use it wherever the company must be named.
|
|
689
|
+
2. **Mark.** The plain n cut from the wordmark, never with a dot or any other shape added. It stands alone where the name does not fit: compact navigation, headers inside the product.
|
|
690
|
+
3. **Icon.** The white n on a `{colors.identity-cobalto}` tile with rounded corners: app icons, favicons and avatars. The tile is the one place the brand colour fills a field.
|
|
766
691
|
|
|
767
|
-
Other companies' marks are not
|
|
692
|
+
Other companies' marks are not nadicode company logos and are not governed by anything in this section. They are generated identity images owned by `@nadicodeai/ui/components/brand-icons`; [`packages/ui/docs/contract.md`](../ui/docs/contract.md) carries their rules. A third-party mark never enters a nadicode logo form, composition, or clear-space measurement.
|
|
768
693
|
|
|
769
|
-
Agent orbs, Nadia's included, and generated imagery are not
|
|
694
|
+
Agent orbs, Nadia's included, and generated imagery are not nadicode company logos. The orbs live in [`packages/ui/docs/agent-orb.md`](../ui/docs/agent-orb.md); editorial imagery routes through [`skills/marketing/blog-imagegen/references/editorial-register.md`](../../skills/marketing/blog-imagegen/references/editorial-register.md). This contract owns only the package delivery interface.
|
|
770
695
|
|
|
771
|
-
All
|
|
696
|
+
All forms derive from one authored, framework-neutral geometry source exported as `@nadicodeai/design-system/assets/logo-geometry`: on a 100-unit x-height, an 18-unit stroke with flat ends, bowls and the n's arch of radius 41, and the dot of radius 14 centred 79 units above the baseline over the i's stem. No SVG, React component, favicon, document, or app re-authors, traces, typesets, or rearranges those shapes. The eight reference files beside the ADR are the target each generated output matches, byte for byte, and the package guard fails on any output that drifts from them.
|
|
772
697
|
|
|
773
|
-
|
|
698
|
+
On `{colors.canvas}` and the soft neutral canvases, the letters are ink and the dot is `{colors.logo-dot}`. On `{colors.identity-ink}` and other dark grounds, the letters are `{colors.identity-white}` and the dot is `{colors.dark-logo-dot}`, a brighter cobalt, so it does not sink into black. `{colors.logo-dot}` is the logo's own colour role and the only token a consumer paints the dot with; the generated mode layer flips it under any dark ancestor, so React draws one form on both grounds. A one-ink form, letters and dot in one colour, exists only where a single ink prints: embossing, stamps, one-colour print. On photography, place the logo in a quiet area or over a scrim that keeps every part legible; when neither is available, mount it on an approved solid field. One surface uses one treatment.
|
|
774
699
|
|
|
775
|
-
The clear-space unit is
|
|
700
|
+
The clear-space unit is one stroke width of the rendered wordmark or mark. Keep at least one unit free on every side, with no text, rule, image, or container edge inside it. Minimum rendered sizes are 72 CSS pixels wide for the wordmark, 12 CSS pixels for the mark, and 16 CSS pixels for the favicon. Browser and operating-system icon slots use the supplied favicon or app-icon files at the platform's required size. Never compress, crop, or distort a logo to fit.
|
|
776
701
|
|
|
777
|
-
For a meaningful standalone image, use the accessible name `
|
|
702
|
+
For a meaningful standalone image, use the accessible name `nadicode`; the accessible name is the label that identifies an image, link, or control to assistive technology. When a containing link or control already has that accessible name, hide the logo image from assistive technology with empty alt text. Never repeat the same accessible name on both the container and the image.
|
|
778
703
|
|
|
779
|
-
Do not redraw, retype, reorder, stretch, crop, rotate, recolor, outline, shadow, animate, or add effects or gradients to a logo form. Do not
|
|
704
|
+
Do not redraw, retype, reorder, stretch, crop, rotate, recolor, outline, shadow, animate, or add effects or gradients to a logo form. Do not add a dot or any shape to the mark, move the dot off the i, or substitute Nadia imagery for the logo.
|
|
780
705
|
|
|
781
|
-
The package build renders and publicly exports
|
|
706
|
+
The package build renders and publicly exports seven files as SVG and transparent PNG from the geometry and the current `colors.*` contract: `assets/logo` and `assets/logo-white`, `assets/logo-one-ink` and `assets/logo-one-ink-white`, `assets/mark` and `assets/mark-white`, and `assets/app-icon`. React consumers use `BrandMark` or `BrandWordmark` according to the roles above; there is no lockup adapter, because the wordmark is the logo and the mark is already inside it, so no surface places the two together. The operator-only favicon generator draws the same icon tile at the sizes a browser and a platform ask for; it does not substitute another mark. Private geometry templates do not ship. A contract or geometry change is completed by regeneration, never by repainting an output or updating a fallback by hand.
|
|
782
707
|
|
|
783
708
|
## CSS Architecture & Token Pipeline
|
|
784
709
|
|
|
785
|
-
How this contract becomes shipped CSS. The private CSS authoring graph lives in `src/css/`; the build flattens that graph and inlines its component icon dependencies into the single public `dist/css/index.css` artifact exported as `@nadicodeai/design-system/css`. Generated files and partials never ship as package subpaths. The cascade is `@layer tokens, theme, reset, foundation, motion,
|
|
710
|
+
How this contract becomes shipped CSS. The private CSS authoring graph lives in `src/css/`; the build flattens that graph and inlines its component icon dependencies into the single public `dist/css/index.css` artifact exported as `@nadicodeai/design-system/css`. Generated files and partials never ship as package subpaths. The cascade is `@layer tokens, theme, reset, foundation, motion, primitives, components;` with no `layout` and no `sections` layer. The bundle ships only framework-agnostic brand and display CSS components; generic marketing and SaaS components ship as React components from `@nadicodeai/ui`.
|
|
786
711
|
|
|
787
712
|
### Public style interfaces
|
|
788
713
|
|
|
@@ -795,17 +720,17 @@ Callers never import generated files, CSS partials, or framework adapters direct
|
|
|
795
720
|
|
|
796
721
|
### Authoring homes
|
|
797
722
|
|
|
798
|
-
Each
|
|
723
|
+
Each part of the shipped CSS has exactly one authoring file:
|
|
799
724
|
|
|
800
|
-
- Tokens: `src/css/tokens.generated.css`, built from this contract and never hand-edited. Runtime composition belongs to the owning layer, such as responsive switching in `
|
|
725
|
+
- Tokens: `src/css/tokens.generated.css`, built from this contract and never hand-edited. Runtime composition belongs to the owning layer, such as the website's responsive switching in `foundation.css`; there is no hand-authored token partial.
|
|
801
726
|
- Type utilities: the `.nc-type-*` classes live in `foundation.css`.
|
|
802
|
-
-
|
|
727
|
+
- The website's content column, `.nc-page`, and the responsive `@media` switching behind it: `foundation.css`.
|
|
803
728
|
- CSS primitives and components: `primitives.css` plus `components/*`. Every shipped component is named once in `## Components`; the two-way guard derives the CSS relationship from that catalog.
|
|
804
729
|
- Specimens: `examples/`, which only assemble already-defined tiers.
|
|
805
730
|
|
|
806
731
|
### Authored token extension
|
|
807
732
|
|
|
808
|
-
The YAML front matter carries the four groups the Google design schema defines: colors, typography, rounded, spacing. Everything else this contract owns is authored in the one `json design-tokens` fence below, as DTCG 2025.10. It holds `core.material`, `core.elevation` (four rungs per mode, each recipe ending in its own ring), `core.motion.duration` and `core.motion.ease`, and the register groups: `register.website.layout` (the
|
|
733
|
+
The YAML front matter carries the four groups the Google design schema defines: colors, typography, rounded, spacing. Everything else this contract owns is authored in the one `json design-tokens` fence below, as DTCG 2025.10. It holds `core.material`, `core.elevation` (four rungs per mode, each recipe ending in its own ring), `core.motion.duration` and `core.motion.ease`, and the register groups: `register.website.layout` (the website's column and section rhythm), `register.portal.density` (the filter-chip sizes), and `register.nadia` (the desktop's colour and radius aliases onto `core`, plus deprecated elevation data retained for older consumers).
|
|
809
734
|
|
|
810
735
|
An alias is written in the short `{core.color.canvas}` form here; the build rewrites it to the public rooted form `{nadicode.core.color.canvas}` in `dist/tokens/nadicode.dtcg.json`. `$extensions."ai.nadicode.targets"` on a register group lists where its values go: `css` puts them in the generated stylesheets, `data` keeps them in the token files only. A register group without that key fails the build. `core` carries no key and always reaches both.
|
|
811
736
|
|
|
@@ -871,7 +796,7 @@ An alias is written in the short `{core.color.canvas}` form here; the build rewr
|
|
|
871
796
|
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":5.25,"unit":"px"},"blur":{"value":7,"unit":"px"},"spread":{"value":0,"unit":"px"},"color":{"colorSpace":"srgb","components":[0,0,0],"alpha":0.02}},
|
|
872
797
|
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":2.79,"unit":"px"},"blur":{"value":3.72,"unit":"px"},"spread":{"value":-2,"unit":"px"},"color":{"colorSpace":"srgb","components":[0,0,0],"alpha":0.01}},
|
|
873
798
|
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":1.16,"unit":"px"},"blur":{"value":1.5,"unit":"px"},"spread":{"value":0,"unit":"px"},"color":{"colorSpace":"srgb","components":[0,0,0],"alpha":0.01}},
|
|
874
|
-
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":0,"unit":"px"},"blur":{"value":0,"unit":"px"},"spread":{"value":1,"unit":"px"},"color":{"colorSpace":"srgb","components":[1,1,1],"alpha":0.
|
|
799
|
+
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":0,"unit":"px"},"blur":{"value":0,"unit":"px"},"spread":{"value":1,"unit":"px"},"color":{"colorSpace":"srgb","components":[1,1,1],"alpha":0.12}}
|
|
875
800
|
]
|
|
876
801
|
},
|
|
877
802
|
"raised": {
|
|
@@ -881,7 +806,7 @@ An alias is written in the short `{core.color.canvas}` form here; the build rewr
|
|
|
881
806
|
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":6,"unit":"px"},"blur":{"value":12,"unit":"px"},"spread":{"value":0,"unit":"px"},"color":{"colorSpace":"srgb","components":[0,0,0],"alpha":0.03}},
|
|
882
807
|
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":3,"unit":"px"},"blur":{"value":6,"unit":"px"},"spread":{"value":0,"unit":"px"},"color":{"colorSpace":"srgb","components":[0,0,0],"alpha":0.02}},
|
|
883
808
|
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":1.5,"unit":"px"},"blur":{"value":3,"unit":"px"},"spread":{"value":0,"unit":"px"},"color":{"colorSpace":"srgb","components":[0,0,0],"alpha":0.02}},
|
|
884
|
-
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":0,"unit":"px"},"blur":{"value":0,"unit":"px"},"spread":{"value":1,"unit":"px"},"color":{"colorSpace":"srgb","components":[1,1,1],"alpha":0.
|
|
809
|
+
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":0,"unit":"px"},"blur":{"value":0,"unit":"px"},"spread":{"value":1,"unit":"px"},"color":{"colorSpace":"srgb","components":[1,1,1],"alpha":0.16}}
|
|
885
810
|
]
|
|
886
811
|
},
|
|
887
812
|
"floating": {
|
|
@@ -891,7 +816,7 @@ An alias is written in the short `{core.color.canvas}` form here; the build rewr
|
|
|
891
816
|
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":10,"unit":"px"},"blur":{"value":20,"unit":"px"},"spread":{"value":0,"unit":"px"},"color":{"colorSpace":"srgb","components":[0,0,0],"alpha":0.04}},
|
|
892
817
|
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":5,"unit":"px"},"blur":{"value":10,"unit":"px"},"spread":{"value":0,"unit":"px"},"color":{"colorSpace":"srgb","components":[0,0,0],"alpha":0.03}},
|
|
893
818
|
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":2,"unit":"px"},"blur":{"value":4,"unit":"px"},"spread":{"value":0,"unit":"px"},"color":{"colorSpace":"srgb","components":[0,0,0],"alpha":0.02}},
|
|
894
|
-
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":0,"unit":"px"},"blur":{"value":0,"unit":"px"},"spread":{"value":1,"unit":"px"},"color":{"colorSpace":"srgb","components":[1,1,1],"alpha":0.
|
|
819
|
+
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":0,"unit":"px"},"blur":{"value":0,"unit":"px"},"spread":{"value":1,"unit":"px"},"color":{"colorSpace":"srgb","components":[1,1,1],"alpha":0.22}}
|
|
895
820
|
]
|
|
896
821
|
},
|
|
897
822
|
"modal": {
|
|
@@ -901,7 +826,7 @@ An alias is written in the short `{core.color.canvas}` form here; the build rewr
|
|
|
901
826
|
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":15,"unit":"px"},"blur":{"value":30,"unit":"px"},"spread":{"value":0,"unit":"px"},"color":{"colorSpace":"srgb","components":[0,0,0],"alpha":0.05}},
|
|
902
827
|
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":7.5,"unit":"px"},"blur":{"value":15,"unit":"px"},"spread":{"value":0,"unit":"px"},"color":{"colorSpace":"srgb","components":[0,0,0],"alpha":0.04}},
|
|
903
828
|
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":3,"unit":"px"},"blur":{"value":6,"unit":"px"},"spread":{"value":0,"unit":"px"},"color":{"colorSpace":"srgb","components":[0,0,0],"alpha":0.03}},
|
|
904
|
-
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":0,"unit":"px"},"blur":{"value":0,"unit":"px"},"spread":{"value":1,"unit":"px"},"color":{"colorSpace":"srgb","components":[1,1,1],"alpha":0.
|
|
829
|
+
{"offsetX":{"value":0,"unit":"px"},"offsetY":{"value":0,"unit":"px"},"blur":{"value":0,"unit":"px"},"spread":{"value":1,"unit":"px"},"color":{"colorSpace":"srgb","components":[1,1,1],"alpha":0.28}}
|
|
905
830
|
]
|
|
906
831
|
}
|
|
907
832
|
}
|
|
@@ -918,10 +843,7 @@ An alias is written in the short `{core.color.canvas}` form here; the build rewr
|
|
|
918
843
|
"transition": {"$value":{"value":240,"unit":"ms"}},
|
|
919
844
|
"drawer-swipe": {"$value":{"value":400,"unit":"ms"}},
|
|
920
845
|
"drawer": {"$value":{"value":450,"unit":"ms"}},
|
|
921
|
-
"
|
|
922
|
-
"typing": {"$value":{"value":1,"unit":"s"}},
|
|
923
|
-
"pulse": {"$value":{"value":1.6,"unit":"s"}},
|
|
924
|
-
"shimmer": {"$value":{"value":2,"unit":"s"}}
|
|
846
|
+
"wait": {"$value":{"value":1.6,"unit":"s"}}
|
|
925
847
|
},
|
|
926
848
|
"ease": {
|
|
927
849
|
"$type": "cubicBezier",
|
|
@@ -937,51 +859,12 @@ An alias is written in the short `{core.color.canvas}` form here; the build rewr
|
|
|
937
859
|
"$extensions": {"ai.nadicode.targets":["css","data"]},
|
|
938
860
|
"layout": {
|
|
939
861
|
"$type": "dimension",
|
|
940
|
-
"
|
|
941
|
-
"
|
|
942
|
-
"
|
|
943
|
-
"
|
|
944
|
-
"
|
|
945
|
-
"
|
|
946
|
-
"frame-gap": {"$value":{"value":24,"unit":"px"}},
|
|
947
|
-
"cell-padding": {"$value":{"value":24,"unit":"px"}},
|
|
948
|
-
"section-gap": {"$value":{"value":48,"unit":"px"}},
|
|
949
|
-
"cross-size-mobile": {"$value":{"value":11,"unit":"px"}},
|
|
950
|
-
"cross-size-tablet": {"$value":{"value":15,"unit":"px"}},
|
|
951
|
-
"cross-size-desktop": {"$value":{"value":21,"unit":"px"}},
|
|
952
|
-
"h-strip-mobile": {"$value":{"value":72,"unit":"px"}},
|
|
953
|
-
"h-strip-tablet": {"$value":{"value":80,"unit":"px"}},
|
|
954
|
-
"h-strip-desktop": {"$value":{"value":88,"unit":"px"}},
|
|
955
|
-
"h-cell-sm": {"$value":{"value":120,"unit":"px"}},
|
|
956
|
-
"h-cell-md-mobile": {"$value":{"value":144,"unit":"px"}},
|
|
957
|
-
"h-cell-md-tablet": {"$value":{"value":160,"unit":"px"}},
|
|
958
|
-
"h-cell-md-desktop": {"$value":{"value":168,"unit":"px"}},
|
|
959
|
-
"h-cell-lg-mobile": {"$value":{"value":220,"unit":"px"}},
|
|
960
|
-
"h-cell-lg-desktop": {"$value":{"value":240,"unit":"px"}},
|
|
961
|
-
"h-visual-mobile": {"$value":{"value":276,"unit":"px"}},
|
|
962
|
-
"h-visual-tablet": {"$value":{"value":318,"unit":"px"}},
|
|
963
|
-
"h-visual-desktop": {"$value":{"value":360,"unit":"px"}},
|
|
964
|
-
"h-precision-mobile": {"$value":{"value":276,"unit":"px"}},
|
|
965
|
-
"h-precision-tablet": {"$value":{"value":480,"unit":"px"}},
|
|
966
|
-
"h-precision-desktop": {"$value":{"value":720,"unit":"px"}},
|
|
967
|
-
"h-hero-mobile": {"$value":{"value":560,"unit":"px"}},
|
|
968
|
-
"h-hero-desktop": {"$value":{"value":720,"unit":"px"}},
|
|
969
|
-
"h-action-strip-mobile": {"$value":{"value":20,"unit":"px"}},
|
|
970
|
-
"h-action-strip-desktop": {"$value":{"value":32,"unit":"px"}},
|
|
971
|
-
"h-action-body-mobile": {"$value":{"value":320,"unit":"px"}},
|
|
972
|
-
"h-action-body-tablet": {"$value":{"value":338,"unit":"px"}},
|
|
973
|
-
"h-action-band": {"$value":{"value":260,"unit":"px"}},
|
|
974
|
-
"h-feature-mobile": {"$value":{"value":360,"unit":"px"}},
|
|
975
|
-
"h-feature-tablet": {"$value":{"value":400,"unit":"px"}},
|
|
976
|
-
"h-feature-desktop": {"$value":{"value":456,"unit":"px"}},
|
|
977
|
-
"h-editorial-feature-mobile": {"$value":{"value":360,"unit":"px"}},
|
|
978
|
-
"h-editorial-feature-tablet": {"$value":{"value":440,"unit":"px"}},
|
|
979
|
-
"h-editorial-feature-desktop": {"$value":{"value":560,"unit":"px"}},
|
|
980
|
-
"h-bento-primary": {"$value":{"value":384,"unit":"px"}},
|
|
981
|
-
"h-bento-secondary": {"$value":{"value":240,"unit":"px"}},
|
|
982
|
-
"h-bento-mobile-copy": {"$value":{"value":248,"unit":"px"}},
|
|
983
|
-
"h-bento-mobile-main": {"$value":{"value":537,"unit":"px"}},
|
|
984
|
-
"h-bento-strip": {"$value":{"value":20,"unit":"px"}}
|
|
862
|
+
"content-max": {"$value":{"value":1200,"unit":"px"}},
|
|
863
|
+
"gutter-mobile": {"$value":{"value":20,"unit":"px"}},
|
|
864
|
+
"gutter-tablet": {"$value":{"value":40,"unit":"px"}},
|
|
865
|
+
"gutter-desktop": {"$value":{"value":64,"unit":"px"}},
|
|
866
|
+
"section-step-mobile": {"$value":{"value":64,"unit":"px"}},
|
|
867
|
+
"section-step-desktop": {"$value":{"value":96,"unit":"px"}}
|
|
985
868
|
}
|
|
986
869
|
},
|
|
987
870
|
"portal": {
|