@orion-studios/payload-admin-components 0.2.0-beta.3 → 0.2.0-beta.5

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/dist/admin.css CHANGED
@@ -1,85 +1,231 @@
1
1
  /**
2
2
  * Orion Studios Admin Theme System
3
3
  *
4
- * Import all theme files and overrides.
5
- * Usage in payload.config.ts:
6
- * export default buildConfig({
7
- * admin: {
8
- * css: require.resolve('@orion-studios/payload-admin-components/dist/admin.css'),
9
- * },
10
- * })
4
+ * Overrides Payload CMS's own CSS variables for theming.
5
+ * Payload uses --theme-elevation-*, --color-success-*, --style-radius-*, etc.
6
+ * Our CSS lives OUTSIDE @layer to override Payload's @layer payload-default.
7
+ *
8
+ * Theme system:
9
+ * - Light/Dark: Payload's built-in data-theme="dark" (we toggle it)
10
+ * - Brand mode: data-orion-brand attribute overrides accent colors with brand colors
11
+ * - Combinations: light, dark, brand-light (brand + no dark), brand-dark (brand + dark)
11
12
  */
12
13
 
13
- /* Default brand colors (overridden by configureAdmin) */
14
+ /* ============================================================
15
+ Brand color defaults (overridden by configureAdmin inline style)
16
+ ============================================================ */
14
17
  :root {
15
18
  --brand-primary: #3b82f6;
16
19
  --brand-secondary: #8b5cf6;
17
20
  }
18
21
 
19
- /* Theme files */
20
- @import './themes/light.css';
21
- @import './themes/dark.css';
22
- @import './themes/brand-light.css';
23
- @import './themes/brand-dark.css';
24
-
25
- /* Payload UI overrides */
26
- @import './overrides.css';
27
-
28
- /* Default to light theme when no data-theme attribute is set */
29
- :root:not([data-theme]) {
30
- --admin-bg: #ffffff;
31
- --admin-surface: #f9fafb;
32
- --admin-surface-elevated: #ffffff;
33
- --admin-border: #e5e7eb;
34
- --admin-border-subtle: #f3f4f6;
35
- --admin-text: #111827;
36
- --admin-text-secondary: #4b5563;
37
- --admin-text-muted: #9ca3af;
38
- --admin-text-inverse: #ffffff;
39
- --admin-accent: #3b82f6;
40
- --admin-accent-hover: #2563eb;
41
- --admin-accent-subtle: #eff6ff;
42
- --admin-accent-secondary: #8b5cf6;
43
- --admin-accent-secondary-hover: #7c3aed;
44
- --admin-accent-secondary-subtle: #f5f3ff;
45
- --admin-nav-bg: #f8fafc;
46
- --admin-nav-text: #374151;
47
- --admin-nav-text-active: #111827;
48
- --admin-nav-item-hover: #f1f5f9;
49
- --admin-nav-item-active: #e0e7ff;
50
- --admin-nav-group-text: #6b7280;
51
- --admin-nav-border: #e2e8f0;
52
- --admin-input-bg: #ffffff;
53
- --admin-input-border: #d1d5db;
54
- --admin-input-border-focus: var(--admin-accent);
55
- --admin-input-placeholder: #9ca3af;
56
- --admin-card-bg: #ffffff;
57
- --admin-card-border: #e5e7eb;
58
- --admin-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
59
- --admin-card-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.04);
60
- --admin-success: #16a34a;
61
- --admin-success-bg: #f0fdf4;
62
- --admin-warning: #d97706;
63
- --admin-warning-bg: #fffbeb;
64
- --admin-error: #dc2626;
65
- --admin-error-bg: #fef2f2;
66
- --admin-info: #0284c7;
67
- --admin-info-bg: #f0f9ff;
68
- --admin-tooltip-bg: #1f2937;
69
- --admin-tooltip-text: #f9fafb;
70
- --admin-overlay: rgba(0, 0, 0, 0.3);
71
- --admin-scrollbar-track: #f1f5f9;
72
- --admin-scrollbar-thumb: #cbd5e1;
73
- --admin-scrollbar-thumb-hover: #94a3b8;
74
- --admin-focus-ring: 0 0 0 2px #eff6ff, 0 0 0 4px #3b82f6;
75
- --admin-radius-sm: 6px;
76
- --admin-radius-md: 8px;
77
- --admin-radius-lg: 12px;
78
- --admin-radius-xl: 16px;
79
- --admin-badge-draft-bg: #fef3c7;
80
- --admin-badge-draft-text: #92400e;
81
- --admin-badge-published-bg: #dcfce7;
82
- --admin-badge-published-text: #166534;
83
- --admin-badge-changed-bg: #dbeafe;
84
- --admin-badge-changed-text: #1e40af;
22
+ /* ============================================================
23
+ Visual Enhancements (apply to ALL themes)
24
+ Larger border radii for a more modern look
25
+ ============================================================ */
26
+ :root {
27
+ --style-radius-s: 6px;
28
+ --style-radius-m: 8px;
29
+ --style-radius-l: 12px;
30
+ }
31
+
32
+ /* ============================================================
33
+ Brand Theme (Light) — Override Payload's accent colors
34
+ Applied when data-orion-brand is present and NOT dark mode
35
+ ============================================================ */
36
+ html[data-orion-brand]:not([data-theme='dark']) {
37
+ /* Override the "success" (accent) color scale with brand primary shades */
38
+ --color-success-50: color-mix(in srgb, var(--brand-primary) 5%, white);
39
+ --color-success-100: color-mix(in srgb, var(--brand-primary) 10%, white);
40
+ --color-success-150: color-mix(in srgb, var(--brand-primary) 15%, white);
41
+ --color-success-200: color-mix(in srgb, var(--brand-primary) 22%, white);
42
+ --color-success-250: color-mix(in srgb, var(--brand-primary) 30%, white);
43
+ --color-success-300: color-mix(in srgb, var(--brand-primary) 38%, white);
44
+ --color-success-350: color-mix(in srgb, var(--brand-primary) 48%, white);
45
+ --color-success-400: color-mix(in srgb, var(--brand-primary) 60%, white);
46
+ --color-success-450: color-mix(in srgb, var(--brand-primary) 75%, white);
47
+ --color-success-500: var(--brand-primary);
48
+ --color-success-550: color-mix(in srgb, var(--brand-primary) 90%, black);
49
+ --color-success-600: color-mix(in srgb, var(--brand-primary) 80%, black);
50
+ --color-success-650: color-mix(in srgb, var(--brand-primary) 70%, black);
51
+ --color-success-700: color-mix(in srgb, var(--brand-primary) 60%, black);
52
+ --color-success-750: color-mix(in srgb, var(--brand-primary) 50%, black);
53
+ --color-success-800: color-mix(in srgb, var(--brand-primary) 42%, black);
54
+ --color-success-850: color-mix(in srgb, var(--brand-primary) 35%, black);
55
+ --color-success-900: color-mix(in srgb, var(--brand-primary) 25%, black);
56
+ --color-success-950: color-mix(in srgb, var(--brand-primary) 15%, black);
57
+
58
+ /* Also override blue to match (used in some UI elements) */
59
+ --color-blue-50: color-mix(in srgb, var(--brand-primary) 5%, white);
60
+ --color-blue-100: color-mix(in srgb, var(--brand-primary) 10%, white);
61
+ --color-blue-150: color-mix(in srgb, var(--brand-primary) 15%, white);
62
+ --color-blue-200: color-mix(in srgb, var(--brand-primary) 22%, white);
63
+ --color-blue-250: color-mix(in srgb, var(--brand-primary) 30%, white);
64
+ --color-blue-300: color-mix(in srgb, var(--brand-primary) 38%, white);
65
+ --color-blue-350: color-mix(in srgb, var(--brand-primary) 48%, white);
66
+ --color-blue-400: color-mix(in srgb, var(--brand-primary) 60%, white);
67
+ --color-blue-450: color-mix(in srgb, var(--brand-primary) 75%, white);
68
+ --color-blue-500: var(--brand-primary);
69
+ --color-blue-550: color-mix(in srgb, var(--brand-primary) 90%, black);
70
+ --color-blue-600: color-mix(in srgb, var(--brand-primary) 80%, black);
71
+ --color-blue-650: color-mix(in srgb, var(--brand-primary) 70%, black);
72
+ --color-blue-700: color-mix(in srgb, var(--brand-primary) 60%, black);
73
+ --color-blue-750: color-mix(in srgb, var(--brand-primary) 50%, black);
74
+ --color-blue-800: color-mix(in srgb, var(--brand-primary) 42%, black);
75
+ --color-blue-850: color-mix(in srgb, var(--brand-primary) 35%, black);
76
+ --color-blue-900: color-mix(in srgb, var(--brand-primary) 25%, black);
77
+ --color-blue-950: color-mix(in srgb, var(--brand-primary) 15%, black);
78
+
79
+ /* Subtle brand tint on light backgrounds */
80
+ --color-base-50: color-mix(in srgb, var(--brand-primary) 2%, rgb(245, 245, 245));
81
+ --color-base-100: color-mix(in srgb, var(--brand-primary) 3%, rgb(235, 235, 235));
82
+ --color-base-150: color-mix(in srgb, var(--brand-primary) 4%, rgb(221, 221, 221));
83
+ }
84
+
85
+ /* ============================================================
86
+ Brand Theme (Dark) — Override Payload's accent colors in dark mode
87
+ ============================================================ */
88
+ html[data-orion-brand][data-theme='dark'] {
89
+ /* Lighter versions of brand primary for dark mode visibility */
90
+ --color-success-50: color-mix(in srgb, var(--brand-primary) 15%, black);
91
+ --color-success-100: color-mix(in srgb, var(--brand-primary) 25%, black);
92
+ --color-success-150: color-mix(in srgb, var(--brand-primary) 35%, black);
93
+ --color-success-200: color-mix(in srgb, var(--brand-primary) 42%, black);
94
+ --color-success-250: color-mix(in srgb, var(--brand-primary) 50%, black);
95
+ --color-success-300: color-mix(in srgb, var(--brand-primary) 60%, black);
96
+ --color-success-350: color-mix(in srgb, var(--brand-primary) 70%, black);
97
+ --color-success-400: color-mix(in srgb, var(--brand-primary) 80%, black);
98
+ --color-success-450: color-mix(in srgb, var(--brand-primary) 90%, black);
99
+ --color-success-500: var(--brand-primary);
100
+ --color-success-550: color-mix(in srgb, var(--brand-primary) 75%, white);
101
+ --color-success-600: color-mix(in srgb, var(--brand-primary) 60%, white);
102
+ --color-success-650: color-mix(in srgb, var(--brand-primary) 48%, white);
103
+ --color-success-700: color-mix(in srgb, var(--brand-primary) 38%, white);
104
+ --color-success-750: color-mix(in srgb, var(--brand-primary) 30%, white);
105
+ --color-success-800: color-mix(in srgb, var(--brand-primary) 22%, white);
106
+ --color-success-850: color-mix(in srgb, var(--brand-primary) 15%, white);
107
+ --color-success-900: color-mix(in srgb, var(--brand-primary) 10%, white);
108
+ --color-success-950: color-mix(in srgb, var(--brand-primary) 5%, white);
109
+
110
+ --color-blue-50: color-mix(in srgb, var(--brand-primary) 15%, black);
111
+ --color-blue-100: color-mix(in srgb, var(--brand-primary) 25%, black);
112
+ --color-blue-150: color-mix(in srgb, var(--brand-primary) 35%, black);
113
+ --color-blue-200: color-mix(in srgb, var(--brand-primary) 42%, black);
114
+ --color-blue-250: color-mix(in srgb, var(--brand-primary) 50%, black);
115
+ --color-blue-300: color-mix(in srgb, var(--brand-primary) 60%, black);
116
+ --color-blue-350: color-mix(in srgb, var(--brand-primary) 70%, black);
117
+ --color-blue-400: color-mix(in srgb, var(--brand-primary) 80%, black);
118
+ --color-blue-450: color-mix(in srgb, var(--brand-primary) 90%, black);
119
+ --color-blue-500: var(--brand-primary);
120
+ --color-blue-550: color-mix(in srgb, var(--brand-primary) 75%, white);
121
+ --color-blue-600: color-mix(in srgb, var(--brand-primary) 60%, white);
122
+ --color-blue-650: color-mix(in srgb, var(--brand-primary) 48%, white);
123
+ --color-blue-700: color-mix(in srgb, var(--brand-primary) 38%, white);
124
+ --color-blue-750: color-mix(in srgb, var(--brand-primary) 30%, white);
125
+ --color-blue-800: color-mix(in srgb, var(--brand-primary) 22%, white);
126
+ --color-blue-850: color-mix(in srgb, var(--brand-primary) 15%, white);
127
+ --color-blue-900: color-mix(in srgb, var(--brand-primary) 10%, white);
128
+ --color-blue-950: color-mix(in srgb, var(--brand-primary) 5%, white);
129
+
130
+ /* Subtle brand tint on dark backgrounds */
131
+ --color-base-900: color-mix(in srgb, var(--brand-primary) 4%, rgb(20, 20, 20));
132
+ --color-base-850: color-mix(in srgb, var(--brand-primary) 3%, rgb(34, 34, 34));
133
+ --color-base-800: color-mix(in srgb, var(--brand-primary) 2%, rgb(47, 47, 47));
134
+ }
135
+
136
+ /* ============================================================
137
+ Smooth theme transitions
138
+ ============================================================ */
139
+ html {
140
+ transition: background-color 0.2s ease, color 0.2s ease;
141
+ }
142
+
143
+ /* ============================================================
144
+ Collapsible sections — card-like styling
145
+ ============================================================ */
146
+ .collapsible {
147
+ border-radius: var(--style-radius-l) !important;
148
+ margin-bottom: 12px !important;
149
+ overflow: hidden;
150
+ }
151
+
152
+ .collapsible__toggle-wrap {
153
+ border-radius: var(--style-radius-l) var(--style-radius-l) 0 0 !important;
154
+ }
155
+
156
+ /* ============================================================
157
+ Nav group labels (uppercased, refined)
158
+ ============================================================ */
159
+ .nav-group__toggle {
160
+ font-size: 11px !important;
161
+ font-weight: 700 !important;
162
+ letter-spacing: 0.05em !important;
163
+ text-transform: uppercase !important;
164
+ }
165
+
166
+ /* ============================================================
167
+ Primary buttons — more visual pop
168
+ ============================================================ */
169
+ .btn--style-primary:hover {
170
+ transform: translateY(-1px);
171
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
172
+ }
173
+
174
+ .btn--style-primary:active {
175
+ transform: translateY(0);
176
+ }
177
+
178
+ /* ============================================================
179
+ Table row hover
180
+ ============================================================ */
181
+ .table tr:hover td {
182
+ background-color: var(--theme-elevation-50);
183
+ }
184
+
185
+ /* ============================================================
186
+ Status pills — rounder
187
+ ============================================================ */
188
+ .pill {
189
+ border-radius: 20px !important;
190
+ }
191
+
192
+ /* ============================================================
193
+ Dropzone — better styling
194
+ ============================================================ */
195
+ .file-field__upload.dropzone {
196
+ border-radius: var(--style-radius-l);
197
+ }
198
+
199
+ /* ============================================================
200
+ Toast notifications — rounder corners
201
+ ============================================================ */
202
+ .payload-toast-item {
203
+ border-radius: var(--style-radius-m) !important;
204
+ }
205
+
206
+ /* ============================================================
207
+ Custom scrollbars (webkit)
208
+ ============================================================ */
209
+ ::-webkit-scrollbar {
210
+ width: 8px;
211
+ height: 8px;
212
+ }
213
+
214
+ ::-webkit-scrollbar-track {
215
+ background: var(--theme-elevation-50);
216
+ }
217
+
218
+ ::-webkit-scrollbar-thumb {
219
+ background: var(--theme-elevation-250);
220
+ border-radius: 4px;
221
+ }
222
+
223
+ ::-webkit-scrollbar-thumb:hover {
224
+ background: var(--theme-elevation-350);
225
+ }
226
+
227
+ /* Firefox scrollbar */
228
+ * {
229
+ scrollbar-width: thin;
230
+ scrollbar-color: var(--theme-elevation-250) var(--theme-elevation-50);
85
231
  }
package/dist/client.js CHANGED
@@ -113,7 +113,19 @@ var import_react = require("react");
113
113
  var STORAGE_KEY = "orion-admin-theme";
114
114
  var DEFAULT_THEME = "light";
115
115
  function applyTheme(theme) {
116
- document.documentElement.setAttribute("data-theme", theme);
116
+ const html = document.documentElement;
117
+ const isDark = theme === "dark" || theme === "brand-dark";
118
+ const isBrand = theme === "brand-light" || theme === "brand-dark";
119
+ if (isDark) {
120
+ html.setAttribute("data-theme", "dark");
121
+ } else {
122
+ html.removeAttribute("data-theme");
123
+ }
124
+ if (isBrand) {
125
+ html.setAttribute("data-orion-brand", "true");
126
+ } else {
127
+ html.removeAttribute("data-orion-brand");
128
+ }
117
129
  }
118
130
  function getCachedTheme() {
119
131
  try {
@@ -243,19 +255,21 @@ var buttonBase = {
243
255
  justifyContent: "center",
244
256
  width: 32,
245
257
  height: 32,
246
- borderRadius: "var(--admin-radius-sm)",
247
- border: "1px solid var(--admin-border)",
248
- background: "var(--admin-surface)",
249
- color: "var(--admin-text-secondary)",
258
+ borderRadius: "var(--style-radius-s)",
259
+ borderWidth: 1,
260
+ borderStyle: "solid",
261
+ borderColor: "var(--theme-elevation-150)",
262
+ background: "var(--theme-elevation-0)",
263
+ color: "var(--theme-elevation-450)",
250
264
  cursor: "pointer",
251
265
  transition: "all 0.2s ease",
252
266
  padding: 0
253
267
  };
254
268
  var buttonActive = {
255
269
  ...buttonBase,
256
- background: "var(--admin-accent-subtle)",
257
- borderColor: "var(--admin-accent)",
258
- color: "var(--admin-accent)"
270
+ background: "var(--theme-success-50)",
271
+ borderColor: "var(--theme-success-500)",
272
+ color: "var(--theme-success-500)"
259
273
  };
260
274
  function ThemeSwitcher() {
261
275
  const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme();
@@ -301,13 +315,25 @@ function ThemeProvider({ children }) {
301
315
  (0, import_react2.useEffect)(() => {
302
316
  try {
303
317
  const stored = localStorage.getItem("orion-admin-theme");
318
+ const html = document.documentElement;
304
319
  if (stored && ["light", "dark", "brand-light", "brand-dark"].includes(stored)) {
305
- document.documentElement.setAttribute("data-theme", stored);
320
+ const isDark = stored === "dark" || stored === "brand-dark";
321
+ const isBrand = stored === "brand-light" || stored === "brand-dark";
322
+ if (isDark) {
323
+ html.setAttribute("data-theme", "dark");
324
+ } else {
325
+ html.removeAttribute("data-theme");
326
+ }
327
+ if (isBrand) {
328
+ html.setAttribute("data-orion-brand", "true");
329
+ } else {
330
+ html.removeAttribute("data-orion-brand");
331
+ }
306
332
  } else {
307
- document.documentElement.setAttribute("data-theme", "light");
333
+ html.removeAttribute("data-theme");
334
+ html.removeAttribute("data-orion-brand");
308
335
  }
309
336
  } catch {
310
- document.documentElement.setAttribute("data-theme", "light");
311
337
  }
312
338
  }, []);
313
339
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
package/dist/client.mjs CHANGED
@@ -77,7 +77,19 @@ import { useCallback, useEffect, useRef, useState } from "react";
77
77
  var STORAGE_KEY = "orion-admin-theme";
78
78
  var DEFAULT_THEME = "light";
79
79
  function applyTheme(theme) {
80
- document.documentElement.setAttribute("data-theme", theme);
80
+ const html = document.documentElement;
81
+ const isDark = theme === "dark" || theme === "brand-dark";
82
+ const isBrand = theme === "brand-light" || theme === "brand-dark";
83
+ if (isDark) {
84
+ html.setAttribute("data-theme", "dark");
85
+ } else {
86
+ html.removeAttribute("data-theme");
87
+ }
88
+ if (isBrand) {
89
+ html.setAttribute("data-orion-brand", "true");
90
+ } else {
91
+ html.removeAttribute("data-orion-brand");
92
+ }
81
93
  }
82
94
  function getCachedTheme() {
83
95
  try {
@@ -207,19 +219,21 @@ var buttonBase = {
207
219
  justifyContent: "center",
208
220
  width: 32,
209
221
  height: 32,
210
- borderRadius: "var(--admin-radius-sm)",
211
- border: "1px solid var(--admin-border)",
212
- background: "var(--admin-surface)",
213
- color: "var(--admin-text-secondary)",
222
+ borderRadius: "var(--style-radius-s)",
223
+ borderWidth: 1,
224
+ borderStyle: "solid",
225
+ borderColor: "var(--theme-elevation-150)",
226
+ background: "var(--theme-elevation-0)",
227
+ color: "var(--theme-elevation-450)",
214
228
  cursor: "pointer",
215
229
  transition: "all 0.2s ease",
216
230
  padding: 0
217
231
  };
218
232
  var buttonActive = {
219
233
  ...buttonBase,
220
- background: "var(--admin-accent-subtle)",
221
- borderColor: "var(--admin-accent)",
222
- color: "var(--admin-accent)"
234
+ background: "var(--theme-success-50)",
235
+ borderColor: "var(--theme-success-500)",
236
+ color: "var(--theme-success-500)"
223
237
  };
224
238
  function ThemeSwitcher() {
225
239
  const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme();
@@ -265,13 +279,25 @@ function ThemeProvider({ children }) {
265
279
  useEffect2(() => {
266
280
  try {
267
281
  const stored = localStorage.getItem("orion-admin-theme");
282
+ const html = document.documentElement;
268
283
  if (stored && ["light", "dark", "brand-light", "brand-dark"].includes(stored)) {
269
- document.documentElement.setAttribute("data-theme", stored);
284
+ const isDark = stored === "dark" || stored === "brand-dark";
285
+ const isBrand = stored === "brand-light" || stored === "brand-dark";
286
+ if (isDark) {
287
+ html.setAttribute("data-theme", "dark");
288
+ } else {
289
+ html.removeAttribute("data-theme");
290
+ }
291
+ if (isBrand) {
292
+ html.setAttribute("data-orion-brand", "true");
293
+ } else {
294
+ html.removeAttribute("data-orion-brand");
295
+ }
270
296
  } else {
271
- document.documentElement.setAttribute("data-theme", "light");
297
+ html.removeAttribute("data-theme");
298
+ html.removeAttribute("data-orion-brand");
272
299
  }
273
300
  } catch {
274
- document.documentElement.setAttribute("data-theme", "light");
275
301
  }
276
302
  }, []);
277
303
  return /* @__PURE__ */ jsx3(Fragment, { children });
package/dist/index.js CHANGED
@@ -276,7 +276,19 @@ var import_react = require("react");
276
276
  var STORAGE_KEY = "orion-admin-theme";
277
277
  var DEFAULT_THEME = "light";
278
278
  function applyTheme(theme) {
279
- document.documentElement.setAttribute("data-theme", theme);
279
+ const html = document.documentElement;
280
+ const isDark = theme === "dark" || theme === "brand-dark";
281
+ const isBrand = theme === "brand-light" || theme === "brand-dark";
282
+ if (isDark) {
283
+ html.setAttribute("data-theme", "dark");
284
+ } else {
285
+ html.removeAttribute("data-theme");
286
+ }
287
+ if (isBrand) {
288
+ html.setAttribute("data-orion-brand", "true");
289
+ } else {
290
+ html.removeAttribute("data-orion-brand");
291
+ }
280
292
  }
281
293
  function getCachedTheme() {
282
294
  try {
@@ -406,19 +418,21 @@ var buttonBase = {
406
418
  justifyContent: "center",
407
419
  width: 32,
408
420
  height: 32,
409
- borderRadius: "var(--admin-radius-sm)",
410
- border: "1px solid var(--admin-border)",
411
- background: "var(--admin-surface)",
412
- color: "var(--admin-text-secondary)",
421
+ borderRadius: "var(--style-radius-s)",
422
+ borderWidth: 1,
423
+ borderStyle: "solid",
424
+ borderColor: "var(--theme-elevation-150)",
425
+ background: "var(--theme-elevation-0)",
426
+ color: "var(--theme-elevation-450)",
413
427
  cursor: "pointer",
414
428
  transition: "all 0.2s ease",
415
429
  padding: 0
416
430
  };
417
431
  var buttonActive = {
418
432
  ...buttonBase,
419
- background: "var(--admin-accent-subtle)",
420
- borderColor: "var(--admin-accent)",
421
- color: "var(--admin-accent)"
433
+ background: "var(--theme-success-50)",
434
+ borderColor: "var(--theme-success-500)",
435
+ color: "var(--theme-success-500)"
422
436
  };
423
437
  function ThemeSwitcher() {
424
438
  const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme();
@@ -464,13 +478,25 @@ function ThemeProvider({ children }) {
464
478
  (0, import_react2.useEffect)(() => {
465
479
  try {
466
480
  const stored = localStorage.getItem("orion-admin-theme");
481
+ const html = document.documentElement;
467
482
  if (stored && ["light", "dark", "brand-light", "brand-dark"].includes(stored)) {
468
- document.documentElement.setAttribute("data-theme", stored);
483
+ const isDark = stored === "dark" || stored === "brand-dark";
484
+ const isBrand = stored === "brand-light" || stored === "brand-dark";
485
+ if (isDark) {
486
+ html.setAttribute("data-theme", "dark");
487
+ } else {
488
+ html.removeAttribute("data-theme");
489
+ }
490
+ if (isBrand) {
491
+ html.setAttribute("data-orion-brand", "true");
492
+ } else {
493
+ html.removeAttribute("data-orion-brand");
494
+ }
469
495
  } else {
470
- document.documentElement.setAttribute("data-theme", "light");
496
+ html.removeAttribute("data-theme");
497
+ html.removeAttribute("data-orion-brand");
471
498
  }
472
499
  } catch {
473
- document.documentElement.setAttribute("data-theme", "light");
474
500
  }
475
501
  }, []);
476
502
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
package/dist/index.mjs CHANGED
@@ -236,7 +236,19 @@ import { useCallback, useEffect, useRef, useState } from "react";
236
236
  var STORAGE_KEY = "orion-admin-theme";
237
237
  var DEFAULT_THEME = "light";
238
238
  function applyTheme(theme) {
239
- document.documentElement.setAttribute("data-theme", theme);
239
+ const html = document.documentElement;
240
+ const isDark = theme === "dark" || theme === "brand-dark";
241
+ const isBrand = theme === "brand-light" || theme === "brand-dark";
242
+ if (isDark) {
243
+ html.setAttribute("data-theme", "dark");
244
+ } else {
245
+ html.removeAttribute("data-theme");
246
+ }
247
+ if (isBrand) {
248
+ html.setAttribute("data-orion-brand", "true");
249
+ } else {
250
+ html.removeAttribute("data-orion-brand");
251
+ }
240
252
  }
241
253
  function getCachedTheme() {
242
254
  try {
@@ -366,19 +378,21 @@ var buttonBase = {
366
378
  justifyContent: "center",
367
379
  width: 32,
368
380
  height: 32,
369
- borderRadius: "var(--admin-radius-sm)",
370
- border: "1px solid var(--admin-border)",
371
- background: "var(--admin-surface)",
372
- color: "var(--admin-text-secondary)",
381
+ borderRadius: "var(--style-radius-s)",
382
+ borderWidth: 1,
383
+ borderStyle: "solid",
384
+ borderColor: "var(--theme-elevation-150)",
385
+ background: "var(--theme-elevation-0)",
386
+ color: "var(--theme-elevation-450)",
373
387
  cursor: "pointer",
374
388
  transition: "all 0.2s ease",
375
389
  padding: 0
376
390
  };
377
391
  var buttonActive = {
378
392
  ...buttonBase,
379
- background: "var(--admin-accent-subtle)",
380
- borderColor: "var(--admin-accent)",
381
- color: "var(--admin-accent)"
393
+ background: "var(--theme-success-50)",
394
+ borderColor: "var(--theme-success-500)",
395
+ color: "var(--theme-success-500)"
382
396
  };
383
397
  function ThemeSwitcher() {
384
398
  const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme();
@@ -424,13 +438,25 @@ function ThemeProvider({ children }) {
424
438
  useEffect2(() => {
425
439
  try {
426
440
  const stored = localStorage.getItem("orion-admin-theme");
441
+ const html = document.documentElement;
427
442
  if (stored && ["light", "dark", "brand-light", "brand-dark"].includes(stored)) {
428
- document.documentElement.setAttribute("data-theme", stored);
443
+ const isDark = stored === "dark" || stored === "brand-dark";
444
+ const isBrand = stored === "brand-light" || stored === "brand-dark";
445
+ if (isDark) {
446
+ html.setAttribute("data-theme", "dark");
447
+ } else {
448
+ html.removeAttribute("data-theme");
449
+ }
450
+ if (isBrand) {
451
+ html.setAttribute("data-orion-brand", "true");
452
+ } else {
453
+ html.removeAttribute("data-orion-brand");
454
+ }
429
455
  } else {
430
- document.documentElement.setAttribute("data-theme", "light");
456
+ html.removeAttribute("data-theme");
457
+ html.removeAttribute("data-orion-brand");
431
458
  }
432
459
  } catch {
433
- document.documentElement.setAttribute("data-theme", "light");
434
460
  }
435
461
  }, []);
436
462
  return /* @__PURE__ */ jsx3(Fragment, { children });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orion-studios/payload-admin-components",
3
- "version": "0.2.0-beta.3",
3
+ "version": "0.2.0-beta.5",
4
4
  "description": "Custom admin UI components for Payload CMS",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -23,7 +23,7 @@
23
23
  "src"
24
24
  ],
25
25
  "scripts": {
26
- "build": "tsup && node -e \"const fs=require('fs'),path=require('path');function copyDir(s,d){fs.mkdirSync(d,{recursive:true});for(const f of fs.readdirSync(s)){const sp=path.join(s,f),dp=path.join(d,f);fs.statSync(sp).isDirectory()?copyDir(sp,dp):fs.copyFileSync(sp,dp)}}copyDir('src/styles','dist/styles');fs.copyFileSync('src/styles/admin.css','dist/admin.css')\"",
26
+ "build": "tsup && node -e \"require('fs').copyFileSync('src/styles/admin.css','dist/admin.css')\"",
27
27
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
28
28
  "typecheck": "tsc --noEmit"
29
29
  },
@@ -47,10 +47,12 @@ const buttonBase: React.CSSProperties = {
47
47
  justifyContent: 'center',
48
48
  width: 32,
49
49
  height: 32,
50
- borderRadius: 'var(--admin-radius-sm)',
51
- border: '1px solid var(--admin-border)',
52
- background: 'var(--admin-surface)',
53
- color: 'var(--admin-text-secondary)',
50
+ borderRadius: 'var(--style-radius-s)',
51
+ borderWidth: 1,
52
+ borderStyle: 'solid',
53
+ borderColor: 'var(--theme-elevation-150)',
54
+ background: 'var(--theme-elevation-0)',
55
+ color: 'var(--theme-elevation-450)',
54
56
  cursor: 'pointer',
55
57
  transition: 'all 0.2s ease',
56
58
  padding: 0,
@@ -58,9 +60,9 @@ const buttonBase: React.CSSProperties = {
58
60
 
59
61
  const buttonActive: React.CSSProperties = {
60
62
  ...buttonBase,
61
- background: 'var(--admin-accent-subtle)',
62
- borderColor: 'var(--admin-accent)',
63
- color: 'var(--admin-accent)',
63
+ background: 'var(--theme-success-50)',
64
+ borderColor: 'var(--theme-success-500)',
65
+ color: 'var(--theme-success-500)',
64
66
  }
65
67
 
66
68
  export function ThemeSwitcher() {
@@ -112,13 +114,26 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
112
114
  useEffect(() => {
113
115
  try {
114
116
  const stored = localStorage.getItem('orion-admin-theme')
117
+ const html = document.documentElement
115
118
  if (stored && ['light', 'dark', 'brand-light', 'brand-dark'].includes(stored)) {
116
- document.documentElement.setAttribute('data-theme', stored)
119
+ const isDark = stored === 'dark' || stored === 'brand-dark'
120
+ const isBrand = stored === 'brand-light' || stored === 'brand-dark'
121
+ if (isDark) {
122
+ html.setAttribute('data-theme', 'dark')
123
+ } else {
124
+ html.removeAttribute('data-theme')
125
+ }
126
+ if (isBrand) {
127
+ html.setAttribute('data-orion-brand', 'true')
128
+ } else {
129
+ html.removeAttribute('data-orion-brand')
130
+ }
117
131
  } else {
118
- document.documentElement.setAttribute('data-theme', 'light')
132
+ html.removeAttribute('data-theme')
133
+ html.removeAttribute('data-orion-brand')
119
134
  }
120
135
  } catch {
121
- document.documentElement.setAttribute('data-theme', 'light')
136
+ // no-op
122
137
  }
123
138
  }, [])
124
139
 
@@ -7,8 +7,33 @@ export type ThemeOption = 'light' | 'dark' | 'brand-light' | 'brand-dark'
7
7
  const STORAGE_KEY = 'orion-admin-theme'
8
8
  const DEFAULT_THEME: ThemeOption = 'light'
9
9
 
10
+ /**
11
+ * Applies the theme by setting Payload's data-theme attribute for dark mode
12
+ * and our data-orion-brand attribute for brand colors.
13
+ *
14
+ * - light: no data-theme, no data-orion-brand
15
+ * - dark: data-theme="dark", no data-orion-brand
16
+ * - brand-light: no data-theme, data-orion-brand present
17
+ * - brand-dark: data-theme="dark", data-orion-brand present
18
+ */
10
19
  function applyTheme(theme: ThemeOption) {
11
- document.documentElement.setAttribute('data-theme', theme)
20
+ const html = document.documentElement
21
+ const isDark = theme === 'dark' || theme === 'brand-dark'
22
+ const isBrand = theme === 'brand-light' || theme === 'brand-dark'
23
+
24
+ // Payload's dark mode attribute
25
+ if (isDark) {
26
+ html.setAttribute('data-theme', 'dark')
27
+ } else {
28
+ html.removeAttribute('data-theme')
29
+ }
30
+
31
+ // Our brand attribute
32
+ if (isBrand) {
33
+ html.setAttribute('data-orion-brand', 'true')
34
+ } else {
35
+ html.removeAttribute('data-orion-brand')
36
+ }
12
37
  }
13
38
 
14
39
  function getCachedTheme(): ThemeOption | null {
@@ -1,85 +1,231 @@
1
1
  /**
2
2
  * Orion Studios Admin Theme System
3
3
  *
4
- * Import all theme files and overrides.
5
- * Usage in payload.config.ts:
6
- * export default buildConfig({
7
- * admin: {
8
- * css: require.resolve('@orion-studios/payload-admin-components/dist/admin.css'),
9
- * },
10
- * })
4
+ * Overrides Payload CMS's own CSS variables for theming.
5
+ * Payload uses --theme-elevation-*, --color-success-*, --style-radius-*, etc.
6
+ * Our CSS lives OUTSIDE @layer to override Payload's @layer payload-default.
7
+ *
8
+ * Theme system:
9
+ * - Light/Dark: Payload's built-in data-theme="dark" (we toggle it)
10
+ * - Brand mode: data-orion-brand attribute overrides accent colors with brand colors
11
+ * - Combinations: light, dark, brand-light (brand + no dark), brand-dark (brand + dark)
11
12
  */
12
13
 
13
- /* Default brand colors (overridden by configureAdmin) */
14
+ /* ============================================================
15
+ Brand color defaults (overridden by configureAdmin inline style)
16
+ ============================================================ */
14
17
  :root {
15
18
  --brand-primary: #3b82f6;
16
19
  --brand-secondary: #8b5cf6;
17
20
  }
18
21
 
19
- /* Theme files */
20
- @import './themes/light.css';
21
- @import './themes/dark.css';
22
- @import './themes/brand-light.css';
23
- @import './themes/brand-dark.css';
24
-
25
- /* Payload UI overrides */
26
- @import './overrides.css';
27
-
28
- /* Default to light theme when no data-theme attribute is set */
29
- :root:not([data-theme]) {
30
- --admin-bg: #ffffff;
31
- --admin-surface: #f9fafb;
32
- --admin-surface-elevated: #ffffff;
33
- --admin-border: #e5e7eb;
34
- --admin-border-subtle: #f3f4f6;
35
- --admin-text: #111827;
36
- --admin-text-secondary: #4b5563;
37
- --admin-text-muted: #9ca3af;
38
- --admin-text-inverse: #ffffff;
39
- --admin-accent: #3b82f6;
40
- --admin-accent-hover: #2563eb;
41
- --admin-accent-subtle: #eff6ff;
42
- --admin-accent-secondary: #8b5cf6;
43
- --admin-accent-secondary-hover: #7c3aed;
44
- --admin-accent-secondary-subtle: #f5f3ff;
45
- --admin-nav-bg: #f8fafc;
46
- --admin-nav-text: #374151;
47
- --admin-nav-text-active: #111827;
48
- --admin-nav-item-hover: #f1f5f9;
49
- --admin-nav-item-active: #e0e7ff;
50
- --admin-nav-group-text: #6b7280;
51
- --admin-nav-border: #e2e8f0;
52
- --admin-input-bg: #ffffff;
53
- --admin-input-border: #d1d5db;
54
- --admin-input-border-focus: var(--admin-accent);
55
- --admin-input-placeholder: #9ca3af;
56
- --admin-card-bg: #ffffff;
57
- --admin-card-border: #e5e7eb;
58
- --admin-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
59
- --admin-card-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.04);
60
- --admin-success: #16a34a;
61
- --admin-success-bg: #f0fdf4;
62
- --admin-warning: #d97706;
63
- --admin-warning-bg: #fffbeb;
64
- --admin-error: #dc2626;
65
- --admin-error-bg: #fef2f2;
66
- --admin-info: #0284c7;
67
- --admin-info-bg: #f0f9ff;
68
- --admin-tooltip-bg: #1f2937;
69
- --admin-tooltip-text: #f9fafb;
70
- --admin-overlay: rgba(0, 0, 0, 0.3);
71
- --admin-scrollbar-track: #f1f5f9;
72
- --admin-scrollbar-thumb: #cbd5e1;
73
- --admin-scrollbar-thumb-hover: #94a3b8;
74
- --admin-focus-ring: 0 0 0 2px #eff6ff, 0 0 0 4px #3b82f6;
75
- --admin-radius-sm: 6px;
76
- --admin-radius-md: 8px;
77
- --admin-radius-lg: 12px;
78
- --admin-radius-xl: 16px;
79
- --admin-badge-draft-bg: #fef3c7;
80
- --admin-badge-draft-text: #92400e;
81
- --admin-badge-published-bg: #dcfce7;
82
- --admin-badge-published-text: #166534;
83
- --admin-badge-changed-bg: #dbeafe;
84
- --admin-badge-changed-text: #1e40af;
22
+ /* ============================================================
23
+ Visual Enhancements (apply to ALL themes)
24
+ Larger border radii for a more modern look
25
+ ============================================================ */
26
+ :root {
27
+ --style-radius-s: 6px;
28
+ --style-radius-m: 8px;
29
+ --style-radius-l: 12px;
30
+ }
31
+
32
+ /* ============================================================
33
+ Brand Theme (Light) — Override Payload's accent colors
34
+ Applied when data-orion-brand is present and NOT dark mode
35
+ ============================================================ */
36
+ html[data-orion-brand]:not([data-theme='dark']) {
37
+ /* Override the "success" (accent) color scale with brand primary shades */
38
+ --color-success-50: color-mix(in srgb, var(--brand-primary) 5%, white);
39
+ --color-success-100: color-mix(in srgb, var(--brand-primary) 10%, white);
40
+ --color-success-150: color-mix(in srgb, var(--brand-primary) 15%, white);
41
+ --color-success-200: color-mix(in srgb, var(--brand-primary) 22%, white);
42
+ --color-success-250: color-mix(in srgb, var(--brand-primary) 30%, white);
43
+ --color-success-300: color-mix(in srgb, var(--brand-primary) 38%, white);
44
+ --color-success-350: color-mix(in srgb, var(--brand-primary) 48%, white);
45
+ --color-success-400: color-mix(in srgb, var(--brand-primary) 60%, white);
46
+ --color-success-450: color-mix(in srgb, var(--brand-primary) 75%, white);
47
+ --color-success-500: var(--brand-primary);
48
+ --color-success-550: color-mix(in srgb, var(--brand-primary) 90%, black);
49
+ --color-success-600: color-mix(in srgb, var(--brand-primary) 80%, black);
50
+ --color-success-650: color-mix(in srgb, var(--brand-primary) 70%, black);
51
+ --color-success-700: color-mix(in srgb, var(--brand-primary) 60%, black);
52
+ --color-success-750: color-mix(in srgb, var(--brand-primary) 50%, black);
53
+ --color-success-800: color-mix(in srgb, var(--brand-primary) 42%, black);
54
+ --color-success-850: color-mix(in srgb, var(--brand-primary) 35%, black);
55
+ --color-success-900: color-mix(in srgb, var(--brand-primary) 25%, black);
56
+ --color-success-950: color-mix(in srgb, var(--brand-primary) 15%, black);
57
+
58
+ /* Also override blue to match (used in some UI elements) */
59
+ --color-blue-50: color-mix(in srgb, var(--brand-primary) 5%, white);
60
+ --color-blue-100: color-mix(in srgb, var(--brand-primary) 10%, white);
61
+ --color-blue-150: color-mix(in srgb, var(--brand-primary) 15%, white);
62
+ --color-blue-200: color-mix(in srgb, var(--brand-primary) 22%, white);
63
+ --color-blue-250: color-mix(in srgb, var(--brand-primary) 30%, white);
64
+ --color-blue-300: color-mix(in srgb, var(--brand-primary) 38%, white);
65
+ --color-blue-350: color-mix(in srgb, var(--brand-primary) 48%, white);
66
+ --color-blue-400: color-mix(in srgb, var(--brand-primary) 60%, white);
67
+ --color-blue-450: color-mix(in srgb, var(--brand-primary) 75%, white);
68
+ --color-blue-500: var(--brand-primary);
69
+ --color-blue-550: color-mix(in srgb, var(--brand-primary) 90%, black);
70
+ --color-blue-600: color-mix(in srgb, var(--brand-primary) 80%, black);
71
+ --color-blue-650: color-mix(in srgb, var(--brand-primary) 70%, black);
72
+ --color-blue-700: color-mix(in srgb, var(--brand-primary) 60%, black);
73
+ --color-blue-750: color-mix(in srgb, var(--brand-primary) 50%, black);
74
+ --color-blue-800: color-mix(in srgb, var(--brand-primary) 42%, black);
75
+ --color-blue-850: color-mix(in srgb, var(--brand-primary) 35%, black);
76
+ --color-blue-900: color-mix(in srgb, var(--brand-primary) 25%, black);
77
+ --color-blue-950: color-mix(in srgb, var(--brand-primary) 15%, black);
78
+
79
+ /* Subtle brand tint on light backgrounds */
80
+ --color-base-50: color-mix(in srgb, var(--brand-primary) 2%, rgb(245, 245, 245));
81
+ --color-base-100: color-mix(in srgb, var(--brand-primary) 3%, rgb(235, 235, 235));
82
+ --color-base-150: color-mix(in srgb, var(--brand-primary) 4%, rgb(221, 221, 221));
83
+ }
84
+
85
+ /* ============================================================
86
+ Brand Theme (Dark) — Override Payload's accent colors in dark mode
87
+ ============================================================ */
88
+ html[data-orion-brand][data-theme='dark'] {
89
+ /* Lighter versions of brand primary for dark mode visibility */
90
+ --color-success-50: color-mix(in srgb, var(--brand-primary) 15%, black);
91
+ --color-success-100: color-mix(in srgb, var(--brand-primary) 25%, black);
92
+ --color-success-150: color-mix(in srgb, var(--brand-primary) 35%, black);
93
+ --color-success-200: color-mix(in srgb, var(--brand-primary) 42%, black);
94
+ --color-success-250: color-mix(in srgb, var(--brand-primary) 50%, black);
95
+ --color-success-300: color-mix(in srgb, var(--brand-primary) 60%, black);
96
+ --color-success-350: color-mix(in srgb, var(--brand-primary) 70%, black);
97
+ --color-success-400: color-mix(in srgb, var(--brand-primary) 80%, black);
98
+ --color-success-450: color-mix(in srgb, var(--brand-primary) 90%, black);
99
+ --color-success-500: var(--brand-primary);
100
+ --color-success-550: color-mix(in srgb, var(--brand-primary) 75%, white);
101
+ --color-success-600: color-mix(in srgb, var(--brand-primary) 60%, white);
102
+ --color-success-650: color-mix(in srgb, var(--brand-primary) 48%, white);
103
+ --color-success-700: color-mix(in srgb, var(--brand-primary) 38%, white);
104
+ --color-success-750: color-mix(in srgb, var(--brand-primary) 30%, white);
105
+ --color-success-800: color-mix(in srgb, var(--brand-primary) 22%, white);
106
+ --color-success-850: color-mix(in srgb, var(--brand-primary) 15%, white);
107
+ --color-success-900: color-mix(in srgb, var(--brand-primary) 10%, white);
108
+ --color-success-950: color-mix(in srgb, var(--brand-primary) 5%, white);
109
+
110
+ --color-blue-50: color-mix(in srgb, var(--brand-primary) 15%, black);
111
+ --color-blue-100: color-mix(in srgb, var(--brand-primary) 25%, black);
112
+ --color-blue-150: color-mix(in srgb, var(--brand-primary) 35%, black);
113
+ --color-blue-200: color-mix(in srgb, var(--brand-primary) 42%, black);
114
+ --color-blue-250: color-mix(in srgb, var(--brand-primary) 50%, black);
115
+ --color-blue-300: color-mix(in srgb, var(--brand-primary) 60%, black);
116
+ --color-blue-350: color-mix(in srgb, var(--brand-primary) 70%, black);
117
+ --color-blue-400: color-mix(in srgb, var(--brand-primary) 80%, black);
118
+ --color-blue-450: color-mix(in srgb, var(--brand-primary) 90%, black);
119
+ --color-blue-500: var(--brand-primary);
120
+ --color-blue-550: color-mix(in srgb, var(--brand-primary) 75%, white);
121
+ --color-blue-600: color-mix(in srgb, var(--brand-primary) 60%, white);
122
+ --color-blue-650: color-mix(in srgb, var(--brand-primary) 48%, white);
123
+ --color-blue-700: color-mix(in srgb, var(--brand-primary) 38%, white);
124
+ --color-blue-750: color-mix(in srgb, var(--brand-primary) 30%, white);
125
+ --color-blue-800: color-mix(in srgb, var(--brand-primary) 22%, white);
126
+ --color-blue-850: color-mix(in srgb, var(--brand-primary) 15%, white);
127
+ --color-blue-900: color-mix(in srgb, var(--brand-primary) 10%, white);
128
+ --color-blue-950: color-mix(in srgb, var(--brand-primary) 5%, white);
129
+
130
+ /* Subtle brand tint on dark backgrounds */
131
+ --color-base-900: color-mix(in srgb, var(--brand-primary) 4%, rgb(20, 20, 20));
132
+ --color-base-850: color-mix(in srgb, var(--brand-primary) 3%, rgb(34, 34, 34));
133
+ --color-base-800: color-mix(in srgb, var(--brand-primary) 2%, rgb(47, 47, 47));
134
+ }
135
+
136
+ /* ============================================================
137
+ Smooth theme transitions
138
+ ============================================================ */
139
+ html {
140
+ transition: background-color 0.2s ease, color 0.2s ease;
141
+ }
142
+
143
+ /* ============================================================
144
+ Collapsible sections — card-like styling
145
+ ============================================================ */
146
+ .collapsible {
147
+ border-radius: var(--style-radius-l) !important;
148
+ margin-bottom: 12px !important;
149
+ overflow: hidden;
150
+ }
151
+
152
+ .collapsible__toggle-wrap {
153
+ border-radius: var(--style-radius-l) var(--style-radius-l) 0 0 !important;
154
+ }
155
+
156
+ /* ============================================================
157
+ Nav group labels (uppercased, refined)
158
+ ============================================================ */
159
+ .nav-group__toggle {
160
+ font-size: 11px !important;
161
+ font-weight: 700 !important;
162
+ letter-spacing: 0.05em !important;
163
+ text-transform: uppercase !important;
164
+ }
165
+
166
+ /* ============================================================
167
+ Primary buttons — more visual pop
168
+ ============================================================ */
169
+ .btn--style-primary:hover {
170
+ transform: translateY(-1px);
171
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
172
+ }
173
+
174
+ .btn--style-primary:active {
175
+ transform: translateY(0);
176
+ }
177
+
178
+ /* ============================================================
179
+ Table row hover
180
+ ============================================================ */
181
+ .table tr:hover td {
182
+ background-color: var(--theme-elevation-50);
183
+ }
184
+
185
+ /* ============================================================
186
+ Status pills — rounder
187
+ ============================================================ */
188
+ .pill {
189
+ border-radius: 20px !important;
190
+ }
191
+
192
+ /* ============================================================
193
+ Dropzone — better styling
194
+ ============================================================ */
195
+ .file-field__upload.dropzone {
196
+ border-radius: var(--style-radius-l);
197
+ }
198
+
199
+ /* ============================================================
200
+ Toast notifications — rounder corners
201
+ ============================================================ */
202
+ .payload-toast-item {
203
+ border-radius: var(--style-radius-m) !important;
204
+ }
205
+
206
+ /* ============================================================
207
+ Custom scrollbars (webkit)
208
+ ============================================================ */
209
+ ::-webkit-scrollbar {
210
+ width: 8px;
211
+ height: 8px;
212
+ }
213
+
214
+ ::-webkit-scrollbar-track {
215
+ background: var(--theme-elevation-50);
216
+ }
217
+
218
+ ::-webkit-scrollbar-thumb {
219
+ background: var(--theme-elevation-250);
220
+ border-radius: 4px;
221
+ }
222
+
223
+ ::-webkit-scrollbar-thumb:hover {
224
+ background: var(--theme-elevation-350);
225
+ }
226
+
227
+ /* Firefox scrollbar */
228
+ * {
229
+ scrollbar-width: thin;
230
+ scrollbar-color: var(--theme-elevation-250) var(--theme-elevation-50);
85
231
  }