flashts 1.0.0 → 1.0.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ All notable changes to FlashTS will be documented in this file.
4
+
5
+ ## 1.0.2
6
+
7
+ Initial release of the FlashTS CLI and Unified Playground.
8
+
9
+ ### Added
10
+
11
+ - **NPM Package**: FlashTS is now available as a globally installable CLI.
12
+ - **Unified Server**: The backend now serves the frontend, simplifying deployment and local usage.
13
+ - **Smart CLI**: New `flashts` command with support for `--port`, `--share`, and `--no-open`.
14
+ - **Public Sharing**: Integration with `localtunnel` to generate shareable links.
15
+ - **Tunnel Password Detection**: The CLI now automatically displays the public IP required for the tunnel landing page.
16
+ - **Multi-file Support**: Full support for projects with multiple files and relative imports.
17
+ - **IntelliSense**: Automatic type injection for NPM packages.
18
+ - **NPM Manager**: Built-in UI to search, install, and manage dependencies.
19
+ - **Welcome Screen**: New user onboarding experience.
20
+
21
+ ### Technical Improvements
22
+
23
+ - Moved to a consolidated root `package.json` for better dependency management.
24
+ - Implemented Double-Sync VFS strategy in Monaco for seamless multi-file resolution.
25
+ - Added session-based execution isolation for better security.
@@ -0,0 +1,60 @@
1
+ # Contributing to FlashTS
2
+
3
+ First off, thanks for taking the time to contribute! FlashTS is a complex tool involving a virtual filesystem, a custom execution engine, and a unified CLI.
4
+
5
+ ## Architecture
6
+
7
+ ### Monorepo Structure
8
+
9
+ - `/client`: React 19 + Vite frontend.
10
+ - `/server`: Hono + Bun backend that handles execution and type serving.
11
+ - `/bin`: CLI entry point (`cli.ts`).
12
+
13
+ ### How Execution Works
14
+
15
+ When you click **Run**, the frontend bundles all project files into a JSON payload and sends it to the server. The server then:
16
+
17
+ 1. Creates an isolated session directory in `/tmp`.
18
+ 2. Writes the files to disk.
19
+ 3. Spawns a `bun run` process to execute the entry point.
20
+ 4. Streams logs back to the console via Hono.
21
+
22
+ ### Type Injection
23
+
24
+ FlashTS parses the dependency tree of installed NPM packages on the server and serves `.d.ts` files to the client, which are injected into Monaco's virtual filesystem (VFS).
25
+
26
+ ## Local Development
27
+
28
+ 1. **Clone the repo**
29
+
30
+ ```bash
31
+ git clone https://github.com/your-repo/flashts.git
32
+ cd flashts
33
+ ```
34
+
35
+ 2. **Install all dependencies** (from the root)
36
+
37
+ ```bash
38
+ bun install
39
+ ```
40
+
41
+ 3. **Development Servers**
42
+ To work on the frontend and backend simultaneously:
43
+ - **Frontend**: `cd client && bun run dev`
44
+ - **Backend**: `cd server && bun run index.ts`
45
+
46
+ 4. **Testing the CLI**
47
+ You can run the CLI locally using:
48
+ ```bash
49
+ bun bin/cli.ts
50
+ ```
51
+
52
+ ## Pull Request Process
53
+
54
+ 1. Fork the repository.
55
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`).
56
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`).
57
+ 4. Push to the branch (`git push origin feature/amazing-feature`).
58
+ 5. Open a Pull Request.
59
+
60
+ ---
package/README.md CHANGED
@@ -1,87 +1,57 @@
1
1
  <div align="center">
2
- <img src="./client/public/favicon.svg" alt="FlashTS" />
2
+ <img src="https://raw.githubusercontent.com/ZtaMDev/FlashTS/refs/heads/main/client/public/favicon.svg" alt="FlashTS" width="80" />
3
3
  <h1>FlashTS</h1>
4
+ <p><b>High-performance TypeScript/JavaScript Playground powered by Bun</b></p>
4
5
  </div>
5
6
 
6
- FlashTS is an ultra-fast, modern **JavaScript & TypeScript Playground** powered by [Bun](https://bun.sh/). It provides a professional IDE-like experience in the browser with instant execution, multi-file support, and automatic IntelliSense.
7
-
8
- ## Features
9
-
10
- - **Instant Execution**: Powered by Bun's high-performance runtime.
11
- - **Multi-file Workspace**: Create complex projects with imports and modules.
12
- - **Smart IntelliSense**: Automatic type injection for NPM packages via Monaco Editor.
13
- - **Live NPM Manager**: Install and manage dependencies in real-time.
14
- - **Safe Environment**: Session-based execution for isolated code running.
15
-
16
- ## Tech Stack
17
-
18
- ### Frontend (`/client`)
19
-
20
- - **React 19 + Vite**: Modern, high-performance UI framework.
21
- - **Monaco Editor**: The powerful editor behind VS Code, customized for FlashTS.
22
- - **Tailwind CSS**: For a sleek, responsive, and maintainable design.
23
- - **Lucide Icons**: Beautiful, consistent iconography.
24
- - **React Resizable Panels**: Professional workspace layouts.
25
-
26
- ### Backend (`/server`)
27
-
28
- - **Bun**: The fast all-in-one JavaScript runtime (Bundler, Runner, Package Manager).
29
- - **Hono**: Ultrafast web framework for the API layer.
30
- - **TypeScript VFS**: In-memory type resolution for project files.
31
-
32
- ## Getting Started
33
-
34
- ### Prerequisites
35
-
36
- - [Bun](https://bun.sh/) installed on your system.
37
-
38
- ### Installation
39
-
40
- 1. **Setup Server**:
41
-
42
- ```bash
43
- cd server
44
- bun install
45
- bun run index.ts
46
- ```
47
-
48
- 2. **Setup Client**:
7
+ ---
49
8
 
50
- ```bash
51
- cd client
52
- bun install
53
- bun run dev
54
- ```
9
+ FlashTS is an ultra-fast, modern playground that brings a professional IDE-like experience to your browser. Create, run, and share TypeScript projects with full NPM module support instantly.
55
10
 
56
- 3. **Open FlashTS**:
57
- Navigate to `http://localhost:5173` in your browser.
11
+ ## Quick Start (via NPM)
58
12
 
59
- ## Technical Architecture
13
+ The fastest way to experience FlashTS is via our CLI.
60
14
 
61
- ### Execution Engine
15
+ ```bash
16
+ # Run without installing
17
+ bunx flashts
62
18
 
63
- When you click **Run**, the frontend bundles all your project files and sends them to the server. The server:
19
+ # Or install globally
20
+ bun install -g flashts
21
+ flashts
22
+ ```
64
23
 
65
- 1. Creates a unique, isolated session directory in `/tmp`.
66
- 2. Writes all your files to disk.
67
- 3. Spawns a Bun process to execute the active entry point.
68
- 4. Streams the output (stdout/stderr) back to the client console.
24
+ ### Options
69
25
 
70
- ### Type Injection
26
+ | Flag | Description |
27
+ | --------------------- | ----------------------------------------------------- |
28
+ | `-p, --port <number>` | Set a custom port (default: 3000) |
29
+ | `-s, --share` | Generate a shareable public link with tunnel password |
30
+ | `--no-open` | Prevent the browser from opening automatically |
71
31
 
72
- FlashTS automatically fetches type definitions for any NPM package you install. The server parses the package's type tree and serves the `.d.ts` files to the frontend, which Monaco injects into its virtual filesystem. This ensures you always have perfect autocomplete.
32
+ ## Key Features
73
33
 
74
- ### Multi-file VFS
34
+ - **Blazing Fast**: Powered by **Bun**, the all-in-one JavaScript runtime.
35
+ - **Multi-file Workspace**: Work on complex projects with relative imports (`import { x } from "./utils"`).
36
+ - **Smart IntelliSense**: Real-time type definitions for your NPM dependencies.
37
+ - **NPM Management**: Search and install packages directly from the UI.
38
+ - **Instant Sharing**: Generate public links to share your playground with others.
39
+ - **Premium UI**: Dark mode, responsive design, and smooth animations.
75
40
 
76
- The editor maintains a **Double-Sync** strategy:
41
+ ## Usage Tips
77
42
 
78
- - Every file is a **Monaco Model** for active editing.
79
- - Every file is also registered as an **Ambient ExtraLib**, allowing the TypeScript engine to resolve relative imports (e.g., `./utils.ts`) instantly across tabs.
43
+ - **Run Shortcut**: `Ctrl + Shift + F` to execute the current file.
44
+ - **Package Manager**: `Ctrl + Shift + L` to quickly find and install new packages.
45
+ - **Sharing**: Use `flashts --share` to get a public URL and your tunnel password (IP).
80
46
 
81
47
  ## License
82
48
 
83
- Distributed under the **MIT License**.
49
+ FlashTS is open-source software licensed under the [MIT License](LICENSE).
84
50
 
85
51
  ---
86
52
 
87
- Built by ZMDev because all online options are payed, not open source or does not support npm modules correctly.
53
+ ### Contributing & Development
54
+
55
+ Interested in how FlashTS works or want to contribute? Check out our [CONTRIBUTING.md](./CONTRIBUTING.md) for architecture details and local setup instructions.
56
+
57
+ Built by **ZMDev** because all online options are payed, not open source or doesn't support npm modules correctly.
package/bin/cli.ts CHANGED
@@ -16,13 +16,13 @@ program
16
16
  .option("--no-open", "Do not open the browser automatically")
17
17
  .action(async (options: { port: string; share: any; open: any; }) => {
18
18
  const port = parseInt(options.port);
19
- const rootDir = process.cwd();
19
+ const packageRoot = join(import.meta.dir, "..");
20
20
 
21
21
  console.log(`\n⚡ ${pc.bold(pc.cyan("FlashTS"))} ${pc.dim("v1.0.0")}`);
22
22
  console.log(`${pc.green("➜")} Local: ${pc.cyan(`http://localhost:${port}`)}`);
23
23
 
24
24
  // Start the server process
25
- const serverPath = join(rootDir, "server", "index.ts");
25
+ const serverPath = join(packageRoot, "server", "index.ts");
26
26
  const serverProc = Bun.spawn(["bun", "run", serverPath], {
27
27
  env: { ...process.env, PORT: port.toString() },
28
28
  stdout: "inherit",
@@ -0,0 +1 @@
1
+ *,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--font-sans);font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--font-mono);font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.inset-x-0{left:0;right:0}.left-1{left:.25rem}.top-0{top:0}.top-1{top:.25rem}.z-10{z-index:10}.z-50{z-index:50}.z-\[10000\]{z-index:10000}.z-\[20000\]{z-index:20000}.z-\[9999\]{z-index:9999}.mx-1{margin-left:.25rem;margin-right:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-auto{margin-top:auto;margin-bottom:auto}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.ml-1{margin-left:.25rem}.mr-2{margin-right:.5rem}.mr-4{margin-right:1rem}.mt-2{margin-top:.5rem}.mt-auto{margin-top:auto}.flex{display:flex}.grid{display:grid}.hidden{display:none}.\!h-auto{height:auto!important}.h-1{height:.25rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-\[500px\]{max-height:500px}.max-h-\[90vh\]{max-height:90vh}.min-h-0{min-height:0}.w-10{width:2.5rem}.w-2{width:.5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-4{width:1rem}.w-6{width:1.5rem}.w-8{width:2rem}.w-\[600px\]{width:600px}.w-full{width:100%}.w-px{width:1px}.w-screen{width:100vw}.min-w-0{min-width:0}.max-w-2xl{max-width:42rem}.max-w-\[120px\]{max-width:120px}.max-w-sm{max-width:24rem}.flex-1{flex:1}.flex-shrink-0,.shrink-0{flex-shrink:0}.translate-x-0{--tw-translate-x:0px;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-5{--tw-translate-x:1.25rem;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:1s linear infinite spin}.cursor-pointer{cursor:pointer}.cursor-wait{cursor:wait}.touch-none{touch-action:none}.select-none{-webkit-user-select:none;user-select:none}.resize{resize:both}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.scroll-smooth{scroll-behavior:smooth}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-2{border-width:2px}.border-x{border-left-width:1px;border-right-width:1px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-t{border-top-width:1px}.border-none{border-style:none}.border-accent-primary{border-color:var(--accent-primary)}.border-border-color{border-color:var(--border-color)}.border-transparent{border-color:#0000}.border-white\/10{border-color:#ffffff1a}.border-white\/5{border-color:#ffffff0d}.border-white\/50{border-color:#ffffff80}.border-t-transparent{border-top-color:#0000}.border-t-white{--tw-border-opacity:1;border-top-color:rgb(255 255 255/var(--tw-border-opacity,1))}.bg-\[\#09090b\]{--tw-bg-opacity:1;background-color:rgb(9 9 11/var(--tw-bg-opacity,1))}.bg-\[\#0c0c0e\]{--tw-bg-opacity:1;background-color:rgb(12 12 14/var(--tw-bg-opacity,1))}.bg-\[\#1e1e20\]{--tw-bg-opacity:1;background-color:rgb(30 30 32/var(--tw-bg-opacity,1))}.bg-accent-primary{background-color:var(--accent-primary)}.bg-bg-primary{background-color:var(--bg-primary)}.bg-bg-secondary{background-color:var(--bg-secondary)}.bg-bg-tertiary{background-color:var(--bg-tertiary)}.bg-black\/20{background-color:#0003}.bg-black\/50{background-color:#00000080}.bg-black\/60{background-color:#0009}.bg-black\/80{background-color:#000c}.bg-blue-500\/10{background-color:#3b82f61a}.bg-border-color{background-color:var(--border-color)}.bg-green-500\/10{background-color:#22c55e1a}.bg-orange-500\/10{background-color:#f973161a}.bg-purple-500\/10{background-color:#a855f71a}.bg-red-500\/10{background-color:#ef44441a}.bg-transparent{background-color:#0000}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/10{background-color:#ffffff1a}.bg-white\/20{background-color:#fff3}.bg-white\/5{background-color:#ffffff0d}.bg-gradient-to-r{background-image:linear-gradient(to right, var(--tw-gradient-stops))}.from-transparent{--tw-gradient-from:transparent var(--tw-gradient-from-position);--tw-gradient-to:#0000 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.from-yellow-100{--tw-gradient-from:#fef9c3 var(--tw-gradient-from-position);--tw-gradient-to:#fef9c300 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to)}.via-accent-primary{--tw-gradient-to:#fff0 var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--accent-primary) var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-orange-100{--tw-gradient-to:#ffedd5 var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.\!p-0{padding:0!important}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pt-24{padding-top:6rem}.pt-4{padding-top:1rem}.text-center{text-align:center}.font-mono{font-family:var(--font-mono)}.text-\[10px\]{font-size:10px}.text-\[9px\]{font-size:9px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-medium{font-weight:500}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.italic{font-style:italic}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-accent-primary{color:var(--accent-primary)}.text-blue-400{--tw-text-opacity:1;color:rgb(96 165 250/var(--tw-text-opacity,1))}.text-green-400{--tw-text-opacity:1;color:rgb(74 222 128/var(--tw-text-opacity,1))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity,1))}.text-orange-400{--tw-text-opacity:1;color:rgb(251 146 60/var(--tw-text-opacity,1))}.text-purple-400{--tw-text-opacity:1;color:rgb(192 132 252/var(--tw-text-opacity,1))}.text-red-400{--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity,1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-text-primary{color:var(--text-primary)}.text-text-secondary{color:var(--text-secondary)}.text-transparent{color:#0000}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/80{color:#fffc}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-75{opacity:.75}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.outline-none{outline-offset:2px;outline:2px solid #0000}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-\[background-color\,color\]{transition-property:background-color,color;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-all{transition-property:all;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-opacity{transition-property:opacity;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-transform{transition-property:transform;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}:root{--bg-primary:#09090b;--bg-secondary:#18181b;--bg-tertiary:#27272a;--accent-primary:#f59e0b;--accent-glow:#f59e0b80;--text-primary:#f4f4f5;--text-secondary:#a1a1aa;--border-color:#27272a;--font-mono:"JetBrains Mono", "Fira Code", source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;--font-sans:"Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif}*{box-sizing:border-box;margin:0;padding:0}body{background-color:var(--bg-primary);color:var(--text-primary);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;overflow:hidden}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--bg-primary)}::-webkit-scrollbar-thumb{background:var(--bg-tertiary);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:#3f3f46}.glass{-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);background:#18181b99;border:1px solid #ffffff0d}.flex-center{justify-content:center;align-items:center;display:flex}.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{-ms-overflow-style:none;scrollbar-width:none}@keyframes glow{0%{box-shadow:0 0 5px var(--accent-glow)}50%{box-shadow:0 0 20px var(--accent-glow)}to{box-shadow:0 0 5px var(--accent-glow)}}@keyframes modal-entrance{0%{opacity:0;filter:blur(10px);transform:scale(.9)translateY(20px)}60%{filter:blur();transform:scale(1.02)translateY(-5px)}to{opacity:1;transform:scale(1)translateY(0)}}.animate-modal{animation:.5s cubic-bezier(.34,1.56,.64,1) forwards modal-entrance}.btn-primary{color:#fff;cursor:pointer;background:linear-gradient(135deg,#f59e0b,#ea580c);border:none;border-radius:8px;align-items:center;gap:.5rem;padding:.5rem 1.5rem;font-weight:600;transition:all .2s;display:flex}.btn-primary:hover{box-shadow:0 4px 12px var(--accent-glow);transform:translateY(-1px)}.btn-primary:active{transform:translateY(0)}.panel-header{border-bottom:1px solid var(--border-color);background:var(--bg-secondary);height:48px;color:var(--text-secondary);-webkit-user-select:none;user-select:none;justify-content:space-between;align-items:center;padding:0 1rem;font-size:.875rem;font-weight:500;display:flex}.placeholder\:text-white\/20::placeholder{color:#fff3}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:bg-accent-primary:hover{background-color:var(--accent-primary)}.hover\:bg-black\/30:hover{background-color:#0000004d}.hover\:bg-red-500\/20:hover{background-color:#ef444433}.hover\:bg-white\/10:hover{background-color:#ffffff1a}.hover\:bg-white\/20:hover{background-color:#fff3}.hover\:bg-white\/30:hover{background-color:#ffffff4d}.hover\:bg-white\/5:hover{background-color:#ffffff0d}.hover\:bg-white\/\[0\.08\]:hover{background-color:#ffffff14}.hover\:text-accent-primary:hover{color:var(--accent-primary)}.hover\:text-red-400:hover{--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity,1))}.hover\:text-text-primary:hover{color:var(--text-primary)}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.focus\:border-accent-primary:focus{border-color:var(--accent-primary)}.active\:scale-95:active{--tw-scale-x:.95;--tw-scale-y:.95;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:hover\:bg-transparent:hover:disabled{background-color:#0000}.group:hover .group-hover\:scale-110{--tw-scale-x:1.1;--tw-scale-y:1.1;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-text-primary{color:var(--text-primary)}.group:hover .group-hover\:opacity-100{opacity:1}@media (min-width:640px){.sm\:block{display:block}.sm\:flex{display:flex}.sm\:w-32{width:8rem}.sm\:w-auto{width:auto}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}}@media (min-width:768px){.md\:mb-8{margin-bottom:2rem}.md\:block{display:block}.md\:flex{display:flex}.md\:h-14{height:3.5rem}.md\:h-4{height:1rem}.md\:h-6{height:1.5rem}.md\:h-8{height:2rem}.md\:h-auto{height:auto}.md\:max-h-none{max-height:none}.md\:w-1{width:.25rem}.md\:w-12{width:3rem}.md\:w-14{width:3.5rem}.md\:w-4{width:1rem}.md\:w-6{width:1.5rem}.md\:w-8{width:2rem}.md\:translate-x-6{--tw-translate-x:1.5rem;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:gap-4{gap:1rem}.md\:gap-6{gap:1.5rem}.md\:rounded-2xl{border-radius:1rem}.md\:p-4{padding:1rem}.md\:p-6{padding:1.5rem}.md\:p-8{padding:2rem}.md\:px-6{padding-left:1.5rem;padding-right:1.5rem}.md\:py-3{padding-top:.75rem;padding-bottom:.75rem}.md\:text-3xl{font-size:1.875rem;line-height:2.25rem}.md\:text-\[10px\]{font-size:10px}.md\:text-base{font-size:1rem;line-height:1.5rem}.md\:text-sm{font-size:.875rem;line-height:1.25rem}.md\:text-xs{font-size:.75rem;line-height:1rem}}