grok-studio 0.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.
- package/README.md +117 -0
- package/dist/client/assets/index-CxpDl-6Y.css +1 -0
- package/dist/client/assets/index-aP61AD4r.js +15 -0
- package/dist/client/index.html +13 -0
- package/dist/server/cli.js +1949 -0
- package/package.json +71 -0
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Grok Studio
|
|
2
|
+
|
|
3
|
+
Self-hosted Grok generation workspace for local/LAN use. The app keeps xAI credentials on the server, lets the browser upload or paste an image, optionally prepares a video-ready first frame, then generates and stores video outputs on disk.
|
|
4
|
+
|
|
5
|
+
## Product Model
|
|
6
|
+
|
|
7
|
+
The UI is organized around generated outputs, active work, and source-scoped lineage.
|
|
8
|
+
|
|
9
|
+
- **Left rail**: `+` creates a new source image. Active Jobs appears above the output gallery when queued or running work exists; it is global and not tied to the currently selected source. Outputs are typed as `Frame` or `Video`; status text is only for exceptional or in-progress states.
|
|
10
|
+
- **Result Graph**: the center canvas shows lineage for the current source. Nodes are concrete artifacts/runs:
|
|
11
|
+
- `Source` is the root image.
|
|
12
|
+
- each Prep run creates a separate `Frame` node.
|
|
13
|
+
- each Video run creates a separate `Video` node.
|
|
14
|
+
- **Inspector**: the right panel is the only place for details and actions. Select a node to inspect it, download video output, rerun, prepare another frame, or animate the selected frame.
|
|
15
|
+
|
|
16
|
+
Lineage is data-driven:
|
|
17
|
+
|
|
18
|
+
- Source-linked video jobs attach only when `inputFrame.source === "source"` and the job's `clientSourceId` matches the current source.
|
|
19
|
+
- Frame-linked video jobs attach only when `inputFrame.source === "prep"` and `preparedImageId` matches a frame in the current graph.
|
|
20
|
+
- UI cache must not decide graph edges. If lineage fields are missing, do not guess by recent history.
|
|
21
|
+
|
|
22
|
+
## Run
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
vp install
|
|
26
|
+
cp .env.example .env
|
|
27
|
+
vpr build
|
|
28
|
+
vpr start
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
For normal local use:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
vpr launch
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`launch` builds the app, checks xAI auth, opens the browser login flow when no token exists, then starts the web app. Open <http://127.0.0.1:8787>.
|
|
38
|
+
|
|
39
|
+
## LAN Access
|
|
40
|
+
|
|
41
|
+
For local-network access, set:
|
|
42
|
+
|
|
43
|
+
```dotenv
|
|
44
|
+
HOST=0.0.0.0
|
|
45
|
+
ACCESS_TOKEN=
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Then restart the service and open `http://<mac-lan-ip>:8787` or `http://<mac-local-hostname>.local:8787` from another device on the same LAN.
|
|
49
|
+
|
|
50
|
+
`ACCESS_TOKEN` can be left empty for trusted local/LAN use. Set it before exposing the app outside a trusted network.
|
|
51
|
+
|
|
52
|
+
## Configuration
|
|
53
|
+
|
|
54
|
+
- `HOST` / `PORT` control where the server binds.
|
|
55
|
+
- `ACCESS_TOKEN` optionally protects browser/API access outside loopback.
|
|
56
|
+
- `WORKSPACE_DIR` stores `images/`, `videos/`, `jobs/`, and `prepared-images/`.
|
|
57
|
+
- `XAI_AUTH_MODE=oauth` reads `XAI_OAUTH_TOKEN_FILE`, refreshes it when needed, and `vpr launch` can bootstrap it interactively.
|
|
58
|
+
- `XAI_AUTH_MODE=api_key` uses `XAI_API_KEY`.
|
|
59
|
+
- `XAI_VIDEO_MODEL` controls image-to-video generation.
|
|
60
|
+
- `XAI_IMAGE_MODEL` controls first-frame image editing.
|
|
61
|
+
- `DEFAULT_DURATION_SECONDS` supports up to 15 seconds.
|
|
62
|
+
- `MAX_VARIATIONS` limits sequential variations per video job.
|
|
63
|
+
|
|
64
|
+
The app binds to `127.0.0.1` by default. Use `HOST=0.0.0.0` only for LAN/tunnel exposure.
|
|
65
|
+
|
|
66
|
+
## Grok Login Test
|
|
67
|
+
|
|
68
|
+
To test the xAI/Grok browser login without touching the token file used by the running service:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
vpr login
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The command opens the xAI authorization page, waits for the local callback, saves the token state to a test path, and verifies it with the API. If xAI shows a fallback code instead of redirecting, paste that code into the terminal prompt.
|
|
75
|
+
|
|
76
|
+
Useful variants:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
vpr login --check
|
|
80
|
+
vpr login --print-url-only
|
|
81
|
+
vpr login --live --force
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`vpr login` is Vite+'s shorthand for `vp run login`. Vite+ built-in top-level commands such as `vp build` and `vp test` cannot be extended by this project, so custom project commands use `vp run <task>` / `vpr <task>`.
|
|
85
|
+
|
|
86
|
+
By default, login writes to `~/.grok-video-web/login-test/xai-oauth.json` so repeated login-flow tests do not disturb the live service token. Use `--live --force` only when intentionally repairing `XAI_OAUTH_TOKEN_FILE`. `--print-url-only` is only for smoke-checking that the OAuth authorization URL can be built; it exits immediately, so do not use that URL to complete a real login.
|
|
87
|
+
|
|
88
|
+
## Quality Loop
|
|
89
|
+
|
|
90
|
+
Vite+ (`vp`/`vpr`) owns build, lint/format/type checks, and tests:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
vpr fmt
|
|
94
|
+
vpr fmt:check
|
|
95
|
+
vpr lint
|
|
96
|
+
vpr lint:fix
|
|
97
|
+
vpr check
|
|
98
|
+
vp test
|
|
99
|
+
vpr build
|
|
100
|
+
vpr smoke
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Quality gates include:
|
|
104
|
+
|
|
105
|
+
- React-specific lint rules for hooks, effect dependencies, JSX keys, nested components, unsafe JSX, and button types.
|
|
106
|
+
- Type-aware linting and TypeScript checks.
|
|
107
|
+
- Architecture guardrails in `tests/architecture.test.ts` to keep the main app shell thin, limit local React state in `App.tsx`, split stylesheet ownership, and keep server route files focused.
|
|
108
|
+
- Browser smoke coverage in `scripts/smoke.mjs`, including paste input, image lightbox, video-card scroll behavior, and legacy history not restoring unrelated Prep outputs.
|
|
109
|
+
|
|
110
|
+
## Local Service
|
|
111
|
+
|
|
112
|
+
If installed as the local launchd service, restart it after building:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
launchctl kickstart -k gui/$(id -u)/com.pengx17.grok-video-web
|
|
116
|
+
curl -fsS http://127.0.0.1:8787/health
|
|
117
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.yarl__fullsize{width:100%;height:100%}.yarl__relative{position:relative}.yarl__portal{opacity:0;pointer-events:auto;transition:opacity var(--yarl__fade_animation_duration,.25s) var(--yarl__fade_animation_timing_function,ease);z-index:var(--yarl__portal_zindex,9999);position:fixed;inset:0;overflow:hidden}.yarl__portal_open{opacity:1}.yarl__container{background-color:var(--yarl__container_background_color,var(--yarl__color_backdrop,#000));overscroll-behavior:var(--yarl__controller_overscroll_behavior,contain);touch-action:var(--yarl__controller_touch_action,none);-webkit-user-select:none;user-select:none;outline:none;position:absolute;inset:0;overflow:hidden}.yarl__carousel{height:100%;opacity:var(--yarl__pull_opacity,1);transform:translate(var(--yarl__swipe_offset,0),var(--yarl__pull_offset,0));width:calc(100% + (var(--yarl__carousel_slides_count) - 1)*(100% + var(--yarl__carousel_spacing_px,0)*1px + var(--yarl__carousel_spacing_percent,0)*1%));flex:none;place-content:center;align-items:stretch;display:flex}.yarl__carousel_with_slides{-moz-column-gap:calc(var(--yarl__carousel_spacing_px,0)*1px + 100/(var(--yarl__carousel_slides_count)*100 + (var(--yarl__carousel_slides_count) - 1)*var(--yarl__carousel_spacing_percent,0))*var(--yarl__carousel_spacing_percent,0)*1%);column-gap:calc(var(--yarl__carousel_spacing_px,0)*1px + 100/(var(--yarl__carousel_slides_count)*100 + (var(--yarl__carousel_slides_count) - 1)*var(--yarl__carousel_spacing_percent,0))*var(--yarl__carousel_spacing_percent,0)*1%)}.yarl__flex_center{place-content:center;align-items:center;display:flex}.yarl__slide{padding:calc(var(--yarl__carousel_padding_px,0)*1px + 100/(var(--yarl__carousel_slides_count)*100 + (var(--yarl__carousel_slides_count) - 1)*var(--yarl__carousel_spacing_percent,0))*var(--yarl__carousel_padding_percent,0)*1%);flex:1;position:relative;overflow:hidden}[dir=rtl] .yarl__slide{--yarl__direction:-1}.yarl__slide_image{-o-object-fit:contain;object-fit:contain;touch-action:var(--yarl__controller_touch_action,none);-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;max-width:100%;max-height:100%}.yarl__slide_image_cover{-o-object-fit:cover;object-fit:cover;width:100%;height:100%}.yarl__slide_image_loading{opacity:0}@media screen and (width>=800px){.yarl__slide_wrapper:not(.yarl__slide_wrapper_interactive) .yarl__slide_image{-webkit-backface-visibility:hidden;-webkit-transform-style:preserve-3d;-webkit-transform:translateZ(0)}}.yarl__slide_placeholder{line-height:0;position:absolute;top:50%;left:50%;transform:translate(-50%)translateY(-50%)}.yarl__slide_loading{color:var(--yarl__slide_icon_loading_color,var(--yarl__color_button,#fffc));animation:1s linear yarl__delayed_fadein}.yarl__slide_loading line{animation:1s linear infinite yarl__stroke_opacity}.yarl__slide_loading line:first-of-type{animation-delay:-1.875s}.yarl__slide_loading line:nth-of-type(2){animation-delay:-1.75s}.yarl__slide_loading line:nth-of-type(3){animation-delay:-1.625s}.yarl__slide_loading line:nth-of-type(4){animation-delay:-1.5s}.yarl__slide_loading line:nth-of-type(5){animation-delay:-1.375s}.yarl__slide_loading line:nth-of-type(6){animation-delay:-1.25s}.yarl__slide_loading line:nth-of-type(7){animation-delay:-1.125s}.yarl__slide_loading line:nth-of-type(8){animation-delay:-1s}.yarl__slide_error{color:var(--yarl__slide_icon_error_color,red);height:var(--yarl__slide_icon_error_size,48px);width:var(--yarl__slide_icon_error_size,48px)}@media (prefers-reduced-motion){.yarl__portal,.yarl__slide{transition:unset}.yarl__slide_loading,.yarl__slide_loading line{animation:unset}}.yarl__toolbar{padding:var(--yarl__toolbar_padding,8px);justify-content:flex-end;display:flex;position:absolute;inset:0 0 auto auto}[dir=rtl] .yarl__toolbar{inset:0 auto auto 0}.yarl__icon{height:var(--yarl__icon_size,32px);width:var(--yarl__icon_size,32px)}.yarl__button{appearance:none;background-color:var(--yarl__button_background_color,transparent);border:var(--yarl__button_border,0);color:var(--yarl__color_button,#fffc);cursor:pointer;filter:var(--yarl__button_filter,drop-shadow(2px 2px 2px #000c));margin:var(--yarl__button_margin,0);padding:var(--yarl__button_padding,8px);-webkit-tap-highlight-color:transparent;outline:none;line-height:0}.yarl__button:focus{color:var(--yarl__color_button_active,#fff)}.yarl__button:focus:not(:focus-visible){color:var(--yarl__color_button,#fffc)}.yarl__button:focus-visible{color:var(--yarl__color_button_active,#fff)}@media (hover:hover){.yarl__button:focus-visible:hover,.yarl__button:focus:hover,.yarl__button:hover{color:var(--yarl__color_button_active,#fff)}}.yarl__button:disabled{color:var(--yarl__color_button_disabled,#fff6);cursor:default}.yarl__navigation_next,.yarl__navigation_prev{padding:var(--yarl__navigation_button_padding,24px 16px);position:absolute;top:50%;transform:translateY(-50%)}.yarl__navigation_prev{left:0}[dir=rtl] .yarl__navigation_prev{left:unset;right:0;transform:translateY(-50%)rotate(180deg)}.yarl__navigation_next{right:0}[dir=rtl] .yarl__navigation_next{left:0;right:unset;transform:translateY(-50%)rotate(180deg)}.yarl__no_scroll{overscroll-behavior:none;height:100%;overflow:hidden}@keyframes yarl__delayed_fadein{0%{opacity:0}80%{opacity:0}to{opacity:1}}@keyframes yarl__stroke_opacity{0%{stroke-opacity:1}to{stroke-opacity:.125}}.react-flow{--xy-edge-stroke-default:#b1b1b7;--xy-edge-stroke-width-default:1;--xy-edge-stroke-selected-default:#555;--xy-connectionline-stroke-default:#b1b1b7;--xy-connectionline-stroke-width-default:1;--xy-attribution-background-color-default:#ffffff80;--xy-minimap-background-color-default:#fff;--xy-minimap-mask-background-color-default:#f0f0f099;--xy-minimap-mask-stroke-color-default:transparent;--xy-minimap-mask-stroke-width-default:1;--xy-minimap-node-background-color-default:#e2e2e2;--xy-minimap-node-stroke-color-default:transparent;--xy-minimap-node-stroke-width-default:2;--xy-background-color-default:transparent;--xy-background-pattern-dots-color-default:#91919a;--xy-background-pattern-lines-color-default:#eee;--xy-background-pattern-cross-color-default:#e2e2e2;background-color:var(--xy-background-color,var(--xy-background-color-default));--xy-node-color-default:inherit;--xy-node-border-default:1px solid #1a192b;--xy-node-background-color-default:#fff;--xy-node-group-background-color-default:#f0f0f040;--xy-node-boxshadow-hover-default:0 1px 4px 1px #00000014;--xy-node-boxshadow-selected-default:0 0 0 .5px #1a192b;--xy-node-border-radius-default:3px;--xy-handle-background-color-default:#1a192b;--xy-handle-border-color-default:#fff;--xy-selection-background-color-default:#0059dc14;--xy-selection-border-default:1px dotted #0059dccc;--xy-controls-button-background-color-default:#fefefe;--xy-controls-button-background-color-hover-default:#f4f4f4;--xy-controls-button-color-default:inherit;--xy-controls-button-color-hover-default:inherit;--xy-controls-button-border-color-default:#eee;--xy-controls-box-shadow-default:0 0 2px 1px #00000014;--xy-edge-label-background-color-default:#fff;--xy-edge-label-color-default:inherit;--xy-resize-background-color-default:#3367d9;direction:ltr}.react-flow.dark{--xy-edge-stroke-default:#3e3e3e;--xy-edge-stroke-width-default:1;--xy-edge-stroke-selected-default:#727272;--xy-connectionline-stroke-default:#b1b1b7;--xy-connectionline-stroke-width-default:1;--xy-attribution-background-color-default:#96969640;--xy-minimap-background-color-default:#141414;--xy-minimap-mask-background-color-default:#3c3c3c99;--xy-minimap-mask-stroke-color-default:transparent;--xy-minimap-mask-stroke-width-default:1;--xy-minimap-node-background-color-default:#2b2b2b;--xy-minimap-node-stroke-color-default:transparent;--xy-minimap-node-stroke-width-default:2;--xy-background-color-default:#141414;--xy-background-pattern-dots-color-default:#777;--xy-background-pattern-lines-color-default:#777;--xy-background-pattern-cross-color-default:#777;--xy-node-color-default:#f8f8f8;--xy-node-border-default:1px solid #3c3c3c;--xy-node-background-color-default:#1e1e1e;--xy-node-group-background-color-default:#f0f0f040;--xy-node-boxshadow-hover-default:0 1px 4px 1px #ffffff14;--xy-node-boxshadow-selected-default:0 0 0 .5px #999;--xy-handle-background-color-default:#bebebe;--xy-handle-border-color-default:#1e1e1e;--xy-selection-background-color-default:#c8c8dc14;--xy-selection-border-default:1px dotted #c8c8dccc;--xy-controls-button-background-color-default:#2b2b2b;--xy-controls-button-background-color-hover-default:#3e3e3e;--xy-controls-button-color-default:#f8f8f8;--xy-controls-button-color-hover-default:#fff;--xy-controls-button-border-color-default:#5b5b5b;--xy-controls-box-shadow-default:0 0 2px 1px #00000014;--xy-edge-label-background-color-default:#141414;--xy-edge-label-color-default:#f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props,var(--xy-background-color,var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{width:100%;height:100%;position:absolute;top:0;left:0}.react-flow__pane{z-index:1;touch-action:none}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke,var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width,var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke,var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width,var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{pointer-events:none;position:absolute;overflow:visible}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:.5s linear infinite dashdraw}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected,var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke,var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke,var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:.5s linear infinite dashdraw}svg.react-flow__connectionline{z-index:1001;position:absolute;overflow:visible}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{-webkit-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default;position:absolute}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:0 0;pointer-events:none}.react-flow__nodesselection-rect{pointer-events:all;cursor:grab;position:absolute}.react-flow__handle{pointer-events:none;background-color:var(--xy-handle-background-color,var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color,var(--xy-handle-border-color-default));border-radius:100%;width:6px;min-width:5px;height:6px;min-height:5px;position:absolute}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;bottom:0;left:50%;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{z-index:5;margin:15px;position:absolute}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px)translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px)translateY(-50%)}.react-flow__attribution{background:var(--xy-attribution-background-color,var(--xy-attribution-background-color-default));margin:0;padding:2px 3px;font-size:10px}.react-flow__attribution a{color:#999;text-decoration:none}@keyframes dashdraw{0%{stroke-dashoffset:10px}}.react-flow__edgelabel-renderer{pointer-events:none;-webkit-user-select:none;user-select:none;width:100%;height:100%;position:absolute;top:0;left:0}.react-flow__viewport-portal{-webkit-user-select:none;user-select:none;width:100%;height:100%;position:absolute;top:0;left:0}.react-flow__minimap{background:var(--xy-minimap-background-color-props,var(--xy-minimap-background-color,var(--xy-minimap-background-color-default)))}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var(--xy-minimap-mask-background-color-props,var(--xy-minimap-mask-background-color,var(--xy-minimap-mask-background-color-default)));stroke:var(--xy-minimap-mask-stroke-color-props,var(--xy-minimap-mask-stroke-color,var(--xy-minimap-mask-stroke-color-default)));stroke-width:var(--xy-minimap-mask-stroke-width-props,var(--xy-minimap-mask-stroke-width,var(--xy-minimap-mask-stroke-width-default)))}.react-flow__minimap-node{fill:var(--xy-minimap-node-background-color-props,var(--xy-minimap-node-background-color,var(--xy-minimap-node-background-color-default)));stroke:var(--xy-minimap-node-stroke-color-props,var(--xy-minimap-node-stroke-color,var(--xy-minimap-node-stroke-color-default)));stroke-width:var(--xy-minimap-node-stroke-width-props,var(--xy-minimap-node-stroke-width,var(--xy-minimap-node-stroke-width-default)))}.react-flow__background-pattern.dots{fill:var(--xy-background-pattern-color-props,var(--xy-background-pattern-color,var(--xy-background-pattern-dots-color-default)))}.react-flow__background-pattern.lines{stroke:var(--xy-background-pattern-color-props,var(--xy-background-pattern-color,var(--xy-background-pattern-lines-color-default)))}.react-flow__background-pattern.cross{stroke:var(--xy-background-pattern-color-props,var(--xy-background-pattern-color,var(--xy-background-pattern-cross-color-default)))}.react-flow__controls{box-shadow:var(--xy-controls-box-shadow,var(--xy-controls-box-shadow-default));flex-direction:column;display:flex}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{background:var(--xy-controls-button-background-color,var(--xy-controls-button-background-color-default));border:none;border-bottom:1px solid var(--xy-controls-button-border-color-props,var(--xy-controls-button-border-color,var(--xy-controls-button-border-color-default)));width:26px;height:26px;color:var(--xy-controls-button-color-props,var(--xy-controls-button-color,var(--xy-controls-button-color-default)));cursor:pointer;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;padding:4px;display:flex}.react-flow__controls-button svg{fill:currentColor;width:100%;max-width:12px;max-height:12px}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{border-radius:var(--xy-node-border-radius,var(--xy-node-border-radius-default));width:150px;color:var(--xy-node-color,var(--xy-node-color-default));text-align:center;border:var(--xy-node-border,var(--xy-node-border-default));background-color:var(--xy-node-background-color,var(--xy-node-background-color-default));padding:10px;font-size:12px}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover,var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected,var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color,var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color,var(--xy-selection-background-color-default));border:var(--xy-selection-border,var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var(--xy-controls-button-background-color-hover-props,var(--xy-controls-button-background-color-hover,var(--xy-controls-button-background-color-hover-default)));color:var(--xy-controls-button-color-hover-props,var(--xy-controls-button-color-hover,var(--xy-controls-button-color-hover-default)))}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var(--xy-controls-button-border-color-props,var(--xy-controls-button-border-color,var(--xy-controls-button-border-color-default)))}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{background-color:var(--xy-resize-background-color,var(--xy-resize-background-color-default));border:1px solid #fff;border-radius:1px;width:5px;height:5px;translate:-50% -50%}.react-flow__resize-control.handle.left{top:50%;left:0}.react-flow__resize-control.handle.right{top:50%;left:100%}.react-flow__resize-control.handle.top{top:0;left:50%}.react-flow__resize-control.handle.bottom{top:100%;left:50%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color,var(--xy-resize-background-color-default));border-style:solid;border-width:0}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;height:100%;top:0;transform:translate(-50%)}.react-flow__resize-control.line.left{border-left-width:1px;left:0}.react-flow__resize-control.line.right{border-right-width:1px;left:100%}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{width:100%;height:1px;left:0;transform:translateY(-50%)}.react-flow__resize-control.line.top{border-top-width:1px;top:0}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color,var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color,var(--xy-edge-label-color-default))}:root{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;--paper:#d8d6ca;--ink:#181a18;--muted:#676b63;--panel:#eeeee4;--line:#8d9186;--accent:#f36b22;--accent-dark:#9c4219;--mint:#287563;--charcoal:#1d211f;--steel:#4d5654;--warning:#f4b43f;--danger:#8d2f23;--shadow:0 18px 0 #181a1814, 0 28px 60px #181a182b;background:var(--paper);color:var(--ink);font-family:DIN Alternate,Avenir Next Condensed,PingFang SC,Hiragino Sans GB,sans-serif}*{box-sizing:border-box}body{background:linear-gradient(90deg, #181a181a 1px, transparent 1px), linear-gradient(#181a1814 1px, transparent 1px), linear-gradient(135deg, #f4b43f24, transparent 26%), var(--paper);background-size:30px 30px,30px 30px,100% 100%;min-height:100vh;margin:0}button,textarea,input{font:inherit}button{touch-action:manipulation}h1,h2,h3,p{margin:0}.shell{width:min(1560px,100vw - 36px);margin:0 auto;padding:24px 0 28px}.topbar{justify-content:space-between;align-items:end;gap:16px;padding:8px 0 18px;display:flex}h1{text-transform:uppercase;letter-spacing:0;font-family:DIN Condensed,Avenir Next Condensed,PingFang SC,sans-serif;font-size:clamp(38px,5.2vw,76px);line-height:.86}.eyebrow{color:var(--accent-dark);text-transform:uppercase;letter-spacing:0;align-items:center;gap:6px;font-size:12px;font-weight:850;display:inline-flex}.app-layout{grid-template-columns:148px minmax(0,1fr);align-items:start;gap:14px;display:grid}.history-sidebar{border:2px solid var(--charcoal);max-height:calc(100svh - 32px);box-shadow:var(--shadow);background:linear-gradient(#f7f7eff0,#e2e2d8f2);border-radius:4px;padding:10px;position:sticky;top:16px;overflow:hidden}.history-head{border-bottom:2px solid #181a182e;justify-content:space-between;align-items:end;gap:8px;padding:0 0 9px;display:flex}.history-head span{font-size:17px;font-weight:950}.history-head small{color:var(--muted);font-size:11px;font-weight:850}.history-new{border:2px solid var(--charcoal);background:var(--accent);color:#fff;cursor:pointer;border-radius:3px;place-items:center;width:28px;height:28px;display:grid;box-shadow:0 3px #181a182e}.history-toggle{border:2px solid var(--charcoal);border-radius:3px;display:inline-flex;overflow:hidden}.history-toggle button{text-transform:uppercase;cursor:pointer;color:var(--muted);background:#f3f2e8;padding:4px 9px;font-size:11px;font-weight:950}.history-toggle button.active{background:var(--charcoal);color:#f5f0d5}.outputs-panel{gap:8px;margin-top:10px;display:grid}.output-filter{gap:5px;display:flex}.output-filter button{text-transform:uppercase;border:1px solid var(--line);color:var(--muted);cursor:pointer;background:#f3f2e8;border-radius:3px;flex:1;padding:3px 4px;font-size:10px;font-weight:900}.output-filter button.active{background:var(--accent);border-color:var(--charcoal);color:#fff}.outputs-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:7px;max-height:calc(100svh - 150px);padding-right:2px;display:grid;overflow:auto}.output-card{border:2px solid var(--charcoal);cursor:pointer;background:#f3f2e8;border-radius:3px;gap:4px;padding:4px;display:grid;position:relative}.output-card.active{outline:2px solid var(--accent);outline-offset:1px}.output-card img{aspect-ratio:1;object-fit:cover;background:#151715;border-radius:2px;width:100%}.output-card>i{aspect-ratio:1;background:#151715;border-radius:2px;width:100%}.output-kind{border:1px solid var(--charcoal);text-transform:uppercase;color:var(--ink);background:#f4f3e9;border-radius:999px;padding:1px 6px;font-size:9px;font-weight:900;position:absolute;top:7px;left:7px}.output-kind.video{background:var(--charcoal);color:#f5f0d5}.output-card small{color:var(--muted);font-size:10px;font-weight:800}.history-list{gap:9px;max-height:calc(100svh - 96px);margin-top:10px;padding-right:2px;display:grid;overflow:auto}.history-list button{border:2px solid var(--charcoal);cursor:pointer;text-align:left;background:#f3f2e8;border-radius:3px;gap:5px;width:100%;padding:5px;display:grid;position:relative}.history-list button.active{border-color:var(--accent);color:#f5f0d5;box-shadow:inset 0 0 0 2px var(--accent);background:#191d1b}.history-list img{aspect-ratio:1;object-fit:cover;background:#222;border-radius:2px;width:100%}.history-list strong{font-size:12px;line-height:1.1}.history-list small{color:var(--muted);font-size:10px;line-height:1.25}.history-list button.active small{color:#d6cfad}.history-current-dot{background:var(--accent);border:2px solid #f5f0d5;border-radius:999px;width:13px;height:13px;position:absolute;top:9px;right:9px;box-shadow:0 0 0 2px #181a189e}.history-status{background:var(--charcoal);min-height:20px;color:var(--warning);border:1px solid #ffffffb8;border-radius:2px;align-items:center;padding:0 6px;font-size:10px;font-weight:950;display:inline-flex;position:absolute;top:8px;left:8px}.history-status.succeeded{background:var(--mint);color:#fff}.history-status.running,.history-status.queued{background:var(--warning);color:var(--ink)}.history-status.failed{background:var(--danger);color:#fff}.empty-history{min-height:140px;color:var(--muted);text-align:center;border:2px dashed var(--line);place-items:center;gap:8px;padding:14px;display:grid}.workspace{grid-template-columns:minmax(660px,1.42fr) minmax(420px,.82fr);align-items:start;gap:14px;display:grid}.graph-pane,.inspector-pane,.gate-panel{border:2px solid var(--charcoal);box-shadow:var(--shadow);background:linear-gradient(#f7f7eff0,#e2e2d8f5);border-radius:4px}.graph-pane,.inspector-pane{padding:14px}.graph-pane{align-self:start;position:sticky;top:16px}.pane-title{border-bottom:2px solid #181a1833;grid-template-columns:38px minmax(0,1fr);align-items:start;gap:10px;margin-bottom:12px;padding-bottom:11px;display:grid}.pane-title>span{background:var(--charcoal);width:34px;height:34px;color:var(--warning);border:2px solid var(--charcoal);border-radius:2px;place-items:center;display:grid}.pane-title h2{font-size:22px;line-height:1.05}.pane-title p{color:var(--muted);margin-top:4px;font-size:12px;font-weight:800;line-height:1.4}.node-library{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin-bottom:12px;display:grid}.node-library button:disabled{opacity:.45;cursor:not-allowed}.node-library-label{color:var(--muted);text-transform:uppercase;margin-bottom:6px;font-size:12px;font-weight:950}.node-library button,.inspector-tabs button,.toggle,.ghost,.generate,.preset,.segment button,.prep-button,.output-pick,.prompt-preview-head button{border:2px solid var(--charcoal);color:var(--ink);cursor:pointer;background:#f5f4ea;border-radius:3px;transition:background .12s,color .12s,border-color .12s,box-shadow .12s,transform .12s}.node-library button{text-align:left;align-content:start;gap:3px;min-height:54px;padding:8px;display:grid}.node-library b{text-transform:uppercase;font-size:13px;font-weight:950}.node-library span{color:var(--muted);font-size:11px;font-weight:800;line-height:1.25}.operator-canvas{border:2px solid var(--charcoal);background-color:#d3d5cc;background-image:radial-gradient(circle at 1px 1px,#181a1840 1px,#0000 0),none;background-position:0 0,0 0;background-repeat:repeat,repeat;background-size:18px 18px;background-attachment:scroll,scroll;background-origin:padding-box,padding-box;background-clip:border-box,border-box;border-radius:3px;height:clamp(420px,56svh,640px);position:relative;overflow:hidden}.graph-loader{z-index:20;border:2px solid var(--charcoal);color:var(--ink);text-transform:uppercase;background:#f4f3e9;border-radius:3px;align-items:center;gap:6px;padding:5px 10px;font-size:11px;font-weight:900;display:flex;position:absolute;top:12px;right:12px;box-shadow:0 4px #181a1829}.operator-canvas .react-flow__controls{border:2px solid var(--charcoal);box-shadow:none}.operator-canvas .react-flow__controls button{background:#f5f4ea;border-bottom:1px solid #181a1840}.operator-canvas .react-flow__edge-textbg{fill:#f4f3e9;stroke:var(--charcoal);stroke-width:1px}.operator-canvas .react-flow__edge-text{fill:var(--charcoal);font-size:11px;font-weight:900}.operator-canvas .react-flow__edge-path{stroke:#59605b;stroke-width:2.5px}.operator-canvas .react-flow__node{max-height:none;overflow:visible}.operator-canvas .operator-edge.active .react-flow__edge-path{stroke:var(--accent);stroke-width:3.25px}.operator-node{border:2px solid var(--charcoal);width:236px;min-height:252px;color:var(--ink);text-align:left;cursor:pointer;background:#f4f3e9;border-radius:3px;max-height:none;padding:9px;display:block;overflow:visible;box-shadow:0 8px #181a181f}.operator-node.active{color:#f5f0d5;box-shadow:inset 0 0 0 2px var(--accent), 0 8px 0 #181a1833;background:#191d1b}.operator-node.video{height:auto;min-height:0}.operator-node-head{justify-content:space-between;align-items:center;gap:8px;margin-bottom:7px;display:flex}.operator-node-head strong{font-size:18px;font-weight:950;line-height:1}.operator-node-head span{color:var(--accent-dark);text-transform:uppercase;font-family:Menlo,SF Mono,monospace;font-size:10px;font-weight:950}.operator-node.active .operator-node-head span{color:var(--warning)}.operator-node-preview,.input-frame-empty{color:var(--muted);background:#151715;border:1px solid #181a186b;border-radius:2px;place-items:center;display:grid}.operator-node-preview{aspect-ratio:16/10;width:100%;overflow:hidden}.operator-node-preview img,.output-row img,.run-list img{object-fit:cover;width:100%;height:100%}.input-chip{min-height:22px;color:var(--accent-dark);background:#f4b43f2e;border:1px solid #181a1857;border-radius:2px;align-items:center;margin-top:7px;padding:2px 7px;font-size:11px;font-weight:900;display:inline-flex}.operator-node.active .input-chip{color:var(--warning);background:#f4b43f14;border-color:#6b6f65}.operator-node p{color:var(--muted);margin-top:7px;font-size:12px;font-weight:800;line-height:1.25}.operator-node.active p{color:#d6cfad}.operator-node-prompt{-webkit-line-clamp:3;color:var(--muted);background:#ffffff4d;border:1px solid #181a1857;border-radius:2px;-webkit-box-orient:vertical;margin-top:7px;padding:6px 7px;font-family:Menlo,SF Mono,monospace;font-size:10px;font-weight:750;line-height:1.35;display:-webkit-box;overflow:hidden}.operator-node.active .operator-node-prompt{color:#d6cfad;background:#ffffff0f;border-color:#636b62}.port-stack{gap:6px;margin-top:8px;display:grid}.port-row{background:#ffffff57;border:1px solid #181a1866;border-radius:2px;grid-template-columns:minmax(0,1fr) auto 24px 20px;align-items:center;gap:5px;min-height:31px;padding:4px 18px 4px 7px;font-size:11px;font-weight:900;display:grid;position:relative}.operator-node.active .port-row{background:#ffffff0f;border-color:#636b62}.port-row.active{border-color:var(--accent);box-shadow:inset 3px 0 0 var(--accent)}.port-row.running{border-color:var(--warning);background:#f4b43f33}.port-row small{color:var(--muted);white-space:nowrap;font-size:9px;font-weight:850}.operator-node.active .port-row small{color:#bfc0b6}.port-row i,.output-row i{opacity:.4;border:2px solid;border-radius:999px;width:18px;height:18px;display:inline-block}.port-row img{object-fit:cover;border:1px solid #181a1866;border-radius:2px;width:22px;height:22px}.port-row>button{border:1px solid var(--charcoal);background:var(--warning);width:22px;height:22px;color:var(--ink);cursor:pointer;border-radius:2px;place-items:center;display:grid}.react-flow__handle{border:2px solid var(--charcoal);background:var(--warning);width:10px;height:10px}.operator-canvas .result-edge.active .react-flow__edge-path{stroke:var(--accent);stroke-width:3.25px}.result-node{border:2px solid var(--charcoal);width:212px;color:var(--ink);text-align:left;cursor:pointer;background:#f4f3e9;border-radius:3px;padding:9px;display:block;box-shadow:0 6px #181a181f}.result-node.active{color:#f5f0d5;box-shadow:inset 0 0 0 2px var(--accent), 0 6px 0 #181a1833;background:#191d1b}.result-node-head{flex-direction:column;gap:1px;margin-bottom:6px;display:flex}.result-node-kind{color:var(--accent-dark);letter-spacing:.05em;text-transform:uppercase;font-family:Menlo,SF Mono,monospace;font-size:9px;font-weight:950}.result-node.active .result-node-kind{color:var(--warning)}.result-node-head strong{font-size:15px;font-weight:900;line-height:1.1}.result-node-preview{aspect-ratio:16/10;width:100%;color:var(--muted);background:#151715;border:1px solid #181a186b;border-radius:2px;place-items:center;display:grid;position:relative;overflow:hidden}.result-node-preview img{object-fit:cover;width:100%;height:100%}.result-node-play{color:#fff;background:#141410b8;border:1px solid #ffffff59;border-radius:999px;place-items:center;width:30px;height:30px;display:grid;position:absolute}.result-node-lineage{color:var(--muted);margin-top:6px;font-family:Menlo,SF Mono,monospace;font-size:10px}.result-node.active .result-node-lineage{color:#cdd0c2}.result-node-foot{justify-content:space-between;align-items:center;gap:6px;margin-top:5px;display:flex}.result-node-foot small{color:var(--muted);font-family:Menlo,SF Mono,monospace;font-size:10px}.result-node.active .result-node-foot small{color:#cdd0c2}.result-node-status{text-transform:uppercase;border:1px solid var(--charcoal);border-radius:999px;padding:1px 6px;font-family:Menlo,SF Mono,monospace;font-size:9px;font-weight:900}.result-node-status.done{background:var(--mint);color:#fff}.result-node-status.running{background:var(--warning);color:#191d1b}.result-node-status.error{background:var(--danger);color:#fff}.result-node-status.idle{color:var(--muted)}.run-console{border:2px solid var(--charcoal);background:#ebeae0;border-radius:3px;margin-top:12px;padding:10px}.run-console-head{border-bottom:1px solid #181a1833;justify-content:space-between;align-items:center;gap:8px;min-height:30px;margin-bottom:8px;display:flex}.run-console-head span{text-transform:uppercase;font-size:14px;font-weight:950}.run-console-head small{color:var(--muted);font-size:12px;font-weight:850}.inspector-pane{position:sticky;top:16px;overflow:visible}.inspector-tabs{grid-template-columns:repeat(3,1fr);gap:6px;margin-bottom:12px;display:grid}.inspector-tabs button{text-transform:uppercase;min-height:36px;font-size:12px;font-weight:950}.inspector-tabs button.active{background:var(--charcoal);color:var(--warning);box-shadow:inset 0 -4px 0 var(--accent)}.inspector-stack{gap:12px;display:grid}.file-input{display:none}.dropzone{aspect-ratio:4/5;cursor:pointer;background:repeating-linear-gradient(135deg,#f4b43f38 0 12px,#0000 12px 24px),#d7d9d1;border:2px dashed #59605b;border-radius:3px;place-items:center;width:100%;padding:0;display:grid;position:relative;overflow:hidden}.empty-upload{color:#40463f;place-items:center;gap:12px;font-weight:850;display:grid}.source-preview{aspect-ratio:4/5;border:2px solid var(--charcoal);background:#111;border-radius:3px;width:100%;position:relative;overflow:hidden}.source-preview .preview-image{width:100%;height:100%}.source-actions{gap:8px;display:flex}.source-actions button{border:2px solid var(--charcoal);min-height:38px;color:var(--ink);cursor:pointer;background:#f4f3e9;border-radius:3px;flex:1;padding:0 10px;font-size:12px;font-weight:900;box-shadow:0 4px #181a181f}.source-actions button.primary{background:var(--accent);color:#fff}.preview-action{border:2px solid var(--charcoal);background:var(--warning);min-height:30px;color:var(--ink);cursor:pointer;text-transform:uppercase;border-radius:2px;padding:0 10px;font-size:12px;font-weight:950;position:absolute;top:10px;right:10px}.preview-image{cursor:zoom-in;background:#111;border:0;border-radius:2px;place-items:center;width:100%;height:100%;padding:0;display:grid;position:relative;overflow:hidden}.preview-image img{object-fit:contain;width:100%;height:100%}.operator-node-preview .preview-image img,.output-row .preview-image img,.run-list .preview-image img,.history-list img{object-fit:cover}.preview-image span{width:26px;height:26px;color:var(--warning);opacity:0;background:#181a18c7;border:2px solid #f5f0d5db;border-radius:2px;place-items:center;transition:opacity .12s,transform .12s;display:grid;position:absolute;bottom:7px;right:7px;transform:translateY(3px)}.preview-image:hover span,.preview-image:focus-visible span{opacity:1;transform:translateY(0)}.input-frame{border:2px solid var(--charcoal);background:#e7e7dc;border-radius:3px;gap:9px;padding:10px;display:grid}.input-frame>div:first-child{justify-content:space-between;align-items:end;gap:8px;display:flex}.input-frame span,.mini-title,.control-section h3{color:var(--muted);text-transform:uppercase;font-size:12px;font-weight:950}.input-frame b{font-size:13px;font-weight:950}.input-frame .preview-image,.input-frame-empty{aspect-ratio:16/10;border:2px solid var(--charcoal);background:#111;border-radius:3px;width:100%}.control-section{gap:10px;display:grid}.control-section+.control-section{margin-top:4px}.frame-prep-textarea,.prompt-box textarea{resize:vertical;border:2px solid var(--charcoal);width:100%;color:var(--ink);background:#f8f7ed;border-radius:3px;padding:10px;font-family:Menlo,SF Mono,PingFang SC,monospace;font-size:12px;line-height:1.45}.frame-prep-textarea{min-height:86px}.prompt-box{gap:8px;font-size:13px;font-weight:850;display:grid}.prompt-box span{gap:3px;display:grid}.prompt-box small{color:var(--muted);font-size:12px;font-weight:750}.prompt-box textarea{min-height:120px}.frame-prep-controls,.prep-toggles,.toggles{gap:8px;display:grid}.prep-toggles{grid-template-columns:repeat(4,1fr)}.toggles{grid-template-columns:repeat(3,1fr)}.toggle{text-align:center;justify-content:center;align-items:center;min-height:40px;padding:7px 10px;font-size:12px;font-weight:850;display:flex}.toggle:hover,.preset:hover,.segment button:hover,.ghost:hover,.prompt-preview-head button:hover,.node-library button:hover,.inspector-tabs button:hover{transform:translateY(-1px)}.toggle.active,.segment .selected{background:var(--charcoal);color:var(--warning);border-color:var(--charcoal);box-shadow:inset 4px 0 0 var(--accent)}.ghost{align-items:center;gap:8px;height:40px;padding:0 14px;font-weight:850;display:inline-flex}.prep-button{background:var(--charcoal);min-height:40px;color:var(--warning);justify-content:center;align-items:center;gap:8px;font-size:13px;font-weight:950;display:inline-flex}.prep-button:disabled,.generate:disabled{color:#5d6259;cursor:not-allowed;box-shadow:none;background:repeating-linear-gradient(135deg,#181a1824 0 8px,#0000 8px 16px),#d7d4c6}.mini-title{margin-top:2px}.category-filter{flex-wrap:wrap;gap:5px;display:flex}.category-filter button{border:2px solid var(--charcoal);min-height:28px;color:var(--muted);cursor:pointer;background:#f5f4ea;border-radius:3px;padding:2px 9px;font-size:11px;font-weight:850}.category-filter button.active{background:var(--charcoal);color:var(--warning);box-shadow:inset 3px 0 0 var(--accent)}.preset-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;display:grid}.preset{text-align:left;align-content:start;gap:4px;min-height:74px;padding:10px;display:grid}.preset-top{justify-content:space-between;align-items:start;gap:8px;display:flex}.preset-top b{font-size:14px}.preset span{color:var(--muted);font-size:12px;line-height:1.35}.preset.selected{background:var(--charcoal);color:#f5f0d5;box-shadow:inset 4px 0 0 var(--accent)}.preset.selected span{color:#d6cfad}.segment-row{grid-template-columns:62px minmax(0,1fr);align-items:center;gap:8px;display:grid}.segment-row>span{color:var(--muted);font-size:12px;font-weight:900}.segment{flex-wrap:wrap;gap:5px;display:flex}.segment button{align-items:center;gap:5px;min-height:32px;padding:4px 7px;font-size:12px;font-weight:850;display:inline-flex}.generate{background:var(--accent);border-color:var(--accent);color:#181a18;text-transform:uppercase;width:100%;min-height:48px;box-shadow:0 5px 0 var(--accent-dark);justify-content:center;align-items:center;gap:9px;font-size:16px;font-weight:950;display:inline-flex}.spin{animation:1s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.toast{z-index:60;border:2px solid var(--charcoal);border-radius:3px;padding:10px 14px;font-size:13px;line-height:1.4;position:fixed;bottom:18px;left:50%;transform:translate(-50%);box-shadow:0 8px #181a1829}.toast.ok{color:#245840;background:#ecf7ef}.toast.warn{color:#96321f;background:#fff2ec}.prompt-disclosure{border:2px solid var(--charcoal);background:#f4f3e9;border-radius:3px}.prompt-disclosure summary{cursor:pointer;justify-content:space-between;align-items:center;gap:12px;min-height:46px;padding:8px 12px;list-style:none;display:flex}.prompt-disclosure summary::-webkit-details-marker{display:none}.prompt-disclosure summary:after{content:"+";border:2px solid var(--charcoal);background:#ebe9dd;place-items:center;width:24px;height:24px;font-weight:950;display:grid}.prompt-disclosure[open] summary:after{content:"-"}.prompt-disclosure summary span{gap:2px;display:grid}.prompt-disclosure summary b{text-transform:uppercase;color:var(--accent-dark);font-size:13px}.prompt-disclosure summary em{color:var(--muted);font-size:12px;font-style:normal}.prompt-preview{border-top:2px solid var(--charcoal);color:#e8eadf;background:#191d1b}.prompt-preview-head{min-height:36px;color:var(--warning);text-transform:uppercase;border-bottom:1px solid #525951;justify-content:space-between;align-items:center;padding:0 9px 0 11px;font-size:12px;font-weight:900;display:flex}.prompt-preview-head button{color:#e8eadf;background:#2a302d;align-items:center;gap:5px;min-height:26px;padding:0 8px;font-size:12px;font-weight:850;display:inline-flex}.prompt-preview pre{white-space:pre-wrap;word-break:break-word;margin:0;padding:11px;font-family:Menlo,SF Mono,monospace;font-size:11px;line-height:1.55;overflow:visible}.output-list,.run-list{gap:8px;display:grid}.output-row{text-align:left;border:2px solid var(--charcoal);background:#f5f4ea;border-radius:3px;grid-template-columns:64px minmax(0,1fr) auto;align-items:center;gap:10px;width:100%;min-height:70px;padding:7px;display:grid}.output-row.active{color:#f5f0d5;box-shadow:inset 4px 0 0 var(--accent);background:#191d1b}.output-row img,.output-row i,.output-row .preview-image{object-fit:cover;background:#111;border:1px solid #181a185c;border-radius:2px;width:64px;height:54px}.output-pick{background:var(--warning);width:32px;height:32px;color:var(--ink);place-items:center;display:grid}.output-row span{gap:3px;display:grid}.output-row b{font-size:13px;font-weight:950}.output-row small{color:var(--muted);font-size:11px;font-weight:850}.output-row.active small{color:#d6cfad}.run-list article{border:2px solid var(--charcoal);background:#f4f3e9;border-radius:3px;grid-template-columns:52px minmax(0,1fr);align-items:center;gap:9px;min-height:66px;padding:8px;display:grid}.run-list article>svg,.run-list .preview-image{object-fit:cover;background:#111;border:1px solid #181a185c;border-radius:2px;width:52px;height:46px}.run-list span{gap:3px;display:grid}.run-list b{font-size:13px;font-weight:950}.run-list small{color:var(--muted);font-size:11px;font-weight:850}.job-status-bar{color:var(--muted);flex-wrap:wrap;align-items:center;gap:8px;font-size:12px;font-weight:850;display:flex}.job-pill{border:2px solid var(--charcoal);min-height:28px;color:var(--ink);background:#ebe9dd;align-items:center;padding:0 10px;font-weight:950;display:inline-flex}.job-pill.succeeded{background:var(--mint);border-color:var(--mint);color:#fff}.job-pill.running,.job-pill.queued{background:var(--warning);color:var(--ink)}.job-pill.failed{background:var(--danger);color:#fff}.video-stack{gap:10px;display:grid}.video-stack.compact{grid-template-columns:repeat(auto-fit,minmax(210px,1fr))}.video-card{gap:8px;display:grid}.video-card video{aspect-ratio:16/9;border:2px solid var(--charcoal);background:#151715;border-radius:3px;width:100%;height:auto}.yarl__container{background-color:#0a0c0be6}.yarl__button{color:var(--warning);filter:none}.yarl__slide_image{border:2px solid var(--warning);background:#070807}.video-card a{background:var(--mint);color:#fff;border-radius:3px;justify-content:center;align-items:center;gap:7px;min-height:34px;font-weight:900;text-decoration:none;display:inline-flex}.pending,.empty-inspector{min-height:180px;color:var(--muted);border:2px solid var(--charcoal);text-align:center;background:#d6d9d0;border-radius:3px;place-items:center;gap:10px;padding:20px;display:grid}.pending.compact{min-height:112px}.empty-inspector p,.pending p{font-size:13px;font-weight:850}.gate{place-items:center;min-height:100vh;padding:24px;display:grid}.gate-panel{gap:18px;width:min(460px,100vw - 36px);padding:26px;display:grid}.gate-panel .mark{background:var(--charcoal);width:46px;height:46px;color:var(--warning);border-radius:3px;place-items:center;display:grid}.gate-panel p{color:var(--muted);font-weight:850}.gate-panel form{grid-template-columns:minmax(0,1fr) auto;gap:8px;display:grid}.gate-panel input{border:2px solid var(--charcoal);background:#f8f7ed;border-radius:3px;min-height:44px;padding:0 12px}.gate-panel button{border:2px solid var(--accent);background:var(--accent);min-height:44px;color:var(--ink);border-radius:3px;padding:0 14px;font-weight:950}@media (width<=1220px){.app-layout{grid-template-columns:128px minmax(0,1fr)}.workspace{grid-template-columns:minmax(0,1fr)}.inspector-pane{max-height:none;position:static}}@media (width<=820px){.shell{width:min(100vw - 22px,760px);padding-top:14px}.topbar{align-items:start}.app-layout{grid-template-columns:minmax(0,1fr)}.history-sidebar{max-height:none;position:static;overflow:visible}.history-list{grid-template-columns:repeat(auto-fill,minmax(94px,1fr));max-height:150px}.outputs-grid{max-height:none;overflow:visible}.graph-pane{position:static}.node-library,.preset-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.operator-canvas{height:320px}.operator-node{width:210px}.react-flow__pane,.react-flow__node{touch-action:pan-y}}@media (width<=560px){.topbar{display:grid}.node-library,.preset-grid,.prep-toggles,.toggles,.gate-panel form{grid-template-columns:minmax(0,1fr)}}.active-jobs{border:2px solid var(--charcoal);background:#f3f2e8;border-radius:3px;gap:6px;margin-top:10px;padding:8px;display:grid}.active-jobs-head{justify-content:space-between;align-items:center;display:flex}.active-jobs-head span{text-transform:uppercase;font-size:11px;font-weight:950}.active-jobs-head small{color:var(--accent-dark);font-size:10px;font-weight:900}.active-job{border:1px solid var(--line);cursor:pointer;text-align:left;background:#fff;border-radius:3px;grid-template-columns:32px minmax(0,1fr) 10px;align-items:center;gap:8px;padding:4px;display:grid}.active-job img{object-fit:cover;background:#222;border-radius:2px;width:32px;height:32px}.active-job-body{gap:1px;min-width:0;display:grid}.active-job-body b{font-size:11px;line-height:1.1}.active-job-body small{color:var(--muted);white-space:nowrap;text-overflow:ellipsis;font-size:9px;overflow:hidden}.active-job-dot{background:var(--warning);border-radius:999px;width:8px;height:8px}.active-job-dot.queued{background:var(--muted)}
|