@gcoredev/fastedge-test 0.0.1-beta.0 → 0.1.0-beta.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.
Files changed (43) hide show
  1. package/README.md +6 -6
  2. package/bin/fastedge-debug.js +2 -0
  3. package/dist/fastedge-cli/METADATA.json +1 -3
  4. package/dist/fastedge-cli/{fastedge-run-linux-x64-unkown → fastedge-run-darwin-arm64} +0 -0
  5. package/dist/fastedge-cli/fastedge-run-linux-x64 +0 -0
  6. package/dist/fastedge-cli/fastedge-run.exe +0 -0
  7. package/dist/frontend/assets/index-CEFjsU8e.js +35 -0
  8. package/dist/frontend/assets/index-DdlINQc_.css +1 -0
  9. package/dist/frontend/index.html +2 -2
  10. package/dist/lib/index.cjs +329 -112
  11. package/dist/lib/index.js +331 -115
  12. package/dist/lib/runner/HostFunctions.d.ts +8 -0
  13. package/dist/lib/runner/HttpWasmRunner.d.ts +34 -14
  14. package/dist/lib/runner/IStateManager.d.ts +3 -2
  15. package/dist/lib/runner/IWasmRunner.d.ts +18 -1
  16. package/dist/lib/runner/NullStateManager.d.ts +1 -0
  17. package/dist/lib/runner/PortManager.d.ts +17 -19
  18. package/dist/lib/runner/ProxyWasmRunner.d.ts +7 -0
  19. package/dist/lib/runner/standalone.d.ts +1 -1
  20. package/dist/lib/schemas/api.d.ts +8 -2
  21. package/dist/lib/schemas/config.d.ts +4 -1
  22. package/dist/lib/test-framework/index.cjs +330 -114
  23. package/dist/lib/test-framework/index.js +332 -117
  24. package/dist/lib/test-framework/suite-runner.d.ts +1 -1
  25. package/dist/server.js +30 -30
  26. package/docs/API.md +758 -360
  27. package/docs/DEBUGGER.md +151 -0
  28. package/docs/INDEX.md +111 -0
  29. package/docs/RUNNER.md +582 -0
  30. package/docs/TEST_CONFIG.md +242 -0
  31. package/docs/TEST_FRAMEWORK.md +384 -284
  32. package/docs/WEBSOCKET.md +499 -0
  33. package/docs/quickstart.md +171 -0
  34. package/llms.txt +72 -14
  35. package/package.json +17 -6
  36. package/schemas/api-config.schema.json +12 -5
  37. package/schemas/api-load.schema.json +11 -6
  38. package/schemas/{test-config.schema.json → fastedge-config.test.schema.json} +12 -5
  39. package/dist/fastedge-cli/.gitkeep +0 -0
  40. package/dist/frontend/assets/index-CnXStFTd.css +0 -1
  41. package/dist/frontend/assets/index-FR9Oqsow.js +0 -37
  42. package/docs/HYBRID_LOADING.md +0 -546
  43. package/docs/LOCAL_SERVER.md +0 -153
package/llms.txt CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Test FastEdge WASM binaries programmatically — no server required. Supports CDN (proxy-wasm) and HTTP-WASM (component model) binaries. WASM type is detected automatically.
4
4
 
5
- Repository: https://github.com/G-Core/fastedge-debugger
5
+ Repository: https://github.com/G-Core/fastedge-test
6
6
 
7
7
  ## Installation
8
8
 
@@ -10,26 +10,31 @@ Repository: https://github.com/G-Core/fastedge-debugger
10
10
  npm install @gcoredev/fastedge-test
11
11
  ```
12
12
 
13
- Requires Node.js 18+.
13
+ Requires Node.js >=22.12.
14
14
 
15
15
  ## Entry Points
16
16
 
17
- - `@gcoredev/fastedge-test` — low-level runner (createRunner, createRunnerFromBuffer)
17
+ - `@gcoredev/fastedge-test` — low-level runner (createRunner, createRunnerFromBuffer, WasmRunnerFactory, ProxyWasmRunner, HttpWasmRunner)
18
18
  - `@gcoredev/fastedge-test/test` — high-level test framework (defineTestSuite, runTestSuite, runAndExit, runFlow, all assertion helpers)
19
+ - `@gcoredev/fastedge-test/server` — debugger server entry point
20
+ - `@gcoredev/fastedge-test/schemas` — JSON schemas for config and API bodies
19
21
 
20
22
  ## Key Exports: @gcoredev/fastedge-test/test
21
23
 
22
24
  - `defineTestSuite(config)` — validates and returns a typed TestSuite; config has `wasmPath` OR `wasmBuffer`, optional `runnerConfig`, and `tests` array
23
25
  - `runTestSuite(suite)` → `SuiteResult` — runs all tests sequentially, each with a fresh runner; returns `{ passed, failed, total, durationMs, results }`
24
26
  - `runAndExit(suite)` — runs suite, prints summary, exits 0 (all pass) or 1 (any fail); use in CI scripts
25
- - `runFlow(runner, options)` → `FullFlowResult` — CDN full flow helper; options: `{ url, method?, requestHeaders?, requestBody?, responseStatus?, responseHeaders?, responseBody?, properties?, enforceProductionPropertyRules? }`
26
- - `loadConfigFile(path)` → `TestConfig` — loads and validates a test-config.json file
27
+ - `runFlow(runner, options)` → `FullFlowResult` — CDN full flow helper; options: `{ url, method?, requestHeaders?, requestBody?, responseStatus?, responseStatusText?, responseHeaders?, responseBody?, properties?, enforceProductionPropertyRules? }`
28
+ - `loadConfigFile(path)` → `TestConfig` — loads and validates a fastedge-config.test.json file
27
29
 
28
30
  ## Key Exports: @gcoredev/fastedge-test (low-level)
29
31
 
30
32
  - `createRunner(wasmPath: string)` → runner — loads WASM from file path
31
33
  - `createRunnerFromBuffer(buffer: Buffer)` → runner — loads WASM from buffer
32
- - runner methods: `callFullFlow(url, method, reqHeaders, reqBody, resHeaders, resBody, resStatus, resStatusText, properties, enforceRules)`, `execute({ path, method, headers, body? })`, `cleanup()`
34
+ - `WasmRunnerFactory` factory class for creating runners with explicit type/config
35
+ - `ProxyWasmRunner` — CDN proxy-wasm runner class
36
+ - `HttpWasmRunner` — HTTP-WASM component model runner class
37
+ - runner methods: `callFullFlow(...)`, `execute({ path, method, headers, body? })`, `callHook(hookCall)`, `applyDotenv(enabled, path?)`, `cleanup()`, `getType()`
33
38
 
34
39
  ## Assertion Helpers (all from @gcoredev/fastedge-test/test)
35
40
 
@@ -68,10 +73,18 @@ type TestSuite =
68
73
  | { wasmBuffer: Buffer; runnerConfig?: RunnerConfig; tests: TestCase[] }
69
74
 
70
75
  interface RunnerConfig {
71
- dotenvEnabled?: boolean; // default: false
76
+ dotenv?: {
77
+ enabled?: boolean;
78
+ /** Directory to load .env files from (defaults to process CWD) */
79
+ path?: string;
80
+ };
72
81
  enforceProductionPropertyRules?: boolean; // default: true
82
+ /** Override automatic WASM type detection */
83
+ runnerType?: WasmType;
73
84
  }
74
85
 
86
+ type WasmType = 'http-wasm' | 'proxy-wasm';
87
+
75
88
  interface TestCase {
76
89
  name: string;
77
90
  run: (runner: IWasmRunner) => Promise<void>;
@@ -85,6 +98,26 @@ interface SuiteResult {
85
98
  results: TestResult[];
86
99
  }
87
100
 
101
+ interface TestResult {
102
+ name: string;
103
+ passed: boolean;
104
+ error?: string;
105
+ durationMs: number;
106
+ }
107
+
108
+ interface FlowOptions {
109
+ url: string;
110
+ method?: string;
111
+ requestHeaders?: Record<string, string>;
112
+ requestBody?: string;
113
+ responseStatus?: number;
114
+ responseStatusText?: string;
115
+ responseHeaders?: Record<string, string>;
116
+ responseBody?: string;
117
+ properties?: Record<string, unknown>;
118
+ enforceProductionPropertyRules?: boolean; // default: true
119
+ }
120
+
88
121
  interface FullFlowResult {
89
122
  hookResults: Record<string, HookResult>;
90
123
  finalResponse: { status: number; statusText: string; headers: Record<string, string>; body: string; contentType: string; isBase64?: boolean };
@@ -94,10 +127,35 @@ interface FullFlowResult {
94
127
  interface HookResult {
95
128
  returnCode: number | null;
96
129
  logs: { level: number; message: string }[];
97
- input: { request: { headers: Record<string, string>; body: string }; response: { headers: Record<string, string>; body: string } };
98
- output: { request: { headers: Record<string, string>; body: string }; response: { headers: Record<string, string>; body: string } };
130
+ input: {
131
+ request: { headers: Record<string, string>; body: string };
132
+ response: { headers: Record<string, string>; body: string };
133
+ properties?: Record<string, unknown>;
134
+ };
135
+ output: {
136
+ request: { headers: Record<string, string>; body: string };
137
+ response: { headers: Record<string, string>; body: string };
138
+ properties?: Record<string, unknown>;
139
+ };
99
140
  properties: Record<string, unknown>;
100
141
  }
142
+
143
+ interface HttpRequest {
144
+ path: string;
145
+ method: string;
146
+ headers: Record<string, string>;
147
+ body?: string;
148
+ }
149
+
150
+ interface HttpResponse {
151
+ status: number;
152
+ statusText: string;
153
+ headers: Record<string, string>;
154
+ body: string;
155
+ contentType: string | null;
156
+ isBase64?: boolean;
157
+ logs: { level: number; message: string }[];
158
+ }
101
159
  ```
102
160
 
103
161
  hookResults keys for CDN proxy-wasm: `onRequestHeaders`, `onRequestBody`, `onResponseHeaders`, `onResponseBody`
@@ -132,7 +190,7 @@ await runAndExit(defineTestSuite({
132
190
  }));
133
191
  ```
134
192
 
135
- ## HTTP-WASM Quick Example
193
+ ## HTTP-WASM Quick Example:
136
194
 
137
195
  ```typescript
138
196
  import { defineTestSuite, runAndExit } from '@gcoredev/fastedge-test/test';
@@ -153,12 +211,12 @@ await runAndExit(defineTestSuite({
153
211
 
154
212
  ## JSON Schemas
155
213
 
156
- Schemas for test-config.json and API bodies ship in the package under `schemas/`.
157
- Import path: `@gcoredev/fastedge-test/schemas/test-config.schema.json`
214
+ Schemas for fastedge-config.test.json and API bodies ship in the package under `schemas/`.
215
+ Import path: `@gcoredev/fastedge-test/schemas/fastedge-config.test.schema.json`
158
216
 
159
- Use in test-config.json for IDE autocomplete:
217
+ Use in fastedge-config.test.json for IDE autocomplete:
160
218
  ```json
161
- { "$schema": "./node_modules/@gcoredev/fastedge-test/schemas/test-config.schema.json" }
219
+ { "$schema": "./node_modules/@gcoredev/fastedge-test/schemas/fastedge-config.test.schema.json" }
162
220
  ```
163
221
 
164
222
  ## Full Documentation
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@gcoredev/fastedge-test",
3
- "version": "0.0.1-beta.0",
3
+ "version": "0.1.0-beta.2",
4
4
  "private": false,
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/G-Core/fastedge-test.git"
8
+ },
5
9
  "publishConfig": {
6
10
  "access": "public"
7
11
  },
@@ -18,9 +22,10 @@
18
22
  "./schemas": "./schemas/"
19
23
  },
20
24
  "bin": {
21
- "fastedge-debug": "./dist/server.js"
25
+ "fastedge-debug": "./bin/fastedge-debug.js"
22
26
  },
23
27
  "files": [
28
+ "bin/",
24
29
  "dist/lib/",
25
30
  "dist/server.js",
26
31
  "dist/frontend/",
@@ -37,14 +42,17 @@
37
42
  "build:schemas": "ts-node --project tsconfig.scripts.json scripts/generate-schemas.ts",
38
43
  "build:backend": "node esbuild/bundle-server.js",
39
44
  "build:frontend": "cd frontend && pnpm exec vite build",
40
- "check-types": "tsc -p server/tsconfig.json --noEmit",
41
45
  "build:test-apps": "npm-run-all -p build:cdn-test-apps build:http-test-apps",
42
46
  "build:cdn-test-apps": "pnpm -r --filter './test-applications/cdn-apps/*' build",
43
47
  "build:http-test-apps": "pnpm -r --filter './test-applications/http-apps/*' build",
44
- "start": "node dist/server.js",
48
+ "check-types": "tsc -p server/tsconfig.json --noEmit",
45
49
  "dev": "npm-run-all -p dev:backend dev:frontend",
46
- "dev:backend": "node esbuild/watch-server.js & sleep 2 && node --watch dist/server.js",
50
+ "dev:backend": "run-p dev:backend:esbuild dev:backend:server",
51
+ "dev:backend:esbuild": "node esbuild/watch-server.js",
52
+ "dev:backend:server": "sleep 2 && node --watch dist/server.js",
47
53
  "dev:frontend": "cd frontend && pnpm exec vite",
54
+ "generate-docs": "./fastedge-plugin-source/generate-docs.sh",
55
+ "start": "node dist/server.js",
48
56
  "test": "npm-run-all -s test:unit test:integration",
49
57
  "test:unit": "npm-run-all -p test:backend test:frontend",
50
58
  "test:backend": "vitest run",
@@ -63,7 +71,7 @@
63
71
  "dependencies": {
64
72
  "@assemblyscript/wasi-shim": "^0.1.0",
65
73
  "@gcoredev/fastedge-sdk-js": "^2.2.0",
66
- "@gcoredev/proxy-wasm-sdk-as": "^1.2.1",
74
+ "@gcoredev/proxy-wasm-sdk-as": "^1.2.2",
67
75
  "@types/ws": "^8.18.1",
68
76
  "express": "^4.19.2",
69
77
  "immer": "^11.1.3",
@@ -75,6 +83,9 @@
75
83
  "zustand": "^5.0.11",
76
84
  "zustand-debounce": "^2.3.0"
77
85
  },
86
+ "engines": {
87
+ "node": ">=22.12"
88
+ },
78
89
  "devDependencies": {
79
90
  "@testing-library/jest-dom": "^6.9.1",
80
91
  "@testing-library/react": "^16.3.2",
@@ -91,15 +91,22 @@
91
91
  },
92
92
  "additionalProperties": {}
93
93
  },
94
- "dotenvEnabled": {
95
- "default": true,
96
- "type": "boolean"
94
+ "dotenv": {
95
+ "type": "object",
96
+ "properties": {
97
+ "enabled": {
98
+ "type": "boolean"
99
+ },
100
+ "path": {
101
+ "type": "string"
102
+ }
103
+ },
104
+ "additionalProperties": false
97
105
  }
98
106
  },
99
107
  "required": [
100
108
  "request",
101
- "properties",
102
- "dotenvEnabled"
109
+ "properties"
103
110
  ],
104
111
  "additionalProperties": false
105
112
  }
@@ -8,13 +8,18 @@
8
8
  "wasmPath": {
9
9
  "type": "string"
10
10
  },
11
- "dotenvEnabled": {
12
- "default": true,
13
- "type": "boolean"
11
+ "dotenv": {
12
+ "type": "object",
13
+ "properties": {
14
+ "enabled": {
15
+ "type": "boolean"
16
+ },
17
+ "path": {
18
+ "type": "string"
19
+ }
20
+ },
21
+ "additionalProperties": false
14
22
  }
15
23
  },
16
- "required": [
17
- "dotenvEnabled"
18
- ],
19
24
  "additionalProperties": false
20
25
  }
@@ -88,15 +88,22 @@
88
88
  },
89
89
  "additionalProperties": {}
90
90
  },
91
- "dotenvEnabled": {
92
- "default": true,
93
- "type": "boolean"
91
+ "dotenv": {
92
+ "type": "object",
93
+ "properties": {
94
+ "enabled": {
95
+ "type": "boolean"
96
+ },
97
+ "path": {
98
+ "type": "string"
99
+ }
100
+ },
101
+ "additionalProperties": false
94
102
  }
95
103
  },
96
104
  "required": [
97
105
  "request",
98
- "properties",
99
- "dotenvEnabled"
106
+ "properties"
100
107
  ],
101
108
  "additionalProperties": false
102
109
  }
File without changes
@@ -1 +0,0 @@
1
- ._wasmLoader_f0kjf_1{padding:16px 20px;background:#2d2d2d;border-bottom:1px solid #3d3d3d}._header_f0kjf_7{display:flex;justify-content:space-between;align-items:center}._header_f0kjf_7 h2{color:#e0e0e0;margin:0 0 12px;font-size:14px;font-weight:600}._actions_f0kjf_20{display:flex;gap:8px}._secondaryButton_f0kjf_25{background:#3d3d3d;color:#e0e0e0;padding:6px 12px;font-size:12px}._secondaryButton_f0kjf_25:hover:not(:disabled){background:#4d4d4d}._wasmLoader_f0kjf_1 input[type=file]{color:#e0e0e0;font-size:13px}._loadingIndicator_f0kjf_41{margin-left:10px;color:#ff6c37}._pathInputGroup_f0kjf_46{display:flex;gap:8px;align-items:center}._pathInput_f0kjf_46{flex:1;padding:8px 12px;background:#1e1e1e;border:1px solid #3d3d3d;border-radius:4px;color:#e0e0e0;font-size:13px;font-family:Consolas,Monaco,Courier New,monospace}._pathInput_f0kjf_46:focus{outline:none;border-color:#ff6c37;background:#2d2d2d}._pathInput_f0kjf_46:disabled{opacity:.5;cursor:not-allowed}._pathInput_f0kjf_46::placeholder{color:#666}._pathButton_f0kjf_78{padding:8px 16px;background:#ff6c37;color:#fff;border:none;border-radius:4px;font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap;transition:background .2s}._pathButton_f0kjf_78:hover:not(:disabled){background:#ff7c47}._pathButton_f0kjf_78:disabled{opacity:.5;cursor:not-allowed}._tabs_f0kjf_101{display:flex;justify-content:space-between;align-items:center;gap:16px;margin-bottom:12px;border-bottom:1px solid #3d3d3d}._tabButtons_f0kjf_110{display:flex;gap:4px;flex:0 0 auto}._tab_f0kjf_101{display:flex;align-items:center;gap:6px;padding:10px 16px;background:transparent;color:#b0b0b0;border:none;border-bottom:2px solid transparent;cursor:pointer;font-size:13px;font-weight:500;transition:all .2s;position:relative;bottom:-1px}._tab_f0kjf_101:hover:not(:disabled){color:#e0e0e0;background:#ff6c371a}._tabActive_f0kjf_138{color:#ff6c37!important;border-bottom-color:#ff6c37!important;font-weight:600}._tab_f0kjf_101:disabled{opacity:.5;cursor:not-allowed}._tabIcon_f0kjf_149{font-size:14px}._tabContent_f0kjf_153{margin-top:12px}._pathPanel_f0kjf_157,._uploadPanel_f0kjf_158{padding:16px;background:#252525;border-radius:4px;border:1px solid #3d3d3d}._panelDescription_f0kjf_165{font-size:12px;color:#b0b0b0;margin-bottom:12px;line-height:1.5}._fileInputWrapper_f0kjf_173{display:flex;align-items:center;gap:12px;padding:8px;background:#1e1e1e;border:1px solid #3d3d3d;border-radius:4px}._chooseFileButton_f0kjf_184{background:#ff6c37;color:#fff;border:none;padding:6px 12px;border-radius:4px;cursor:pointer;font-size:12px;font-weight:600;white-space:nowrap;transition:background .2s}._chooseFileButton_f0kjf_184:hover:not(:disabled){background:#ff7c47}._chooseFileButton_f0kjf_184:disabled{opacity:.5;cursor:not-allowed}._hiddenFileInput_f0kjf_207{display:none}._noFileChosen_f0kjf_212{color:#888;font-size:13px;font-style:italic}._selectedFile_f0kjf_219{display:flex;align-items:center;gap:6px;flex:1}._selectedFileIcon_f0kjf_226{color:#4caf50;font-size:14px;font-weight:700}._selectedFileName_f0kjf_232{color:#e0e0e0;font-size:13px;font-family:Consolas,Monaco,Courier New,monospace}._selectedFileSize_f0kjf_238{color:#b0b0b0;font-size:12px}._tabInfo_f0kjf_244{display:flex;align-items:center;gap:6px;font-size:12px;color:#b0b0b0;padding:0 12px 8px;white-space:nowrap;flex-shrink:0}._tabInfoIcon_f0kjf_255{font-size:13px}._tabInfoText_f0kjf_259{color:#e0e0e0;font-weight:500}._tabInfoTime_f0kjf_264,._tabInfoSize_f0kjf_268{color:#b0b0b0}._container_1g2xx_1{display:flex;align-items:center;gap:8px;font-size:12px;color:#b0b0b0}._indicator_1g2xx_9{width:8px;height:8px;border-radius:50%;transition:background-color .3s ease}._indicatorConnected_1g2xx_16{background-color:#4caf50}._indicatorReconnecting_1g2xx_20{background-color:#ff9800}._indicatorError_1g2xx_24{background-color:#f44336}._indicatorDisconnected_1g2xx_28{background-color:#757575}._text_1g2xx_32{font-weight:500}._container_qhpt2_1{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:400px;gap:1.5rem;padding:2rem}._spinner_qhpt2_11{width:60px;height:60px;border:4px solid rgba(255,108,55,.2);border-top-color:#ff6c37;border-radius:50%;animation:_spin_qhpt2_11 1s linear infinite}@keyframes _spin_qhpt2_11{to{transform:rotate(360deg)}}._message_qhpt2_26{margin:0;font-size:1.1rem;color:#e0e0e0;font-weight:500}._container_1czu6_1{display:flex;flex-direction:column;height:100%;gap:12px}._toolbar_1czu6_8{display:flex;justify-content:space-between;align-items:center;padding-bottom:12px;border-bottom:1px solid #3d3d3d}._info_1czu6_16{display:flex;align-items:center;gap:12px}._label_1czu6_22{font-size:13px;color:#b0b0b0;font-weight:500}._errorBadge_1czu6_28{font-size:11px;padding:4px 8px;background:#5d2f2f;color:#ff6b6b;border-radius:4px;font-weight:600;text-transform:uppercase}._successBadge_1czu6_38{font-size:11px;padding:4px 8px;background:#2f5d2f;color:#6bff6b;border-radius:4px;font-weight:600;text-transform:uppercase}._error_1czu6_28{background:#3d1f1f;color:#ff6b6b;padding:12px;border-radius:4px;border:1px solid #5d2f2f;font-size:13px;line-height:1.5}._error_1czu6_28 strong{display:block;margin-bottom:4px;color:#f88}._editor_1czu6_64{flex:1;min-height:400px;max-height:600px;padding:16px;background:#1e1e1e;border:1px solid #3d3d3d;border-radius:4px;color:#e0e0e0;font-size:13px;font-family:Consolas,Monaco,Courier New,monospace;line-height:1.6;resize:vertical;tab-size:2;white-space:pre;overflow-x:auto;overflow-y:auto}._editor_1czu6_64:focus{outline:none;border-color:#ff6c37;box-shadow:0 0 0 2px #ff6c3733}._footer_1czu6_89{padding-top:12px;border-top:1px solid #3d3d3d}._hint_1czu6_94{font-size:12px;color:gray;font-style:italic}._backdrop_5qu2q_1{position:fixed;inset:0;background:#000000b3;display:flex;align-items:center;justify-content:center;z-index:1000;padding:20px}._modal_5qu2q_15{background:#252525;border-radius:8px;border:1px solid #3d3d3d;width:100%;max-width:900px;max-height:90vh;display:flex;flex-direction:column;box-shadow:0 8px 32px #0006}._header_5qu2q_27{padding:16px 20px;border-bottom:1px solid #3d3d3d;display:flex;justify-content:space-between;align-items:center}._header_5qu2q_27 h2{margin:0;font-size:16px;color:#e0e0e0}._closeButton_5qu2q_41{background:transparent;color:#b0b0b0;border:none;font-size:20px;padding:4px 8px;cursor:pointer;border-radius:4px;transition:background .2s,color .2s}._closeButton_5qu2q_41:hover{background:#3d3d3d;color:#e0e0e0}._tabs_5qu2q_57{display:flex;border-bottom:1px solid #3d3d3d;background:#2d2d2d}._tab_5qu2q_57{flex:1;padding:12px 16px;background:transparent;border:none;border-bottom:2px solid transparent;color:#b0b0b0;font-size:13px;font-weight:500;cursor:pointer;transition:all .2s}._tab_5qu2q_57:hover:not(:disabled){background:#3d3d3d;color:#e0e0e0}._tab_5qu2q_57:disabled{cursor:not-allowed;opacity:.5}._activeTab_5qu2q_86{color:#ff6c37!important;border-bottom-color:#ff6c37!important;background:#252525!important}._content_5qu2q_92{flex:1;overflow:auto;padding:20px;min-height:400px}._comingSoon_5qu2q_99{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:#b0b0b0;text-align:center}._comingSoon_5qu2q_99 p{margin:8px 0;font-size:14px}._footer_5qu2q_114{padding:16px 20px;border-top:1px solid #3d3d3d;display:flex;justify-content:flex-end;gap:12px}._configButtons_c1h87_1{display:flex;gap:.75rem;padding:0 1rem;justify-content:flex-end}._dropZone_10z7x_1{position:relative;width:100%;min-height:100vh}._overlay_10z7x_7{position:fixed;inset:0;background:#000000d9;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:9999;animation:_fadeIn_10z7x_1 .2s ease-out;pointer-events:none}@keyframes _fadeIn_10z7x_1{0%{opacity:0}to{opacity:1}}._overlayContent_10z7x_32{text-align:center;color:#fff;padding:3rem;border:3px dashed rgba(255,255,255,.5);border-radius:12px;background:#ffffff0d;max-width:500px;animation:_slideUp_10z7x_1 .3s ease-out}@keyframes _slideUp_10z7x_1{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}._icon_10z7x_54{font-size:4rem;margin-bottom:1rem;animation:_bounce_10z7x_1 .6s ease-in-out infinite}@keyframes _bounce_10z7x_1{0%,to{transform:translateY(0)}50%{transform:translateY(-10px)}}._title_10z7x_69{font-size:1.5rem;font-weight:600;margin-bottom:.5rem}._subtitle_10z7x_75{font-size:1rem;opacity:.8;color:#aaa}._panel_fsc9y_1{border:1px solid #3d3d3d;border-radius:4px;overflow:hidden;background:#252525}._header_fsc9y_8{cursor:pointer;padding:12px 20px;background:#2d2d2d;border-bottom:1px solid #3d3d3d;display:flex;align-items:center;justify-content:space-between}._titleContainer_fsc9y_18{display:flex;align-items:center;gap:12px}._title_fsc9y_18{margin:0;font-size:14px;font-weight:600;color:#e0e0e0}._headerRight_fsc9y_31{display:flex;align-items:center;gap:60px}._arrow_fsc9y_37{width:10px;height:10px;border-right:2px solid #b0b0b0;border-bottom:2px solid #b0b0b0;transform:rotate(45deg);transition:transform .2s;flex-shrink:0}._arrow_fsc9y_37._expanded_fsc9y_47{transform:rotate(-135deg)}._content_fsc9y_51{padding:1rem 1.25rem;background:#252525}._requestBar_1drr4_1{padding:16px 20px;background:#2d2d2d;border-bottom:1px solid #3d3d3d;display:flex;gap:10px;align-items:center}._urlInputContainer_1drr4_10{flex:1;display:flex;align-items:stretch;background:#1e1e1e;border:1px solid #3d3d3d;border-radius:4px;overflow:hidden;transition:border-color .2s}._urlInputContainer_1drr4_10:focus-within{border-color:#ff6c37;box-shadow:0 0 0 1px #ff6c37}._urlPrefix_1drr4_26{padding:8px 0 8px 12px;color:gray;font-family:Monaco,Menlo,Ubuntu Mono,Consolas,monospace;font-size:13px;line-height:1.5;-webkit-user-select:none;user-select:none;white-space:nowrap;flex-shrink:0;display:flex;align-items:center;cursor:pointer}._methodSelect_1drr4_40{padding:8px 12px;background:#2d2d2d;color:#e0e0e0;border:none;border-right:1px solid #3d3d3d;border-radius:0;font-size:13px;font-weight:600;cursor:pointer;outline:none;width:auto;flex-shrink:0}._methodSelect_1drr4_40:focus{outline:none;box-shadow:none;border:none;border-right:1px solid #3d3d3d;border-color:transparent}._methodSelect_1drr4_40:hover{background:#3d3d3d}._urlInput_1drr4_10{flex:1;padding:8px 12px;background:transparent;color:#e0e0e0;border:none!important;border-radius:0;font-size:13px;font-family:Monaco,Menlo,Ubuntu Mono,Consolas,monospace;outline:none;box-shadow:none!important}._urlInput_1drr4_10:focus{outline:none!important;box-shadow:none!important;border:none!important;border-color:transparent!important}._urlPrefix_1drr4_26+._urlInput_1drr4_10{padding-left:0!important;border-left:none!important}._urlInput_1drr4_10::placeholder{color:#6d6d6d}._sendButton_1drr4_97{min-width:100px;flex-shrink:0;font-weight:600;display:flex;align-items:center;justify-content:center;gap:.5rem;background-color:#ff6c37;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;transition:all .2s}._sendButton_1drr4_97:hover:not(:disabled){background-color:#ff8555;transform:translateY(-1px);box-shadow:0 2px 8px #ff6c374d}._sendButton_1drr4_97:active:not(:disabled){transform:translateY(0)}._sendButton_1drr4_97:disabled{background-color:#555;color:#888;cursor:not-allowed}._spinner_1drr4_130{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:_spin_1drr4_130 .8s linear infinite}@keyframes _spin_1drr4_130{to{transform:rotate(360deg)}}._container_l9qpb_1{border:1px solid #3d3d3d;border-radius:4px;background:#1e1e1e;overflow:hidden}._header_l9qpb_8{display:grid;grid-template-columns:32px 1fr 1fr 40px;gap:1px;background:#3d3d3d;padding:8px 12px;font-size:11px;font-weight:600;color:#b0b0b0;text-transform:uppercase;letter-spacing:.5px}._headerEnabled_l9qpb_21,._headerKey_l9qpb_22,._headerValue_l9qpb_23{color:gray}._headerActions_l9qpb_27{width:40px}._row_l9qpb_31{display:grid;grid-template-columns:32px 1fr 1fr 40px;gap:1px;background:#3d3d3d;border-top:1px solid #3d3d3d}._row_l9qpb_31._noDelete_l9qpb_39{grid-template-columns:32px 1fr 1fr}._row_l9qpb_31:first-child{border-top:none}._enabled_l9qpb_47{background:#252525;display:flex;align-items:center;justify-content:center;padding:8px}._enabled_l9qpb_47 input[type=checkbox]{cursor:pointer;width:16px;height:16px;accent-color:#ff6c37}._enabled_l9qpb_47 input[type=checkbox]:disabled{opacity:.3;cursor:not-allowed}._key_l9qpb_67,._value_l9qpb_68{background:#252525;border:none;padding:8px 12px;color:#e0e0e0;font-family:inherit;font-size:13px;outline:none}._key_l9qpb_67:focus,._value_l9qpb_68:focus{background:#2a2a2a;outline:1px solid #ff6c37;outline-offset:-1px}._key_l9qpb_67:read-only,._value_l9qpb_68:read-only{cursor:default;pointer-events:none}._key_l9qpb_67:read-only:focus,._value_l9qpb_68:read-only:focus{background:#252525;outline:none}._key_l9qpb_67::placeholder,._value_l9qpb_68::placeholder{color:#666;font-style:italic}._deleteButton_l9qpb_103{background:#252525;border:none;color:#666;cursor:pointer;font-size:16px;padding:8px;transition:all .15s;display:flex;align-items:center;justify-content:center}._deleteButton_l9qpb_103:hover:not(:disabled){background:#ff6c37;color:#fff}._deleteButton_l9qpb_103:disabled{opacity:.3;cursor:not-allowed}._requestInfoTabs_1holq_1{display:flex;flex-direction:column}._tabs_1holq_6{display:flex;gap:.5rem;border-bottom:1px solid #3d3d3d}._tab_1holq_6{padding:.5rem 1rem;background-color:transparent;color:#b0b0b0;border:none;border-bottom:2px solid transparent;cursor:pointer;font-size:.9rem;transition:all .2s}._tab_1holq_6:hover{color:#e0e0e0;background-color:#2d2d2d}._tab_1holq_6._active_1holq_28{color:#ff6c37;border-bottom-color:#ff6c37}._tabContent_1holq_33{padding:1rem 0}._headersTab_1holq_37,._bodyTab_1holq_38{display:flex;flex-direction:column;gap:.5rem}._headersTab_1holq_37 label,._bodyTab_1holq_38 label{font-size:.9rem;font-weight:500;color:#e0e0e0}._bodyTextarea_1holq_51{width:100%;padding:.75rem;background-color:#1e1e1e;color:#e0e0e0;border:1px solid #3d3d3d;border-radius:4px;font-family:Monaco,Menlo,Ubuntu Mono,Consolas,monospace;font-size:.85rem;line-height:1.5;resize:vertical}._bodyTextarea_1holq_51:focus{outline:none;border-color:#ff6c37}._requestPanel_1y172_1{display:flex;flex-direction:column;gap:0}._container_1n5rg_1{background:#1e1e1e;padding:12px;border-radius:4px;font-size:12px;margin:0;overflow:auto}._title_1n5rg_10{color:#e0e0e0;font-size:13px;margin-bottom:8px}._content_1n5rg_16{font-family:Consolas,Monaco,Courier New,monospace;white-space:pre-wrap;word-wrap:break-word;color:#d4d4d4}._diffLine_1n5rg_23{display:block;padding-left:8px;padding-right:8px;margin:0}._diffLineAdded_1n5rg_30{color:#b5cea8;background-color:#39b95926}._diffLineRemoved_1n5rg_35{color:#f48771;background-color:#f8877126}._diffPrefix_1n5rg_40{opacity:.5;margin-right:8px;-webkit-user-select:none;user-select:none}._responsePanel_mkkfd_1{border-top:2px solid #3d3d3d;background:#252525;display:flex;flex-direction:column;flex:1;min-height:200px}._responseEmpty_mkkfd_10{padding:40px 20px;text-align:center;color:#666;font-style:italic}._responseStatus_mkkfd_17{display:flex;align-items:center}._tabs_mkkfd_22{display:flex;background:#2d2d2d;border-bottom:1px solid #3d3d3d;padding:0 20px;gap:4px}._tab_mkkfd_22{padding:10px 16px;background:transparent;color:#b0b0b0;border:none;cursor:pointer;font-size:13px;border-bottom:2px solid transparent;transition:all .2s}._tab_mkkfd_22:hover{color:#e0e0e0;background:#333}._tab_mkkfd_22._active_mkkfd_46{color:#ff6c37;border-bottom-color:#ff6c37}._tab_mkkfd_22._active_mkkfd_46:hover{color:#ff6c37}._responseContent_mkkfd_55{flex:1;overflow:hidden;display:flex;flex-direction:column}._responseBody_mkkfd_62,._responsePreview_mkkfd_63,._responseHeaders_mkkfd_64{flex:1;overflow:auto;padding:0}._responseBody_mkkfd_62{background:#1e1e1e;padding:16px;font-family:Consolas,Monaco,Courier New,monospace;font-size:12px;color:#b0b0b0}._responsePreview_mkkfd_63{background:#1e1e1e;height:100%}._imagePreview_mkkfd_83{padding:20px;text-align:center;background:#f5f5f5}._previewImage_mkkfd_89{max-width:100%;height:auto}._htmlPreview_mkkfd_94{width:100%;height:100%;border:none;background:#fff}._binaryNotice_mkkfd_101{padding:20px;color:#b0b0b0}._headersList_mkkfd_106{padding:16px 20px}._headerItem_mkkfd_110{padding:8px 0;border-bottom:1px solid #2d2d2d;display:flex;gap:12px;font-size:12px;font-family:Consolas,Monaco,Courier New,monospace}._headerItem_mkkfd_110:last-child{border-bottom:none}._headerKey_mkkfd_123{color:#ff6c37;font-weight:600;min-width:200px;flex-shrink:0}._headerValue_mkkfd_130{color:#b0b0b0;word-break:break-all}._noHeaders_mkkfd_135{color:#666;font-style:italic;padding:20px}._logsViewer_1akjc_1{display:flex;flex-direction:column;gap:.5rem}._filterBar_1akjc_7{display:flex;align-items:center;gap:.5rem;padding:.5rem;background-color:#252525;border-radius:4px}._filterBar_1akjc_7 label{font-size:.9rem;font-weight:500;color:#e0e0e0}._levelSelect_1akjc_22{padding:.25rem .5rem;background-color:#1e1e1e;color:#e0e0e0;border:1px solid #3d3d3d;border-radius:4px;font-size:.9rem}._levelSelect_1akjc_22:hover{border-color:#ff6c37}._levelSelect_1akjc_22:focus{outline:none;border-color:#ff6c37}._filterInfo_1akjc_40{font-size:.85rem;color:#b0b0b0;margin-left:auto}._logsContainer_1akjc_46{background-color:#1e1e1e;border:1px solid #3d3d3d;border-radius:4px;padding:1rem;max-height:400px;overflow-y:auto;font-family:Monaco,Menlo,Ubuntu Mono,Consolas,monospace;font-size:.85rem;line-height:1.5;margin:0}._logEntry_1akjc_59{display:flex;gap:.5rem;padding:.25rem 0}._logLevel_1akjc_65{font-weight:600;min-width:80px;flex-shrink:0}._logMessage_1akjc_71{word-wrap:break-word;white-space:pre-wrap;flex:1}._trace_1akjc_78{color:gray}._debug_1akjc_82{color:#6495ed}._info_1akjc_86{color:#90ee90}._warn_1akjc_90{color:gold}._error_1akjc_94{color:#ff6b6b}._critical_1akjc_98{color:red;font-weight:700}._emptyState_1akjc_103{padding:2rem;text-align:center;color:#b0b0b0;background-color:#1e1e1e;border:1px solid #3d3d3d;border-radius:4px}._emptyState_1akjc_103 p{margin:0;font-size:.9rem}._noLogs_1akjc_117{color:#b0b0b0;text-align:center;padding:1rem;font-style:italic}._logsContainer_1akjc_46::-webkit-scrollbar{width:8px}._logsContainer_1akjc_46::-webkit-scrollbar-track{background:#1e1e1e}._logsContainer_1akjc_46::-webkit-scrollbar-thumb{background:#3d3d3d;border-radius:4px}._logsContainer_1akjc_46::-webkit-scrollbar-thumb:hover{background:#555}._logLevelSelector_1dmmk_1{display:flex;align-items:center;gap:.5rem;white-space:nowrap}._logLevelSelector_1dmmk_1 label{font-size:.75rem;color:#e0e0e0;font-weight:500;white-space:nowrap}._logLevelSelector_1dmmk_1 select{padding:.35rem .75rem;background-color:#1e1e1e;color:#e0e0e0;border:1px solid #3d3d3d;border-radius:4px;font-size:.85rem;cursor:pointer;transition:all .2s}._logLevelSelector_1dmmk_1 select:hover{border-color:#ff6c37}._logLevelSelector_1dmmk_1 select:focus{outline:none;border-color:#ff6c37;box-shadow:0 0 0 2px #ff6c3733}._httpWasmView_zirrp_1{display:flex;flex-direction:column;gap:1.5rem;height:100%;padding:.75rem 1rem 1.5rem}._panels_zirrp_9{display:flex;flex-direction:column;gap:1.5rem;flex:1;overflow-y:auto}._panels_zirrp_9::-webkit-scrollbar{width:8px}._panels_zirrp_9::-webkit-scrollbar-track{background:#1e1e1e}._panels_zirrp_9::-webkit-scrollbar-thumb{background:#3d3d3d;border-radius:4px}._panels_zirrp_9::-webkit-scrollbar-thumb:hover{background:#555}._hint_zirrp_35{font-size:.85rem;color:#b0b0b0;font-style:italic;padding:.5rem 0;text-align:left}._loggingContent_zirrp_44{display:flex;flex-direction:column;gap:0}._loggingHeader_zirrp_50{display:flex;align-items:center;justify-content:space-between;padding:0 0 .75rem;border-bottom:1px solid #3d3d3d}._logTab_zirrp_58{display:flex;align-items:center;padding:.5rem 1rem;border-bottom:2px solid #ff6c37;color:#ff6c37}._tabLabel_zirrp_66{font-size:.9rem;font-weight:500}._countryPresets_1xq35_1{margin-bottom:12px;display:flex;gap:16px}._countryLabel_1xq35_7{display:flex;align-items:center;gap:6px;cursor:pointer}._flag_1xq35_14{font-size:20px}._toggleLabel_1jgsn_1{display:flex;align-items:center;gap:8px;cursor:pointer;-webkit-user-select:none;user-select:none}._toggleLabel_1jgsn_1._disabled_1jgsn_9{cursor:not-allowed;opacity:.5}._toggleSwitch_1jgsn_14{position:relative;width:44px;height:24px;background-color:#cbd5e1;border-radius:12px;transition:background-color .2s ease;cursor:pointer}._toggleSwitch_1jgsn_14._checked_1jgsn_24{background-color:#4ade80}._toggleSwitch_1jgsn_14._disabled_1jgsn_9{cursor:not-allowed}._toggleSlider_1jgsn_32{position:absolute;top:2px;left:2px;width:20px;height:20px;background-color:#fff;border-radius:50%;transition:left .2s ease;box-shadow:0 2px 4px #0003}._toggleSwitch_1jgsn_14._checked_1jgsn_24 ._toggleSlider_1jgsn_32{left:22px}._toggleLabel_1jgsn_1 span{font-size:14px}._toggleLabel_1jgsn_1._compact_1jgsn_53{gap:6px}._toggleLabel_1jgsn_1._compact_1jgsn_53 span{font-size:11px;color:#b0b0b0;line-height:1}._toggleSwitch_1jgsn_14._compact_1jgsn_53{width:32px;height:18px;border-radius:9px}._toggleSwitch_1jgsn_14._compact_1jgsn_53 ._toggleSlider_1jgsn_32{width:14px;height:14px;top:2px;left:2px}._toggleSwitch_1jgsn_14._compact_1jgsn_53._checked_1jgsn_24 ._toggleSlider_1jgsn_32{left:16px}._toggleContainer_nufij_1{display:flex;align-items:center;gap:12px;font-size:14px}._toggleContainerRight_nufij_8{display:flex;align-items:center;padding-top:2px}._activeIndicator_nufij_14{color:#4ade80;font-size:12px}._dotenvNotice_nufij_19{margin-top:12px;padding:8px 12px;background:#f0fdf4;border:1px solid #86efac;border-radius:4px;font-size:13px;color:#166534}._hookStagesPanel_nt1hf_1{display:flex;flex-direction:column;background:#252525;overflow:hidden;flex-shrink:0}._stagesHeader_nt1hf_9{display:flex;align-items:center;justify-content:space-between;background:#2d2d2d;border-bottom:1px solid #3d3d3d;padding-right:20px}._tabs_nt1hf_18{display:flex;background:#2d2d2d;border-bottom:1px solid #3d3d3d;padding:0;gap:4px;flex:1}._tab_nt1hf_18{padding:10px 16px;background:transparent;color:#b0b0b0;border:none;cursor:pointer;font-size:13px;border-bottom:2px solid transparent;transition:all .2s}._tab_nt1hf_18:hover{color:#e0e0e0;background:#333}._tab_nt1hf_18._active_nt1hf_43{color:#ff6c37;border-bottom-color:#ff6c37}._tab_nt1hf_18._active_nt1hf_43:hover{color:#ff6c37}._logLevelSelector_nt1hf_52{display:flex;align-items:center;gap:8px;flex-shrink:0}._logLevelSelector_nt1hf_52 label{margin:0;font-size:12px;text-transform:uppercase}._logLevelSelector_nt1hf_52 select{width:150px}._subViewTabs_nt1hf_69{display:flex;background:#272727;border-bottom:1px solid #3d3d3d;padding:0 20px;gap:2px}._subTab_nt1hf_77{padding:8px 16px;background:transparent;color:#888;border:none;cursor:pointer;font-size:12px;border-bottom:2px solid transparent;transition:all .2s;text-transform:uppercase;font-weight:500}._subTab_nt1hf_77:hover{color:#b0b0b0;background:#2d2d2d}._subTab_nt1hf_77._active_nt1hf_43{color:#e0e0e0;border-bottom-color:#e0e0e0}._stageContent_nt1hf_100{flex:1;overflow:auto;padding:20px}._hookInputs_nt1hf_106,._hookLogs_nt1hf_107,._hookOutputs_nt1hf_108{max-width:1200px}._metadata_nt1hf_112{color:#b0b0b0;font-size:13px;margin-bottom:16px}._section_nt1hf_118{margin-bottom:20px}._noData_nt1hf_122{color:#666;font-style:italic;padding:20px}._error_nt1hf_128{background:#3d1f1f;color:#ff6b6b;padding:10px;border-radius:4px;margin-bottom:12px;border:1px solid #5d2f2f;font-size:13px}._returnValue_nt1hf_138{margin-bottom:12px;color:#b0b0b0;font-size:13px}._outputHeader_nt1hf_144{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}._outputTitle_nt1hf_151{color:#e0e0e0;font-size:13px;margin:0}._filterInfo_nt1hf_157{color:#888;font-size:11px}._logsContainer_nt1hf_162{background:#1e1e1e;padding:12px;border-radius:4px;font-size:12px;max-height:400px;overflow:auto}._logEntry_nt1hf_171{margin-bottom:4px}._logLevel_nt1hf_52{color:#666;margin-right:8px}._noLogs_nt1hf_180{color:#888;font-style:italic}._accessViolation_nt1hf_186{background:#3d1f1f;border-left:3px solid #ff6b6b;padding:8px 12px;margin:6px 0;border-radius:4px;display:flex;align-items:flex-start;gap:8px}._accessViolation_nt1hf_186 ._logLevel_nt1hf_52{color:#ff6b6b;font-weight:600}._violationIcon_nt1hf_202{font-size:16px;flex-shrink:0;line-height:1}._proxyWasmView_jh16a_1{display:flex;flex-direction:column;gap:1.5rem;padding:.75rem 1rem 1.5rem}*{box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;margin:0;padding:0;background:#1e1e1e;color:#e0e0e0}.container{max-width:1400px;margin:0 auto;background:#252525;min-height:100vh;display:flex;flex-direction:column}header{padding:12px 20px;background:#2d2d2d;border-bottom:1px solid #3d3d3d;display:flex;justify-content:space-between;align-items:center}h1{margin:0;color:#ff6c37;font-size:18px;font-weight:600}h2{color:#e0e0e0;margin:0 0 12px;font-size:14px;font-weight:600}h3{color:#b0b0b0;margin:0 0 8px;font-size:13px;font-weight:500}section{margin-bottom:10px}label{display:block;margin:0 0 6px;font-weight:500;color:#b0b0b0;font-size:12px;text-transform:uppercase}input[type=file],input[type=text],select,textarea{width:100%;padding:8px 12px;background:#1e1e1e;border:1px solid #3d3d3d;border-radius:4px;color:#e0e0e0;font-size:13px;font-family:Consolas,Monaco,Courier New,monospace}input[type=file]{padding:6px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}input:focus,select:focus,textarea:focus{outline:none;border-color:#ff6c37}textarea{resize:vertical;min-height:100px}button{background:#ff6c37;color:#fff;border:none;padding:8px 16px;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;transition:background .2s}button:hover:not(:disabled){background:#ff5722}button:disabled{background:#3d3d3d;color:#666;cursor:not-allowed}button.secondary{background:#3d3d3d;color:#e0e0e0}button.secondary:hover:not(:disabled){background:#4d4d4d}.error{background:#3d1f1f;color:#ff6b6b;padding:10px;border-radius:4px;margin-bottom:12px;border:1px solid #5d2f2f;font-size:13px}pre{white-space:pre-wrap;word-wrap:break-word;margin:8px 0;font-size:12px;font-family:Consolas,Monaco,Courier New,monospace;color:#b0b0b0;line-height:1.4}.empty-state{padding:4rem 2rem;text-align:center;color:#b0b0b0;background-color:#1e1e1e;border:2px dashed #3d3d3d;border-radius:8px;margin:2rem}.empty-state p{margin:0;font-size:1.1rem}