@rozenite/vite-plugin 1.13.0 → 2.1.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 (57) hide show
  1. package/README.md +12 -0
  2. package/dist/bundle-dts.d.ts.map +1 -1
  3. package/dist/client-plugin.d.ts.map +1 -1
  4. package/dist/dev-host/assets/index-BgAxGQdD.js +13 -0
  5. package/dist/dev-host/assets/index-ClIYIppU.css +1 -0
  6. package/dist/dev-host/index.html +3 -3
  7. package/dist/dev-host/manifest.json +2 -2
  8. package/dist/index.cjs +34 -63
  9. package/dist/index.d.ts +9 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +34 -63
  12. package/dist/load-config.d.ts.map +1 -1
  13. package/dist/package-json.d.ts.map +1 -1
  14. package/dist/react-native-plugin.d.ts.map +1 -1
  15. package/dist/require-plugin.d.ts.map +1 -1
  16. package/dist/sdk-plugin.d.ts.map +1 -1
  17. package/dist/server-plugin.d.ts.map +1 -1
  18. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  19. package/dist/utils.d.ts.map +1 -1
  20. package/package.json +29 -30
  21. package/src/bundle-dts.ts +6 -14
  22. package/src/client-plugin.ts +13 -36
  23. package/src/dev-host/App.tsx +184 -414
  24. package/src/dev-host/components/DispatchForm.tsx +97 -121
  25. package/src/dev-host/components/FlowList.tsx +70 -102
  26. package/src/dev-host/components/MessageDetailsPane.tsx +50 -83
  27. package/src/dev-host/components/MessageLogPane.tsx +75 -66
  28. package/src/dev-host/components/PanelTabs.tsx +19 -10
  29. package/src/dev-host/constants.ts +0 -19
  30. package/src/dev-host/flow-runtime.ts +15 -12
  31. package/src/dev-host/index.html +1 -1
  32. package/src/dev-host/main.tsx +1 -10
  33. package/src/dev-host/styles.css +162 -830
  34. package/src/dev-host/types.ts +0 -9
  35. package/src/dev-host/utils.ts +1 -7
  36. package/src/dev-host/vite.config.mts +2 -0
  37. package/src/index.ts +16 -16
  38. package/src/load-config.ts +9 -20
  39. package/src/package-json.ts +1 -3
  40. package/src/react-native-plugin.ts +4 -2
  41. package/src/require-plugin.ts +6 -18
  42. package/src/sdk-plugin.ts +3 -0
  43. package/src/server-plugin.ts +3 -0
  44. package/src/utils.ts +1 -4
  45. package/dist/dev-host/assets/index-CkxvBMpp.css +0 -1
  46. package/dist/dev-host/assets/index-cNKHRwej.js +0 -11
  47. package/src/dev-host/components/MessagePayloadDetail.tsx +0 -32
  48. package/src/dev-host/components/ResizeHandle.tsx +0 -33
  49. package/src/dev-host/components/icons.tsx +0 -79
  50. package/src/dev-host/components/ui/Button.tsx +0 -91
  51. package/src/dev-host/components/ui/DropdownMenu.tsx +0 -84
  52. package/src/dev-host/components/ui/IconButton.tsx +0 -41
  53. package/src/dev-host/components/ui/Input.tsx +0 -73
  54. package/src/dev-host/components/ui/ScrollArea.tsx +0 -20
  55. package/src/dev-host/components/ui/Tabs.tsx +0 -166
  56. package/src/dev-host/components/ui/Textarea.tsx +0 -79
  57. package/src/dev-host/components/ui/ToggleGroup.tsx +0 -120
@@ -50,12 +50,3 @@ export type PluginMessage = {
50
50
  type: string;
51
51
  payload: unknown;
52
52
  };
53
-
54
- export type ResizeHandleId = 'devtools-height' | 'command-width' | 'details-width';
55
-
56
- export type ResizeSession = {
57
- handleId: ResizeHandleId;
58
- pointerId: number;
59
- element: HTMLElement;
60
- onMove: (event: PointerEvent) => void;
61
- };
@@ -21,10 +21,6 @@ export const formatPayloadPreview = (payload: unknown) => {
21
21
  }
22
22
  };
23
23
 
24
- export const isJsonTreeData = (value: unknown): value is Record<string, unknown> | unknown[] => {
25
- return Array.isArray(value) || (typeof value === 'object' && value !== null);
26
- };
27
-
28
24
  export const formatMessageDate = (date: string) => {
29
25
  return new Date(date).toLocaleString();
30
26
  };
@@ -71,9 +67,7 @@ export const getInitialPanel = (panels: DevHostPanelEntry[]) => {
71
67
  return panels[0] ?? null;
72
68
  };
73
69
 
74
- export const createMessageEntry = (
75
- input: Omit<MessageEntry, 'id' | 'date'>,
76
- ): MessageEntry => {
70
+ export const createMessageEntry = (input: Omit<MessageEntry, 'id' | 'date'>): MessageEntry => {
77
71
  return {
78
72
  id: crypto.randomUUID(),
79
73
  date: new Date().toISOString(),
@@ -1,5 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { fileURLToPath } from 'node:url';
3
+ import tailwindcss from '@tailwindcss/vite';
3
4
  import { defineConfig } from 'vite';
4
5
 
5
6
  const HOST_APP_ROOT = fileURLToPath(new URL('./', import.meta.url));
@@ -9,6 +10,7 @@ export default defineConfig({
9
10
  root: HOST_APP_ROOT,
10
11
  base: './',
11
12
  publicDir: false,
13
+ plugins: [tailwindcss()],
12
14
  build: {
13
15
  outDir: path.join(PACKAGE_ROOT, 'dist', 'dev-host'),
14
16
  emptyOutDir: true,
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { PluginOption } from 'vite';
2
+ import tailwindcss from '@tailwindcss/vite';
2
3
  import react from '@vitejs/plugin-react';
3
4
  import reactNativeWeb from 'vite-plugin-react-native-web';
4
5
  import path from 'node:path';
@@ -12,20 +13,12 @@ import { bundleTargetDeclarations } from './bundle-dts.js';
12
13
 
13
14
  // vite-plugin-dts exports differently in CJS and ESM
14
15
  const dtsPlugin =
15
- 'default' in maybeDtsPlugin
16
- ? (maybeDtsPlugin.default as typeof maybeDtsPlugin)
17
- : maybeDtsPlugin;
16
+ 'default' in maybeDtsPlugin ? (maybeDtsPlugin.default as typeof maybeDtsPlugin) : maybeDtsPlugin;
18
17
 
19
- const getDtsPlugin = (
20
- target: 'react-native' | 'metro' | 'sdk',
21
- ): PluginOption => {
18
+ const getDtsPlugin = (target: 'react-native' | 'metro' | 'sdk'): PluginOption => {
22
19
  const projectRoot = process.cwd();
23
20
  const entryRoot =
24
- target === 'react-native'
25
- ? 'react-native.ts'
26
- : target === 'metro'
27
- ? 'metro.ts'
28
- : 'sdk.ts';
21
+ target === 'react-native' ? 'react-native.ts' : target === 'metro' ? 'metro.ts' : 'sdk.ts';
29
22
  const distRoot = path.join(projectRoot, 'dist');
30
23
  const targetRoot = path.join(distRoot, target);
31
24
  const publicEntryPath = path.join(projectRoot, 'dist', target, 'index.d.ts');
@@ -57,10 +50,7 @@ const getDtsPlugin = (
57
50
  };
58
51
  }
59
52
 
60
- if (
61
- target === 'sdk' &&
62
- filePath === rawSdkEntryPath
63
- ) {
53
+ if (target === 'sdk' && filePath === rawSdkEntryPath) {
64
54
  return {
65
55
  // vite-plugin-dts emits the SDK root declaration at dist/sdk.d.ts.
66
56
  // Move it under dist/sdk/ before API Extractor rolls it up into the
@@ -87,7 +77,16 @@ const getDtsPlugin = (
87
77
  });
88
78
  };
89
79
 
90
- export const rozenitePlugin = (): PluginOption[] => {
80
+ export type RozenitePluginOptions = {
81
+ /**
82
+ * Configure Tailwind CSS v4 for client panels.
83
+ *
84
+ * @default true
85
+ */
86
+ tailwind?: boolean;
87
+ };
88
+
89
+ export const rozenitePlugin = ({ tailwind = true }: RozenitePluginOptions = {}): PluginOption[] => {
91
90
  const isServer = process.env.VITE_ROZENITE_TARGET === 'server';
92
91
  const isReactNative = process.env.VITE_ROZENITE_TARGET === 'react-native';
93
92
  const isSdk = process.env.VITE_ROZENITE_TARGET === 'sdk';
@@ -106,6 +105,7 @@ export const rozenitePlugin = (): PluginOption[] => {
106
105
  }
107
106
 
108
107
  return [
108
+ ...(tailwind ? [tailwindcss()] : []),
109
109
  react(),
110
110
  // @ts-expect-error: TypeScript gets confused by the dual export
111
111
  reactNativeWeb(),
@@ -66,9 +66,7 @@ export type RozeniteConfig = {
66
66
  dev?: DevConfig;
67
67
  };
68
68
 
69
- export const loadConfig = async (
70
- configPath: string
71
- ): Promise<RozeniteConfig> => {
69
+ export const loadConfig = async (configPath: string): Promise<RozeniteConfig> => {
72
70
  const absoluteConfigPath = path.resolve(process.cwd(), configPath);
73
71
 
74
72
  if (!fs.existsSync(absoluteConfigPath)) {
@@ -76,20 +74,13 @@ export const loadConfig = async (
76
74
  }
77
75
 
78
76
  try {
79
- const configContent = await fs.promises.readFile(
80
- absoluteConfigPath,
81
- 'utf-8'
82
- );
83
-
84
- const result = await transformWithEsbuild(
85
- configContent,
86
- absoluteConfigPath,
87
- {
88
- loader: 'ts',
89
- format: 'cjs',
90
- target: 'esnext',
91
- }
92
- );
77
+ const configContent = await fs.promises.readFile(absoluteConfigPath, 'utf-8');
78
+
79
+ const result = await transformWithEsbuild(configContent, absoluteConfigPath, {
80
+ loader: 'ts',
81
+ format: 'cjs',
82
+ target: 'esnext',
83
+ });
93
84
 
94
85
  const moduleExports: { default?: unknown } = {};
95
86
  const module = { exports: moduleExports };
@@ -108,9 +99,7 @@ export const loadConfig = async (
108
99
  return config as RozeniteConfig;
109
100
  } catch (error) {
110
101
  if (error instanceof Error) {
111
- throw new Error(
112
- `Failed to load configuration from ${configPath}: ${error.message}`
113
- );
102
+ throw new Error(`Failed to load configuration from ${configPath}: ${error.message}`);
114
103
  }
115
104
  throw new Error(`Failed to load configuration from ${configPath}`);
116
105
  }
@@ -7,9 +7,7 @@ export type PackageJSON = {
7
7
  version: string;
8
8
  };
9
9
 
10
- export const getPackageJSON = async (
11
- projectRoot: string
12
- ): Promise<PackageJSON> => {
10
+ export const getPackageJSON = async (projectRoot: string): Promise<PackageJSON> => {
13
11
  const packageJSONPath = path.join(projectRoot, 'package.json');
14
12
  const packageJSON = await fs.readFile(packageJSONPath, 'utf8');
15
13
  return JSON.parse(packageJSON);
@@ -8,12 +8,14 @@ export const rozeniteReactNativePlugin = (): Plugin => {
8
8
  const projectRoot = config.root ?? process.cwd();
9
9
 
10
10
  config.build ??= {};
11
+ if (process.env.ROZENITE_BUILD === '1') {
12
+ config.build.emptyOutDir = false;
13
+ }
11
14
  config.build.rollupOptions ??= {};
12
15
 
13
16
  config.build.lib = {
14
17
  entry: path.resolve(projectRoot, 'react-native.ts'),
15
- fileName: (format) =>
16
- `react-native/index.${format === 'es' ? 'js' : 'cjs'}`,
18
+ fileName: (format) => `react-native/index.${format === 'es' ? 'js' : 'cjs'}`,
17
19
  };
18
20
 
19
21
  config.build.rollupOptions.external = (id) => {
@@ -86,9 +86,7 @@ const transformRequireToChunkReferences = (
86
86
  }
87
87
 
88
88
  const outFileName = getFileName(moduleInfo.referenceId);
89
- const relPath = normalizePath(
90
- path.posix.relative('react-native', outFileName),
91
- );
89
+ const relPath = normalizePath(path.posix.relative('react-native', outFileName));
92
90
  const requirePath = relPath.startsWith('.') ? relPath : `./${relPath}`;
93
91
 
94
92
  return `require('${requirePath}')`;
@@ -143,10 +141,7 @@ export default function requirePlugin(): Plugin {
143
141
  async buildStart(options) {
144
142
  try {
145
143
  assert(Array.isArray(options.input), 'input must be an array');
146
- assert(
147
- options.input.length === 1,
148
- 'input must be an array with one entry',
149
- );
144
+ assert(options.input.length === 1, 'input must be an array with one entry');
150
145
 
151
146
  input = options.input[0];
152
147
  inputName = extractModuleName(input);
@@ -167,16 +162,11 @@ export default function requirePlugin(): Plugin {
167
162
 
168
163
  this.addWatchFile(resolved.id);
169
164
 
170
- const exportName = sanitizeChunkName(
171
- extractModuleName(resolved.id),
172
- );
165
+ const exportName = sanitizeChunkName(extractModuleName(resolved.id));
173
166
  const wrapperName = `${exportName}${REQUIRE_WRAPPER_SUFFIX}`;
174
167
  const virtualId = `${VIRTUAL_REQUIRE_PREFIX}${wrapperName}`;
175
168
 
176
- virtualModuleSources.set(
177
- virtualId,
178
- `export * from ${JSON.stringify(req)};`,
179
- );
169
+ virtualModuleSources.set(virtualId, `export * from ${JSON.stringify(req)};`);
180
170
 
181
171
  const referenceId = this.emitFile({
182
172
  type: 'chunk',
@@ -205,10 +195,8 @@ export default function requirePlugin(): Plugin {
205
195
  }
206
196
 
207
197
  return {
208
- code: transformRequireToChunkReferences(
209
- code,
210
- moduleInfoMap,
211
- (referenceId) => normalizePath(this.getFileName(referenceId)),
198
+ code: transformRequireToChunkReferences(code, moduleInfoMap, (referenceId) =>
199
+ normalizePath(this.getFileName(referenceId)),
212
200
  ),
213
201
  map: null,
214
202
  };
package/src/sdk-plugin.ts CHANGED
@@ -8,6 +8,9 @@ export const rozeniteSdkPlugin = (): Plugin => {
8
8
  const projectRoot = config.root ?? process.cwd();
9
9
 
10
10
  config.build ??= {};
11
+ if (process.env.ROZENITE_BUILD === '1') {
12
+ config.build.emptyOutDir = false;
13
+ }
11
14
  config.build.lib = {
12
15
  entry: path.resolve(projectRoot, 'sdk.ts'),
13
16
  formats: ['es' as const, 'cjs' as const],
@@ -10,6 +10,9 @@ export const rozeniteServerPlugin = (): Plugin => {
10
10
  const projectRoot = config.root ?? process.cwd();
11
11
 
12
12
  config.build ??= {};
13
+ if (process.env.ROZENITE_BUILD === '1') {
14
+ config.build.emptyOutDir = false;
15
+ }
13
16
  config.build.lib = {
14
17
  entry: path.resolve(projectRoot, 'metro.ts'),
15
18
  formats: ['es' as const, 'cjs' as const],
package/src/utils.ts CHANGED
@@ -1,10 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
- export const resolveFileWithExtensions = (
5
- directory: string,
6
- baseName: string
7
- ): string | null => {
4
+ export const resolveFileWithExtensions = (directory: string, baseName: string): string | null => {
8
5
  const extensions = ['.tsx', '.ts', '.jsx', '.js'];
9
6
 
10
7
  for (const ext of extensions) {
@@ -1 +0,0 @@
1
- :root{color-scheme:dark;font-family:Switzer Variable,Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;background:#000;color:#fff}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{overflow:hidden;background:#000}button,input,textarea,select{font:inherit}.rz-shell{display:flex;height:100dvh;flex-direction:column;overflow:hidden;background:#000}.rz-topbar{display:flex;align-items:center;justify-content:space-between;gap:16px;min-height:52px;padding:10px 14px;border-bottom:1px solid rgba(255,255,255,.08);overflow:hidden;background:#0a0a0a}.rz-topbar-brand{display:inline-flex;align-items:center;flex:0 0 auto}.rz-topbar-brand svg{display:block;width:auto;height:20px}.rz-topbar-panel-picker{display:flex;align-items:center;min-width:0;justify-content:flex-end}.rz-workspace{flex:1;min-height:0;display:grid;grid-template-rows:minmax(0,1fr) 12px minmax(180px,var(--rz-devtools-height, 288px));overflow:hidden}.rz-card{min-height:0;overflow:hidden;border-top:1px solid rgba(255,255,255,.08)}.rz-card:first-child{border-top:0}.rz-iframe{display:block;width:100%;height:100%;border:0;background:#fff}.rz-iframe[data-resizing=true]{pointer-events:none}.rz-devtools{display:grid;min-height:0;grid-template-columns:minmax(0,1fr) var(--rz-command-splitter-width, 6px) minmax(260px,var(--rz-command-width, 320px))}.rz-devtools-mobile{display:flex;min-height:0;height:100%;width:100%;overflow:hidden}.rz-log-workspace{display:grid;min-height:0;position:relative;grid-template-columns:minmax(0,1fr) var(--rz-details-splitter-width, 0px) var(--rz-details-width, 0px)}.rz-resize-handle{position:relative;cursor:row-resize;background:#0a0a0a;-webkit-user-select:none;user-select:none;touch-action:none}.rz-resize-handle:before{content:"";position:absolute;top:50%;left:50%;width:72px;height:2px;border-radius:999px;background:#fff3;transform:translate(-50%,-50%)}.rz-resize-handle:after{content:"";position:absolute;inset:0;border-top:1px solid rgba(255,255,255,.08);border-bottom:1px solid rgba(255,255,255,.08)}.rz-resize-handle[data-dragging=true]:before,.rz-resize-handle:hover:before{background:#fff}.rz-column-resize-handle{position:relative;width:6px;min-width:6px;cursor:col-resize;background:#0a0a0a;-webkit-user-select:none;user-select:none;touch-action:none}.rz-column-resize-handle:before{content:"";position:absolute;top:50%;left:50%;width:2px;height:72px;border-radius:999px;background:#fff3;transform:translate(-50%,-50%)}.rz-column-resize-handle:after{content:"";position:absolute;inset:0;border-left:1px solid rgba(255,255,255,.08);border-right:1px solid rgba(255,255,255,.08)}.rz-column-resize-handle[data-dragging=true]:before,.rz-column-resize-handle:hover:before{background:#fff}.rz-column-resize-handle[data-dragging=true]:after,.rz-column-resize-handle:hover:after{border-left-color:#ffffff14;border-right-color:#ffffff14}.rz-pane{display:flex;flex-direction:column;min-height:0;overflow:hidden}.rz-pane+.rz-pane{border-left:1px solid rgba(255,255,255,.08)}.rz-pane[data-hidden=true],.rz-column-resize-handle[data-hidden=true]{display:none}.rz-devtools-mobile-tabs{display:grid;grid-template-rows:auto minmax(0,1fr);gap:8px;min-height:0;height:100%;width:100%;padding-top:8px}.rz-devtools-mobile-toggle{display:flex;align-items:flex-start;padding:0 8px}.rz-devtools-mobile-panel{display:flex;min-height:0;width:100%;overflow:hidden}.rz-devtools-mobile-panel>.rz-pane{flex:1;width:100%}.rz-tabs-root{width:100%;min-width:0}.rz-tabs-list{display:inline-flex;min-height:26px;max-width:100%;align-items:center;gap:2px;overflow:auto hidden;border:1px solid rgba(255,255,255,.08);border-radius:4px;background:#ffffff0a;padding:2px;scrollbar-width:none}.rz-tabs-list::-webkit-scrollbar{display:none}.rz-tabs-trigger{display:inline-flex;align-items:center;justify-content:center;white-space:nowrap;border:0;border-radius:2px;background:transparent;min-height:22px;padding:3px 9px;color:#fff9;font-size:12px;font-weight:500;line-height:1.2;letter-spacing:0;transition:background-color .12s ease,color .12s ease}.rz-tabs-trigger:hover{color:#fff}.rz-tabs-trigger[data-state=active]{background:#fff;color:#000}.rz-tabs-trigger:focus-visible,.rz-input:focus-visible,.rz-textarea:focus-visible,.rz-sidebar-close:focus-visible{outline:2px solid rgba(130,50,255,.95);outline-offset:-2px}.rz-scroll-area{position:relative;height:100%;width:100%;overflow:hidden}.rz-scroll-viewport{height:100%;width:100%;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.18) transparent}.rz-scroll-viewport::-webkit-scrollbar{width:12px}.rz-scroll-viewport::-webkit-scrollbar-track{background:transparent}.rz-scroll-viewport::-webkit-scrollbar-thumb{border:3px solid transparent;border-radius:999px;background:#ffffff2e;background-clip:padding-box}.rz-message-list{min-width:100%;font-family:Geist Mono,ui-monospace,SFMono-Regular,Menlo,monospace}.rz-log-pane{display:grid;grid-template-rows:auto minmax(0,1fr);min-height:0;background:#050505}.rz-message-list-header,.rz-message-row{display:grid;grid-template-columns:40px 168px minmax(120px,180px) minmax(0,1fr);gap:0;align-items:center}.rz-message-list-header{position:sticky;top:0;z-index:1;background:#0a0a0a;color:#fff6;font-size:11px;line-height:16px;letter-spacing:.06em;text-transform:uppercase;border-bottom:1px solid rgba(255,255,255,.08)}.rz-message-header-cell,.rz-message-cell{min-width:0;padding:8px 12px}.rz-message-header-cell:first-child,.rz-message-cell:first-child{text-align:center}.rz-message-header-cell+.rz-message-header-cell,.rz-message-cell+.rz-message-cell{border-left:1px solid rgba(255,255,255,.04)}.rz-message-row{width:100%;border:0;background:transparent;color:inherit;text-align:left;padding:0;border-bottom:1px solid rgba(255,255,255,.06);cursor:pointer;transition:background-color .12s ease,box-shadow .12s ease}.rz-message-row:last-child{border-bottom:0}.rz-message-row:hover{background:#ffffff09}.rz-message-row[data-selected=true]{background:#3b82f624;box-shadow:inset 2px 0 #4da3ff}.rz-message-direction{display:flex;align-items:center;justify-content:center;color:#ffffffb3;font-size:12px;line-height:18px}.rz-message-arrow{display:inline-flex;width:16px;justify-content:center;font-size:14px;font-weight:700}.rz-message-dir-in .rz-message-arrow{color:#22c55e}.rz-message-dir-out .rz-message-arrow{color:#f59e0b}.rz-message-type{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#ffffffeb;font-size:12px;font-weight:500;line-height:18px}.rz-message-date{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#ffffff85;font-size:12px;line-height:18px}.rz-message-preview{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#ffffff85;font-size:12px;line-height:18px}.rz-sidebar{display:grid;grid-template-rows:auto minmax(0,1fr);min-height:0;background:#050505;flex-grow:1}.rz-message-detail{display:flex;flex-direction:column;gap:16px;padding:16px;min-height:100%}.rz-sidebar-header{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:53px;padding:12px 16px;border-bottom:1px solid rgba(255,255,255,.08);background:#ffffff05}.rz-sidebar-scroll{min-height:0}.rz-sidebar-scroll>.rz-scroll-viewport>*{min-height:100%}.rz-sidebar-title{color:#ffffffe0;font-size:12px;font-weight:600;line-height:18px;letter-spacing:.04em;text-transform:uppercase;font-family:Geist Mono,ui-monospace,SFMono-Regular,Menlo,monospace}.rz-header-actions{display:flex;align-items:center;gap:8px}.rz-sidebar-close{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:0;border-radius:4px;background:transparent;color:#ffffff8f;cursor:pointer}.rz-sidebar-close:hover{background:#ffffff0f;color:#fff}.rz-sidebar-close:disabled{cursor:default;opacity:.4}.rz-sidebar-close:disabled:hover{background:transparent;color:#ffffff8f}.rz-sidebar-action-primary{background:#fff;color:#000}.rz-sidebar-action-primary:hover{background:#ffffffe0;color:#000}.rz-sidebar-action-primary:disabled:hover{background:#fff;color:#000}.rz-detail-section{display:grid;align-content:start;gap:8px;min-width:0}.rz-detail-value{min-width:0;border:1px solid rgba(255,255,255,.08);border-radius:4px;background:#ffffff08;padding:10px 12px;color:#ffffffe6;font-size:13px;line-height:1.5;letter-spacing:-.02em}.rz-detail-mono{font-family:Geist Mono,ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.5}.rz-detail-payload{display:flex;border:1px solid rgba(255,255,255,.08);border-radius:4px;background:#ffffff08;padding:12px}.rz-detail-pre{margin:0;white-space:pre-wrap;word-break:break-word}.rz-detail-json-tree{font-family:Geist Mono,ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.5}.rz-detail-json-tree ul,.rz-detail-json-tree li,.rz-detail-json-tree label,.rz-detail-json-tree span{font-size:inherit}.rz-command-form{display:flex;flex-direction:column;gap:12px;padding:16px;min-height:100%}.rz-action-tabs{min-height:100%}.rz-action-tabs-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.rz-action-tab-panel{min-height:0}.rz-action-form{display:flex;flex-direction:column;gap:12px;min-height:100%}.rz-field{display:grid;gap:6px}.rz-template-list{display:flex;flex-wrap:wrap;gap:8px}.rz-preset-menu{position:relative}.rz-preset-icon-button{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:1px solid rgba(255,255,255,.08);border-radius:6px;background:#ffffff0a;color:#ffffffe0;cursor:pointer;flex-shrink:0}.rz-preset-icon-button:hover{background:#ffffff14;color:#fff}.rz-baseui-preset-menu{min-width:220px;max-width:min(320px,calc(100vw - 24px))}.rz-template-button{border:1px solid rgba(255,255,255,.08);border-radius:999px;background:#ffffff0a;color:#ffffffdb;padding:6px 10px;font-size:12px;line-height:1.4;cursor:pointer}.rz-template-button:hover{background:#ffffff1a;color:#fff}.rz-template-button:focus-visible{outline:2px solid rgba(130,50,255,.95);outline-offset:1px}.rz-template-button:disabled{cursor:default;opacity:.4}.rz-template-button[data-active=true]{background:#8232ff2e;border-color:#8232ff80;color:#fff}.rz-flow-panel{display:grid;gap:16px}.rz-flow-list{display:grid;gap:8px}.rz-flow-list-button{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;border:1px solid rgba(255,255,255,.08);border-radius:8px;background:#ffffff08;color:#ffffffe0;padding:10px 12px;text-align:left;cursor:pointer}.rz-flow-list-button:hover{background:#ffffff0f;color:#fff}.rz-flow-list-button:focus-visible{outline:2px solid rgba(130,50,255,.95);outline-offset:1px}.rz-flow-list-button:disabled{cursor:default;opacity:.4}.rz-flow-list-button[data-active=true]{background:#8232ff24;border-color:#8232ff73}.rz-flow-list-name{display:inline-flex;align-items:center;gap:6px;font-size:13px;line-height:1.4}.rz-flow-list-badge,.rz-flow-state-badge{display:inline-flex;align-items:center;justify-content:center;min-height:18px;padding:0 6px;border-radius:999px;background:#8232ff29;color:#c9a9ff;font-size:10px;line-height:1;font-family:Geist Mono,ui-monospace,SFMono-Regular,Menlo,monospace;text-transform:uppercase}.rz-flow-list-action{color:#ffffff8f;font-size:11px;line-height:1.4;font-family:Geist Mono,ui-monospace,SFMono-Regular,Menlo,monospace;text-transform:uppercase}.rz-flow-empty-state{border:1px dashed rgba(255,255,255,.12);border-radius:8px;padding:12px;color:#fff9;font-size:13px;line-height:1.5}.rz-flow-runs{display:grid;gap:12px}.rz-flow-state{display:grid;gap:8px;padding:12px;border:1px solid rgba(255,255,255,.08);border-radius:8px;background:#ffffff08}.rz-flow-state[data-status=running]{border-color:#8232ff73}.rz-flow-state[data-status=failed]{border-color:#ff787866}.rz-flow-state-header{display:flex;align-items:center;justify-content:space-between;gap:8px}.rz-flow-state-title{display:inline-flex;align-items:center;gap:6px;color:#ffffffe6;font-size:13px;line-height:1.4}.rz-flow-state-status{color:#fff9;font-size:12px;line-height:1.4;font-family:Geist Mono,ui-monospace,SFMono-Regular,Menlo,monospace;text-transform:uppercase}.rz-flow-state-error,.rz-flow-state-result{margin:0;border-radius:4px;background:#ffffff0a;padding:10px 12px;color:#ffffffd6;font-size:12px;line-height:1.5;white-space:pre-wrap;word-break:break-word}.rz-flow-state-error{color:#ffb4b4}.rz-flow-stop-button{flex-shrink:0}.rz-label{color:#fff9;font-size:12px;line-height:20px;letter-spacing:-.04em;font-family:Geist Mono,ui-monospace,SFMono-Regular,Menlo,monospace}.rz-input,.rz-textarea{width:100%;border:1px solid rgba(255,255,255,.08);border-radius:4px;background:#ffffff0a;color:#fff;padding:10px 12px;font-size:14px;line-height:1.5;letter-spacing:-.02em}.rz-textarea{min-height:112px;resize:none}.rz-button-row{display:flex;justify-content:flex-end;gap:8px;margin-top:auto}.rz-empty-state{display:flex;height:100%;align-items:center;justify-content:center;color:#ffffffb3;padding:24px;text-align:center;font-size:16px;line-height:1.5;letter-spacing:-.02em}@media(max-width:960px){.rz-topbar{padding-left:8px;padding-right:8px}.rz-topbar-brand svg{height:18px}.rz-topbar-panel-picker{overflow:hidden}.rz-workspace{grid-template-rows:minmax(0,1fr) 12px minmax(180px,var(--rz-devtools-height, 272px))}.rz-devtools-mobile-tabs{padding-top:8px}.rz-column-resize-handle{width:100%;min-width:0;min-height:6px;cursor:row-resize}.rz-column-resize-handle:before{width:72px;height:2px}.rz-column-resize-handle:after{border-left:0;border-right:0;border-top:1px solid rgba(255,255,255,.08);border-bottom:1px solid rgba(255,255,255,.08)}.rz-column-resize-handle[data-dragging=true]:after,.rz-column-resize-handle:hover:after{border-top-color:#ffffff14;border-bottom-color:#ffffff14}.rz-action-tabs-header{flex-wrap:wrap;align-items:flex-start}}@media(max-width:640px){.rz-message-list-header,.rz-message-row{grid-template-columns:36px 136px minmax(92px,136px) minmax(0,1fr)}.rz-message-header-cell,.rz-message-cell{padding:8px 10px}}