@gradeui/ui 3.0.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/components/ui/button.md +11 -7
  2. package/components/ui/combobox.md +46 -0
  3. package/components/ui/data-view.md +59 -0
  4. package/components/ui/dropdown-menu.md +1 -0
  5. package/components/ui/logo.md +8 -6
  6. package/components/ui/map.md +9 -0
  7. package/components/ui/media-surface.md +1 -0
  8. package/components/ui/property-list.md +43 -0
  9. package/components/ui/sidebar.md +2 -1
  10. package/components/ui/swatch.md +88 -0
  11. package/dist/contracts.js +6 -6
  12. package/dist/contracts.js.map +1 -1
  13. package/dist/contracts.mjs +6 -6
  14. package/dist/contracts.mjs.map +1 -1
  15. package/dist/index.d.mts +902 -415
  16. package/dist/index.d.ts +902 -415
  17. package/dist/index.js +609 -72
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +609 -72
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/map/google.d.mts +1 -1
  22. package/dist/map/google.d.ts +1 -1
  23. package/dist/map/google.js +1 -1
  24. package/dist/map/google.js.map +1 -1
  25. package/dist/map/google.mjs +1 -1
  26. package/dist/map/google.mjs.map +1 -1
  27. package/dist/map/leaflet.d.mts +1 -1
  28. package/dist/map/leaflet.d.ts +1 -1
  29. package/dist/map/leaflet.js +2 -2
  30. package/dist/map/leaflet.js.map +1 -1
  31. package/dist/map/leaflet.mjs +2 -2
  32. package/dist/map/leaflet.mjs.map +1 -1
  33. package/dist/map/mapbox.d.mts +1 -1
  34. package/dist/map/mapbox.d.ts +1 -1
  35. package/dist/map/mapbox.js +2 -2
  36. package/dist/map/mapbox.js.map +1 -1
  37. package/dist/map/mapbox.mjs +2 -2
  38. package/dist/map/mapbox.mjs.map +1 -1
  39. package/dist/map/maplibre.d.mts +1 -1
  40. package/dist/map/maplibre.d.ts +1 -1
  41. package/dist/map/maplibre.js +1 -1
  42. package/dist/map/maplibre.js.map +1 -1
  43. package/dist/map/maplibre.mjs +1 -1
  44. package/dist/map/maplibre.mjs.map +1 -1
  45. package/dist/styles.css +1 -1
  46. package/dist/{types-BxywIwvG.d.mts → types-B45Uirkp.d.mts} +23 -0
  47. package/dist/{types-BxywIwvG.d.ts → types-B45Uirkp.d.ts} +23 -0
  48. package/package.json +2 -1
  49. package/styles/globals.css +306 -95
@@ -7,6 +7,20 @@ import * as React from 'react';
7
7
  */
8
8
  type Coords = [lng: number, lat: number];
9
9
  type MapAppearance = "light" | "dark" | "satellite" | "auto";
10
+ /**
11
+ * Which built-in map UI (zoom buttons today; compass/scale could join)
12
+ * renders on the map. `"auto"` (default) shows zoom buttons whenever the
13
+ * map is `interactive`; `"zoom"` forces them on regardless; `"none"`
14
+ * hides every tool. Attribution is NOT a tool — it's a license
15
+ * requirement and always renders.
16
+ */
17
+ type MapTools = "auto" | "zoom" | "none";
18
+ /**
19
+ * Corner the tools dock to. One vocabulary across providers — each
20
+ * adapter maps it to its native enum (Leaflet `topleft`, MapLibre/Mapbox
21
+ * `top-left`, Google `ControlPosition.*`).
22
+ */
23
+ type MapToolsPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";
10
24
  type MapErrorCode = "sdk-missing" | "api-key-missing" | "provider-init-failed" | "style-load-failed" | "tile-load-failed";
11
25
  type MapError = {
12
26
  code: MapErrorCode;
@@ -51,6 +65,13 @@ type MapBaseProps = {
51
65
  appearance?: MapAppearance;
52
66
  /** Default `true`. `false` disables pan/zoom/rotate (static display). */
53
67
  interactive?: boolean;
68
+ /** Which built-in map UI shows. Default `"auto"` — zoom buttons follow
69
+ * `interactive`. `"none"` for chrome-free maps (hero backdrops,
70
+ * posters); attribution always stays (license). */
71
+ tools?: MapTools;
72
+ /** Corner the tools dock to. Default `"top-left"`. Handy when the
73
+ * layout puts a search bar or legend over the default corner. */
74
+ toolsPosition?: MapToolsPosition;
54
75
  /** Controlled hovered marker id — pairs with `onHoveredIdChange` for list↔map sync. */
55
76
  hoveredId?: string | null;
56
77
  onHoveredIdChange?: (id: string | null) => void;
@@ -116,6 +137,8 @@ type AdapterOpts = {
116
137
  bounds?: [Coords, Coords];
117
138
  appearance: "light" | "dark" | "satellite";
118
139
  interactive: boolean;
140
+ tools: MapTools;
141
+ toolsPosition: MapToolsPosition;
119
142
  styleUrl?: string;
120
143
  tilerKey?: string;
121
144
  accessToken?: string;
@@ -7,6 +7,20 @@ import * as React from 'react';
7
7
  */
8
8
  type Coords = [lng: number, lat: number];
9
9
  type MapAppearance = "light" | "dark" | "satellite" | "auto";
10
+ /**
11
+ * Which built-in map UI (zoom buttons today; compass/scale could join)
12
+ * renders on the map. `"auto"` (default) shows zoom buttons whenever the
13
+ * map is `interactive`; `"zoom"` forces them on regardless; `"none"`
14
+ * hides every tool. Attribution is NOT a tool — it's a license
15
+ * requirement and always renders.
16
+ */
17
+ type MapTools = "auto" | "zoom" | "none";
18
+ /**
19
+ * Corner the tools dock to. One vocabulary across providers — each
20
+ * adapter maps it to its native enum (Leaflet `topleft`, MapLibre/Mapbox
21
+ * `top-left`, Google `ControlPosition.*`).
22
+ */
23
+ type MapToolsPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";
10
24
  type MapErrorCode = "sdk-missing" | "api-key-missing" | "provider-init-failed" | "style-load-failed" | "tile-load-failed";
11
25
  type MapError = {
12
26
  code: MapErrorCode;
@@ -51,6 +65,13 @@ type MapBaseProps = {
51
65
  appearance?: MapAppearance;
52
66
  /** Default `true`. `false` disables pan/zoom/rotate (static display). */
53
67
  interactive?: boolean;
68
+ /** Which built-in map UI shows. Default `"auto"` — zoom buttons follow
69
+ * `interactive`. `"none"` for chrome-free maps (hero backdrops,
70
+ * posters); attribution always stays (license). */
71
+ tools?: MapTools;
72
+ /** Corner the tools dock to. Default `"top-left"`. Handy when the
73
+ * layout puts a search bar or legend over the default corner. */
74
+ toolsPosition?: MapToolsPosition;
54
75
  /** Controlled hovered marker id — pairs with `onHoveredIdChange` for list↔map sync. */
55
76
  hoveredId?: string | null;
56
77
  onHoveredIdChange?: (id: string | null) => void;
@@ -116,6 +137,8 @@ type AdapterOpts = {
116
137
  bounds?: [Coords, Coords];
117
138
  appearance: "light" | "dark" | "satellite";
118
139
  interactive: boolean;
140
+ tools: MapTools;
141
+ toolsPosition: MapToolsPosition;
119
142
  styleUrl?: string;
120
143
  tilerKey?: string;
121
144
  accessToken?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradeui/ui",
3
- "version": "3.0.0",
3
+ "version": "3.2.0",
4
4
  "description": "Grade Design System — React components, theme engine, and design tokens",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -146,6 +146,7 @@
146
146
  "@radix-ui/react-toggle": "^1.1.10",
147
147
  "@radix-ui/react-toggle-group": "^1.1.11",
148
148
  "@radix-ui/react-tooltip": "^1.2.8",
149
+ "@tanstack/react-table": "^8.20.0",
149
150
  "class-variance-authority": "^0.7.1",
150
151
  "clsx": "^2.1.1",
151
152
  "cmdk": "^1.1.1",
@@ -48,102 +48,108 @@
48
48
  @theme {
49
49
  --text-2xs: 0.6875rem;
50
50
  --text-2xs--line-height: 1rem;
51
+ /* Accent font role — gives a `font-accent` utility that references the
52
+ runtime --font-accent var (set by the theme generator / apply.ts).
53
+ Plain @theme (not inline) so the utility stays var-referencing and
54
+ re-skins live; falls back to the display/sans stack until a theme
55
+ sets one. */
56
+ --font-accent: var(--font-display, var(--font-sans));
51
57
  }
52
58
 
53
59
  @theme inline reference {
54
60
  /* -- Brand color ramps — values live in @gradeui/core as --gds-* vars. -- */
55
- --color-rds-green: var(--gds-green);
56
- --color-rds-green-50: var(--gds-green-50);
57
- --color-rds-green-100: var(--gds-green-100);
58
- --color-rds-green-200: var(--gds-green-200);
59
- --color-rds-green-300: var(--gds-green-300);
60
- --color-rds-green-400: var(--gds-green-400);
61
- --color-rds-green-500: var(--gds-green-500);
62
- --color-rds-green-600: var(--gds-green-600);
63
- --color-rds-green-700: var(--gds-green-700);
64
- --color-rds-green-800: var(--gds-green-800);
65
- --color-rds-green-900: var(--gds-green-900);
66
- --color-rds-green-950: var(--gds-green-950);
67
- --color-rds-yellow: var(--gds-yellow);
68
- --color-rds-yellow-50: var(--gds-yellow-50);
69
- --color-rds-yellow-100: var(--gds-yellow-100);
70
- --color-rds-yellow-200: var(--gds-yellow-200);
71
- --color-rds-yellow-300: var(--gds-yellow-300);
72
- --color-rds-yellow-400: var(--gds-yellow-400);
73
- --color-rds-yellow-500: var(--gds-yellow-500);
74
- --color-rds-yellow-600: var(--gds-yellow-600);
75
- --color-rds-yellow-700: var(--gds-yellow-700);
76
- --color-rds-yellow-800: var(--gds-yellow-800);
77
- --color-rds-yellow-900: var(--gds-yellow-900);
78
- --color-rds-orange: var(--gds-orange);
79
- --color-rds-orange-50: var(--gds-orange-50);
80
- --color-rds-orange-100: var(--gds-orange-100);
81
- --color-rds-orange-200: var(--gds-orange-200);
82
- --color-rds-orange-300: var(--gds-orange-300);
83
- --color-rds-orange-400: var(--gds-orange-400);
84
- --color-rds-orange-500: var(--gds-orange-500);
85
- --color-rds-orange-600: var(--gds-orange-600);
86
- --color-rds-orange-700: var(--gds-orange-700);
87
- --color-rds-orange-800: var(--gds-orange-800);
88
- --color-rds-orange-900: var(--gds-orange-900);
89
- --color-rds-red: var(--gds-red);
90
- --color-rds-red-50: var(--gds-red-50);
91
- --color-rds-red-100: var(--gds-red-100);
92
- --color-rds-red-200: var(--gds-red-200);
93
- --color-rds-red-300: var(--gds-red-300);
94
- --color-rds-red-400: var(--gds-red-400);
95
- --color-rds-red-500: var(--gds-red-500);
96
- --color-rds-red-600: var(--gds-red-600);
97
- --color-rds-red-700: var(--gds-red-700);
98
- --color-rds-red-800: var(--gds-red-800);
99
- --color-rds-red-900: var(--gds-red-900);
100
- --color-rds-teal: var(--gds-teal);
101
- --color-rds-teal-50: var(--gds-teal-50);
102
- --color-rds-teal-100: var(--gds-teal-100);
103
- --color-rds-teal-200: var(--gds-teal-200);
104
- --color-rds-teal-300: var(--gds-teal-300);
105
- --color-rds-teal-400: var(--gds-teal-400);
106
- --color-rds-teal-500: var(--gds-teal-500);
107
- --color-rds-teal-600: var(--gds-teal-600);
108
- --color-rds-teal-700: var(--gds-teal-700);
109
- --color-rds-teal-800: var(--gds-teal-800);
110
- --color-rds-teal-900: var(--gds-teal-900);
111
- --color-rds-teal-950: var(--gds-teal-950);
112
- --color-rds-navy: var(--gds-navy);
113
- --color-rds-navy-50: var(--gds-navy-50);
114
- --color-rds-navy-100: var(--gds-navy-100);
115
- --color-rds-navy-200: var(--gds-navy-200);
116
- --color-rds-navy-300: var(--gds-navy-300);
117
- --color-rds-navy-400: var(--gds-navy-400);
118
- --color-rds-navy-500: var(--gds-navy-500);
119
- --color-rds-navy-600: var(--gds-navy-600);
120
- --color-rds-navy-700: var(--gds-navy-700);
121
- --color-rds-navy-800: var(--gds-navy-800);
122
- --color-rds-navy-900: var(--gds-navy-900);
123
- --color-rds-blue: var(--gds-blue);
124
- --color-rds-blue-50: var(--gds-blue-50);
125
- --color-rds-blue-100: var(--gds-blue-100);
126
- --color-rds-blue-200: var(--gds-blue-200);
127
- --color-rds-blue-300: var(--gds-blue-300);
128
- --color-rds-blue-400: var(--gds-blue-400);
129
- --color-rds-blue-500: var(--gds-blue-500);
130
- --color-rds-blue-600: var(--gds-blue-600);
131
- --color-rds-blue-700: var(--gds-blue-700);
132
- --color-rds-blue-800: var(--gds-blue-800);
133
- --color-rds-blue-900: var(--gds-blue-900);
134
- --color-rds-gray-50: var(--gds-gray-50);
135
- --color-rds-gray-100: var(--gds-gray-100);
136
- --color-rds-gray-200: var(--gds-gray-200);
137
- --color-rds-gray-300: var(--gds-gray-300);
138
- --color-rds-gray-400: var(--gds-gray-400);
139
- --color-rds-gray-500: var(--gds-gray-500);
140
- --color-rds-gray-600: var(--gds-gray-600);
141
- --color-rds-gray-700: var(--gds-gray-700);
142
- --color-rds-gray-800: var(--gds-gray-800);
143
- --color-rds-gray-900: var(--gds-gray-900);
144
- --color-rds-gray-950: var(--gds-gray-950);
145
- --color-rds-black: var(--gds-black);
146
- --color-rds-white: var(--gds-white);
61
+ --color-gds-green: var(--gds-green);
62
+ --color-gds-green-50: var(--gds-green-50);
63
+ --color-gds-green-100: var(--gds-green-100);
64
+ --color-gds-green-200: var(--gds-green-200);
65
+ --color-gds-green-300: var(--gds-green-300);
66
+ --color-gds-green-400: var(--gds-green-400);
67
+ --color-gds-green-500: var(--gds-green-500);
68
+ --color-gds-green-600: var(--gds-green-600);
69
+ --color-gds-green-700: var(--gds-green-700);
70
+ --color-gds-green-800: var(--gds-green-800);
71
+ --color-gds-green-900: var(--gds-green-900);
72
+ --color-gds-green-950: var(--gds-green-950);
73
+ --color-gds-yellow: var(--gds-yellow);
74
+ --color-gds-yellow-50: var(--gds-yellow-50);
75
+ --color-gds-yellow-100: var(--gds-yellow-100);
76
+ --color-gds-yellow-200: var(--gds-yellow-200);
77
+ --color-gds-yellow-300: var(--gds-yellow-300);
78
+ --color-gds-yellow-400: var(--gds-yellow-400);
79
+ --color-gds-yellow-500: var(--gds-yellow-500);
80
+ --color-gds-yellow-600: var(--gds-yellow-600);
81
+ --color-gds-yellow-700: var(--gds-yellow-700);
82
+ --color-gds-yellow-800: var(--gds-yellow-800);
83
+ --color-gds-yellow-900: var(--gds-yellow-900);
84
+ --color-gds-orange: var(--gds-orange);
85
+ --color-gds-orange-50: var(--gds-orange-50);
86
+ --color-gds-orange-100: var(--gds-orange-100);
87
+ --color-gds-orange-200: var(--gds-orange-200);
88
+ --color-gds-orange-300: var(--gds-orange-300);
89
+ --color-gds-orange-400: var(--gds-orange-400);
90
+ --color-gds-orange-500: var(--gds-orange-500);
91
+ --color-gds-orange-600: var(--gds-orange-600);
92
+ --color-gds-orange-700: var(--gds-orange-700);
93
+ --color-gds-orange-800: var(--gds-orange-800);
94
+ --color-gds-orange-900: var(--gds-orange-900);
95
+ --color-gds-red: var(--gds-red);
96
+ --color-gds-red-50: var(--gds-red-50);
97
+ --color-gds-red-100: var(--gds-red-100);
98
+ --color-gds-red-200: var(--gds-red-200);
99
+ --color-gds-red-300: var(--gds-red-300);
100
+ --color-gds-red-400: var(--gds-red-400);
101
+ --color-gds-red-500: var(--gds-red-500);
102
+ --color-gds-red-600: var(--gds-red-600);
103
+ --color-gds-red-700: var(--gds-red-700);
104
+ --color-gds-red-800: var(--gds-red-800);
105
+ --color-gds-red-900: var(--gds-red-900);
106
+ --color-gds-teal: var(--gds-teal);
107
+ --color-gds-teal-50: var(--gds-teal-50);
108
+ --color-gds-teal-100: var(--gds-teal-100);
109
+ --color-gds-teal-200: var(--gds-teal-200);
110
+ --color-gds-teal-300: var(--gds-teal-300);
111
+ --color-gds-teal-400: var(--gds-teal-400);
112
+ --color-gds-teal-500: var(--gds-teal-500);
113
+ --color-gds-teal-600: var(--gds-teal-600);
114
+ --color-gds-teal-700: var(--gds-teal-700);
115
+ --color-gds-teal-800: var(--gds-teal-800);
116
+ --color-gds-teal-900: var(--gds-teal-900);
117
+ --color-gds-teal-950: var(--gds-teal-950);
118
+ --color-gds-navy: var(--gds-navy);
119
+ --color-gds-navy-50: var(--gds-navy-50);
120
+ --color-gds-navy-100: var(--gds-navy-100);
121
+ --color-gds-navy-200: var(--gds-navy-200);
122
+ --color-gds-navy-300: var(--gds-navy-300);
123
+ --color-gds-navy-400: var(--gds-navy-400);
124
+ --color-gds-navy-500: var(--gds-navy-500);
125
+ --color-gds-navy-600: var(--gds-navy-600);
126
+ --color-gds-navy-700: var(--gds-navy-700);
127
+ --color-gds-navy-800: var(--gds-navy-800);
128
+ --color-gds-navy-900: var(--gds-navy-900);
129
+ --color-gds-blue: var(--gds-blue);
130
+ --color-gds-blue-50: var(--gds-blue-50);
131
+ --color-gds-blue-100: var(--gds-blue-100);
132
+ --color-gds-blue-200: var(--gds-blue-200);
133
+ --color-gds-blue-300: var(--gds-blue-300);
134
+ --color-gds-blue-400: var(--gds-blue-400);
135
+ --color-gds-blue-500: var(--gds-blue-500);
136
+ --color-gds-blue-600: var(--gds-blue-600);
137
+ --color-gds-blue-700: var(--gds-blue-700);
138
+ --color-gds-blue-800: var(--gds-blue-800);
139
+ --color-gds-blue-900: var(--gds-blue-900);
140
+ --color-gds-gray-50: var(--gds-gray-50);
141
+ --color-gds-gray-100: var(--gds-gray-100);
142
+ --color-gds-gray-200: var(--gds-gray-200);
143
+ --color-gds-gray-300: var(--gds-gray-300);
144
+ --color-gds-gray-400: var(--gds-gray-400);
145
+ --color-gds-gray-500: var(--gds-gray-500);
146
+ --color-gds-gray-600: var(--gds-gray-600);
147
+ --color-gds-gray-700: var(--gds-gray-700);
148
+ --color-gds-gray-800: var(--gds-gray-800);
149
+ --color-gds-gray-900: var(--gds-gray-900);
150
+ --color-gds-gray-950: var(--gds-gray-950);
151
+ --color-gds-black: var(--gds-black);
152
+ --color-gds-white: var(--gds-white);
147
153
 
148
154
  /* -- Semantic roles — runtime vars hold bare "L C H" OKLCH triplets,
149
155
  wrapped with oklch() at use. Opacity shortcuts (bg-primary/50) come
@@ -830,6 +836,24 @@
830
836
  --gds-media-placeholder-bg: oklch(var(--muted));
831
837
  --gds-media-placeholder-fg: oklch(var(--muted-foreground));
832
838
 
839
+ /* Fidelity fade — how long a MediaSurface takes to cross-fade between
840
+ full imagery and the wireframe placeholder when `data-fidelity`
841
+ flips on an ancestor (Studio's toggle, an embed's `fidelity`
842
+ parameter). One knob, read by the "MediaSurface fidelity" rules
843
+ further down. */
844
+ --gds-media-fidelity-fade: 280ms;
845
+
846
+ /* Transparency checkerboard — the standard alpha backdrop drawn behind
847
+ image previews (Studio's inspector image well; anywhere else that
848
+ needs to say "these pixels are transparent"). Consumed as
849
+ `repeating-conic-gradient(var(--gds-media-checker-color) 0% 25%,
850
+ transparent 0% 50%)` sized by the size token. Mode-aware for free:
851
+ the colour rides on --muted-foreground at low alpha, so it reads as
852
+ grey/white in light mode and grey/dark in dark without a `.dark`
853
+ override. */
854
+ --gds-media-checker-color: oklch(var(--muted-foreground) / 0.16);
855
+ --gds-media-checker-size: 14px;
856
+
833
857
  /* Canvas fill — the standard backdrop behind a screen when it doesn't fill
834
858
  its frame: the letterbox bars in an embed/share, and the stage a
835
859
  `<ScreenAnimator>` reveals when it flies in or pulls below 1× zoom. One
@@ -840,6 +864,31 @@
840
864
  mode. Set it to `transparent` to let the host page show through. */
841
865
  --gds-canvas-fill: #e8e8ec;
842
866
 
867
+ /* Map marker chrome — the baseline "lift" every MapMarker child gets
868
+ so pin labels never melt into the tiles (see the map-marker rule
869
+ near the fidelity block). Map tiles are EXTERNAL imagery — they
870
+ don't ride the theme's surface tokens — so marker content needs
871
+ its own guaranteed separation in both modes: a 1px border + a soft
872
+ ambient shadow. Light mode: a slightly-darker-than---border line
873
+ reads against pale tiles. Dark mode override below flips to a
874
+ light hairline (a dark border on dark tiles lifts nothing). */
875
+ --gds-map-marker-border: oklch(var(--border));
876
+ --gds-map-marker-shadow: 0 1px 3px oklch(0 0 0 / 0.22),
877
+ 0 0 0 1px oklch(0 0 0 / 0.05);
878
+ /* Halo behind floating map labels (the text-stroke that separates a
879
+ label from busy tiles). Mode-aware: a white halo reads on pale
880
+ light tiles; the dark-mode override flips it to near-black so a
881
+ light label on dark tiles isn't a white-on-white wash-out. Applied
882
+ via the `.gds-map-label` helper. */
883
+ --gds-map-label-halo: oklch(1 0 0);
884
+ /* Map canvas — the backing colour BEHIND the raster tiles. Leaflet's
885
+ default is `#dddddd`, so subpixel gaps between tiles flash light
886
+ "seams" over a dark basemap. Defaulting this to the tile base
887
+ colour (here, the CARTO voyager land tone) makes those gaps blend
888
+ away. Neutral on purpose: tint it and the seams come back as
889
+ coloured lines unless your tiles match. */
890
+ --gds-map-canvas: oklch(0.97 0.004 95);
891
+
843
892
  /* Sidebar knobs — the width pair drives the collapsed/expanded animation
844
893
  on `<Sidebar>` (compound nav primitive). Header height + section
845
894
  padding + per-section gap are exposed so consumers can retune density
@@ -851,6 +900,33 @@
851
900
  --gds-sidebar-section-px: 0.5rem;
852
901
  --gds-sidebar-section-gap: 0.125rem;
853
902
 
903
+ /* Property list knobs — <PropertyList> renders a single record as
904
+ label / value rows (a Table row transposed). The label column width
905
+ and the row/column rhythm are exposed so a dense inspector and an
906
+ airy settings page share one primitive. Read as
907
+ `var(--gds-property-list-* , <fallback>)` in the component, so a
908
+ missing stanza degrades gracefully. */
909
+ --gds-property-list-label-width: 8.5rem;
910
+ --gds-property-list-col-gap: 1rem;
911
+ --gds-property-list-row-gap: 0.625rem;
912
+ --gds-property-list-row-gap-compact: 0.375rem;
913
+ --gds-property-list-row-gap-relaxed: 1rem;
914
+ --gds-property-list-icon-size: 0.875rem;
915
+ --gds-property-list-label-color: oklch(var(--muted-foreground));
916
+ --gds-property-list-divider-color: oklch(var(--border));
917
+
918
+ /* Data view knobs — <DataView> draws one dataset as a table, cards, or a
919
+ grid. The card / grid tiles auto-fill, so these min column widths set
920
+ how many tiles sit per row at a given container width; the pinned and
921
+ header backgrounds back the sticky column / header so scrolled content
922
+ doesn't bleed through. */
923
+ --gds-data-view-card-min: 18rem;
924
+ --gds-data-view-grid-min: 11rem;
925
+ --gds-data-view-gap: 0.75rem;
926
+ --gds-data-view-pinned-bg: oklch(var(--background));
927
+ --gds-data-view-header-bg: oklch(var(--background));
928
+ --gds-data-view-table-max-h: 28rem; /* scroll height when stickyHeader is on */
929
+
854
930
  /* Carousel knobs — every visual dimension of <Carousel> is driven from
855
931
  this stanza so consumers can re-skin the slideshow (dot shape, arrow
856
932
  chrome, transition feel) without prop-drilling. The component reads
@@ -971,6 +1047,20 @@
971
1047
  bars in embed/share/preview and the ScreenAnimator stage all match. */
972
1048
  --gds-canvas-fill: #0b0b0e;
973
1049
 
1050
+ /* Map marker chrome — dark mode: a light hairline + deeper shadow.
1051
+ Dark-mode pin surfaces (bg-card etc.) sit on dark tiles, so the
1052
+ border has to be the bright element; the alpha keeps it a lift,
1053
+ not a frame. */
1054
+ --gds-map-marker-border: oklch(1 0 0 / 0.3);
1055
+ --gds-map-marker-shadow: 0 1px 3px oklch(0 0 0 / 0.5),
1056
+ 0 0 0 1px oklch(0 0 0 / 0.4);
1057
+ /* Dark-mode label halo — near-black so light labels stay legible on
1058
+ dark tiles (mirror of the light-mode white halo above). */
1059
+ --gds-map-label-halo: oklch(0.18 0 0);
1060
+ /* Dark-mode map canvas — near-black to match the CARTO dark_all base,
1061
+ so tile seams vanish on the dark basemap. */
1062
+ --gds-map-canvas: oklch(0.17 0 0);
1063
+
974
1064
  /* Alert surface pairs — dark-mode variant: tint sits just above the dark
975
1065
  background without going gray; deep text stays bright and readable. */
976
1066
  --destructive-soft: 0.220 0.075 27;
@@ -1091,6 +1181,10 @@
1091
1181
  font-feature-settings: "rlig" 1, "calt" 1;
1092
1182
  font-size: var(--text-body);
1093
1183
  line-height: var(--text-body-line);
1184
+ /* Theme-driven width cut (variable-font wdth axis). Inherits into
1185
+ every span/component, so a theme set to e.g. 90% re-cuts ALL text;
1186
+ per-element font-stretch-[…] utilities still override. */
1187
+ font-stretch: var(--font-body-stretch, normal);
1094
1188
  }
1095
1189
 
1096
1190
  /* Theme-driven heading font.
@@ -1102,6 +1196,7 @@
1102
1196
  font-family: var(--font-display, var(--font-sans));
1103
1197
  font-weight: var(--font-heading-weight, 600);
1104
1198
  letter-spacing: var(--font-heading-tracking, -0.01em);
1199
+ font-stretch: var(--font-display-stretch, var(--font-body-stretch, normal));
1105
1200
  }
1106
1201
 
1107
1202
  /* Link styles */
@@ -1221,9 +1316,6 @@
1221
1316
  style overrides like `style={{ "--btn-glow": "var(--warning)" }}`. */
1222
1317
  --btn-glow: var(--accent-glow, var(--selected-glow));
1223
1318
 
1224
- background-color: oklch(var(--secondary));
1225
- color: oklch(var(--secondary-foreground));
1226
-
1227
1319
  box-shadow: var(--elevation-3);
1228
1320
 
1229
1321
  transition:
@@ -1232,6 +1324,17 @@
1232
1324
  background-color var(--gds-transition-base) var(--gds-ease-out);
1233
1325
  }
1234
1326
 
1327
+ /* Surface for the STANDALONE raised look. June 2026: raised became a
1328
+ TRAIT (the `raised` prop on Button adds .gds-button-raised only, so
1329
+ elevation + glow compose with ANY colour variant — raised primary,
1330
+ raised outline). This companion class supplies the classic neutral
1331
+ "key" surface and is applied only by the variant="raised" alias,
1332
+ which is kept for back-compat. */
1333
+ .gds-button-raised-surface {
1334
+ background-color: oklch(var(--secondary));
1335
+ color: oklch(var(--secondary-foreground));
1336
+ }
1337
+
1235
1338
  .gds-button-raised:hover {
1236
1339
  box-shadow: var(--elevation-hot);
1237
1340
  }
@@ -1578,6 +1681,114 @@
1578
1681
  0 0 var(--aura-ring-blur) 0 oklch(var(--aura-color) / calc(var(--aura-ring-alpha-max) * 0.4));
1579
1682
  }
1580
1683
 
1684
+ /* ============================================
1685
+ MEDIASURFACE FIDELITY — data-fidelity on any ancestor
1686
+ ============================================
1687
+ The pure-CSS half of MediaSurface's filled/wireframe model. The
1688
+ component keeps its tiered placeholder MOUNTED beneath a filled
1689
+ image and stamps `data-filled` on it; these rules decide what's
1690
+ visible. Flipping `data-fidelity="wireframe"` on ANY ancestor
1691
+ (Studio's iframe root, an embed wrapper, a docs demo) cross-fades
1692
+ imagery out and the placeholder back in — no React, so the toggle
1693
+ works in static embeds and respects the data-motion="off" reset
1694
+ above (transition collapses to 0.01ms).
1695
+
1696
+ Default (full fidelity): a filled slot hides its placeholder with
1697
+ `visibility: hidden` — NOT unmount — so transparent imagery (logos
1698
+ on alpha) never shows the glyph/`--gds-media-placeholder-bg`
1699
+ through its pixels, while the layer stays in the DOM for this very
1700
+ toggle. The `visibility` transition is delayed by the fade length
1701
+ (the standard fade-then-hide pattern) so the placeholder finishes
1702
+ fading before it stops hit-testing/painting. */
1703
+ [data-gds-part="media-surface-placeholder"][data-filled] {
1704
+ opacity: 0;
1705
+ visibility: hidden;
1706
+ transition:
1707
+ opacity var(--gds-media-fidelity-fade, 280ms) ease,
1708
+ visibility 0s linear var(--gds-media-fidelity-fade, 280ms);
1709
+ }
1710
+ [data-gds-part="media-surface-content"] {
1711
+ transition: opacity var(--gds-media-fidelity-fade, 280ms) ease;
1712
+ }
1713
+
1714
+ /* Wireframe: imagery fades out, placeholder fades back in. Content is
1715
+ opacity-faded (not display-toggled) so the swap reads as a cross-fade;
1716
+ pointer-events off so the invisible imagery can't intercept clicks. */
1717
+ [data-fidelity="wireframe"] [data-gds-part="media-surface-placeholder"][data-filled] {
1718
+ opacity: 1;
1719
+ visibility: visible;
1720
+ transition-delay: 0s, 0s;
1721
+ }
1722
+ [data-fidelity="wireframe"] [data-gds-part="media-surface-content"] {
1723
+ opacity: 0;
1724
+ pointer-events: none;
1725
+ }
1726
+
1727
+ /* ============================================
1728
+ MAP MARKER LIFT — every pin gets a border
1729
+ ============================================
1730
+ Map tiles are external imagery and don't follow the theme, so marker
1731
+ content (Badge price pins, numbered markers, avatars) can melt into
1732
+ them — illegible dark-on-dark pins were the symptom. Guarantee the
1733
+ lift at the DS level: every DIRECT child of a MapMarker's content
1734
+ wrapper gets a 1px border + ambient shadow from the mode-aware
1735
+ `--gds-map-marker-*` pair (light hairline on dark tiles, dark line
1736
+ on light). Being unlayered, this wins over a Badge's own
1737
+ border-transparent utility — deliberate: the border is the floor,
1738
+ not a suggestion. Backgrounds/text are NOT touched; content keeps
1739
+ its own surface tokens. */
1740
+ [data-gds-part="map-marker-content"] > * {
1741
+ border: 1px solid var(--gds-map-marker-border);
1742
+ box-shadow: var(--gds-map-marker-shadow);
1743
+ }
1744
+
1745
+ /* Floating map label halo — put this class on a text element inside a
1746
+ MapMarker to give it a mode-aware outline (white on light tiles,
1747
+ near-black on dark) instead of hard-coding a white text-stroke that
1748
+ washes out in dark mode. Pairs with the `--gds-map-label-halo` token. */
1749
+ .gds-map-label {
1750
+ -webkit-text-stroke: 1.5px var(--gds-map-label-halo);
1751
+ paint-order: stroke;
1752
+ }
1753
+
1754
+ /* Vendor font reset — Leaflet (`.leaflet-container`) and MapLibre
1755
+ (`.maplibregl-map`) both hard-set `font-family` on their map
1756
+ containers, which beats inheritance and strands marker content on
1757
+ the vendor stack ("pins don't carry the custom font" — they can,
1758
+ the vendor CSS was just in the way). Re-assert the theme stack at
1759
+ the marker-content boundary so Badges/Cards inside pins type-match
1760
+ the rest of the screen, including custom uploaded faces riding
1761
+ `--font-sans`. */
1762
+ [data-gds-part="map-marker-content"] {
1763
+ font-family: var(--font-sans);
1764
+ }
1765
+
1766
+ /* Vendor z-index neutralizer — Leaflet's stylesheet sets `z-index: 200`
1767
+ on every `<svg>` inside the map. That hijacks an inline SVG used as
1768
+ marker content (e.g. a pin shield) and paints it ABOVE later sibling
1769
+ DOM — so a count/label sitting on top of the shield vanishes behind
1770
+ it. The Mapbox/MapLibre/Google adapters have no such rule, so the
1771
+ same marker markup renders fine there; this made pins look provider-
1772
+ dependent ("numbers show on Mapbox, not Leaflet"). Reset marker SVGs
1773
+ to `z-index: auto` so author paint order (DOM order) holds on every
1774
+ provider. `!important` to beat Leaflet's vendor selector. */
1775
+ [data-gds-part="map-marker-content"] svg {
1776
+ z-index: auto !important;
1777
+ }
1778
+
1779
+ /* Map canvas backing — sits behind the tiles so Leaflet's default
1780
+ `#dddddd` no longer flashes through the subpixel gaps between raster
1781
+ tiles ("seams"), most visible on a dark basemap. Harmless on the GL
1782
+ providers (their opaque canvas covers it). Mode-aware via the token.
1783
+ NB the selector is compounded with `[data-gds-part="map"]` on purpose:
1784
+ Leaflet stamps `.leaflet-container` (which sets `background:#ddd`) onto
1785
+ the SAME element, and its stylesheet loads after ours — a bare
1786
+ `.gds-map` ties on specificity and loses. The data-part attribute
1787
+ (present on every provider's root) lifts us above Leaflet's default. */
1788
+ .gds-map[data-gds-part="map"] {
1789
+ background-color: var(--gds-map-canvas);
1790
+ }
1791
+
1581
1792
  /* ============================================
1582
1793
  STREAM-IN — data-gds-streaming on <html>
1583
1794
  ============================================