dsh-image-gen 0.5.0 → 0.6.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.en.md +345 -344
- package/README.md +345 -344
- package/README.zh-CN.md +3 -3
- package/lib/client.js +115006 -228
- package/lib/client.js.map +1 -1
- package/lib/index.js +2270 -601
- package/lib/types/canvas-state-route.d.ts +37 -0
- package/lib/types/canvas-state.d.ts +77 -0
- package/lib/types/canvas-tools.d.ts +44 -0
- package/lib/types/client/browser-image-utils.d.ts +4 -0
- package/lib/types/client/canvas/canvas-bridge.d.ts +10 -0
- package/lib/types/client/canvas/canvas-model.d.ts +129 -0
- package/lib/types/client/canvas/canvas-nodes.d.ts +23 -0
- package/lib/types/client/canvas/canvas-store.d.ts +29 -0
- package/lib/types/client/canvas/canvas-style.d.ts +1 -0
- package/lib/types/client/canvas/canvas-view.d.ts +8 -0
- package/lib/types/client/canvas/rf-base-css.d.ts +2 -0
- package/lib/types/client/gallery-store.d.ts +2 -0
- package/lib/types/client/gallery-view.d.ts +13 -2
- package/lib/types/client/image-result-node.d.ts +2 -0
- package/lib/types/client/index.d.ts +4 -2
- package/lib/types/client/studio-chat-panel.d.ts +23 -0
- package/lib/types/client/studio-style.d.ts +1 -1
- package/lib/types/client/studio-view.d.ts +8 -6
- package/lib/types/client/tl/canvas-sync.d.ts +22 -0
- package/lib/types/client/tl/studio-tl-canvas.d.ts +2 -0
- package/lib/types/client/tl/tl-canvas-bridge.d.ts +53 -0
- package/lib/types/client/tl/tl-css.d.ts +2 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/reference-image.d.ts +1 -0
- package/lib/types/shared.d.ts +86 -0
- package/lib/types/studio-chat.d.ts +48 -0
- package/package.json +22 -15
- package/skills/install-dsh-image-gen/SKILL.md +22 -22
- package/lib/types/client/inspiration-api.d.ts +0 -10
- package/lib/types/client/inspiration-detail.d.ts +0 -14
- package/lib/types/inspiration/cache.d.ts +0 -20
- package/lib/types/inspiration/downloader.d.ts +0 -27
- package/lib/types/inspiration/routes.d.ts +0 -13
- package/lib/types/inspiration/sources.d.ts +0 -33
- package/lib/types/inspiration/types.d.ts +0 -65
- package/lib/types/inspiration/updater.d.ts +0 -7
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Same-origin HTTP route receiving live canvas-state pushes from the
|
|
3
|
+
* workbench infinite canvas in the browser.
|
|
4
|
+
*
|
|
5
|
+
* The browser owns the tldraw canvas; this route is the only door that state
|
|
6
|
+
* enters the host process through. Every push is validated end to end
|
|
7
|
+
* (origin, method, body size, field shapes, embedded image bytes) before it
|
|
8
|
+
* reaches the mirror. Selection screenshots stay in memory: the mirror holds
|
|
9
|
+
* the decoded bytes and a tool persists them only when the model actually
|
|
10
|
+
* consumes them (view_canvas), so dead screenshots never hit the disk.
|
|
11
|
+
*/
|
|
12
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
13
|
+
import type { ImageMediaType } from '@deepseek-ai/dsh-attachment';
|
|
14
|
+
import { type CanvasStatePush } from './shared.js';
|
|
15
|
+
import type { CanvasMirror } from './canvas-state.js';
|
|
16
|
+
/** Dependencies required by the canvas-state route. */
|
|
17
|
+
export interface CanvasStateRouteDeps {
|
|
18
|
+
mirror: CanvasMirror;
|
|
19
|
+
/** Hard cap for the JSON body; sized by the caller from the attachment limits. */
|
|
20
|
+
maxBodyBytes: number;
|
|
21
|
+
/** Largest accepted selection screenshot in bytes. */
|
|
22
|
+
maxImageBytes: number;
|
|
23
|
+
}
|
|
24
|
+
/** Serve one canvas-state push. */
|
|
25
|
+
export declare function serveCanvasState(req: IncomingMessage, res: ServerResponse, deps: CanvasStateRouteDeps): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Validate one untrusted canvas-state push at the HTTP boundary.
|
|
28
|
+
* Returns a normalized copy, or undefined when any field is malformed.
|
|
29
|
+
* Present-but-malformed known fields reject the whole push: they signal a
|
|
30
|
+
* client/server version skew rather than a legitimately absent value.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseCanvasStatePush(value: unknown): CanvasStatePush | undefined;
|
|
33
|
+
/** Decode and sanity-check an embedded selection screenshot data URL. */
|
|
34
|
+
export declare function decodeSelectionImage(dataUrl: string): {
|
|
35
|
+
data: Uint8Array;
|
|
36
|
+
mediaType: ImageMediaType;
|
|
37
|
+
} | undefined;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory mirror of the workbench infinite canvas.
|
|
3
|
+
*
|
|
4
|
+
* The tldraw canvas lives in the browser; the conversation agent lives in the
|
|
5
|
+
* host process. Browser instances push compact `CanvasStatePush` snapshots
|
|
6
|
+
* through the canvas-state route, and this mirror is the host-side truth the
|
|
7
|
+
* system-prompt digest, the canvas_state / view_canvas tools, and the
|
|
8
|
+
* edit_image `canvas_selection` source all read from. Nothing here is
|
|
9
|
+
* persisted: the mirror dies with the host process, matching the canvas's
|
|
10
|
+
* own session-scratch semantics.
|
|
11
|
+
*/
|
|
12
|
+
import type { ImageMediaType } from '@deepseek-ai/dsh-attachment';
|
|
13
|
+
import type { CanvasNodeSummary, CanvasStatePush } from './shared.js';
|
|
14
|
+
/**
|
|
15
|
+
* Decoded selection screenshot held in memory only. Nothing touches the
|
|
16
|
+
* durable attachment store until a tool actually consumes it: most
|
|
17
|
+
* screenshots are replaced within seconds (selection changed) or die with
|
|
18
|
+
* the canvas (closed), and the immutable content-addressed store has no
|
|
19
|
+
* deletion — persisting them eagerly would leak disk forever.
|
|
20
|
+
*/
|
|
21
|
+
export interface CanvasSelectionImage {
|
|
22
|
+
data: Uint8Array;
|
|
23
|
+
mediaType: ImageMediaType;
|
|
24
|
+
}
|
|
25
|
+
/** Server-side view of one client push after validation. */
|
|
26
|
+
export interface CanvasMirrorEntry {
|
|
27
|
+
clientInstance: string;
|
|
28
|
+
connected: true;
|
|
29
|
+
nodeCount: number;
|
|
30
|
+
nodes: readonly CanvasNodeSummary[];
|
|
31
|
+
selectionCount: number;
|
|
32
|
+
selectionKinds: readonly string[];
|
|
33
|
+
/** Capped identity list of the selected shapes (name, attachment id, ...). */
|
|
34
|
+
selectionItems: readonly CanvasNodeSummary[];
|
|
35
|
+
/**
|
|
36
|
+
* Identity-bearing selection signature (count + kinds + item identities).
|
|
37
|
+
* Two selections of different shapes never share it, so a stale screenshot
|
|
38
|
+
* is never kept across a selection swap — even when count and kinds match.
|
|
39
|
+
*/
|
|
40
|
+
selectionSignature: string;
|
|
41
|
+
/** In-memory screenshot of the current selection, when one was pushed. */
|
|
42
|
+
selectionImage?: CanvasSelectionImage;
|
|
43
|
+
/** Mirror receive time, used for the digest's "updated N ago" line. */
|
|
44
|
+
receivedAt: number;
|
|
45
|
+
/** Monotonic apply counter; `latest()` prefers the most recently applied instance. */
|
|
46
|
+
seq: number;
|
|
47
|
+
updatedAt: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Host-side mirror of every currently connected workbench canvas.
|
|
51
|
+
*
|
|
52
|
+
* One instance is shared by the canvas-state route, the canvas tools, and the
|
|
53
|
+
* system-prompt context registration. More than one canvas can be mounted at
|
|
54
|
+
* once (right-sidebar studio tab, conversation gallery tab); each instance
|
|
55
|
+
* pushes under its own `clientInstance` id and `latest()` reads the freshest.
|
|
56
|
+
*/
|
|
57
|
+
export declare class CanvasMirror {
|
|
58
|
+
private readonly entries;
|
|
59
|
+
private nextSeq;
|
|
60
|
+
/**
|
|
61
|
+
* Apply one validated push. A disconnect removes the instance; an unchanged
|
|
62
|
+
* selection keeps the previously received screenshot bytes so the model can
|
|
63
|
+
* still view them while unrelated canvas edits keep flowing in.
|
|
64
|
+
*/
|
|
65
|
+
apply(push: CanvasStatePush, selectionImage?: CanvasSelectionImage): void;
|
|
66
|
+
/** The freshest connected canvas entry, or undefined. */
|
|
67
|
+
latest(): CanvasMirrorEntry | undefined;
|
|
68
|
+
/** The in-memory selection screenshot of the freshest canvas, if present. */
|
|
69
|
+
latestSelectionImage(): CanvasSelectionImage | undefined;
|
|
70
|
+
/** Whether any canvas instance is currently connected. */
|
|
71
|
+
connected(): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Compact one-screen digest of the canvas for the system prompt and tools.
|
|
74
|
+
* Evaluated per call so the "updated N ago" line stays current between pushes.
|
|
75
|
+
*/
|
|
76
|
+
digest(now?: number): string;
|
|
77
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-facing tools over the mirrored workbench canvas state.
|
|
3
|
+
*
|
|
4
|
+
* `canvas_state` answers "what is on the canvas right now" with a compact
|
|
5
|
+
* inventory; `view_canvas` returns the latest selection screenshot as a real
|
|
6
|
+
* image block so the model can look at hand-drawn sketches and annotated
|
|
7
|
+
* selections the way it looks at any conversation image. Both tools stay
|
|
8
|
+
* registered when no canvas is connected — their answers then tell the model
|
|
9
|
+
* to ask the user to open the workbench instead of failing silently.
|
|
10
|
+
*/
|
|
11
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
12
|
+
import type { ImageAttachmentRef, StoredImageAttachment } from '@deepseek-ai/dsh-attachment';
|
|
13
|
+
import type { CanvasMirror, CanvasSelectionImage } from './canvas-state.js';
|
|
14
|
+
import type { ReferenceImageAgent, ResolvedReferenceImage } from './reference-image.js';
|
|
15
|
+
/** The small attachment surface the canvas-selection resolver needs. */
|
|
16
|
+
export type CanvasSelectionImageStore = {
|
|
17
|
+
readImage(ref: ImageAttachmentRef, signal?: AbortSignal): Promise<StoredImageAttachment>;
|
|
18
|
+
};
|
|
19
|
+
/** Dependencies of the canvas tools beyond the mirror itself. */
|
|
20
|
+
export interface CanvasToolsDeps {
|
|
21
|
+
/**
|
|
22
|
+
* Materializes an in-memory selection screenshot as a durable attachment.
|
|
23
|
+
* Called by view_canvas only, at the moment the image actually enters the
|
|
24
|
+
* conversation — the durable store is content-addressed, so repeated views
|
|
25
|
+
* of the same bytes reuse one object and dead screenshots never persist.
|
|
26
|
+
*/
|
|
27
|
+
persistSelectionImage(image: CanvasSelectionImage): Promise<ImageAttachmentRef>;
|
|
28
|
+
}
|
|
29
|
+
/** Register the canvas tools on a context that owns a canvas mirror. */
|
|
30
|
+
export declare function registerCanvasTools(ctx: Context, mirror: CanvasMirror, deps: CanvasToolsDeps): void;
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the mirrored canvas selection as an edit reference image for
|
|
33
|
+
* edit_image's `canvas_selection` source. The screenshot comes straight from
|
|
34
|
+
* the mirror's in-memory bytes — identical to what view_canvas shows the
|
|
35
|
+
* model — and is never persisted here: reference images go to the image
|
|
36
|
+
* provider, not the conversation.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveCanvasSelectionReferences(input: {
|
|
39
|
+
mirror: CanvasMirror;
|
|
40
|
+
attachments: CanvasSelectionImageStore;
|
|
41
|
+
agent?: ReferenceImageAgent;
|
|
42
|
+
maxBytes?: number;
|
|
43
|
+
signal: AbortSignal;
|
|
44
|
+
}): Promise<ResolvedReferenceImage[]>;
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Shared browser image and DOM helpers for client views.
|
|
3
3
|
* Completely decoupled from gallery-view and studio-view to prevent circular dependencies.
|
|
4
4
|
*/
|
|
5
|
+
/** Convert a Blob to a data URL. Used for tldraw image assets, which need a
|
|
6
|
+
* self-contained src; the session canvas keeps them in memory only (no
|
|
7
|
+
* persistenceKey, nothing touches disk). */
|
|
8
|
+
export declare function blobToDataUrl(blob: Blob): Promise<string>;
|
|
5
9
|
/** Copy an image Blob to the OS clipboard, converting to PNG if required by the browser. */
|
|
6
10
|
export declare function copyImageBlob(blob: Blob): Promise<boolean>;
|
|
7
11
|
/** Safely trigger a browser file download by mounting an anchor element into the DOM. */
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StudioProviderProfile } from '../../shared.js';
|
|
2
|
+
export interface CanvasBridge {
|
|
3
|
+
updateNodeData: (nodeId: string, patch: Record<string, unknown>) => void;
|
|
4
|
+
requestGenerate: (nodeId: string) => void;
|
|
5
|
+
deleteNode: (nodeId: string) => void;
|
|
6
|
+
profiles: readonly StudioProviderProfile[];
|
|
7
|
+
lang: 'zh' | 'en';
|
|
8
|
+
}
|
|
9
|
+
export declare const CanvasBridgeContext: import("react").Context<CanvasBridge | undefined>;
|
|
10
|
+
export declare function useCanvasBridge(): CanvasBridge | undefined;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas domain model: pure node/edge helpers shared by the canvas view,
|
|
3
|
+
* the import bridge and unit tests. No React, no IO.
|
|
4
|
+
*/
|
|
5
|
+
import { type Edge, type Node } from '@xyflow/react';
|
|
6
|
+
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
7
|
+
import type { StudioGenerateRequest, StudioProviderProfile } from '../../shared.js';
|
|
8
|
+
export interface ImageNodeData extends Record<string, unknown> {
|
|
9
|
+
kind: 'image';
|
|
10
|
+
/** Durable attachment-backed image (generated results, conversation imports). */
|
|
11
|
+
attachment?: ImageAttachmentRef;
|
|
12
|
+
/** Locally uploaded image kept as base64 until used as a generation reference. */
|
|
13
|
+
encoded?: {
|
|
14
|
+
mediaType: string;
|
|
15
|
+
data: string;
|
|
16
|
+
};
|
|
17
|
+
prompt?: string;
|
|
18
|
+
pending?: boolean;
|
|
19
|
+
error?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface TextNodeData extends Record<string, unknown> {
|
|
22
|
+
kind: 'text';
|
|
23
|
+
text: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ConfigNodeData extends Record<string, unknown> {
|
|
26
|
+
kind: 'config';
|
|
27
|
+
provider: string;
|
|
28
|
+
model: string;
|
|
29
|
+
prompt: string;
|
|
30
|
+
ratio: string;
|
|
31
|
+
quality: string;
|
|
32
|
+
count: number;
|
|
33
|
+
generating?: boolean;
|
|
34
|
+
error?: string;
|
|
35
|
+
}
|
|
36
|
+
export type CanvasNode = Node<ImageNodeData | TextNodeData | ConfigNodeData>;
|
|
37
|
+
export type ConfigNode = Node<ConfigNodeData>;
|
|
38
|
+
export interface CanvasDocument {
|
|
39
|
+
nodes: CanvasNode[];
|
|
40
|
+
edges: Edge[];
|
|
41
|
+
viewport?: {
|
|
42
|
+
x: number;
|
|
43
|
+
y: number;
|
|
44
|
+
zoom: number;
|
|
45
|
+
};
|
|
46
|
+
updatedAt: number;
|
|
47
|
+
}
|
|
48
|
+
/** Collision-safe node id (also stable across sessions via the random suffix). */
|
|
49
|
+
export declare function newId(prefix: string): string;
|
|
50
|
+
/** Stable node id for one attachment so repeated imports/generations dedupe. */
|
|
51
|
+
export declare function imageNodeIdOf(attachmentId: string): string;
|
|
52
|
+
export declare function nodeKindOf(node: CanvasNode | undefined): string | undefined;
|
|
53
|
+
export declare function newTextNode(text: string | undefined, x: number, y: number): CanvasNode;
|
|
54
|
+
export declare function newConfigNode(profile: StudioProviderProfile | undefined, x: number, y: number): CanvasNode;
|
|
55
|
+
export declare function newImageNode(input: {
|
|
56
|
+
attachment?: ImageAttachmentRef;
|
|
57
|
+
encoded?: {
|
|
58
|
+
mediaType: string;
|
|
59
|
+
data: string;
|
|
60
|
+
};
|
|
61
|
+
prompt?: string;
|
|
62
|
+
pending?: boolean;
|
|
63
|
+
error?: string;
|
|
64
|
+
x: number;
|
|
65
|
+
y: number;
|
|
66
|
+
}, id?: string): CanvasNode;
|
|
67
|
+
/** Whether an edge is legal in the canvas graph: inputs feed configs, configs emit results, and images chain edits. */
|
|
68
|
+
export declare function isLegalConnection(source: CanvasNode | undefined, target: CanvasNode | undefined): boolean;
|
|
69
|
+
/** Everything a config node needs to know about its incoming edges. */
|
|
70
|
+
export interface ResolvedInputs {
|
|
71
|
+
promptParts: string[];
|
|
72
|
+
referenceAttachments: ImageAttachmentRef[];
|
|
73
|
+
encodedReferences: Array<{
|
|
74
|
+
mediaType: string;
|
|
75
|
+
data: string;
|
|
76
|
+
}>;
|
|
77
|
+
}
|
|
78
|
+
export declare function resolveConfigInputs(nodes: readonly CanvasNode[], edges: readonly Edge[], configNodeId: string): ResolvedInputs;
|
|
79
|
+
/** Build the studio request for one config node. Returns undefined when the prompt is empty. */
|
|
80
|
+
export declare function buildGenerationRequest(config: ConfigNode, inputs: ResolvedInputs): StudioGenerateRequest | undefined;
|
|
81
|
+
/** Position for the k-th output image spawned by one config node. */
|
|
82
|
+
export declare function outputPosition(config: CanvasNode, existingOutputCount: number, index: number): {
|
|
83
|
+
x: number;
|
|
84
|
+
y: number;
|
|
85
|
+
};
|
|
86
|
+
/** One imported generation record (gallery item or pending bridge payload). */
|
|
87
|
+
export interface ImportRecord {
|
|
88
|
+
attachmentId: string;
|
|
89
|
+
attachment: ImageAttachmentRef;
|
|
90
|
+
prompt?: string;
|
|
91
|
+
provider?: string;
|
|
92
|
+
model?: string;
|
|
93
|
+
createdAt?: number;
|
|
94
|
+
sourceAttachmentIds?: readonly string[];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Canonical canvas edge factory: the closed arrowhead is baked in here so
|
|
98
|
+
* generation edges, import edit-chain edges, and user-drawn edges all read
|
|
99
|
+
* direction the same way (React Flow's defaultEdgeOptions never applies to
|
|
100
|
+
* edges inserted directly through the edges state).
|
|
101
|
+
*/
|
|
102
|
+
export declare function canvasEdge(source: string, target: string, className?: string): Edge;
|
|
103
|
+
/** Rebuild image nodes and edit-chain edges from import records (ordered oldest first). */
|
|
104
|
+
export declare function buildImportGraph(records: readonly ImportRecord[]): {
|
|
105
|
+
nodes: CanvasNode[];
|
|
106
|
+
edges: Edge[];
|
|
107
|
+
};
|
|
108
|
+
/** Merge an import graph into existing canvas state (nodes dedupe by id, edges by key). */
|
|
109
|
+
export declare function mergeIntoCanvas(current: {
|
|
110
|
+
nodes: readonly CanvasNode[];
|
|
111
|
+
edges: readonly Edge[];
|
|
112
|
+
}, incoming: {
|
|
113
|
+
nodes: readonly CanvasNode[];
|
|
114
|
+
edges: readonly Edge[];
|
|
115
|
+
}, offset: {
|
|
116
|
+
x: number;
|
|
117
|
+
y: number;
|
|
118
|
+
}): {
|
|
119
|
+
nodes: CanvasNode[];
|
|
120
|
+
edges: Edge[];
|
|
121
|
+
};
|
|
122
|
+
/** Drop volatile runtime flags (generating/pending/selected) — before persisting AND after restoring, so a remount never shows a phantom in-flight generation. */
|
|
123
|
+
export declare function stripVolatile(node: CanvasNode): CanvasNode;
|
|
124
|
+
/** Serialize the graph for persistence (strips volatile flags). */
|
|
125
|
+
export declare function toDocument(nodes: readonly CanvasNode[], edges: readonly Edge[], viewport?: {
|
|
126
|
+
x: number;
|
|
127
|
+
y: number;
|
|
128
|
+
zoom: number;
|
|
129
|
+
}): CanvasDocument;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas node renderers: image (attachment or base64), text prompt, and the
|
|
3
|
+
* generation config form. Data mutations flow through the canvas bridge
|
|
4
|
+
* context, never through node data props.
|
|
5
|
+
*/
|
|
6
|
+
import { type FC } from 'react';
|
|
7
|
+
import { type NodeProps, type Node } from '@xyflow/react';
|
|
8
|
+
import type { ConfigNodeData, ImageNodeData, TextNodeData } from './canvas-model.js';
|
|
9
|
+
type ImageNodeType = Node<ImageNodeData, 'image'>;
|
|
10
|
+
type TextNodeType = Node<TextNodeData, 'text'>;
|
|
11
|
+
type ConfigNodeType = Node<ConfigNodeData, 'config'>;
|
|
12
|
+
/** Attachment-backed or base64 image node; source handle feeds config nodes. */
|
|
13
|
+
export declare const CanvasImageNode: FC<NodeProps<ImageNodeType>>;
|
|
14
|
+
/** Free-form prompt fragment node. */
|
|
15
|
+
export declare const CanvasTextNode: FC<NodeProps<TextNodeType>>;
|
|
16
|
+
/** Generation config form; incoming edges contribute prompt text and reference images. */
|
|
17
|
+
export declare const CanvasConfigNode: FC<NodeProps<ConfigNodeType>>;
|
|
18
|
+
export declare const canvasNodeTypes: {
|
|
19
|
+
readonly image: FC<NodeProps<ImageNodeType>>;
|
|
20
|
+
readonly text: FC<NodeProps<TextNodeType>>;
|
|
21
|
+
readonly config: FC<NodeProps<ConfigNodeType>>;
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IndexedDB persistence for the canvas workspace plus the cross-view import
|
|
3
|
+
* bridge: conversation image cards enqueue pending imports, the canvas tab
|
|
4
|
+
* drains them (live when open, on mount otherwise). Mirrors gallery-store's
|
|
5
|
+
* schemaless pattern so optional fields never need a version bump.
|
|
6
|
+
*/
|
|
7
|
+
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
8
|
+
import type { CanvasDocument } from './canvas-model.js';
|
|
9
|
+
export interface PendingCanvasImport {
|
|
10
|
+
id: string;
|
|
11
|
+
attachment: ImageAttachmentRef;
|
|
12
|
+
prompt?: string;
|
|
13
|
+
provider?: string;
|
|
14
|
+
model?: string;
|
|
15
|
+
createdAt: number;
|
|
16
|
+
sourceAttachmentIds?: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare function loadCanvasDocument(): Promise<CanvasDocument | undefined>;
|
|
19
|
+
export declare function saveCanvasDocument(doc: CanvasDocument): Promise<void>;
|
|
20
|
+
type CanvasListener = () => void;
|
|
21
|
+
/** Subscribe to pending-import arrivals so an open canvas can drain live. */
|
|
22
|
+
export declare function subscribeCanvas(listener: CanvasListener): () => void;
|
|
23
|
+
/** Enqueue one conversation image for the canvas. Fire-and-forget safe. */
|
|
24
|
+
export declare function enqueuePendingCanvasImport(item: Omit<PendingCanvasImport, 'id' | 'createdAt'> & {
|
|
25
|
+
createdAt?: number;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
/** Read and clear the pending-import queue. */
|
|
28
|
+
export declare function drainPendingCanvasImports(): Promise<PendingCanvasImport[]>;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const CANVAS_STYLE: string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type FC } from 'react';
|
|
2
|
+
import type { LocaleService } from '../gallery-view.js';
|
|
3
|
+
export interface CanvasViewTabProps {
|
|
4
|
+
locale?: LocaleService;
|
|
5
|
+
sessionId?: string;
|
|
6
|
+
useSessions?: (selector: (state: any) => any) => any;
|
|
7
|
+
}
|
|
8
|
+
export declare const CanvasViewTab: FC<CanvasViewTabProps>;
|
|
@@ -29,6 +29,8 @@ export interface GalleryItem {
|
|
|
29
29
|
workspaceId?: string | undefined;
|
|
30
30
|
/** Conversation session ID where the image was generated */
|
|
31
31
|
sessionId?: string | undefined;
|
|
32
|
+
/** Attachment ids of the source images this image was edited from; used by the canvas to rebuild edit chains. Optional so records written by older versions stay readable. */
|
|
33
|
+
sourceAttachmentIds?: string[] | undefined;
|
|
32
34
|
}
|
|
33
35
|
type GalleryListener = () => void;
|
|
34
36
|
/**
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* responsive image grid, and placeholder routes.
|
|
5
5
|
*/
|
|
6
6
|
import { type FC } from 'react';
|
|
7
|
+
/** Host-provided locale service; `active` may be missing before the locale loads. */
|
|
7
8
|
export interface LocaleService {
|
|
8
9
|
getSnapshot(): {
|
|
9
|
-
active
|
|
10
|
+
active?: string;
|
|
10
11
|
};
|
|
11
12
|
subscribe(fn: () => void): () => void;
|
|
12
13
|
}
|
|
@@ -186,11 +187,21 @@ declare const DICT: {
|
|
|
186
187
|
};
|
|
187
188
|
export type DictKey = keyof typeof DICT.zh;
|
|
188
189
|
export interface GalleryViewTabProps {
|
|
189
|
-
locale?: LocaleService;
|
|
190
|
+
locale?: LocaleService | undefined;
|
|
190
191
|
sessionId?: string;
|
|
191
192
|
useSession?: (selector: (state: any) => any) => any;
|
|
192
193
|
useSessions?: (selector: (state: any) => any) => any;
|
|
193
194
|
useWorkspaces?: (selector: (state: any) => any) => any;
|
|
195
|
+
/**
|
|
196
|
+
* Right-sidebar variant (DSH official `sidebar.right.pane.tab` seat). The
|
|
197
|
+
* native conversation stays in the main area, so the composer must NOT be
|
|
198
|
+
* hidden and the page-level CSS must not scope to the conversation column.
|
|
199
|
+
*/
|
|
200
|
+
inSidebar?: boolean;
|
|
201
|
+
/** Sub-tab opened first; the sidebar variant starts on the studio workbench. */
|
|
202
|
+
defaultTab?: TabKey;
|
|
203
|
+
/** Canvas surface the studio opens with; the sidebar variant shows the tldraw infinite canvas directly. */
|
|
204
|
+
initialCanvasSurface?: 'preview' | 'infinite';
|
|
194
205
|
}
|
|
195
206
|
export declare const GalleryViewTab: FC<GalleryViewTabProps>;
|
|
196
207
|
export { copyImageBlob } from './browser-image-utils.js';
|
|
@@ -10,6 +10,8 @@ export interface ImageResultPresentation {
|
|
|
10
10
|
readonly savedTo?: string;
|
|
11
11
|
/** Workflow seed reported by the ComfyUI provider, when available. */
|
|
12
12
|
readonly seed?: number;
|
|
13
|
+
/** Attachment ids of the edit sources when this image came from edit_image; used to rebuild canvas edit chains. */
|
|
14
|
+
readonly sourceAttachmentIds?: readonly string[];
|
|
13
15
|
}
|
|
14
16
|
interface ImageResultState {
|
|
15
17
|
readonly turn: number;
|
|
@@ -57,8 +57,8 @@ interface CredentialMutationResult {
|
|
|
57
57
|
interface CredentialsRemote {
|
|
58
58
|
describe(refs: string[]): Promise<CredentialResult>;
|
|
59
59
|
set(ref: string, value: string): Promise<CredentialMutationResult>;
|
|
60
|
-
/** Present only on modern hosts; feature-detected before use. */
|
|
61
|
-
unset
|
|
60
|
+
/** Present only on modern hosts; feature-detected before use; undefined while degraded. */
|
|
61
|
+
unset?: ((ref: string) => Promise<CredentialMutationResult>) | undefined;
|
|
62
62
|
}
|
|
63
63
|
/** Notifies the settings card whenever any credential reference changes on the host. */
|
|
64
64
|
interface CredentialEvents {
|
|
@@ -67,6 +67,8 @@ interface CredentialEvents {
|
|
|
67
67
|
interface SettingsFace {
|
|
68
68
|
scope: SettingsScope<ImageSettings>;
|
|
69
69
|
credentials: CredentialsRemote;
|
|
70
|
+
/** False while the host core exposes no credentials service; the key UI degrades but the card stays mounted. */
|
|
71
|
+
credentialsAvailable: () => boolean;
|
|
70
72
|
locale?: LocaleService | undefined;
|
|
71
73
|
credentialEvents?: CredentialEvents | undefined;
|
|
72
74
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workbench chat panel: the right-side DSH conversation surface.
|
|
3
|
+
*
|
|
4
|
+
* A dedicated archived agent session lives on the host side (studio-chat.ts);
|
|
5
|
+
* this panel pulls its projected event feed through CHAT_ROUTE with adaptive
|
|
6
|
+
* polling (?since=<seq> increments; faster while a turn is running, slower
|
|
7
|
+
* when idle, paused while the webview is hidden) and submits user turns with
|
|
8
|
+
* POST. Tool-generated images are mirrored onto the tldraw canvas through the
|
|
9
|
+
* landing queue and upserted into the gallery (the recent list refreshes via
|
|
10
|
+
* its subscription). The panel is intentionally unmount-friendly: re-pulls
|
|
11
|
+
* from seq 0 on remount, and both landing and gallery writes are deduped by
|
|
12
|
+
* attachmentId, so tab switches are safe.
|
|
13
|
+
*/
|
|
14
|
+
import { type FC } from 'react';
|
|
15
|
+
/** Workspace scoping mirrored onto gallery records; shape-compatible with StudioWorkspaceProps. */
|
|
16
|
+
export interface ChatWorkspaceScope {
|
|
17
|
+
workspaceId?: string | undefined;
|
|
18
|
+
path?: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
export declare const StudioChatPanel: FC<{
|
|
21
|
+
lang: 'zh' | 'en';
|
|
22
|
+
workspace?: ChatWorkspaceScope | null | undefined;
|
|
23
|
+
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const STUDIO_STYLE = "\n.dsh-ig-gallery-page-body.is-workbench{flex:1 1 0;height:100%;min-height:0;padding:0;overflow:hidden;display:flex;flex-direction:column}\n.dsh-ig-workbench{--ig-blue:#2f64f5;--ig-line:color-mix(in srgb,currentColor 11%,transparent);--ig-soft:color-mix(in srgb,currentColor 4%,transparent);position:relative;display:flex;flex-direction:column;min-height:0;height:100%;overflow:hidden;padding:10px 12px 12px;color:var(--foreground,#182033);box-sizing:border-box;background:radial-gradient(circle at 60% -20%,rgba(63,104,246,.07),transparent 30%)}\n.dsh-ig-workbench *{box-sizing:border-box}.dsh-ig-workbench button,.dsh-ig-workbench select,.dsh-ig-workbench textarea{font:inherit;color:inherit}\n.dsh-ig-workbench-grid{display:grid;grid-template-columns:minmax(190px,238px) minmax(0,1fr) minmax(286px,340px);grid-template-rows:minmax(0,1fr);min-height:0;height:0;flex:1 1 0;border:1px solid var(--ig-line);border-radius:12px;overflow:hidden;background:var(--background,#fff);box-shadow:0 12px 32px rgba(30,42,76,.05);transition:grid-template-columns .2s ease}\n.dsh-ig-workbench-grid.is-sidebar-collapsed{grid-template-columns:minmax(0,1fr) minmax(286px,340px)}\n.dsh-ig-recent-panel,.dsh-ig-generate-panel{min-width:0;min-height:0;overflow:hidden;background:color-mix(in srgb,var(--background,#fff) 96%,#f5f7fb)}.dsh-ig-recent-panel{display:flex;flex-direction:column;border-right:1px solid var(--ig-line)}\n.dsh-ig-panel-title{height:48px;flex:0 0 48px;padding:0 12px 0 14px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--ig-line);font-size:13px;font-weight:650}\n.dsh-ig-count-badge{font-size:11px;min-width:22px;text-align:center;padding:2px 6px;border-radius:999px;background:var(--ig-soft);color:#7b8498;font-weight:500}\n.dsh-ig-collapse-btn{width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;border-radius:6px;background:transparent;color:#717b90;cursor:pointer;transition:all .15s}\n.dsh-ig-collapse-btn:hover{border-color:var(--ig-line);background:var(--ig-soft);color:var(--foreground,#182033)}\n.dsh-ig-recent-scroll{flex:1 1 0;height:0;padding:8px;overflow-x:hidden;overflow-y:auto;min-height:0}.dsh-ig-recent-empty{min-height:180px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:10px;color:#929bad;text-align:center;font-size:12px}\n.dsh-ig-recent-item{display:grid;grid-template-columns:70px minmax(0,1fr);gap:10px;width:100%;padding:8px;border:1px solid transparent;border-radius:9px;background:transparent;text-align:left;cursor:pointer;transition:background .16s,border-color .16s,transform .16s}.dsh-ig-recent-item:hover{background:var(--ig-soft);transform:translateY(-1px)}.dsh-ig-recent-item.is-active{border-color:#89a7ff;background:rgba(47,100,245,.075);box-shadow:inset 3px 0 0 var(--ig-blue)}.dsh-ig-recent-thumb{width:70px;height:70px;border-radius:7px;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#eef1f7;color:#929bad}.dsh-ig-recent-thumb img{width:100%;height:100%;object-fit:cover}.dsh-ig-recent-item>div:last-child{min-width:0;padding:1px 0}.dsh-ig-recent-item strong{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;font-size:12.5px;line-height:19px;font-weight:630}.dsh-ig-recent-item span,.dsh-ig-recent-item small{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;color:#828b9e;font-size:10.5px;line-height:16px}\n.dsh-ig-load-more{width:100%;height:32px;margin:8px 0;display:flex;align-items:center;justify-content:center;border:1px dashed var(--ig-line);border-radius:7px;background:transparent;font-size:11px;color:#6b758b;cursor:pointer;transition:background .15s,color .15s}.dsh-ig-load-more:hover{background:var(--ig-soft);color:var(--ig-blue);border-color:#a2b9f6}\n.dsh-ig-mini-btn{height:22px;padding:0 7px;display:inline-flex;align-items:center;gap:3px;border:1px solid var(--ig-line);border-radius:5px;background:var(--background,#fff);font-size:10.5px;font-weight:500;color:var(--foreground,#242f44);cursor:pointer;transition:all .15s}.dsh-ig-mini-btn:hover{border-color:#9bb4f5;color:var(--ig-blue);background:rgba(47,100,245,.06)}\n.dsh-ig-canvas-column{min-width:0;min-height:0;height:100%;overflow:hidden;display:flex;flex-direction:column;background:color-mix(in srgb,var(--background,#fff) 97%,#e8edf7)}\n.dsh-ig-canvas-toolbar{height:46px;flex:0 0 46px;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 14px;border-bottom:1px solid var(--ig-line)}\n.dsh-ig-canvas-toolbar-left,.dsh-ig-canvas-toolbar-right{display:flex;align-items:center;gap:6px}\n.dsh-ig-canvas-toolbar button{height:30px;min-width:30px;padding:0 9px;display:inline-flex;align-items:center;justify-content:center;gap:5px;border:1px solid var(--ig-line);border-radius:7px;background:var(--background,#fff);color:var(--foreground,#242f44);font-size:11.5px;font-weight:500;cursor:pointer;transition:border-color .15s,background .15s,color .15s}\n.dsh-ig-canvas-toolbar button:hover{border-color:#9bb4f5;background:rgba(47,100,245,.05);color:var(--ig-blue)}\n.dsh-ig-canvas-toolbar button.is-active{border-color:#8ba8f8;background:rgba(47,100,245,.08);color:var(--ig-blue);font-weight:550}\n.dsh-ig-zoom-display{font-size:11px;min-width:38px;text-align:center;color:#64748b;user-select:none;font-variant-numeric:tabular-nums}\n.dsh-ig-status-badge-wrap{position:relative;display:inline-flex;align-items:center}\n.dsh-ig-status-badge{height:30px;display:inline-flex;align-items:center;gap:7px;padding:0 10px;border:1px solid var(--ig-line);border-radius:7px;background:var(--background,#fff);cursor:pointer;user-select:none;transition:border-color .15s,background .15s,box-shadow .15s}\n.dsh-ig-status-badge:hover{border-color:#9bb4f5;background:rgba(47,100,245,.04)}\n.dsh-ig-status-dot{width:7px;height:7px;min-width:7px;max-width:7px;border-radius:50%;flex-shrink:0;box-sizing:border-box}\n.dsh-ig-status-dot.is-ready{background:#10b981;box-shadow:0 0 0 2px rgba(16,185,129,.2)}\n.dsh-ig-status-dot.is-muted{background:#ef4444;box-shadow:0 0 0 2px rgba(239,68,68,.2)}\n.dsh-ig-status-text{font-size:11.5px;font-weight:500;color:var(--foreground,#242f44);line-height:1}\n.dsh-ig-status-arrow{color:#94a3b8;transition:transform .15s,color .15s}\n.dsh-ig-status-badge-wrap:hover .dsh-ig-status-arrow{transform:rotate(180deg);color:var(--ig-blue)}\n.dsh-ig-status-popover{position:absolute;left:0;top:calc(100% + 6px);width:260px;background:var(--background,#fff);border:1px solid var(--ig-line);border-radius:9px;box-shadow:0 12px 36px rgba(20,28,45,.14);padding:10px 12px;z-index:40;opacity:0;pointer-events:none;transform:translateY(4px);transition:opacity .15s cubic-bezier(.16,1,.3,1),transform .15s cubic-bezier(.16,1,.3,1)}\n.dsh-ig-status-badge-wrap:hover .dsh-ig-status-popover{opacity:1;pointer-events:auto;transform:translateY(0)}\n.dsh-ig-status-popover-title{display:flex;align-items:center;justify-content:space-between;font-size:10px;font-weight:650;color:#8590a6;margin-bottom:8px;letter-spacing:.02em;text-transform:uppercase}\n.dsh-ig-status-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:5px}\n.dsh-ig-status-list li{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 8px;border-radius:6px;transition:background .12s}\n.dsh-ig-status-list li.is-configured{background:rgba(16,185,129,.05);border:1px solid rgba(16,185,129,.12)}\n.dsh-ig-status-list li.is-missing{background:rgba(239,68,68,.04);border:1px solid rgba(239,68,68,.12);opacity:.75}\n.dsh-ig-status-item-name{display:flex;flex-direction:column;min-width:0}\n.dsh-ig-status-item-name strong{font-size:11.5px;font-weight:600;color:var(--foreground,#182033);line-height:16px}\n.dsh-ig-status-item-name small{font-size:9.5px;color:#7c869a;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:145px;line-height:14px}\n.dsh-ig-status-item-tag{font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;flex-shrink:0}\n.is-configured .dsh-ig-status-item-tag{color:#059669;background:rgba(16,185,129,.14)}\n.is-missing .dsh-ig-status-item-tag{color:#dc2626;background:rgba(239,68,68,.14)}\n.dsh-ig-canvas{position:relative;flex:1 1 0;height:0;min-height:0;display:flex;align-items:center;justify-content:center;overflow:hidden;padding:24px;touch-action:none;user-select:none;cursor:grab;background-image:linear-gradient(45deg,rgba(114,128,156,.035) 25%,transparent 25%),linear-gradient(-45deg,rgba(114,128,156,.035) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(114,128,156,.035) 75%),linear-gradient(-45deg,transparent 75%,rgba(114,128,156,.035) 75%);background-size:24px 24px;background-position:0 0,0 12px,12px -12px,-12px 0}\n.dsh-ig-canvas.is-dragging,.dsh-ig-canvas.is-dragging *{cursor:grabbing!important}\n.dsh-ig-canvas img{display:block;max-width:100%;max-height:100%;width:auto;height:auto;border-radius:10px;box-shadow:0 14px 45px rgba(25,35,63,.18);user-select:none;-webkit-user-drag:none;pointer-events:auto}\n.dsh-ig-canvas-empty,.dsh-ig-generating-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:12px;color:#929bad;font-size:12px;padding:26px;cursor:default}\n.dsh-ig-generating-state strong{font-size:15px;color:var(--foreground,#182033)}.dsh-ig-generating-state span{font-size:11px}.dsh-ig-generation-orbit{width:66px;height:66px;border-radius:50%;display:grid;place-items:center;color:var(--ig-blue);background:rgba(47,100,245,.09);box-shadow:0 0 0 10px rgba(47,100,245,.035);animation:dshIgPulse 1.8s ease-in-out infinite}\n.dsh-ig-result-strip{flex:0 0 auto;min-height:52px;padding:8px 14px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--ig-line)}.dsh-ig-result-strip>span{font-size:12px;font-weight:650}.dsh-ig-result-strip>div,.dsh-ig-result-actions>div{display:flex;gap:7px}.dsh-ig-result-strip button,.dsh-ig-result-actions button{height:32px;display:inline-flex;align-items:center;gap:6px;padding:0 10px;border:1px solid var(--ig-line);border-radius:7px;background:var(--background,#fff);font-size:11px;cursor:pointer}.dsh-ig-result-strip button:hover,.dsh-ig-result-actions button:hover{border-color:#9fb2ed;color:var(--ig-blue)}.dsh-ig-result-actions{flex:0 0 auto;min-height:54px;padding:8px 14px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--ig-line)}.dsh-ig-result-actions p{margin:0;min-width:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:11.5px;line-height:18px;color:#596277}.dsh-ig-result-meta{flex:0 0 auto;min-height:32px;padding:6px 14px;display:flex;gap:13px;align-items:center;flex-wrap:wrap;border-top:1px solid var(--ig-line);font-size:10px;color:#8790a3}.dsh-ig-result-meta span+span:before{content:'\u00B7';margin-right:13px}\n.dsh-ig-generate-panel{height:100%;display:flex;flex-direction:column;border-left:1px solid var(--ig-line);overflow:hidden}.dsh-ig-panel-tabs{height:48px;flex:0 0 48px;display:grid;grid-template-columns:1fr 1fr;border-bottom:1px solid var(--ig-line);padding:0 14px}.dsh-ig-panel-tabs button{position:relative;border:0;background:transparent;font-size:12px;color:#7c8598;cursor:pointer}.dsh-ig-panel-tabs button.is-active{color:var(--ig-blue);font-weight:650}.dsh-ig-panel-tabs button.is-active:after{content:'';position:absolute;left:20%;right:20%;bottom:-1px;height:2px;background:var(--ig-blue);border-radius:2px 2px 0 0}.dsh-ig-generator-form{flex:1 1 0;height:0;padding:15px;display:flex;flex-direction:column;gap:15px;overflow-x:hidden;overflow-y:auto;min-height:0}.dsh-ig-mode-switch{display:grid;grid-template-columns:1fr 1fr;gap:8px}.dsh-ig-mode-switch button{height:39px;border:1px solid var(--ig-line);border-radius:8px;background:var(--background,#fff);display:flex;align-items:center;justify-content:center;gap:7px;font-size:12px;cursor:pointer}.dsh-ig-mode-switch button.is-active{border-color:#789bff;color:var(--ig-blue);background:rgba(47,100,245,.065);box-shadow:inset 0 0 0 1px rgba(47,100,245,.1)}\n.dsh-ig-field{position:relative;display:flex;flex-direction:column;gap:7px}.dsh-ig-field>label,.dsh-ig-field-label label{font-size:11.5px;font-weight:630}.dsh-ig-field>label span{font-weight:400;color:#929bad}.dsh-ig-field-label{display:flex;align-items:center;justify-content:space-between}.dsh-ig-field-label b{color:#e14d4d}.dsh-ig-field-label button{border:0;background:transparent;color:#798397;font-size:10.5px;cursor:pointer}.dsh-ig-field textarea{width:100%;height:112px;padding:11px 12px 22px;resize:vertical;border:1px solid var(--ig-line);border-radius:9px;background:var(--background,#fff);font-size:12px;line-height:19px;outline:none}.dsh-ig-field textarea:focus{border-color:var(--ig-blue);box-shadow:0 0 0 3px rgba(47,100,245,.09)}.dsh-ig-field>small{position:absolute;right:9px;bottom:7px;color:#9aa2b2;font-size:9.5px}.dsh-ig-field-grid{display:grid;grid-template-columns:1fr 1fr;gap:9px}.dsh-ig-field-select{display:flex;flex-direction:column;gap:6px;min-width:0}.dsh-ig-field-select>span{font-size:11px;font-weight:620}.dsh-ig-field-select select{width:100%;height:36px;padding:0 26px 0 9px;border:1px solid var(--ig-line);border-radius:8px;background:var(--background,#fff);font-size:11px;outline:none;text-overflow:ellipsis}.dsh-ig-field-select select:focus{border-color:var(--ig-blue)}.dsh-ig-count-row{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}.dsh-ig-count-pill{height:34px;border:1px solid var(--ig-line);border-radius:7px;background:var(--background,#fff);font-size:12px;font-weight:600;color:#596277;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .15s}.dsh-ig-count-pill:hover{border-color:#9fb2ed;color:var(--ig-blue)}.dsh-ig-count-pill.is-active{border-color:var(--ig-blue);background:rgba(47,100,245,.08);color:var(--ig-blue);box-shadow:inset 0 0 0 1px var(--ig-blue)}\n.dsh-ig-generation-kind{display:grid;grid-template-columns:1fr 1fr;gap:4px;padding:3px;border:1px solid var(--ig-line);border-radius:9px;background:var(--ig-soft)}.dsh-ig-generation-kind button{height:31px;border:0;border-radius:6px;background:transparent;color:#778196;font-size:11.5px;display:flex;align-items:center;justify-content:center;gap:6px;cursor:pointer;transition:background .15s,color .15s,box-shadow .15s}.dsh-ig-generation-kind button.is-active{background:var(--background,#fff);color:var(--ig-blue);font-weight:650;box-shadow:0 2px 8px rgba(30,42,76,.09)}\n.dsh-ig-compare-box{padding:10px;border:1px solid rgba(47,100,245,.2);border-radius:10px;background:linear-gradient(145deg,rgba(47,100,245,.055),rgba(99,102,241,.018));display:flex;flex-direction:column;gap:9px}.dsh-ig-compare-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.dsh-ig-compare-heading>div{min-width:0;display:flex;flex-direction:column;gap:2px}.dsh-ig-compare-heading strong{font-size:11.5px}.dsh-ig-compare-heading small{font-size:9.5px;color:#838da1}.dsh-ig-compare-heading>span{flex:none;padding:2px 6px;border-radius:999px;background:rgba(47,100,245,.11);color:var(--ig-blue);font-size:9.5px;font-weight:650}.dsh-ig-model-checks{display:flex;flex-direction:column;gap:6px}.dsh-ig-model-checks>button{min-height:43px;width:100%;padding:6px 7px;display:grid;grid-template-columns:18px minmax(0,1fr) auto;align-items:center;gap:7px;border:1px solid var(--ig-line);border-radius:8px;background:var(--background,#fff);text-align:left;cursor:pointer;transition:border-color .15s,background .15s,transform .15s}.dsh-ig-model-checks>button:hover{border-color:#9cb2ef;transform:translateY(-1px)}.dsh-ig-model-checks>button.is-selected{border-color:#86a4fa;background:rgba(47,100,245,.055);box-shadow:inset 3px 0 0 var(--ig-blue)}.dsh-ig-model-checkmark{width:17px;height:17px;border:1px solid #bdc6d8;border-radius:5px;display:grid;place-items:center;color:#fff;background:var(--background,#fff)}.dsh-ig-model-checks>button.is-selected .dsh-ig-model-checkmark{border-color:var(--ig-blue);background:var(--ig-blue)}.dsh-ig-model-copy{display:flex;flex-direction:column;min-width:0}.dsh-ig-model-copy strong{font-size:11px;line-height:15px}.dsh-ig-model-copy small{max-width:130px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#80899b;font-size:9.5px;line-height:14px}.dsh-ig-model-settings{display:flex;flex-direction:column;align-items:flex-end;gap:2px;color:#596277;font-size:9.5px;white-space:nowrap}.dsh-ig-model-settings em{font-style:normal;color:#a16a0a;font-size:8.5px}.dsh-ig-compare-box>p{margin:0;color:#8a7180;font-size:9.5px;line-height:14px}\n.dsh-ig-upload{height:92px;border:1px dashed #bcc6d9;border-radius:9px;background:rgba(255,255,255,.45);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;color:#7d879b;cursor:pointer}.dsh-ig-upload strong{font-size:11px;font-weight:570}.dsh-ig-upload small{font-size:9.5px}.dsh-ig-upload:hover,.dsh-ig-upload.is-dragging{border-color:var(--ig-blue);background:rgba(47,100,245,.05);color:var(--ig-blue)}\n.dsh-ig-reference-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(64px,1fr));gap:8px}\n.dsh-ig-reference-card{position:relative;aspect-ratio:1;border-radius:8px;overflow:hidden;background:#eef1f7;border:1px solid var(--ig-line)}\n.dsh-ig-reference-card img{width:100%;height:100%;object-fit:cover}\n.dsh-ig-reference-card button{position:absolute;right:4px;top:4px;width:18px;height:18px;border:0;border-radius:50%;display:grid;place-items:center;background:rgba(20,28,45,.75);color:#fff;cursor:pointer;padding:0;transition:background .15s}\n.dsh-ig-reference-card button:hover{background:#ef4444}\n.dsh-ig-reference-add{aspect-ratio:1;border:1px dashed #bcc6d9;border-radius:8px;background:rgba(255,255,255,.45);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;color:#7d879b;cursor:pointer;font-size:10px;transition:border-color .15s,color .15s,background .15s}\n.dsh-ig-reference-add:hover{border-color:var(--ig-blue);background:rgba(47,100,245,.05);color:var(--ig-blue)}\n.dsh-ig-reference-preview{position:relative;height:108px;border-radius:9px;overflow:hidden;background:#eef1f7}.dsh-ig-reference-preview img{width:100%;height:100%;object-fit:contain}.dsh-ig-reference-preview button{position:absolute;right:7px;top:7px;width:25px;height:25px;border:0;border-radius:50%;display:grid;place-items:center;background:rgba(20,28,45,.72);color:#fff;cursor:pointer}\n.dsh-ig-inline-note,.dsh-ig-form-error{padding:9px 10px;border-radius:7px;font-size:10.5px;line-height:16px}.dsh-ig-inline-note{background:#fff8e7;color:#8b671c;border:1px solid #f1dfae}.dsh-ig-form-error{background:#fff1f1;color:#b63737;border:1px solid #f2caca}.dsh-ig-form-loading{height:70px;display:grid;place-items:center;color:var(--ig-blue)}\n.dsh-ig-config-error{padding:14px;display:flex;flex-direction:column;align-items:center;gap:10px;background:#fff1f1;border:1px solid #f2caca;border-radius:8px;color:#b63737;font-size:11.5px;text-align:center}.dsh-ig-config-error p{margin:0;line-height:17px}.dsh-ig-config-error button{height:30px;display:inline-flex;align-items:center;gap:6px;padding:0 12px;border:1px solid #e0a8a8;border-radius:6px;background:#fff;color:#b63737;font-size:11.5px;font-weight:600;cursor:pointer}.dsh-ig-config-error button:hover{background:#ffebeb}\n.dsh-ig-generate-button{height:42px;flex:0 0 auto;border:0;border-radius:8px;background:linear-gradient(135deg,#386cf6,#2758e7);color:#fff!important;display:flex;align-items:center;justify-content:center;gap:8px;font-size:12px;font-weight:650;cursor:pointer;box-shadow:0 8px 18px rgba(47,100,245,.22);transition:transform .16s,box-shadow .16s}.dsh-ig-generate-button:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 10px 24px rgba(47,100,245,.28)}.dsh-ig-generate-button:disabled{opacity:.55;cursor:not-allowed;box-shadow:none}\n.dsh-ig-generate-button.is-cancel{background:linear-gradient(135deg,#ef4444,#dc2626);box-shadow:0 8px 18px rgba(239,68,68,.25)}.dsh-ig-generate-button.is-cancel:hover{background:linear-gradient(135deg,#dc2626,#b91c1c);box-shadow:0 10px 24px rgba(239,68,68,.35)}\n.dsh-ig-details{padding:16px;margin:0;overflow:auto}.dsh-ig-details>div{padding:12px 0;border-bottom:1px solid var(--ig-line)}.dsh-ig-details dt{font-size:10.5px;color:#8992a4;margin-bottom:5px}.dsh-ig-details dd{margin:0;font-size:11.5px;line-height:18px;word-break:break-word}.dsh-ig-details-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;height:220px;padding:20px;color:#929bad;font-size:11px;text-align:center}\n.dsh-ig-workbench-modal-backdrop{position:fixed;inset:0;background:rgba(15,23,42,.45);backdrop-filter:blur(3px);z-index:999;display:grid;place-items:center;padding:16px}\n.dsh-ig-workbench-modal-box{width:100%;max-width:380px;background:var(--background,#fff);border-radius:12px;padding:20px;box-shadow:0 20px 48px rgba(0,0,0,.22);display:flex;flex-direction:column;gap:14px}\n.dsh-ig-workbench-modal-header{display:flex;align-items:center;gap:10px}\n.dsh-ig-workbench-modal-header strong{font-size:14px;font-weight:650;color:#b91c1c}\n.dsh-ig-workbench-modal-desc{font-size:12px;line-height:18px;color:#555f77;margin:0}\n.dsh-ig-workbench-modal-option{display:flex;align-items:center;gap:8px;font-size:11.5px;color:#4b5563;cursor:pointer}\n.dsh-ig-workbench-modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:4px}\n.dsh-ig-workbench-modal-actions button{height:32px;padding:0 14px;border-radius:7px;font-size:11.5px;font-weight:600;cursor:pointer}\n.dsh-ig-workbench-modal-cancel{border:1px solid var(--ig-line);background:var(--background,#fff);color:#6b7280}\n.dsh-ig-workbench-modal-cancel:hover{background:#f3f4f6}\n.dsh-ig-workbench-modal-danger{border:0;background:#dc2626;color:#fff}\n.dsh-ig-workbench-modal-danger:hover{background:#b91c1c}\n@keyframes dshIgPulse{50%{transform:scale(1.06);box-shadow:0 0 0 16px rgba(47,100,245,.025)}}\n.dsh-ig-workbench-toast{position:fixed;bottom:28px;left:50%;transform:translateX(-50%);background:rgba(15,23,42,0.88);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);color:#fff;padding:8px 18px;border-radius:10px;font-size:12.5px;font-weight:500;box-shadow:0 12px 32px rgba(0,0,0,0.3);z-index:99999;animation:dshIgFade .15s ease-out;pointer-events:none}\n@keyframes dshIgFade{from{opacity:0;transform:translate(-50%,6px)}to{opacity:1;transform:translate(-50%,0)}}\n@media(max-width:1120px){.dsh-ig-workbench-grid{grid-template-columns:190px minmax(360px,1fr) 300px}.dsh-ig-result-actions button,.dsh-ig-result-strip button{padding:0 7px;font-size:10px;gap:4px}.dsh-ig-result-actions>div,.dsh-ig-result-strip>div{gap:5px}}\n@media(max-width:900px){.dsh-ig-gallery-page-body.is-workbench{height:auto;overflow:auto}.dsh-ig-workbench{height:auto;min-height:100%;overflow:visible;padding:12px}.dsh-ig-workbench-heading{height:auto;padding-bottom:12px;align-items:center}.dsh-ig-provider-quick>span{display:none}.dsh-ig-workbench-grid{height:auto;display:flex;flex:none;flex-direction:column;overflow:visible}.dsh-ig-recent-panel{height:auto;overflow:hidden;border-right:0;border-bottom:1px solid var(--ig-line)}.dsh-ig-recent-scroll{height:auto;display:flex;overflow-x:auto;overflow-y:hidden;padding:8px}.dsh-ig-recent-item{min-width:220px}.dsh-ig-canvas-column{height:auto;min-height:560px}.dsh-ig-generate-panel{height:auto;border-left:0;border-top:1px solid var(--ig-line);min-height:560px}.dsh-ig-generator-form{height:auto;overflow:visible}.dsh-ig-canvas{height:auto;min-height:360px}}\n@media(max-width:560px){.dsh-ig-workbench-heading>div{display:block}.dsh-ig-workbench-heading h1{font-size:15px}.dsh-ig-provider-quick select{min-width:128px;max-width:150px}.dsh-ig-canvas{padding:12px;min-height:300px}.dsh-ig-result-strip,.dsh-ig-result-actions{align-items:flex-start;flex-direction:column}.dsh-ig-result-strip>div,.dsh-ig-result-actions>div{width:100%}.dsh-ig-result-strip button,.dsh-ig-result-actions button{flex:1;justify-content:center}.dsh-ig-result-actions button span{display:inline}.dsh-ig-field-grid{grid-template-columns:1fr}.dsh-ig-result-meta span+span:before{display:none}}\n@media(prefers-reduced-motion:reduce){.dsh-ig-workbench *{scroll-behavior:auto!important;animation-duration:.01ms!important;transition-duration:.01ms!important}}\n.dsh-ig-field-label>span{display:flex;align-items:center;gap:5px}.dsh-ig-field-label .dsh-ig-find-inspiration{display:inline-flex;align-items:center;gap:3px;color:var(--ig-blue);font-weight:600}.dsh-ig-field-label .dsh-ig-find-inspiration:hover{color:#1644c1}\n.dsh-ig-workspace-filter-label{height:30px;display:inline-flex;align-items:center;gap:6px;padding:0 10px;border:1px solid var(--ig-line,rgba(0,0,0,.1));border-radius:7px;background:var(--background,#fff);font-size:11.5px;color:var(--foreground,#242f44);cursor:pointer;user-select:none;transition:border-color .15s,background .15s}\n.dsh-ig-workspace-filter-label:hover{border-color:#9bb4f5;background:rgba(47,100,245,.04)}\n.dsh-ig-workspace-checkbox{cursor:pointer;accent-color:#2f64f5;width:13.5px;height:13.5px;margin:0}\n.dsh-ig-workspace-filter-text{font-weight:500;white-space:nowrap}\n.dsh-ig-workspace-filter-badge{font-size:10px;font-weight:600;padding:1px 6px;border-radius:999px;background:color-mix(in srgb,currentColor 7%,transparent);color:#64748b;font-variant-numeric:tabular-nums}\n.dsh-ig-canvas-cluster{display:grid;gap:16px;align-items:center;justify-content:center;user-select:none;pointer-events:auto;flex-shrink:0}\n.dsh-ig-canvas-cluster[data-count=\"2\"]{grid-template-columns:repeat(2,1fr);max-width:880px}\n.dsh-ig-canvas-cluster[data-count=\"3\"],.dsh-ig-canvas-cluster[data-count=\"4\"]{grid-template-columns:repeat(2,1fr);max-width:760px}\n.dsh-ig-canvas-item{position:relative;display:flex;align-items:center;justify-content:center;border-radius:10px;cursor:pointer;transition:transform .12s ease-out}\n.dsh-ig-canvas-item img{display:block;max-width:100%;max-height:360px;width:auto;height:auto;object-fit:contain;border-radius:10px;box-shadow:0 10px 30px rgba(25,35,63,.16);user-select:none;-webkit-user-drag:none;pointer-events:auto;transition:box-shadow .15s,outline .15s}\n.dsh-ig-canvas-item:hover img{box-shadow:0 14px 40px rgba(47,100,245,.2)}\n.dsh-ig-canvas-item.is-active img{box-shadow:0 14px 40px rgba(47,100,245,.28)}\n.dsh-ig-canvas-item.is-checked img{outline:3px solid var(--ig-blue);outline-offset:2px;box-shadow:0 14px 40px rgba(47,100,245,.35)}\n.dsh-ig-canvas-badge{position:absolute;top:10px;left:10px;background:rgba(15,23,42,.7);color:#fff;font-size:11px;font-weight:700;padding:2px 7px;border-radius:5px;backdrop-filter:blur(4px);pointer-events:none;transition:background .15s;z-index:2}\n.dsh-ig-canvas-badge.is-model{max-width:calc(100% - 20px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}\n.dsh-ig-canvas-item.is-checked .dsh-ig-canvas-badge{background:var(--ig-blue)}\n.dsh-ig-canvas-check{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1.5px solid rgba(255,255,255,.85);border-radius:50%;display:grid;place-items:center;background:rgba(15,23,42,.48);color:#fff;box-shadow:0 2px 8px rgba(15,23,42,.18);backdrop-filter:blur(4px);z-index:2;pointer-events:none}.dsh-ig-canvas-item.is-checked .dsh-ig-canvas-check{border-color:#fff;background:var(--ig-blue)}\n.dsh-ig-canvas-item-loading{width:260px;height:260px;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,.45);border:1px solid var(--ig-line);border-radius:10px;color:#929bad}\n.dsh-ig-lightbox-nav{position:absolute;top:50%;transform:translateY(-50%);width:42px;height:42px;border-radius:50%;border:0;background:rgba(15,23,42,.65);color:#fff;display:grid;place-items:center;cursor:pointer;transition:background .15s,transform .15s;z-index:10;backdrop-filter:blur(4px)}\n.dsh-ig-lightbox-nav:hover{background:rgba(47,100,245,.85);transform:translateY(-50%) scale(1.08)}\n.dsh-ig-lightbox-nav.is-prev{left:18px}\n.dsh-ig-lightbox-nav.is-next{right:18px}\n.dsh-ig-save-gallery-btn{color:var(--ig-blue)!important;border-color:rgba(47,100,245,.35)!important;background:rgba(47,100,245,.06)!important}\n.dsh-ig-save-gallery-btn:hover{background:rgba(47,100,245,.12)!important}\n.dsh-ig-save-gallery-btn.is-saved{color:#64748b!important;border-color:var(--ig-line)!important;background:transparent!important}\n";
|
|
1
|
+
export declare const STUDIO_STYLE = "\n.dsh-ig-gallery-page-body.is-workbench{flex:1 1 0;height:100%;min-height:0;padding:0;overflow:hidden;display:flex;flex-direction:column}\n.dsh-ig-workbench{--ig-blue:#2f64f5;--ig-line:color-mix(in srgb,currentColor 11%,transparent);--ig-soft:color-mix(in srgb,currentColor 4%,transparent);position:relative;display:flex;flex-direction:column;min-height:0;height:100%;overflow:hidden;padding:10px 12px 12px;color:var(--foreground,#182033);box-sizing:border-box;background:radial-gradient(circle at 60% -20%,rgba(63,104,246,.07),transparent 30%)}\n.dsh-ig-workbench *{box-sizing:border-box}.dsh-ig-workbench button,.dsh-ig-workbench select,.dsh-ig-workbench textarea{font:inherit;color:inherit}\n.dsh-ig-workbench-grid{display:grid;grid-template-columns:minmax(190px,238px) minmax(0,1fr) minmax(286px,340px);grid-template-rows:minmax(0,1fr);min-height:0;height:0;flex:1 1 0;border:1px solid var(--ig-line);border-radius:12px;overflow:hidden;background:var(--background,#fff);box-shadow:0 12px 32px rgba(30,42,76,.05);transition:grid-template-columns .2s ease}\n.dsh-ig-workbench-grid.is-sidebar-collapsed{grid-template-columns:minmax(0,1fr) minmax(286px,340px)}\n.dsh-ig-workbench-grid.is-generate-collapsed{grid-template-columns:minmax(190px,238px) minmax(0,1fr)}\n.dsh-ig-workbench-grid.is-sidebar-collapsed.is-generate-collapsed{grid-template-columns:minmax(0,1fr)}\n.dsh-ig-recent-panel,.dsh-ig-generate-panel{min-width:0;min-height:0;overflow:hidden;background:color-mix(in srgb,var(--background,#fff) 96%,#f5f7fb)}.dsh-ig-recent-panel{display:flex;flex-direction:column;border-right:1px solid var(--ig-line)}\n.dsh-ig-panel-title{height:48px;flex:0 0 48px;padding:0 12px 0 14px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--ig-line);font-size:13px;font-weight:650}\n.dsh-ig-count-badge{font-size:11px;min-width:22px;text-align:center;padding:2px 6px;border-radius:999px;background:var(--ig-soft);color:#7b8498;font-weight:500}\n.dsh-ig-collapse-btn{width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;border-radius:6px;background:transparent;color:#717b90;cursor:pointer;transition:all .15s}\n.dsh-ig-collapse-btn:hover{border-color:var(--ig-line);background:var(--ig-soft);color:var(--foreground,#182033)}\n.dsh-ig-recent-scroll{flex:1 1 0;height:0;padding:8px;overflow-x:hidden;overflow-y:auto;min-height:0}.dsh-ig-recent-empty{min-height:180px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:10px;color:#929bad;text-align:center;font-size:12px}\n.dsh-ig-recent-item{display:grid;grid-template-columns:70px minmax(0,1fr);gap:10px;width:100%;padding:8px;border:1px solid transparent;border-radius:9px;background:transparent;text-align:left;cursor:pointer;transition:background .16s,border-color .16s,transform .16s}.dsh-ig-recent-item:hover{background:var(--ig-soft);transform:translateY(-1px)}.dsh-ig-recent-item.is-active{border-color:#89a7ff;background:rgba(47,100,245,.075);box-shadow:inset 3px 0 0 var(--ig-blue)}.dsh-ig-recent-thumb{width:70px;height:70px;border-radius:7px;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#eef1f7;color:#929bad}.dsh-ig-recent-thumb img{width:100%;height:100%;object-fit:cover}.dsh-ig-recent-item>div:last-child{min-width:0;padding:1px 0}.dsh-ig-recent-item strong{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;font-size:12.5px;line-height:19px;font-weight:630}.dsh-ig-recent-item span,.dsh-ig-recent-item small{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;color:#828b9e;font-size:10.5px;line-height:16px}\n.dsh-ig-load-more{width:100%;height:32px;margin:8px 0;display:flex;align-items:center;justify-content:center;border:1px dashed var(--ig-line);border-radius:7px;background:transparent;font-size:11px;color:#6b758b;cursor:pointer;transition:background .15s,color .15s}.dsh-ig-load-more:hover{background:var(--ig-soft);color:var(--ig-blue);border-color:#a2b9f6}\n.dsh-ig-mini-btn{height:22px;padding:0 7px;display:inline-flex;align-items:center;gap:3px;border:1px solid var(--ig-line);border-radius:5px;background:var(--background,#fff);font-size:10.5px;font-weight:500;color:var(--foreground,#242f44);cursor:pointer;transition:all .15s}.dsh-ig-mini-btn:hover{border-color:#9bb4f5;color:var(--ig-blue);background:rgba(47,100,245,.06)}\n.dsh-ig-canvas-column{min-width:0;min-height:0;height:100%;overflow:hidden;display:flex;flex-direction:column;background:color-mix(in srgb,var(--background,#fff) 97%,#e8edf7)}\n.dsh-ig-canvas-toolbar{height:46px;flex:0 0 46px;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 14px;border-bottom:1px solid var(--ig-line)}\n.dsh-ig-canvas-toolbar-left,.dsh-ig-canvas-toolbar-right{display:flex;align-items:center;gap:6px}\n.dsh-ig-canvas-toolbar button{height:30px;min-width:30px;padding:0 9px;display:inline-flex;align-items:center;justify-content:center;gap:5px;border:1px solid var(--ig-line);border-radius:7px;background:var(--background,#fff);color:var(--foreground,#242f44);font-size:11.5px;font-weight:500;cursor:pointer;transition:border-color .15s,background .15s,color .15s}\n.dsh-ig-canvas-toolbar button:hover{border-color:#9bb4f5;background:rgba(47,100,245,.05);color:var(--ig-blue)}\n.dsh-ig-canvas-toolbar button.is-active{border-color:#8ba8f8;background:rgba(47,100,245,.08);color:var(--ig-blue);font-weight:550}\n.dsh-ig-zoom-display{font-size:11px;min-width:38px;text-align:center;color:#64748b;user-select:none;font-variant-numeric:tabular-nums}\n.dsh-ig-status-badge-wrap{position:relative;display:inline-flex;align-items:center}\n.dsh-ig-status-badge{height:30px;display:inline-flex;align-items:center;gap:7px;padding:0 10px;border:1px solid var(--ig-line);border-radius:7px;background:var(--background,#fff);cursor:pointer;user-select:none;transition:border-color .15s,background .15s,box-shadow .15s}\n.dsh-ig-status-badge:hover{border-color:#9bb4f5;background:rgba(47,100,245,.04)}\n.dsh-ig-status-dot{width:7px;height:7px;min-width:7px;max-width:7px;border-radius:50%;flex-shrink:0;box-sizing:border-box}\n.dsh-ig-status-dot.is-ready{background:#10b981;box-shadow:0 0 0 2px rgba(16,185,129,.2)}\n.dsh-ig-status-dot.is-muted{background:#ef4444;box-shadow:0 0 0 2px rgba(239,68,68,.2)}\n.dsh-ig-status-text{font-size:11.5px;font-weight:500;color:var(--foreground,#242f44);line-height:1}\n.dsh-ig-status-arrow{color:#94a3b8;transition:transform .15s,color .15s}\n.dsh-ig-status-badge-wrap:hover .dsh-ig-status-arrow{transform:rotate(180deg);color:var(--ig-blue)}\n.dsh-ig-status-popover{position:absolute;left:0;top:calc(100% + 6px);width:260px;background:var(--background,#fff);border:1px solid var(--ig-line);border-radius:9px;box-shadow:0 12px 36px rgba(20,28,45,.14);padding:10px 12px;z-index:40;opacity:0;pointer-events:none;transform:translateY(4px);transition:opacity .15s cubic-bezier(.16,1,.3,1),transform .15s cubic-bezier(.16,1,.3,1)}\n.dsh-ig-status-badge-wrap:hover .dsh-ig-status-popover{opacity:1;pointer-events:auto;transform:translateY(0)}\n.dsh-ig-status-popover-title{display:flex;align-items:center;justify-content:space-between;font-size:10px;font-weight:650;color:#8590a6;margin-bottom:8px;letter-spacing:.02em;text-transform:uppercase}\n.dsh-ig-status-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:5px}\n.dsh-ig-status-list li{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 8px;border-radius:6px;transition:background .12s}\n.dsh-ig-status-list li.is-configured{background:rgba(16,185,129,.05);border:1px solid rgba(16,185,129,.12)}\n.dsh-ig-status-list li.is-missing{background:rgba(239,68,68,.04);border:1px solid rgba(239,68,68,.12);opacity:.75}\n.dsh-ig-status-item-name{display:flex;flex-direction:column;min-width:0}\n.dsh-ig-status-item-name strong{font-size:11.5px;font-weight:600;color:var(--foreground,#182033);line-height:16px}\n.dsh-ig-status-item-name small{font-size:9.5px;color:#7c869a;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:145px;line-height:14px}\n.dsh-ig-status-item-tag{font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;flex-shrink:0}\n.is-configured .dsh-ig-status-item-tag{color:#059669;background:rgba(16,185,129,.14)}\n.is-missing .dsh-ig-status-item-tag{color:#dc2626;background:rgba(239,68,68,.14)}\n.dsh-ig-canvas{position:relative;flex:1 1 0;height:0;min-height:0;display:flex;align-items:center;justify-content:center;overflow:hidden;padding:24px;touch-action:none;user-select:none;cursor:grab;background-image:linear-gradient(45deg,rgba(114,128,156,.035) 25%,transparent 25%),linear-gradient(-45deg,rgba(114,128,156,.035) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(114,128,156,.035) 75%),linear-gradient(-45deg,transparent 75%,rgba(114,128,156,.035) 75%);background-size:24px 24px;background-position:0 0,0 12px,12px -12px,-12px 0}\n.dsh-ig-canvas.is-dragging,.dsh-ig-canvas.is-dragging *{cursor:grabbing!important}\n.dsh-ig-canvas img{display:block;max-width:100%;max-height:100%;width:auto;height:auto;border-radius:10px;box-shadow:0 14px 45px rgba(25,35,63,.18);user-select:none;-webkit-user-drag:none;pointer-events:auto}\n.dsh-ig-canvas-empty,.dsh-ig-generating-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:12px;color:#929bad;font-size:12px;padding:26px;cursor:default}\n.dsh-ig-generating-state strong{font-size:15px;color:var(--foreground,#182033)}.dsh-ig-generating-state span{font-size:11px}.dsh-ig-generation-orbit{width:66px;height:66px;border-radius:50%;display:grid;place-items:center;color:var(--ig-blue);background:rgba(47,100,245,.09);box-shadow:0 0 0 10px rgba(47,100,245,.035);animation:dshIgPulse 1.8s ease-in-out infinite}\n.dsh-ig-result-strip{flex:0 0 auto;min-height:52px;padding:8px 14px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--ig-line)}.dsh-ig-result-strip>span{font-size:12px;font-weight:650}.dsh-ig-result-strip>div,.dsh-ig-result-actions>div{display:flex;gap:7px}.dsh-ig-result-strip button,.dsh-ig-result-actions button{height:32px;display:inline-flex;align-items:center;gap:6px;padding:0 10px;border:1px solid var(--ig-line);border-radius:7px;background:var(--background,#fff);font-size:11px;cursor:pointer}.dsh-ig-result-strip button:hover,.dsh-ig-result-actions button:hover{border-color:#9fb2ed;color:var(--ig-blue)}.dsh-ig-result-actions{flex:0 0 auto;min-height:54px;padding:8px 14px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--ig-line)}.dsh-ig-result-actions p{margin:0;min-width:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:11.5px;line-height:18px;color:#596277}.dsh-ig-result-meta{flex:0 0 auto;min-height:32px;padding:6px 14px;display:flex;gap:13px;align-items:center;flex-wrap:wrap;border-top:1px solid var(--ig-line);font-size:10px;color:#8790a3}.dsh-ig-result-meta span+span:before{content:'\u00B7';margin-right:13px}\n.dsh-ig-generate-panel{height:100%;display:flex;flex-direction:column;border-left:1px solid var(--ig-line);overflow:hidden}.dsh-ig-generator-form{flex:1 1 0;height:0;padding:15px;display:flex;flex-direction:column;gap:15px;overflow-x:hidden;overflow-y:auto;min-height:0}.dsh-ig-mode-switch{display:grid;grid-template-columns:1fr 1fr;gap:8px}.dsh-ig-mode-switch button{height:39px;border:1px solid var(--ig-line);border-radius:8px;background:var(--background,#fff);display:flex;align-items:center;justify-content:center;gap:7px;font-size:12px;cursor:pointer}.dsh-ig-mode-switch button.is-active{border-color:#789bff;color:var(--ig-blue);background:rgba(47,100,245,.065);box-shadow:inset 0 0 0 1px rgba(47,100,245,.1)}\n.dsh-ig-field{position:relative;display:flex;flex-direction:column;gap:7px}.dsh-ig-field>label,.dsh-ig-field-label label{font-size:11.5px;font-weight:630}.dsh-ig-field>label span{font-weight:400;color:#929bad}.dsh-ig-field-label{display:flex;align-items:center;justify-content:space-between}.dsh-ig-field-label b{color:#e14d4d}.dsh-ig-field-label button{border:0;background:transparent;color:#798397;font-size:10.5px;cursor:pointer}.dsh-ig-field textarea{width:100%;height:112px;padding:11px 12px 22px;resize:vertical;border:1px solid var(--ig-line);border-radius:9px;background:var(--background,#fff);font-size:12px;line-height:19px;outline:none}.dsh-ig-field textarea:focus{border-color:var(--ig-blue);box-shadow:0 0 0 3px rgba(47,100,245,.09)}.dsh-ig-field>small{position:absolute;right:9px;bottom:7px;color:#9aa2b2;font-size:9.5px}.dsh-ig-field-grid{display:grid;grid-template-columns:1fr 1fr;gap:9px}.dsh-ig-field-select{display:flex;flex-direction:column;gap:6px;min-width:0}.dsh-ig-field-select>span{font-size:11px;font-weight:620}.dsh-ig-field-select select{width:100%;height:36px;padding:0 26px 0 9px;border:1px solid var(--ig-line);border-radius:8px;background:var(--background,#fff);font-size:11px;outline:none;text-overflow:ellipsis}.dsh-ig-field-select select:focus{border-color:var(--ig-blue)}.dsh-ig-count-row{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}.dsh-ig-count-pill{height:34px;border:1px solid var(--ig-line);border-radius:7px;background:var(--background,#fff);font-size:12px;font-weight:600;color:#596277;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .15s}.dsh-ig-count-pill:hover{border-color:#9fb2ed;color:var(--ig-blue)}.dsh-ig-count-pill.is-active{border-color:var(--ig-blue);background:rgba(47,100,245,.08);color:var(--ig-blue);box-shadow:inset 0 0 0 1px var(--ig-blue)}\n.dsh-ig-generation-kind{display:grid;grid-template-columns:1fr 1fr;gap:4px;padding:3px;border:1px solid var(--ig-line);border-radius:9px;background:var(--ig-soft)}.dsh-ig-generation-kind button{height:31px;border:0;border-radius:6px;background:transparent;color:#778196;font-size:11.5px;display:flex;align-items:center;justify-content:center;gap:6px;cursor:pointer;transition:background .15s,color .15s,box-shadow .15s}.dsh-ig-generation-kind button.is-active{background:var(--background,#fff);color:var(--ig-blue);font-weight:650;box-shadow:0 2px 8px rgba(30,42,76,.09)}\n.dsh-ig-compare-box{padding:10px;border:1px solid rgba(47,100,245,.2);border-radius:10px;background:linear-gradient(145deg,rgba(47,100,245,.055),rgba(99,102,241,.018));display:flex;flex-direction:column;gap:9px}.dsh-ig-compare-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.dsh-ig-compare-heading>div{min-width:0;display:flex;flex-direction:column;gap:2px}.dsh-ig-compare-heading strong{font-size:11.5px}.dsh-ig-compare-heading small{font-size:9.5px;color:#838da1}.dsh-ig-compare-heading>span{flex:none;padding:2px 6px;border-radius:999px;background:rgba(47,100,245,.11);color:var(--ig-blue);font-size:9.5px;font-weight:650}.dsh-ig-model-checks{display:flex;flex-direction:column;gap:6px}.dsh-ig-model-checks>button{min-height:43px;width:100%;padding:6px 7px;display:grid;grid-template-columns:18px minmax(0,1fr) auto;align-items:center;gap:7px;border:1px solid var(--ig-line);border-radius:8px;background:var(--background,#fff);text-align:left;cursor:pointer;transition:border-color .15s,background .15s,transform .15s}.dsh-ig-model-checks>button:hover{border-color:#9cb2ef;transform:translateY(-1px)}.dsh-ig-model-checks>button.is-selected{border-color:#86a4fa;background:rgba(47,100,245,.055);box-shadow:inset 3px 0 0 var(--ig-blue)}.dsh-ig-model-checkmark{width:17px;height:17px;border:1px solid #bdc6d8;border-radius:5px;display:grid;place-items:center;color:#fff;background:var(--background,#fff)}.dsh-ig-model-checks>button.is-selected .dsh-ig-model-checkmark{border-color:var(--ig-blue);background:var(--ig-blue)}.dsh-ig-model-copy{display:flex;flex-direction:column;min-width:0}.dsh-ig-model-copy strong{font-size:11px;line-height:15px}.dsh-ig-model-copy small{max-width:130px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#80899b;font-size:9.5px;line-height:14px}.dsh-ig-model-settings{display:flex;flex-direction:column;align-items:flex-end;gap:2px;color:#596277;font-size:9.5px;white-space:nowrap}.dsh-ig-model-settings em{font-style:normal;color:#a16a0a;font-size:8.5px}.dsh-ig-compare-box>p{margin:0;color:#8a7180;font-size:9.5px;line-height:14px}\n.dsh-ig-upload{height:92px;border:1px dashed #bcc6d9;border-radius:9px;background:rgba(255,255,255,.45);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;color:#7d879b;cursor:pointer}.dsh-ig-upload strong{font-size:11px;font-weight:570}.dsh-ig-upload small{font-size:9.5px}.dsh-ig-upload:hover,.dsh-ig-upload.is-dragging{border-color:var(--ig-blue);background:rgba(47,100,245,.05);color:var(--ig-blue)}\n.dsh-ig-reference-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(64px,1fr));gap:8px}\n.dsh-ig-reference-card{position:relative;aspect-ratio:1;border-radius:8px;overflow:hidden;background:#eef1f7;border:1px solid var(--ig-line)}\n.dsh-ig-reference-card img{width:100%;height:100%;object-fit:cover}\n.dsh-ig-reference-card button{position:absolute;right:4px;top:4px;width:18px;height:18px;border:0;border-radius:50%;display:grid;place-items:center;background:rgba(20,28,45,.75);color:#fff;cursor:pointer;padding:0;transition:background .15s}\n.dsh-ig-reference-card button:hover{background:#ef4444}\n.dsh-ig-reference-add{aspect-ratio:1;border:1px dashed #bcc6d9;border-radius:8px;background:rgba(255,255,255,.45);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;color:#7d879b;cursor:pointer;font-size:10px;transition:border-color .15s,color .15s,background .15s}\n.dsh-ig-reference-add:hover{border-color:var(--ig-blue);background:rgba(47,100,245,.05);color:var(--ig-blue)}\n.dsh-ig-reference-preview{position:relative;height:108px;border-radius:9px;overflow:hidden;background:#eef1f7}.dsh-ig-reference-preview img{width:100%;height:100%;object-fit:contain}.dsh-ig-reference-preview button{position:absolute;right:7px;top:7px;width:25px;height:25px;border:0;border-radius:50%;display:grid;place-items:center;background:rgba(20,28,45,.72);color:#fff;cursor:pointer}\n.dsh-ig-inline-note,.dsh-ig-form-error{padding:9px 10px;border-radius:7px;font-size:10.5px;line-height:16px}.dsh-ig-inline-note{background:#fff8e7;color:#8b671c;border:1px solid #f1dfae}.dsh-ig-form-error{background:#fff1f1;color:#b63737;border:1px solid #f2caca}.dsh-ig-form-loading{height:70px;display:grid;place-items:center;color:var(--ig-blue)}\n.dsh-ig-config-error{padding:14px;display:flex;flex-direction:column;align-items:center;gap:10px;background:#fff1f1;border:1px solid #f2caca;border-radius:8px;color:#b63737;font-size:11.5px;text-align:center}.dsh-ig-config-error p{margin:0;line-height:17px}.dsh-ig-config-error button{height:30px;display:inline-flex;align-items:center;gap:6px;padding:0 12px;border:1px solid #e0a8a8;border-radius:6px;background:#fff;color:#b63737;font-size:11.5px;font-weight:600;cursor:pointer}.dsh-ig-config-error button:hover{background:#ffebeb}\n.dsh-ig-generate-button{height:42px;flex:0 0 auto;border:0;border-radius:8px;background:linear-gradient(135deg,#386cf6,#2758e7);color:#fff!important;display:flex;align-items:center;justify-content:center;gap:8px;font-size:12px;font-weight:650;cursor:pointer;box-shadow:0 8px 18px rgba(47,100,245,.22);transition:transform .16s,box-shadow .16s}.dsh-ig-generate-button:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 10px 24px rgba(47,100,245,.28)}.dsh-ig-generate-button:disabled{opacity:.55;cursor:not-allowed;box-shadow:none}\n.dsh-ig-generate-button.is-cancel{background:linear-gradient(135deg,#ef4444,#dc2626);box-shadow:0 8px 18px rgba(239,68,68,.25)}.dsh-ig-generate-button.is-cancel:hover{background:linear-gradient(135deg,#dc2626,#b91c1c);box-shadow:0 10px 24px rgba(239,68,68,.35)}\n.dsh-ig-details{padding:16px;margin:0;overflow:auto}.dsh-ig-details>div{padding:12px 0;border-bottom:1px solid var(--ig-line)}.dsh-ig-details dt{font-size:10.5px;color:#8992a4;margin-bottom:5px}.dsh-ig-details dd{margin:0;font-size:11.5px;line-height:18px;word-break:break-word}.dsh-ig-details-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;height:220px;padding:20px;color:#929bad;font-size:11px;text-align:center}\n.dsh-ig-workbench-modal-backdrop{position:fixed;inset:0;background:rgba(15,23,42,.45);backdrop-filter:blur(3px);z-index:999;display:grid;place-items:center;padding:16px}\n.dsh-ig-workbench-modal-box{width:100%;max-width:380px;background:var(--background,#fff);border-radius:12px;padding:20px;box-shadow:0 20px 48px rgba(0,0,0,.22);display:flex;flex-direction:column;gap:14px}\n.dsh-ig-workbench-modal-header{display:flex;align-items:center;gap:10px}\n.dsh-ig-workbench-modal-header strong{font-size:14px;font-weight:650;color:#b91c1c}\n.dsh-ig-workbench-modal-desc{font-size:12px;line-height:18px;color:#555f77;margin:0}\n.dsh-ig-workbench-modal-option{display:flex;align-items:center;gap:8px;font-size:11.5px;color:#4b5563;cursor:pointer}\n.dsh-ig-workbench-modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:4px}\n.dsh-ig-workbench-modal-actions button{height:32px;padding:0 14px;border-radius:7px;font-size:11.5px;font-weight:600;cursor:pointer}\n.dsh-ig-workbench-modal-cancel{border:1px solid var(--ig-line);background:var(--background,#fff);color:#6b7280}\n.dsh-ig-workbench-modal-cancel:hover{background:#f3f4f6}\n.dsh-ig-workbench-modal-danger{border:0;background:#dc2626;color:#fff}\n.dsh-ig-workbench-modal-danger:hover{background:#b91c1c}\n@keyframes dshIgPulse{50%{transform:scale(1.06);box-shadow:0 0 0 16px rgba(47,100,245,.025)}}\n.dsh-ig-workbench-toast{position:fixed;bottom:28px;left:50%;transform:translateX(-50%);background:rgba(15,23,42,0.88);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);color:#fff;padding:8px 18px;border-radius:10px;font-size:12.5px;font-weight:500;box-shadow:0 12px 32px rgba(0,0,0,0.3);z-index:99999;animation:dshIgFade .15s ease-out;pointer-events:none}\n@keyframes dshIgFade{from{opacity:0;transform:translate(-50%,6px)}to{opacity:1;transform:translate(-50%,0)}}\n@media(max-width:1120px){.dsh-ig-workbench-grid{grid-template-columns:190px minmax(360px,1fr) 300px}.dsh-ig-result-actions button,.dsh-ig-result-strip button{padding:0 7px;font-size:10px;gap:4px}.dsh-ig-result-actions>div,.dsh-ig-result-strip>div{gap:5px}}\n@media(max-width:900px){.dsh-ig-gallery-page-body.is-workbench{height:auto;overflow:auto}.dsh-ig-workbench{height:auto;min-height:100%;overflow:visible;padding:12px}.dsh-ig-workbench-heading{height:auto;padding-bottom:12px;align-items:center}.dsh-ig-provider-quick>span{display:none}.dsh-ig-workbench-grid{height:auto;display:flex;flex:none;flex-direction:column;overflow:visible}.dsh-ig-recent-panel{height:auto;overflow:hidden;border-right:0;border-bottom:1px solid var(--ig-line)}.dsh-ig-recent-scroll{height:auto;display:flex;overflow-x:auto;overflow-y:hidden;padding:8px}.dsh-ig-recent-item{min-width:220px}.dsh-ig-canvas-column{height:auto;min-height:560px}.dsh-ig-generate-panel{height:auto;border-left:0;border-top:1px solid var(--ig-line);min-height:560px}.dsh-ig-generator-form{height:auto;overflow:visible}.dsh-ig-canvas{height:auto;min-height:360px}}\n@media(max-width:560px){.dsh-ig-workbench-heading>div{display:block}.dsh-ig-workbench-heading h1{font-size:15px}.dsh-ig-provider-quick select{min-width:128px;max-width:150px}.dsh-ig-canvas{padding:12px;min-height:300px}.dsh-ig-result-strip,.dsh-ig-result-actions{align-items:flex-start;flex-direction:column}.dsh-ig-result-strip>div,.dsh-ig-result-actions>div{width:100%}.dsh-ig-result-strip button,.dsh-ig-result-actions button{flex:1;justify-content:center}.dsh-ig-result-actions button span{display:inline}.dsh-ig-field-grid{grid-template-columns:1fr}.dsh-ig-result-meta span+span:before{display:none}}\n@media(prefers-reduced-motion:reduce){.dsh-ig-workbench *{scroll-behavior:auto!important;animation-duration:.01ms!important;transition-duration:.01ms!important}}\n.dsh-ig-field-label>span{display:flex;align-items:center;gap:5px}.dsh-ig-field-label .dsh-ig-find-inspiration{display:inline-flex;align-items:center;gap:3px;color:var(--ig-blue);font-weight:600}.dsh-ig-field-label .dsh-ig-find-inspiration:hover{color:#1644c1}\n.dsh-ig-workspace-filter-label{height:30px;display:inline-flex;align-items:center;gap:6px;padding:0 10px;border:1px solid var(--ig-line,rgba(0,0,0,.1));border-radius:7px;background:var(--background,#fff);font-size:11.5px;color:var(--foreground,#242f44);cursor:pointer;user-select:none;transition:border-color .15s,background .15s}\n.dsh-ig-workspace-filter-label:hover{border-color:#9bb4f5;background:rgba(47,100,245,.04)}\n.dsh-ig-workspace-checkbox{cursor:pointer;accent-color:#2f64f5;width:13.5px;height:13.5px;margin:0}\n.dsh-ig-workspace-filter-text{font-weight:500;white-space:nowrap}\n.dsh-ig-workspace-filter-badge{font-size:10px;font-weight:600;padding:1px 6px;border-radius:999px;background:color-mix(in srgb,currentColor 7%,transparent);color:#64748b;font-variant-numeric:tabular-nums}\n.dsh-ig-canvas-cluster{display:grid;gap:16px;align-items:center;justify-content:center;user-select:none;pointer-events:auto;flex-shrink:0}\n.dsh-ig-canvas-cluster[data-count=\"2\"]{grid-template-columns:repeat(2,1fr);max-width:880px}\n.dsh-ig-canvas-cluster[data-count=\"3\"],.dsh-ig-canvas-cluster[data-count=\"4\"]{grid-template-columns:repeat(2,1fr);max-width:760px}\n.dsh-ig-canvas-item{position:relative;display:flex;align-items:center;justify-content:center;border-radius:10px;cursor:pointer;transition:transform .12s ease-out}\n.dsh-ig-canvas-item img{display:block;max-width:100%;max-height:360px;width:auto;height:auto;object-fit:contain;border-radius:10px;box-shadow:0 10px 30px rgba(25,35,63,.16);user-select:none;-webkit-user-drag:none;pointer-events:auto;transition:box-shadow .15s,outline .15s}\n.dsh-ig-canvas-item:hover img{box-shadow:0 14px 40px rgba(47,100,245,.2)}\n.dsh-ig-canvas-item.is-active img{box-shadow:0 14px 40px rgba(47,100,245,.28)}\n.dsh-ig-canvas-item.is-checked img{outline:3px solid var(--ig-blue);outline-offset:2px;box-shadow:0 14px 40px rgba(47,100,245,.35)}\n.dsh-ig-canvas-badge{position:absolute;top:10px;left:10px;background:rgba(15,23,42,.7);color:#fff;font-size:11px;font-weight:700;padding:2px 7px;border-radius:5px;backdrop-filter:blur(4px);pointer-events:none;transition:background .15s;z-index:2}\n.dsh-ig-canvas-badge.is-model{max-width:calc(100% - 20px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}\n.dsh-ig-canvas-item.is-checked .dsh-ig-canvas-badge{background:var(--ig-blue)}\n.dsh-ig-canvas-check{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1.5px solid rgba(255,255,255,.85);border-radius:50%;display:grid;place-items:center;background:rgba(15,23,42,.48);color:#fff;box-shadow:0 2px 8px rgba(15,23,42,.18);backdrop-filter:blur(4px);z-index:2;pointer-events:none}.dsh-ig-canvas-item.is-checked .dsh-ig-canvas-check{border-color:#fff;background:var(--ig-blue)}\n.dsh-ig-canvas-item-loading{width:260px;height:260px;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,.45);border:1px solid var(--ig-line);border-radius:10px;color:#929bad}\n.dsh-ig-lightbox-nav{position:absolute;top:50%;transform:translateY(-50%);width:42px;height:42px;border-radius:50%;border:0;background:rgba(15,23,42,.65);color:#fff;display:grid;place-items:center;cursor:pointer;transition:background .15s,transform .15s;z-index:10;backdrop-filter:blur(4px)}\n.dsh-ig-lightbox-nav:hover{background:rgba(47,100,245,.85);transform:translateY(-50%) scale(1.08)}\n.dsh-ig-lightbox-nav.is-prev{left:18px}\n.dsh-ig-lightbox-nav.is-next{right:18px}\n.dsh-ig-save-gallery-btn{color:var(--ig-blue)!important;border-color:rgba(47,100,245,.35)!important;background:rgba(47,100,245,.06)!important}\n.dsh-ig-save-gallery-btn:hover{background:rgba(47,100,245,.12)!important}\n.dsh-ig-save-gallery-btn.is-saved{color:#64748b!important;border-color:var(--ig-line)!important;background:transparent!important}\n\n/* tldraw infinite canvas surface (P0 spike) */\n.dsh-ig-tl-canvas{position:relative;flex:1 1 0;height:0;min-height:0;overflow:hidden;isolation:isolate}\n\n/* ---- Right-sidebar seat variant (DSH 0.1.5 'sidebar.right.pane.tab') ----\n The seat is a narrow panel beside the conversation column, not a full\n conversation tab. Specificity (0,2,0) outranks every viewport media query\n above, so these apply regardless of window size: tabs scroll instead of\n wrapping, the page fills the seat box, and the workbench grid shrinks its\n rail and generate-form columns. StudioView's narrow-width observer\n (ResizeObserver) folds the recent rail under 560px. */\n.dsh-ig-page-in-sidebar .dsh-ig-studio-tabs-bar{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:thin}\n.dsh-ig-page-in-sidebar .dsh-ig-studio-tab-btn{flex:0 0 auto;white-space:nowrap}\n.dsh-ig-page-in-sidebar .dsh-ig-gallery-page-body{padding:14px 14px 16px}\n.dsh-ig-page-in-sidebar .dsh-ig-workbench{padding:8px}\n.dsh-ig-page-in-sidebar .dsh-ig-workbench-grid{grid-template-columns:minmax(150px,190px) minmax(0,1fr) minmax(206px,264px)}\n.dsh-ig-page-in-sidebar .dsh-ig-workbench-grid.is-sidebar-collapsed{grid-template-columns:minmax(0,1fr) minmax(206px,264px)}\n.dsh-ig-page-in-sidebar .dsh-ig-workbench-grid.is-generate-collapsed{grid-template-columns:minmax(150px,190px) minmax(0,1fr)}\n.dsh-ig-page-in-sidebar .dsh-ig-workbench-grid.is-sidebar-collapsed.is-generate-collapsed{grid-template-columns:minmax(0,1fr)}\n.dsh-ig-page-in-sidebar .dsh-ig-recent-item{min-width:0}\n.dsh-ig-page-in-sidebar .dsh-ig-generate-panel .dsh-ig-field-grid{grid-template-columns:1fr}\n.dsh-ig-page-in-sidebar .dsh-ig-tl-canvas{min-height:280px}\n";
|