@realiizlabs/admin 0.8.0 → 0.8.2

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.
@@ -88,7 +88,13 @@ function Sidebar({ items, activeHref, basePath }) {
88
88
  };
89
89
  return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: ["rz-sidebar", collapsed && "rz-sidebar--collapsed"].filter(Boolean).join(" "), "aria-label": "Admin navigation", children: [
90
90
  /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "rz-sidebar__nav", children: items.map((item) => {
91
- const active = isActive(item, activeHref, basePath);
91
+ const active = !item.disabled && isActive(item, activeHref, basePath);
92
+ if (item.disabled) {
93
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "rz-sidebar__item rz-sidebar__item--disabled", "aria-disabled": "true", title: collapsed ? `${item.label} \u2014 coming soon` : "Coming soon", children: [
94
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: iconFor(item.icon ?? item.id) }),
95
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rz-sidebar__label", children: item.label })
96
+ ] }, item.id);
97
+ }
92
98
  return /* @__PURE__ */ jsxRuntime.jsxs(
93
99
  "a",
94
100
  {
@@ -104,21 +110,22 @@ function Sidebar({ items, activeHref, basePath }) {
104
110
  item.id
105
111
  );
106
112
  }) }),
107
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rz-sidebar__collapse", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "rz-btn rz-btn--ghost rz-btn--sm", onClick: toggle, "aria-label": collapsed ? "Expand navigation" : "Collapse navigation", children: collapsed ? "\xBB" : "\xAB Collapse" }) })
113
+ /* @__PURE__ */ jsxRuntime.jsxs(
114
+ "button",
115
+ {
116
+ type: "button",
117
+ className: "rz-sidebar__collapse",
118
+ onClick: toggle,
119
+ "aria-label": collapsed ? "Expand navigation" : "Collapse navigation",
120
+ title: collapsed ? "Expand" : "Collapse",
121
+ children: [
122
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", style: { transform: collapsed ? "rotate(180deg)" : void 0 }, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 6l-6 6 6 6" }) }),
123
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rz-sidebar__label", children: "Collapse" })
124
+ ]
125
+ }
126
+ )
108
127
  ] });
109
128
  }
110
- function buttonClass(variant = "secondary", size = "md", extra) {
111
- return ["rz-btn", `rz-btn--${variant}`, `rz-btn--${size}`, extra].filter(Boolean).join(" ");
112
- }
113
- function buttonStyle(variant = "secondary", size = "md") {
114
- return { className: buttonClass(variant, size) };
115
- }
116
- function Button({ variant = "secondary", size = "md", className, type = "button", ...rest }) {
117
- return /* @__PURE__ */ jsxRuntime.jsx("button", { type, className: buttonClass(variant, size, className), ...rest });
118
- }
119
- function LinkButton({ variant = "secondary", size = "md", className, ...rest }) {
120
- return /* @__PURE__ */ jsxRuntime.jsx("a", { className: buttonClass(variant, size, className), ...rest });
121
- }
122
129
  var THEME_KEY = "rz-admin-theme";
123
130
  function useTheme(defaultTheme = "light") {
124
131
  const [theme, setTheme] = react.useState(defaultTheme);
@@ -156,6 +163,17 @@ function initialsOf(user) {
156
163
  if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
157
164
  return (user.email[0] ?? "?").toUpperCase();
158
165
  }
166
+ var ico = { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true };
167
+ var ShieldIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { ...ico, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 3l7 3v5c0 5-3.5 8.5-7 10-3.5-1.5-7-5-7-10V6z" }) });
168
+ var SunIcon = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...ico, children: [
169
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "4" }),
170
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" })
171
+ ] });
172
+ var OutIcon = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...ico, children: [
173
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
174
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 17l5-5-5-5" }),
175
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12H9" })
176
+ ] });
159
177
  function AccountMenu({ user, role, theme, onTheme, signOutPath }) {
160
178
  const [open, setOpen] = react.useState(false);
161
179
  const wrap = react.useRef(null);
@@ -175,46 +193,36 @@ function AccountMenu({ user, role, theme, onTheme, signOutPath }) {
175
193
  };
176
194
  }, [open]);
177
195
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: wrap, style: { position: "relative" }, children: [
178
- /* @__PURE__ */ jsxRuntime.jsx(
179
- "button",
180
- {
181
- type: "button",
182
- className: "rz-avatar",
183
- "aria-haspopup": "menu",
184
- "aria-expanded": open,
185
- "aria-label": "Account menu",
186
- onClick: () => setOpen((v) => !v),
187
- children: initialsOf(user)
188
- }
189
- ),
196
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "rz-avatar", "aria-haspopup": "menu", "aria-expanded": open, "aria-label": "Account menu", onClick: () => setOpen((v) => !v), children: initialsOf(user) }),
190
197
  open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rz-menu", role: "menu", children: [
191
198
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rz-menu__who", children: [
192
199
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rz-menu__name", children: user.name?.trim() || user.email }),
193
200
  user.name?.trim() && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rz-menu__email", children: user.email })
194
201
  ] }),
195
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rz-menu__row", children: [
202
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rz-menu__item rz-menu__item--static", role: "menuitem", "aria-disabled": "true", children: [
203
+ /* @__PURE__ */ jsxRuntime.jsx(ShieldIcon, {}),
196
204
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Role" }),
197
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rz-pill rz-pill--plain", children: role })
205
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rz-menu__end rz-pill rz-pill--plain", children: role })
198
206
  ] }),
199
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rz-menu__sep" }),
200
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rz-menu__row", children: [
207
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rz-menu__item rz-menu__item--static", role: "menuitem", "aria-disabled": "true", children: [
208
+ /* @__PURE__ */ jsxRuntime.jsx(SunIcon, {}),
201
209
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Theme" }),
202
- /* @__PURE__ */ jsxRuntime.jsx(ThemeToggle, { theme, onChange: onTheme })
210
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rz-menu__end", children: /* @__PURE__ */ jsxRuntime.jsx(ThemeToggle, { theme, onChange: onTheme }) })
203
211
  ] }),
204
212
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rz-menu__sep" }),
205
- /* @__PURE__ */ jsxRuntime.jsx("form", { method: "post", action: signOutPath, className: "rz-menu__signout", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: buttonClass("ghost", "sm"), children: "Sign out" }) })
213
+ /* @__PURE__ */ jsxRuntime.jsx("form", { method: "post", action: signOutPath, className: "rz-menu__signout", children: /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "submit", role: "menuitem", className: "rz-menu__item", children: [
214
+ /* @__PURE__ */ jsxRuntime.jsx(OutIcon, {}),
215
+ "Sign out"
216
+ ] }) })
206
217
  ] })
207
218
  ] });
208
219
  }
209
- function TopBar({ siteName, logoUrl, homeHref, user, role, theme, onTheme, signOutPath }) {
220
+ function TopBar({ siteName, productName, logoUrl, homeHref, user, role, theme, onTheme, signOutPath }) {
210
221
  return /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "rz-topbar", children: [
211
222
  /* @__PURE__ */ jsxRuntime.jsxs("a", { href: homeHref, className: "rz-topbar__brand", children: [
212
- logoUrl && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
213
- /* @__PURE__ */ jsxRuntime.jsx("img", { src: logoUrl, alt: "", className: "rz-topbar__logo" }),
214
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rz-topbar__divider", "aria-hidden": "true" })
215
- ] }),
223
+ logoUrl && /* @__PURE__ */ jsxRuntime.jsx("img", { src: logoUrl, alt: "", className: "rz-topbar__logo" }),
216
224
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: siteName }),
217
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rz-muted", style: { fontWeight: 400 }, children: "\xB7 Admin" })
225
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rz-topbar__product", children: productName })
218
226
  ] }),
219
227
  user && role && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rz-topbar__right", children: [
220
228
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "rz-topbar__greeting", "data-testid": "rz-greeting", children: [
@@ -229,22 +237,24 @@ function TopBar({ siteName, logoUrl, homeHref, user, role, theme, onTheme, signO
229
237
  // src/shell/tokens.ts
230
238
  var SHELL_CSS = `
231
239
  .rz-admin, .rz-admin[data-theme="light"] {
232
- --ink: #1a1916; --bone: #f5f0e8; --signal: #166534;
233
- --surface-0: #faf7f2; --surface-1: #f5f0e8; --surface-2: #ede8de; --surface-3: #e2dbd0;
234
- --text-primary: #1a1916; --text-secondary: #4a4640; --text-muted: #8a8480;
235
- --signal-dim: #15803d; --signal-glow: #14532d; --signal-warn: #d97706; --series-blue: #2563eb;
236
- --border: #e2dbd0; --separator: #ede8de;
237
- --status-up: var(--signal); --status-down: #dc2626; --status-neutral: var(--text-muted); --status-blocked: var(--border);
240
+ /* realiiz.com palette (src/app/globals.css): ink, bone, paper, signal blue, slate, line, amber */
241
+ --ink: #0e1726; --bone: #f7f5f0; --signal: #1f6feb;
242
+ --surface-0: #f7f5f0; --surface-1: #ffffff; --surface-2: #f1eee7; --surface-3: #e8e4da;
243
+ --text-primary: #0e1726; --text-secondary: #5b6678; --text-muted: #8a93a5;
244
+ --signal-dim: #1a63d8; --signal-glow: #5b9bff; --signal-warn: #e0a03b; --series-blue: #1f6feb;
245
+ --border: #d9d4c8; --separator: #e9e5dc;
246
+ --status-up: #15803d; --status-down: #dc2626; --status-neutral: var(--text-muted); --status-blocked: var(--border);
238
247
  --signal-fg: #ffffff;
239
248
  }
249
+ .rz-admin[data-theme="dark"] { color-scheme: dark; }
240
250
  .rz-admin[data-theme="dark"] {
241
- --ink: #e8e4d9; --bone: #1a1a18; --signal: #4ade80;
242
- --surface-0: #111110; --surface-1: #1a1a18; --surface-2: #252522; --surface-3: #2e2e2a;
243
- --text-primary: #e8e4d9; --text-secondary: #a8a49a; --text-muted: #6b6762;
244
- --signal-dim: #22c55e; --signal-glow: #86efac; --signal-warn: #f59e0b; --series-blue: #3b82f6;
245
- --border: #2e2e2a; --separator: #252522;
246
- --status-up: var(--signal); --status-down: #f87171; --status-neutral: var(--text-muted); --status-blocked: var(--border);
247
- --signal-fg: #111110;
251
+ --ink: #eef0f5; --bone: #1b2334; --signal: #3b82f6;
252
+ --surface-0: #1b2334; --surface-1: #222c42; --surface-2: #29344a; --surface-3: #36415c;
253
+ --text-primary: #eef0f5; --text-secondary: #a2abbf; --text-muted: #77819a;
254
+ --signal-dim: #8db4ff; --signal-glow: #aec9ff; --signal-warn: #eab058; --series-blue: #3b82f6;
255
+ --border: #36415c; --separator: #2c3750;
256
+ --status-up: #4ade80; --status-down: #f87171; --status-neutral: var(--text-muted); --status-blocked: var(--border);
257
+ --signal-fg: #ffffff;
248
258
  }
249
259
  .rz-admin {
250
260
  --rz-font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
@@ -268,37 +278,59 @@ var SHELL_CSS = `
268
278
  .rz-admin a { color: inherit; }
269
279
  .rz-admin h1, .rz-admin h2, .rz-admin h3 { font-family: var(--rz-font-display); color: var(--text-primary); margin: 0; }
270
280
  .rz-admin .realiiz-form__control { background: var(--surface-0); }
281
+ .rz-admin[data-theme="dark"] .realiiz-form__control::-webkit-calendar-picker-indicator { filter: invert(1) opacity(.7); }
282
+ .rz-admin .realiiz-form__button { background: var(--surface-1); color: var(--text-primary); }
283
+ .rz-admin .realiiz-form__button--primary { background: var(--signal); color: var(--signal-fg); }
271
284
 
272
285
  /* ---- frame ---------------------------------------------------------- */
273
286
  .rz-topbar { height: var(--rz-topbar); display: flex; align-items: center; gap: 1rem; padding: 0 1.25rem; border-bottom: 1px solid var(--border); background: var(--surface-1); flex-shrink: 0; }
274
287
  .rz-topbar__brand { display: flex; align-items: center; gap: .6rem; font-weight: 600; font-size: .9375rem; text-decoration: none; }
275
288
  .rz-topbar__logo { height: 22px; width: auto; display: block; }
276
- .rz-topbar__divider { width: 1px; height: 18px; background: var(--border); }
289
+ .rz-topbar__product { font-weight: 400; color: var(--text-secondary); }
277
290
  .rz-topbar__right { margin-left: auto; display: flex; align-items: center; gap: 1rem; }
278
291
  .rz-topbar__greeting { color: var(--text-secondary); font-size: .8rem; }
279
292
  .rz-body { display: flex; flex: 1; min-height: 0; }
280
- .rz-sidebar { width: var(--rz-sidebar); flex-shrink: 0; border-right: 1px solid var(--border); background: var(--surface-1); display: flex; flex-direction: column; transition: width .15s ease; }
293
+ /* Top bar and sidebar stay put while the content scrolls, so Collapse is always at the bottom-left. */
294
+ .rz-topbar { position: sticky; top: 0; z-index: 20; }
295
+ .rz-sidebar { position: sticky; top: var(--rz-topbar); height: calc(100vh - var(--rz-topbar)); width: var(--rz-sidebar); flex-shrink: 0; border-right: 1px solid var(--border); background: var(--surface-1); display: flex; flex-direction: column; transition: width .15s ease; overflow: hidden; }
281
296
  .rz-sidebar--collapsed { width: var(--rz-sidebar-collapsed); }
282
297
  .rz-sidebar__nav { padding: .75rem 0; flex: 1; overflow-y: auto; }
283
- .rz-sidebar__item { display: flex; align-items: center; gap: .65rem; padding: .5rem .9rem; margin: 1px .5rem; border-radius: var(--rz-radius); color: var(--text-secondary); text-decoration: none; font-size: .8125rem; border-left: 2px solid transparent; white-space: nowrap; overflow: hidden; }
298
+ .rz-sidebar__item { display: flex; align-items: center; gap: .65rem; padding: .55rem 1rem; color: var(--text-secondary); text-decoration: none; font-size: .875rem; font-weight: 400; white-space: nowrap; overflow: hidden; }
284
299
  .rz-sidebar__item:hover { background: var(--surface-2); color: var(--text-primary); }
285
- .rz-sidebar__item--active { background: var(--surface-2); color: var(--text-primary); border-left-color: var(--signal); }
300
+ .rz-sidebar__item--active { background: var(--surface-2); color: var(--signal); font-weight: 500; }
301
+ .rz-sidebar__item--disabled, .rz-sidebar__item--disabled:hover { color: var(--text-muted); opacity: .55; background: transparent; cursor: default; }
302
+ .rz-sidebar--collapsed .rz-sidebar__item { justify-content: center; padding: .55rem 0; }
286
303
  .rz-sidebar--collapsed .rz-sidebar__label { display: none; }
287
- .rz-sidebar__collapse { border-top: 1px solid var(--separator); padding: .3rem .5rem; }
288
- .rz-sidebar__collapse button { width: 100%; }
289
- .rz-main { flex: 1; min-width: 0; overflow-x: hidden; }
290
- .rz-content { max-width: 960px; margin: 0 auto; padding: 28px 28px 80px; }
304
+ .rz-sidebar__collapse { display: flex; align-items: center; gap: .7rem; padding: .6rem 1rem; border: 0; border-top: 1px solid var(--separator); background: transparent; color: var(--text-muted); cursor: pointer; font: inherit; font-size: .8rem; text-align: left; }
305
+ .rz-sidebar__collapse:hover { color: var(--text-primary); }
306
+ .rz-sidebar__collapse svg { flex-shrink: 0; }
307
+ .rz-sidebar--collapsed .rz-sidebar__collapse { justify-content: center; padding: .6rem 0; }
308
+ .rz-main { flex: 1; min-width: 0; }
309
+ .rz-content { max-width: 1400px; margin: 0; padding: 28px 32px 80px; }
310
+ .rz-content .realiiz-form { max-width: none; }
311
+ .rz-content .realiiz-form fieldset, .rz-content .realiiz-form__alert, .rz-content .realiiz-form__actions { max-width: 920px; }
312
+ /* The form's save bar pins to the bottom of the content column: bleed out over .rz-content's padding, then pad back in. */
313
+ .rz-content .realiiz-form__bar { position: sticky; bottom: 0; z-index: 10; margin: 24px -32px -80px; padding: 12px 32px; background: var(--surface-1); border-top: 1px solid var(--border); box-shadow: 0 -6px 16px rgba(14,23,38,.05); }
314
+ .rz-content .realiiz-form__status { color: var(--text-muted); }
315
+ .rz-content .realiiz-form__bar[data-dirty] .realiiz-form__status { color: var(--text-primary); font-weight: 500; }
291
316
 
292
317
  /* ---- primitives ----------------------------------------------------- */
293
- .rz-btn { font-family: inherit; font-weight: 500; border-radius: var(--rz-radius); cursor: pointer; text-decoration: none; display: inline-flex; align-items: center; justify-content: center; gap: .4rem; white-space: nowrap; line-height: 1.2; }
294
- .rz-btn--md { padding: .45rem 1rem; font-size: .8125rem; }
295
- .rz-btn--sm { padding: .3rem .7rem; font-size: .75rem; }
296
- .rz-btn--primary { background: var(--signal); color: var(--signal-fg); border: 1px solid transparent; }
297
- .rz-btn--secondary { background: var(--surface-3); color: var(--text-secondary); border: 1px solid var(--border); }
298
- .rz-btn--danger { background: transparent; color: var(--status-down); border: 1px solid var(--status-down); }
299
- .rz-btn--ghost { background: transparent; color: var(--text-secondary); border: 1px solid var(--border); }
300
- .rz-btn:disabled { opacity: .55; cursor: default; }
318
+ /* Same metrics as the form's Save button (.realiiz-form__button) so every button in the admin matches. */
319
+ .rz-btn { font-family: inherit; font-weight: 600; border-radius: var(--rz-radius); cursor: pointer; text-decoration: none; display: inline-flex; align-items: center; justify-content: center; gap: .4rem; white-space: nowrap; line-height: 1.2; }
320
+ .rz-btn--md { padding: 10px 16px; font-size: 15px; min-height: 40px; }
321
+ .rz-btn--sm { padding: 6px 12px; font-size: 13px; min-height: 32px; }
322
+ .rz-admin .rz-btn--primary, .rz-admin a.rz-btn--primary { background: var(--signal); color: var(--signal-fg); border: 1px solid var(--signal); }
323
+ .rz-admin .rz-btn--secondary, .rz-admin a.rz-btn--secondary { background: var(--surface-1); color: var(--text-primary); border: 1px solid var(--border); }
324
+ .rz-admin .rz-btn--danger, .rz-admin a.rz-btn--danger { background: transparent; color: var(--status-down); border: 1px solid var(--status-down); }
325
+ .rz-admin .rz-btn--ghost, .rz-admin a.rz-btn--ghost { background: var(--surface-1); color: var(--text-primary); border: 1px solid var(--border); }
326
+ .rz-admin .rz-btn:disabled { opacity: .55; cursor: default; }
327
+ .rz-arrow { width: 1.1em; height: 1.1em; flex-shrink: 0; transition: transform .15s ease-out; }
328
+ @media (prefers-reduced-motion: no-preference) {
329
+ .rz-btn:hover .rz-arrow, a:hover .rz-arrow { transform: translate(2px, -2px); }
330
+ .rz-btn:hover .rz-arrow--fwd, a:hover .rz-arrow--fwd { transform: translateX(4px); }
331
+ }
301
332
  .rz-card { background: var(--surface-1); border: 1px solid var(--border); border-radius: 8px; padding: 18px 20px; }
333
+ .rz-card--narrow { max-width: 760px; }
302
334
  .rz-card__title { font-size: .9375rem; font-weight: 600; margin-bottom: .35rem; }
303
335
  .rz-card__meta { color: var(--text-muted); font-size: .8rem; }
304
336
  .rz-card__actions { display: flex; gap: .5rem; margin-top: .9rem; flex-wrap: wrap; }
@@ -307,12 +339,44 @@ var SHELL_CSS = `
307
339
  .rz-pagehead__eyebrow { font-family: var(--rz-font-mono); font-size: .6875rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-muted); margin-bottom: .3rem; }
308
340
  .rz-pagehead h1 { font-size: 1.375rem; font-weight: 600; }
309
341
  .rz-pagehead__sub { color: var(--text-secondary); font-size: .85rem; margin-top: .25rem; }
310
- .rz-pill { display: inline-flex; align-items: center; gap: .4rem; font-family: var(--rz-font-mono); font-size: .6875rem; text-transform: uppercase; letter-spacing: .06em; padding: .15rem .5rem; border: 1px solid var(--border); border-radius: 999px; color: var(--text-secondary); }
342
+ .rz-pill { display: inline-flex; align-items: center; gap: .4rem; white-space: nowrap; font-family: var(--rz-font-mono); font-size: .6875rem; text-transform: uppercase; letter-spacing: .06em; padding: .15rem .5rem; border: 1px solid var(--border); border-radius: 999px; color: var(--text-secondary); }
311
343
  .rz-pill::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--status-neutral); }
312
344
  .rz-pill--up::before { background: var(--status-up); } .rz-pill--warn::before { background: var(--signal-warn); } .rz-pill--down::before { background: var(--status-down); }
313
345
  .rz-pill--plain::before { display: none; }
346
+ /* ---- steps tracker ------------------------------------------------- */
347
+ /* Dots on one rail, connectors dot-to-dot, label under each dot; left-aligned like the rest of the page. */
348
+ .rz-steps { list-style: none; margin: 4px 0 22px; padding: 0 0 22px; display: flex; border-bottom: 1px solid var(--separator); }
349
+ .rz-step { flex: 1; position: relative; display: flex; flex-direction: column; align-items: flex-start; text-align: left; gap: 8px; min-width: 0; }
350
+ .rz-step:last-child { flex: 0 0 auto; }
351
+ .rz-step:not(:last-child)::after { content: ""; position: absolute; top: 12px; left: 26px; right: 0; height: 2px; background: var(--border); }
352
+ .rz-step--done:not(:last-child)::after { background: var(--status-up); }
353
+ .rz-step__dot { width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: .75rem; font-weight: 600; flex-shrink: 0; border: 2px solid var(--border); color: var(--text-muted); background: var(--surface-1); }
354
+ .rz-step--done .rz-step__dot { background: var(--status-up); border-color: var(--status-up); color: #fff; }
355
+ .rz-step--active .rz-step__dot { position: relative; border-color: color-mix(in srgb, var(--signal) 30%, transparent); color: var(--signal); }
356
+ /* A spinning arc over the ring: the step is working, not waiting on you. */
357
+ .rz-step--active .rz-step__dot::after { content: ""; position: absolute; inset: -2px; border-radius: 50%; border: 2px solid transparent; border-top-color: var(--signal); animation: rz-spin .9s linear infinite; }
358
+ @media (prefers-reduced-motion: reduce) { .rz-step--active .rz-step__dot::after { animation: none; border-color: var(--signal); } }
359
+ @keyframes rz-spin { to { transform: rotate(360deg); } }
360
+ .rz-step--failed .rz-step__dot { background: var(--status-down); border-color: var(--status-down); color: #fff; }
361
+ .rz-step__text { display: flex; flex-direction: column; gap: 1px; padding-right: 16px; }
362
+ .rz-step__label { font-size: .875rem; font-weight: 500; color: var(--text-secondary); }
363
+ .rz-step--active .rz-step__label, .rz-step--done .rz-step__label { color: var(--text-primary); }
364
+ .rz-step--failed .rz-step__label { color: var(--status-down); }
365
+ .rz-step__note { font-size: .75rem; color: var(--text-muted); }
366
+ @keyframes rz-pulse { 0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--signal) 18%, transparent); } 50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--signal) 8%, transparent); } }
367
+ .rz-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 20px; }
368
+ .rz-actions__hint { font-size: .8rem; color: var(--text-muted); }
369
+ .rz-notice { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 16px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface-1); margin-bottom: 18px; font-size: .9rem; }
370
+ .rz-notice__text { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
371
+ .rz-status-link { text-decoration: none; }
372
+ .rz-discard { margin-top: 22px; padding-top: 14px; border-top: 1px solid var(--separator); display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: .85rem; color: var(--text-secondary); }
373
+ .rz-discard__link { background: none; border: 0; padding: 0; font: inherit; font-size: .85rem; color: var(--text-muted); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
374
+ .rz-discard__link:hover { color: var(--status-down); }
375
+ .rz-nowrap { white-space: nowrap; }
376
+ .rz-table td.rz-fit, .rz-table th.rz-fit { width: 1%; white-space: nowrap; }
314
377
  .rz-empty { border: 1px dashed var(--border); border-radius: 8px; padding: 32px; text-align: center; color: var(--text-secondary); }
315
378
  .rz-empty h3 { font-size: 1rem; margin-bottom: .4rem; }
379
+ .rz-table-wrap { width: 100%; }
316
380
  .rz-table { width: 100%; border-collapse: collapse; background: var(--surface-1); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
317
381
  .rz-table th, .rz-table td { text-align: left; padding: 10px 14px; border-bottom: 1px solid var(--separator); font-size: .875rem; vertical-align: top; }
318
382
  .rz-table th { font-family: var(--rz-font-mono); font-size: .6875rem; text-transform: uppercase; letter-spacing: .06em; color: var(--text-muted); background: var(--surface-2); }
@@ -323,16 +387,20 @@ var SHELL_CSS = `
323
387
 
324
388
  /* ---- account menu --------------------------------------------------- */
325
389
  .rz-avatar { width: 2rem; height: 2rem; border-radius: 50%; background: var(--surface-3); border: 1px solid var(--border); color: var(--text-primary); font-size: .6875rem; font-weight: 600; letter-spacing: .04em; display: flex; align-items: center; justify-content: center; cursor: pointer; font-family: inherit; padding: 0; }
326
- .rz-menu { position: absolute; right: 0; top: calc(100% + 8px); min-width: 240px; background: var(--surface-1); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 10px 30px rgba(0,0,0,.12); padding: 6px; z-index: 50; }
327
- .rz-menu__who { padding: 10px 10px 8px; }
390
+ .rz-menu { position: absolute; right: 0; top: calc(100% + 8px); min-width: 15rem; background: var(--surface-1); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 24px rgba(14,23,38,.14); overflow: hidden; z-index: 50; }
391
+ .rz-menu__who { padding: .75rem .9rem; border-bottom: 1px solid var(--border); margin-bottom: .3rem; }
328
392
  .rz-menu__name { font-weight: 600; font-size: .875rem; }
329
393
  .rz-menu__email { color: var(--text-muted); font-size: .75rem; word-break: break-all; }
330
- .rz-menu__sep { height: 1px; background: var(--separator); margin: 4px 0; }
331
- .rz-menu__row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 10px; font-size: .8125rem; color: var(--text-secondary); }
332
- .rz-menu__signout { padding: 6px; }
333
- .rz-menu__signout .rz-btn { width: 100%; }
394
+ .rz-menu__sep { height: 1px; background: var(--border); margin: .3rem 0; }
395
+ .rz-menu__item { display: flex; align-items: center; gap: .55rem; width: 100%; padding: .45rem .9rem; font: inherit; font-size: .8125rem; color: var(--text-secondary); background: none; border: 0; text-align: left; cursor: pointer; text-decoration: none; }
396
+ .rz-menu__item:hover { background: var(--surface-2); color: var(--text-primary); }
397
+ .rz-menu__item svg { flex-shrink: 0; }
398
+ .rz-menu__item--static { cursor: default; }
399
+ .rz-menu__item--static:hover { background: none; color: var(--text-secondary); }
400
+ .rz-menu__item .rz-menu__end { margin-left: auto; }
401
+ .rz-menu__signout { margin: 0 0 .3rem; }
334
402
  .rz-seg { display: inline-flex; border: 1px solid var(--border); border-radius: var(--rz-radius); overflow: hidden; }
335
- .rz-seg button { font: inherit; font-size: .75rem; padding: .25rem .6rem; background: transparent; color: var(--text-secondary); border: 0; cursor: pointer; }
403
+ .rz-seg button { font: inherit; font-size: .75rem; padding: .15rem .55rem; line-height: 1.3; background: transparent; color: var(--text-secondary); border: 0; cursor: pointer; }
336
404
  .rz-seg button[aria-pressed="true"] { background: var(--surface-3); color: var(--text-primary); }
337
405
 
338
406
  /* ---- mobile: sidebar becomes a strip under the top bar --------------- */
@@ -340,16 +408,77 @@ var SHELL_CSS = `
340
408
  .rz-body { flex-direction: column; }
341
409
  .rz-sidebar, .rz-sidebar--collapsed { width: 100%; border-right: 0; border-bottom: 1px solid var(--border); flex-direction: row; }
342
410
  .rz-sidebar__nav { display: flex; padding: .35rem .25rem; overflow-x: auto; }
343
- .rz-sidebar__item { flex-direction: column; gap: .2rem; font-size: .6875rem; padding: .4rem .6rem; border-left: 0; border-bottom: 2px solid transparent; }
344
- .rz-sidebar__item--active { border-bottom-color: var(--signal); }
411
+ .rz-sidebar__item { flex-direction: column; gap: .2rem; font-size: .6875rem; padding: .4rem .6rem; border-radius: 6px; }
345
412
  .rz-sidebar--collapsed .rz-sidebar__label { display: block; }
346
413
  .rz-sidebar__collapse { display: none; }
347
414
  .rz-topbar__greeting { display: none; }
348
415
  .rz-content { padding: 18px 14px 60px; }
416
+ /* The sidebar is a top strip now, so it must not be sticky-height; the topbar stays pinned. */
417
+ .rz-sidebar, .rz-sidebar--collapsed { position: static; height: auto; }
418
+ .rz-sidebar__item--disabled { display: none; }
419
+ /* Save bar: bleed matches the narrower content padding; stack status above the buttons. */
420
+ .rz-content .realiiz-form__bar { margin: 18px -14px -60px; padding: 10px 14px; flex-wrap: wrap; }
421
+ .rz-content .realiiz-form__status { flex-basis: 100%; margin-right: 0; font-size: .8rem; }
422
+ /* Editor toolbar wraps; the Insert group drops its label and left rule to save width. */
423
+ .rz-admin .realiiz-md__head { padding: 5px; }
424
+ .rz-admin .realiiz-md__insert { border-left: 0; padding-left: 0; margin-left: 0; }
425
+ .rz-admin .realiiz-md__lab { display: none; }
426
+ .rz-admin .realiiz-md--fs { padding: 8px; }
427
+ /* Tracker: notes hide, labels shrink, so three steps fit a phone. */
428
+ .rz-step__note { display: none; }
429
+ .rz-step__label { font-size: .8rem; }
430
+ .rz-step:not(:last-child)::after { right: 6px; }
431
+ /* Tables scroll sideways inside their own box instead of stretching the page. */
432
+ .rz-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
433
+ .rz-pagehead { align-items: flex-start; flex-direction: column; }
434
+ .rz-notice { flex-direction: column; align-items: flex-start; }
435
+ .rz-card--narrow { max-width: none; }
349
436
  }
437
+
438
+ /* ---- forms extras: markdown editor, chips, gauges, preview prose --------- */
439
+ .rz-admin .realiiz-md { --_md-head: var(--surface-2); --_md-hover: var(--surface-2); --_md-hover-line: var(--signal-glow); --_md-on: color-mix(in srgb, var(--signal) 12%, var(--surface-1)); --_md-tip: var(--ink); }
440
+ .rz-admin .realiiz-md__mode { background: var(--surface-2); }
441
+ .rz-admin .realiiz-md__mode button { color: var(--text-secondary); }
442
+ .rz-admin .realiiz-md__mode button[aria-selected="true"] { background: var(--surface-1); color: var(--text-primary); box-shadow: 0 1px 2px rgba(14,23,38,.12); }
443
+ .rz-admin .realiiz-md__panel, .rz-admin .realiiz-md__tgrid, .rz-admin .realiiz-md--fs, .rz-admin .realiiz-md .realiiz-md__ta, .rz-admin .realiiz-md__preview, .rz-admin .realiiz-md__head button { background: var(--surface-1); }
444
+ .rz-admin .realiiz-md__head { background: var(--surface-2); }
445
+ .rz-admin .realiiz-md__head button { color: var(--text-primary); }
446
+ .rz-admin .realiiz-md__insert button { background: var(--surface-2); color: var(--text-secondary); }
447
+ .rz-admin .realiiz-md__tgcells i { background: var(--surface-1); }
448
+ .rz-admin .realiiz-md__tgcells i.hot { background: color-mix(in srgb, var(--signal) 18%, var(--surface-1)); }
449
+ .rz-admin .realiiz-md__loading { color: var(--text-muted); font-size: .8rem; }
450
+ .rz-admin .realiiz-prose { max-width: 68ch; font-size: 1rem; line-height: 1.65; color: var(--text-primary); }
451
+ .rz-admin .realiiz-prose h1, .rz-admin .realiiz-prose h2, .rz-admin .realiiz-prose h3 { font-family: var(--rz-font-display); line-height: 1.25; margin: 1.4em 0 .5em; }
452
+ .rz-admin .realiiz-prose h2 { font-size: 1.35rem; } .rz-admin .realiiz-prose h3 { font-size: 1.1rem; }
453
+ .rz-admin .realiiz-prose p, .rz-admin .realiiz-prose ul, .rz-admin .realiiz-prose ol, .rz-admin .realiiz-prose blockquote { margin: 0 0 1em; }
454
+ .rz-admin .realiiz-prose a { color: var(--signal); }
455
+ /* The site's prose class picks a slate body colour for a light page; on the dark surface that reads as disabled. */
456
+ .rz-admin[data-theme="dark"] .realiiz-prose, .rz-admin[data-theme="dark"] .realiiz-prose :is(p, li, td, th, dd, dt, figcaption, strong, b, em, i, h1, h2, h3, h4, h5, h6) { color: var(--text-primary); }
457
+ .rz-admin[data-theme="dark"] .realiiz-prose :is(code, kbd) { color: var(--text-primary); background: var(--surface-3); }
458
+ .rz-admin[data-theme="dark"] .realiiz-prose a { color: var(--signal-dim); }
459
+ .rz-admin[data-theme="dark"] .realiiz-prose hr { border-color: var(--border); }
460
+ .rz-admin[data-theme="dark"] .realiiz-prose blockquote { color: var(--text-secondary); }
461
+ .rz-admin .realiiz-prose blockquote { border-left: 3px solid var(--border); padding-left: 1em; color: var(--text-secondary); }
462
+ .rz-admin .realiiz-prose code { background: var(--surface-2); padding: 0 4px; border-radius: 4px; font-family: var(--rz-font-mono); font-size: .9em; }
463
+ .rz-admin .realiiz-prose pre { background: var(--surface-2); padding: 12px 14px; border-radius: 6px; overflow-x: auto; }
464
+ .rz-admin .realiiz-prose img { max-width: 100%; height: auto; border-radius: 6px; }
465
+ .rz-admin .realiiz-chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; min-height: 40px; padding: 5px 8px; background: var(--surface-0); border: 1px solid var(--border); border-radius: var(--rz-radius); }
466
+ .rz-admin .realiiz-chips:focus-within { border-color: var(--signal); box-shadow: var(--realiiz-form-focus-ring); }
467
+ .rz-admin .realiiz-chip { display: inline-flex; align-items: center; gap: 4px; padding: 2px 4px 2px 9px; background: var(--surface-3); border: 1px solid var(--border); border-radius: 999px; font-size: .8rem; color: var(--text-primary); }
468
+ .rz-admin .realiiz-chip button { font: inherit; line-height: 1; width: 18px; height: 18px; border-radius: 50%; border: 0; background: transparent; color: var(--text-muted); cursor: pointer; }
469
+ .rz-admin .realiiz-chip button:hover { background: var(--status-down); color: #fff; }
470
+ .rz-admin .realiiz-chips__input { flex: 1; min-width: 120px; border: 0; background: transparent; font: inherit; color: inherit; outline: none; padding: 4px; }
471
+ .rz-admin .realiiz-chips__count { margin-left: auto; color: var(--text-muted); font-size: .75rem; font-variant-numeric: tabular-nums; }
472
+ .rz-admin .realiiz-gauge { color: var(--text-muted); }
473
+ .rz-admin .realiiz-gauge__bar { background: var(--surface-3); }
474
+ .rz-admin .realiiz-gauge__zone { background: color-mix(in srgb, var(--status-up) 28%, transparent); }
475
+ .rz-admin .realiiz-gauge__fill { background: var(--text-muted); }
476
+ .rz-admin .realiiz-gauge--ok .realiiz-gauge__fill { background: var(--status-up); } .rz-admin .realiiz-gauge--ok { color: var(--status-up); }
477
+ .rz-admin .realiiz-gauge--over .realiiz-gauge__fill { background: var(--status-down); } .rz-admin .realiiz-gauge--over { color: var(--status-down); }
350
478
  `;
351
479
  function AdminShell({
352
480
  siteName,
481
+ productName = "Studio",
353
482
  logoUrl,
354
483
  user,
355
484
  role,
@@ -368,6 +497,7 @@ function AdminShell({
368
497
  TopBar,
369
498
  {
370
499
  siteName,
500
+ productName,
371
501
  logoUrl,
372
502
  homeHref: basePath,
373
503
  user,
@@ -383,6 +513,35 @@ function AdminShell({
383
513
  ] })
384
514
  ] });
385
515
  }
516
+ function buttonClass(variant = "secondary", size = "md", extra) {
517
+ return ["rz-btn", `rz-btn--${variant}`, `rz-btn--${size}`, extra].filter(Boolean).join(" ");
518
+ }
519
+ function buttonStyle(variant = "secondary", size = "md") {
520
+ return { className: buttonClass(variant, size) };
521
+ }
522
+ function Button({ variant = "secondary", size = "md", className, type = "button", ...rest }) {
523
+ return /* @__PURE__ */ jsxRuntime.jsx("button", { type, className: buttonClass(variant, size, className), ...rest });
524
+ }
525
+ function LinkButton({ variant = "secondary", size = "md", className, external, forward, children, ...rest }) {
526
+ const extra = external ? { target: "_blank", rel: "noreferrer", ...rest } : rest;
527
+ return /* @__PURE__ */ jsxRuntime.jsxs("a", { className: buttonClass(variant, size, className), ...extra, children: [
528
+ children,
529
+ external && /* @__PURE__ */ jsxRuntime.jsx(OutboundArrow, {}),
530
+ forward && !external && /* @__PURE__ */ jsxRuntime.jsx(ForwardArrow, {})
531
+ ] });
532
+ }
533
+ function ForwardArrow() {
534
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "rz-arrow rz-arrow--fwd", children: [
535
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 12h14" }),
536
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m13 6 6 6-6 6" })
537
+ ] });
538
+ }
539
+ function OutboundArrow() {
540
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "rz-arrow", children: [
541
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 17 17 7" }),
542
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 7h10v10" })
543
+ ] });
544
+ }
386
545
  function Card({ title, meta, children, actions, className }) {
387
546
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ["rz-card", className].filter(Boolean).join(" "), children: [
388
547
  title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rz-card__title", children: title }),
@@ -411,18 +570,30 @@ function EmptyState({ title, children, action }) {
411
570
  action && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 14 }, children: action })
412
571
  ] });
413
572
  }
573
+ function Steps({ steps }) {
574
+ return /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "rz-steps", "aria-label": "Progress", children: steps.map((st, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: `rz-step rz-step--${st.state}`, "aria-current": st.state === "active" ? "step" : void 0, children: [
575
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rz-step__dot", "aria-hidden": "true", children: st.state === "done" ? "\u2713" : st.state === "failed" ? "!" : i + 1 }),
576
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "rz-step__text", children: [
577
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rz-step__label", children: st.label }),
578
+ st.note && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rz-step__note", children: st.note })
579
+ ] })
580
+ ] }, i)) });
581
+ }
414
582
 
415
583
  exports.AccountMenu = AccountMenu;
416
584
  exports.AdminShell = AdminShell;
417
585
  exports.Button = Button;
418
586
  exports.Card = Card;
419
587
  exports.EmptyState = EmptyState;
588
+ exports.ForwardArrow = ForwardArrow;
420
589
  exports.Icon = Icon;
421
590
  exports.LinkButton = LinkButton;
591
+ exports.OutboundArrow = OutboundArrow;
422
592
  exports.PageHeader = PageHeader;
423
593
  exports.SHELL_CSS = SHELL_CSS;
424
594
  exports.Sidebar = Sidebar;
425
595
  exports.StatusPill = StatusPill;
596
+ exports.Steps = Steps;
426
597
  exports.ThemeToggle = ThemeToggle;
427
598
  exports.TopBar = TopBar;
428
599
  exports.buttonClass = buttonClass;