@neuravision/construct 2.1.5 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,36 @@ All notable changes to `@neuravision/construct` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.2.0] - 2026-07-25
9
+
10
+ ### Added
11
+
12
+ - Frame: new `ct-frame` owned-surface component for figures, code samples, media, and callouts.
13
+ `ct-frame__content` owns rounded clipping while the outer frame owns its border, radius,
14
+ background, shadow, and optional `ct-frame--datum` registration mark. This separation keeps
15
+ the orange and neutral contours pixel-aligned without relying on browser-specific overflow
16
+ behavior. Frame surface decisions are exposed as `component.frame.*` tokens and local
17
+ `--ct-frame-*` override hooks, with a dedicated standalone `components/frame.css` entry.
18
+
19
+ ### Changed
20
+
21
+ - Datum registration-mark painting is centralized in one internal component contract shared by
22
+ `ct-frame--datum`, `ct-card--datum`, and the low-level `ct-datum-frame` decorator. Card marks now
23
+ follow the card's effective radius instead of the global radius directly. Bordered or clipped
24
+ exhibits should use the owned Frame anatomy; `ct-datum-frame` remains available for custom,
25
+ unclipped compositions.
26
+
27
+ ## [2.1.6] - 2026-07-19
28
+
29
+ ### Fixed
30
+
31
+ - Datum registration marks on `ct-datum-frame` and `ct-card--datum` now establish an
32
+ isolated component stacking context and render above component-local chrome. Opaque,
33
+ positioned headers (such as terminal captions at `z-index: 1`) previously painted over
34
+ the orange corner even though `ct-datum-frame` explicitly supports code samples. The
35
+ mark remains contained below global overlays, and the Storybook contract now covers a
36
+ clipped, rounded code frame with layered chrome.
37
+
8
38
  ## [2.1.5] - 2026-07-17
9
39
 
10
40
  ### Fixed
package/README.md CHANGED
@@ -25,7 +25,7 @@
25
25
  Construct is a **single source of design truth** that ships portable CSS, validated design tokens, and opt-in headless behaviors — without framework lock-in. Style values live once as JSON tokens and compile to CSS custom properties, JSON, and typed TypeScript exports. Components use `ct-` classes and ARIA/data state, so they work anywhere that renders DOM.
26
26
 
27
27
  - 🎯 **Three token layers** — primitive, semantic, and component contracts with schema and contrast validation
28
- - 🧩 **Framework-agnostic** — 49 standalone component style entries and a full CSS bundle
28
+ - 🧩 **Framework-agnostic** — 50 standalone component style entries and a full CSS bundle
29
29
  - ♿ **Accessibility first** — WCAG 2.2 AA targets, tested ARIA/keyboard controllers, focus and forced-colors contracts
30
30
  - ⚙️ **Optional behavior** — nine typed, dependency-free ESM controllers; importing CSS never starts JavaScript
31
31
  - 🎨 **Three themes** — `light`, `dark`, `high-contrast`, with system-preference fallback
@@ -133,7 +133,7 @@ npx construct-theme --theme node_modules/@neuravision/construct/themes/walnut.th
133
133
 
134
134
  ## 🧩 Components
135
135
 
136
- 49 standalone component style entries, documented and accessibility-tested in [Storybook](https://samyssmile.github.io/construct/).
136
+ 50 standalone component style entries, documented and accessibility-tested in [Storybook](https://samyssmile.github.io/construct/).
137
137
 
138
138
  | Category | Components |
139
139
  |----------|-----------|
@@ -143,7 +143,7 @@ npx construct-theme --theme node_modules/@neuravision/construct/themes/walnut.th
143
143
  | **Feedback** | Alert · Banner · Toast · Spinner · Skeleton · Progress Bar · Status · Empty State |
144
144
  | **Navigation** | Navbar · Breadcrumbs · Tabs · Pagination · Sidebar · Skip Link |
145
145
  | **Overlays** | Modal · Drawer · Popover · Dropdown |
146
- | **Layout** | Card · Divider · Accordion · App Shell (V1 compatibility + V2 recommended) |
146
+ | **Layout** | Card · Frame · Divider · Accordion · App Shell (V1 compatibility + V2 recommended) |
147
147
 
148
148
  → [**Explore every component in the live Storybook**](https://samyssmile.github.io/construct/)
149
149
 
@@ -214,6 +214,27 @@ Content card with header, body, and footer:
214
214
  </section>
215
215
  ```
216
216
 
217
+ ### Frame
218
+
219
+ Owned surface for figures, code samples, media, and callouts. The outer frame owns its border,
220
+ radius, background, shadow, and optional datum mark. Put content that must be clipped inside
221
+ `ct-frame__content`; never clip the outer frame, because that would cut the mark back to the
222
+ padding edge.
223
+
224
+ ```html
225
+ <div class="ct-frame ct-frame--datum">
226
+ <figure class="ct-frame__content" aria-labelledby="sample-caption">
227
+ <figcaption id="sample-caption">Code sample</figcaption>
228
+ <pre><code>npm install @neuravision/construct</code></pre>
229
+ </figure>
230
+ </div>
231
+ ```
232
+
233
+ Use any semantically appropriate outer element (`aside`, `section`, or `div`). When the framed
234
+ content is a figure, use the `figure` itself as `ct-frame__content` so its `figcaption` remains a
235
+ valid direct child. Customize the owned surface with `--ct-frame-background`, `--ct-frame-border`,
236
+ `--ct-frame-border-width`, `--ct-frame-radius`, and `--ct-frame-shadow`.
237
+
217
238
  ### Datum Primitives
218
239
 
219
240
  The reference-line grammar from `components/datum.css` — Construct's orange signature as reusable
@@ -230,7 +251,9 @@ structural vocabulary. All dimensions are component tokens (`--component-datum-*
230
251
  aria-label="Upload" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"
231
252
  style="--ct-datum-scale-progress: 60%;"></div>
232
253
 
233
- <figure class="ct-datum-frame">…</figure>
254
+ <div class="ct-frame ct-frame--datum">
255
+ <figure class="ct-frame__content">…</figure>
256
+ </div>
234
257
  ```
235
258
 
236
259
  - `ct-eyebrow` - Mono kicker with a leading datum tick; `--numbered` adds drawing-set sheet numbers
@@ -238,7 +261,8 @@ structural vocabulary. All dimensions are component tokens (`--component-datum-*
238
261
  - `ct-datum-scale` - Measured ruler line; decorative, mark it `role="presentation"`
239
262
  - `ct-datum-scale--progress` - The origin segment reports progress via `--ct-datum-scale-progress`;
240
263
  pair with `role="progressbar"` and `aria-value*`
241
- - `ct-datum-frame` - Corner registration mark for figures, code samples, and media
264
+ - `ct-frame--datum` - Preferred owned frame for bordered or clipped figures, code samples, and media
265
+ - `ct-datum-frame` - Low-level corner decorator for custom surfaces that do not clip the decorated element
242
266
  - `ct-card--datum`, active leading edges, the tab indicator, sorted table columns, and
243
267
  `ct-chart__datum-line` speak the same grammar
244
268
 
@@ -0,0 +1,23 @@
1
+ /* Shared datum registration-mark paint contract.
2
+ Owning components provide the inset and radius through local properties so
3
+ every standalone entry renders the same geometry without copying it. */
4
+ :is(.ct-datum-frame, .ct-card--datum, .ct-frame--datum)::before {
5
+ content: '';
6
+ position: absolute;
7
+ inset-block-start: var(--ct-datum-mark-inset);
8
+ inset-inline-start: var(--ct-datum-mark-inset);
9
+ width: var(--component-datum-mark-size);
10
+ height: var(--component-datum-mark-size);
11
+ border-block-start: var(--border-medium) solid var(--color-brand-accent);
12
+ border-inline-start: var(--border-medium) solid var(--color-brand-accent);
13
+ border-start-start-radius: var(--ct-datum-mark-radius);
14
+ z-index: 2;
15
+ pointer-events: none;
16
+ }
17
+
18
+ @media (forced-colors: active) {
19
+ :is(.ct-datum-frame, .ct-card--datum, .ct-frame--datum)::before {
20
+ border-block-start-color: CanvasText;
21
+ border-inline-start-color: CanvasText;
22
+ }
23
+ }
@@ -109,20 +109,13 @@
109
109
  state carries the same orange leading edge as list and sidebar items.
110
110
  Both are opt-in and additive — they don't change default cards. */
111
111
  .ct-card--datum {
112
- position: relative;
113
- }
112
+ --ct-datum-mark-inset: calc(-1 * var(--border-thin));
113
+ --ct-datum-mark-radius: var(--ct-card-radius);
114
114
 
115
- .ct-card--datum::before {
116
- content: '';
117
- position: absolute;
118
- inset-block-start: calc(-1 * var(--border-thin));
119
- inset-inline-start: calc(-1 * var(--border-thin));
120
- width: var(--component-datum-mark-size);
121
- height: var(--component-datum-mark-size);
122
- border-block-start: var(--border-medium) solid var(--color-brand-accent);
123
- border-inline-start: var(--border-medium) solid var(--color-brand-accent);
124
- border-start-start-radius: var(--radius-lg);
125
- pointer-events: none;
115
+ position: relative;
116
+ /* Contain the datum's internal paint layer so it cannot overlap adjacent
117
+ cards or consumer overlays. */
118
+ isolation: isolate;
126
119
  }
127
120
 
128
121
  .ct-card--active,
@@ -254,20 +254,13 @@
254
254
  "exhibit" treatment for figures, code samples, and media. Decorative;
255
255
  forced colors keeps the borders via CanvasText automatically. */
256
256
  .ct-datum-frame {
257
- position: relative;
258
- }
257
+ --ct-datum-mark-inset: 0px;
258
+ --ct-datum-mark-radius: var(--radius-lg);
259
259
 
260
- .ct-datum-frame::before {
261
- content: '';
262
- position: absolute;
263
- inset-block-start: 0;
264
- inset-inline-start: 0;
265
- width: var(--component-datum-mark-size);
266
- height: var(--component-datum-mark-size);
267
- border-block-start: var(--border-medium) solid var(--color-brand-accent);
268
- border-inline-start: var(--border-medium) solid var(--color-brand-accent);
269
- border-start-start-radius: var(--radius-lg);
270
- pointer-events: none;
260
+ position: relative;
261
+ /* Keep the datum's internal paint layer above local figure chrome without
262
+ allowing it to participate in the consumer's global overlay stack. */
263
+ isolation: isolate;
271
264
  }
272
265
 
273
266
  @media (forced-colors: active) {
@@ -0,0 +1,33 @@
1
+ /* ── Frame ────────────────────────────────────────────────────
2
+ An owned surface for content whose inner chrome must clip to a
3
+ rounded boundary while an optional datum mark remains aligned
4
+ with the outer border. Keep clipping on .ct-frame__content;
5
+ clipping the outer frame would cut the registration mark back
6
+ to the padding edge. */
7
+ .ct-frame {
8
+ --ct-frame-background: var(--component-frame-background);
9
+ --ct-frame-border: var(--component-frame-border);
10
+ --ct-frame-border-width: var(--border-thin);
11
+ --ct-frame-radius: var(--component-frame-radius);
12
+ --ct-frame-shadow: var(--component-frame-shadow);
13
+
14
+ position: relative;
15
+ isolation: isolate;
16
+ min-width: 0;
17
+ overflow: visible;
18
+ border: var(--ct-frame-border-width) solid var(--ct-frame-border);
19
+ border-radius: var(--ct-frame-radius);
20
+ background: var(--ct-frame-background);
21
+ box-shadow: var(--ct-frame-shadow);
22
+ }
23
+
24
+ .ct-frame__content {
25
+ min-width: 0;
26
+ overflow: clip;
27
+ border-radius: max(0px, calc(var(--ct-frame-radius) - var(--ct-frame-border-width)));
28
+ }
29
+
30
+ .ct-frame--datum {
31
+ --ct-datum-mark-inset: calc(-1 * var(--ct-frame-border-width));
32
+ --ct-datum-mark-radius: var(--ct-frame-radius);
33
+ }
@@ -5,6 +5,7 @@
5
5
  @import './_keyframes.css';
6
6
 
7
7
  /* Structural grammar — the "datum" reference-line vocabulary */
8
+ @import './_datum-shared.css';
8
9
  @import './datum.css';
9
10
 
10
11
  /* Components */
@@ -17,6 +18,7 @@
17
18
  @import './checkbox.css';
18
19
  @import './switch.css';
19
20
  @import './card.css';
21
+ @import './frame.css';
20
22
  @import './table.css';
21
23
  @import './modal.css';
22
24
  @import './toast.css';
@@ -174,14 +174,18 @@ activation. Use the native `disabled` attribute whenever the HTML element suppor
174
174
  ## The Datum
175
175
 
176
176
  Construct's signature is one orange reference line — "the datum" — that marks what is focused, active,
177
- current, or the reference value. The grammar lives in `components/datum.css` (eyebrow, scale, frame,
178
- metrics), in active leading edges (list, sidebar, card, table rows), in the tab indicator and sorted
179
- column, and in the chart reference line. Its dimensions are component tokens (`--component-datum-*`).
177
+ current, or the reference value. The grammar lives in `components/datum.css` (eyebrow, scale,
178
+ metrics), in the owned `ct-frame--datum` surface, in active leading edges (list, sidebar, card, table
179
+ rows), in the tab indicator and sorted column, and in the chart reference line. Its dimensions are
180
+ component tokens (`--component-datum-*`).
180
181
 
181
182
  Rules that keep the signature strong and accessible:
182
183
 
183
184
  - **One datum per surface.** Orange marks exactly one thing per view region — the current, active, or
184
185
  reference element. Never let two orange edges compete; if everything is highlighted, nothing is.
186
+ - **The component that owns the border owns the datum.** Use `ct-frame ct-frame--datum` for framed
187
+ exhibits and put clipping on `ct-frame__content`. Do not attach overflow clipping to the outer frame
188
+ or rebuild the corner in product CSS.
185
189
  - **Orange is never text.** Labels and values stay on `--color-text-*` neutrals; orange is carried by
186
190
  non-text ticks, edges, rules, and lines.
187
191
  - **Edges are `--color-brand-accent`; meaning-bearing fills are `--color-brand-accent-strong`**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neuravision/construct",
3
- "version": "2.1.5",
3
+ "version": "2.2.0",
4
4
  "description": "Construct Design System - Accessible, token-based design system for modern web applications",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -3,7 +3,7 @@
3
3
  "$id": "https://neuravision.dev/construct/schemas/components.schema.json",
4
4
  "title": "Construct component token contract",
5
5
  "type": "object",
6
- "required": ["button", "control", "card", "status", "metric", "meter", "datum"],
6
+ "required": ["button", "control", "card", "frame", "status", "metric", "meter", "datum"],
7
7
  "additionalProperties": false,
8
8
  "properties": {
9
9
  "button": {
@@ -55,6 +55,17 @@
55
55
  "shadowHover": { "$ref": "#/$defs/token" }
56
56
  }
57
57
  },
58
+ "frame": {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": ["background", "border", "radius", "shadow"],
62
+ "properties": {
63
+ "background": { "$ref": "#/$defs/token" },
64
+ "border": { "$ref": "#/$defs/token" },
65
+ "radius": { "$ref": "#/$defs/token" },
66
+ "shadow": { "$ref": "#/$defs/token" }
67
+ }
68
+ },
58
69
  "status": {
59
70
  "type": "object",
60
71
  "additionalProperties": false,
@@ -1,3 +1,4 @@
1
1
  /* Generated by scripts/build-standalone-components.mjs. Do not edit directly. */
2
2
  @import './core.css';
3
+ @import '../components/_datum-shared.css';
3
4
  @import '../components/card.css';
@@ -1,3 +1,4 @@
1
1
  /* Generated by scripts/build-standalone-components.mjs. Do not edit directly. */
2
2
  @import './core.css';
3
+ @import '../components/_datum-shared.css';
3
4
  @import '../components/datum.css';
@@ -0,0 +1,4 @@
1
+ /* Generated by scripts/build-standalone-components.mjs. Do not edit directly. */
2
+ @import './core.css';
3
+ @import '../components/_datum-shared.css';
4
+ @import '../components/frame.css';
@@ -33,6 +33,12 @@
33
33
  "shadow": "{shadow.card}",
34
34
  "shadowHover": "{shadow.dropdown}"
35
35
  },
36
+ "frame": {
37
+ "background": "{color.background.elevated}",
38
+ "border": "{color.border.subtle}",
39
+ "radius": "{radius.card}",
40
+ "shadow": "{shadow.card}"
41
+ },
36
42
  "status": {
37
43
  "gap": "{space.2}",
38
44
  "fontSize": "{font.size.sm}",
package/tokens/tokens.css CHANGED
@@ -360,6 +360,10 @@
360
360
  --component-card-padding: var(--space-6);
361
361
  --component-card-shadow: var(--shadow-card);
362
362
  --component-card-shadow-hover: var(--shadow-dropdown);
363
+ --component-frame-background: var(--color-bg-elevated);
364
+ --component-frame-border: var(--color-border-subtle);
365
+ --component-frame-radius: var(--radius-card);
366
+ --component-frame-shadow: var(--shadow-card);
363
367
  --component-status-gap: var(--space-2);
364
368
  --component-status-font-size: var(--font-size-sm);
365
369
  --component-status-icon-size: var(--icon-sm);
@@ -535,6 +539,10 @@
535
539
  --component-card-padding: var(--space-6);
536
540
  --component-card-shadow: var(--shadow-card);
537
541
  --component-card-shadow-hover: var(--shadow-dropdown);
542
+ --component-frame-background: var(--color-bg-elevated);
543
+ --component-frame-border: var(--color-border-subtle);
544
+ --component-frame-radius: var(--radius-card);
545
+ --component-frame-shadow: var(--shadow-card);
538
546
  --component-status-gap: var(--space-2);
539
547
  --component-status-font-size: var(--font-size-sm);
540
548
  --component-status-icon-size: var(--icon-sm);
@@ -710,6 +718,10 @@
710
718
  --component-card-padding: var(--space-6);
711
719
  --component-card-shadow: var(--shadow-card);
712
720
  --component-card-shadow-hover: var(--shadow-dropdown);
721
+ --component-frame-background: var(--color-bg-elevated);
722
+ --component-frame-border: var(--color-border-subtle);
723
+ --component-frame-radius: var(--radius-card);
724
+ --component-frame-shadow: var(--shadow-card);
713
725
  --component-status-gap: var(--space-2);
714
726
  --component-status-font-size: var(--font-size-sm);
715
727
  --component-status-icon-size: var(--icon-sm);
@@ -885,6 +897,10 @@
885
897
  --component-card-padding: var(--space-6);
886
898
  --component-card-shadow: var(--shadow-card);
887
899
  --component-card-shadow-hover: var(--shadow-dropdown);
900
+ --component-frame-background: var(--color-bg-elevated);
901
+ --component-frame-border: var(--color-border-subtle);
902
+ --component-frame-radius: var(--radius-card);
903
+ --component-frame-shadow: var(--shadow-card);
888
904
  --component-status-gap: var(--space-2);
889
905
  --component-status-font-size: var(--font-size-sm);
890
906
  --component-status-icon-size: var(--icon-sm);
@@ -1060,6 +1076,10 @@
1060
1076
  --component-card-padding: var(--space-6);
1061
1077
  --component-card-shadow: var(--shadow-card);
1062
1078
  --component-card-shadow-hover: var(--shadow-dropdown);
1079
+ --component-frame-background: var(--color-bg-elevated);
1080
+ --component-frame-border: var(--color-border-subtle);
1081
+ --component-frame-radius: var(--radius-card);
1082
+ --component-frame-shadow: var(--shadow-card);
1063
1083
  --component-status-gap: var(--space-2);
1064
1084
  --component-status-font-size: var(--font-size-sm);
1065
1085
  --component-status-icon-size: var(--icon-sm);
@@ -1303,6 +1323,10 @@
1303
1323
  --component-card-padding: var(--space-6);
1304
1324
  --component-card-shadow: var(--shadow-card);
1305
1325
  --component-card-shadow-hover: var(--shadow-dropdown);
1326
+ --component-frame-background: var(--color-bg-elevated);
1327
+ --component-frame-border: var(--color-border-subtle);
1328
+ --component-frame-radius: var(--radius-card);
1329
+ --component-frame-shadow: var(--shadow-card);
1306
1330
  --component-status-gap: var(--space-2);
1307
1331
  --component-status-font-size: var(--font-size-sm);
1308
1332
  --component-status-icon-size: var(--icon-sm);
@@ -1479,6 +1503,10 @@
1479
1503
  --component-card-padding: var(--space-6);
1480
1504
  --component-card-shadow: var(--shadow-card);
1481
1505
  --component-card-shadow-hover: var(--shadow-dropdown);
1506
+ --component-frame-background: var(--color-bg-elevated);
1507
+ --component-frame-border: var(--color-border-subtle);
1508
+ --component-frame-radius: var(--radius-card);
1509
+ --component-frame-shadow: var(--shadow-card);
1482
1510
  --component-status-gap: var(--space-2);
1483
1511
  --component-status-font-size: var(--font-size-sm);
1484
1512
  --component-status-icon-size: var(--icon-sm);
package/tokens/tokens.js CHANGED
@@ -499,6 +499,12 @@ export const components = {
499
499
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
500
500
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
501
501
  },
502
+ "frame": {
503
+ "background": "#FFFFFF",
504
+ "border": "#E4E2DB",
505
+ "radius": "12px",
506
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
507
+ },
502
508
  "status": {
503
509
  "gap": "4px",
504
510
  "fontSize": "0.875rem",
@@ -1284,6 +1290,12 @@ export const componentThemes = {
1284
1290
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
1285
1291
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
1286
1292
  },
1293
+ "frame": {
1294
+ "background": "#FFFFFF",
1295
+ "border": "#E4E2DB",
1296
+ "radius": "12px",
1297
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
1298
+ },
1287
1299
  "status": {
1288
1300
  "gap": "4px",
1289
1301
  "fontSize": "0.875rem",
@@ -1348,6 +1360,12 @@ export const componentThemes = {
1348
1360
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
1349
1361
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
1350
1362
  },
1363
+ "frame": {
1364
+ "background": "#4B473E",
1365
+ "border": "#66604E",
1366
+ "radius": "12px",
1367
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
1368
+ },
1351
1369
  "status": {
1352
1370
  "gap": "4px",
1353
1371
  "fontSize": "0.875rem",
@@ -1412,6 +1430,12 @@ export const componentThemes = {
1412
1430
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
1413
1431
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
1414
1432
  },
1433
+ "frame": {
1434
+ "background": "#FFFFFF",
1435
+ "border": "#8E887A",
1436
+ "radius": "12px",
1437
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
1438
+ },
1415
1439
  "status": {
1416
1440
  "gap": "4px",
1417
1441
  "fontSize": "0.875rem",
@@ -1476,6 +1500,12 @@ export const componentThemes = {
1476
1500
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
1477
1501
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
1478
1502
  },
1503
+ "frame": {
1504
+ "background": "#211E18",
1505
+ "border": "#8E887A",
1506
+ "radius": "12px",
1507
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
1508
+ },
1479
1509
  "status": {
1480
1510
  "gap": "4px",
1481
1511
  "fontSize": "0.875rem",
@@ -1990,6 +2020,12 @@ export const cssVars = {
1990
2020
  "shadow": "var(--component-card-shadow)",
1991
2021
  "shadowHover": "var(--component-card-shadow-hover)"
1992
2022
  },
2023
+ "frame": {
2024
+ "background": "var(--component-frame-background)",
2025
+ "border": "var(--component-frame-border)",
2026
+ "radius": "var(--component-frame-radius)",
2027
+ "shadow": "var(--component-frame-shadow)"
2028
+ },
1993
2029
  "status": {
1994
2030
  "gap": "var(--component-status-gap)",
1995
2031
  "fontSize": "var(--component-status-font-size)",
@@ -495,6 +495,12 @@
495
495
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
496
496
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
497
497
  },
498
+ "frame": {
499
+ "background": "#FFFFFF",
500
+ "border": "#E4E2DB",
501
+ "radius": "12px",
502
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
503
+ },
498
504
  "status": {
499
505
  "gap": "4px",
500
506
  "fontSize": "0.875rem",
@@ -1278,6 +1284,12 @@
1278
1284
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
1279
1285
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
1280
1286
  },
1287
+ "frame": {
1288
+ "background": "#FFFFFF",
1289
+ "border": "#E4E2DB",
1290
+ "radius": "12px",
1291
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
1292
+ },
1281
1293
  "status": {
1282
1294
  "gap": "4px",
1283
1295
  "fontSize": "0.875rem",
@@ -1342,6 +1354,12 @@
1342
1354
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
1343
1355
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
1344
1356
  },
1357
+ "frame": {
1358
+ "background": "#4B473E",
1359
+ "border": "#66604E",
1360
+ "radius": "12px",
1361
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
1362
+ },
1345
1363
  "status": {
1346
1364
  "gap": "4px",
1347
1365
  "fontSize": "0.875rem",
@@ -1406,6 +1424,12 @@
1406
1424
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
1407
1425
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
1408
1426
  },
1427
+ "frame": {
1428
+ "background": "#FFFFFF",
1429
+ "border": "#8E887A",
1430
+ "radius": "12px",
1431
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
1432
+ },
1409
1433
  "status": {
1410
1434
  "gap": "4px",
1411
1435
  "fontSize": "0.875rem",
@@ -1470,6 +1494,12 @@
1470
1494
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
1471
1495
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
1472
1496
  },
1497
+ "frame": {
1498
+ "background": "#211E18",
1499
+ "border": "#8E887A",
1500
+ "radius": "12px",
1501
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
1502
+ },
1473
1503
  "status": {
1474
1504
  "gap": "4px",
1475
1505
  "fontSize": "0.875rem",
@@ -1983,6 +2013,12 @@
1983
2013
  "shadow": "var(--component-card-shadow)",
1984
2014
  "shadowHover": "var(--component-card-shadow-hover)"
1985
2015
  },
2016
+ "frame": {
2017
+ "background": "var(--component-frame-background)",
2018
+ "border": "var(--component-frame-border)",
2019
+ "radius": "var(--component-frame-radius)",
2020
+ "shadow": "var(--component-frame-shadow)"
2021
+ },
1986
2022
  "status": {
1987
2023
  "gap": "var(--component-status-gap)",
1988
2024
  "fontSize": "var(--component-status-font-size)",
package/tokens/tokens.ts CHANGED
@@ -499,6 +499,12 @@ export const components = {
499
499
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
500
500
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
501
501
  },
502
+ "frame": {
503
+ "background": "#FFFFFF",
504
+ "border": "#E4E2DB",
505
+ "radius": "12px",
506
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
507
+ },
502
508
  "status": {
503
509
  "gap": "4px",
504
510
  "fontSize": "0.875rem",
@@ -1284,6 +1290,12 @@ export const componentThemes = {
1284
1290
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
1285
1291
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
1286
1292
  },
1293
+ "frame": {
1294
+ "background": "#FFFFFF",
1295
+ "border": "#E4E2DB",
1296
+ "radius": "12px",
1297
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
1298
+ },
1287
1299
  "status": {
1288
1300
  "gap": "4px",
1289
1301
  "fontSize": "0.875rem",
@@ -1348,6 +1360,12 @@ export const componentThemes = {
1348
1360
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
1349
1361
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
1350
1362
  },
1363
+ "frame": {
1364
+ "background": "#4B473E",
1365
+ "border": "#66604E",
1366
+ "radius": "12px",
1367
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
1368
+ },
1351
1369
  "status": {
1352
1370
  "gap": "4px",
1353
1371
  "fontSize": "0.875rem",
@@ -1412,6 +1430,12 @@ export const componentThemes = {
1412
1430
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
1413
1431
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
1414
1432
  },
1433
+ "frame": {
1434
+ "background": "#FFFFFF",
1435
+ "border": "#8E887A",
1436
+ "radius": "12px",
1437
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
1438
+ },
1415
1439
  "status": {
1416
1440
  "gap": "4px",
1417
1441
  "fontSize": "0.875rem",
@@ -1476,6 +1500,12 @@ export const componentThemes = {
1476
1500
  "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)",
1477
1501
  "shadowHover": "0 8px 20px rgba(28, 20, 10, 0.11)"
1478
1502
  },
1503
+ "frame": {
1504
+ "background": "#211E18",
1505
+ "border": "#8E887A",
1506
+ "radius": "12px",
1507
+ "shadow": "0 2px 6px rgba(28, 20, 10, 0.09)"
1508
+ },
1479
1509
  "status": {
1480
1510
  "gap": "4px",
1481
1511
  "fontSize": "0.875rem",
@@ -1990,6 +2020,12 @@ export const cssVars = {
1990
2020
  "shadow": "var(--component-card-shadow)",
1991
2021
  "shadowHover": "var(--component-card-shadow-hover)"
1992
2022
  },
2023
+ "frame": {
2024
+ "background": "var(--component-frame-background)",
2025
+ "border": "var(--component-frame-border)",
2026
+ "radius": "var(--component-frame-radius)",
2027
+ "shadow": "var(--component-frame-shadow)"
2028
+ },
1993
2029
  "status": {
1994
2030
  "gap": "var(--component-status-gap)",
1995
2031
  "fontSize": "var(--component-status-font-size)",