jev-devtools 0.4.0 → 0.5.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 +20 -13
- package/lib/flow/compare.d.ts +61 -0
- package/lib/flow/compare.js +336 -0
- package/lib/flow/index.d.ts +6 -1
- package/lib/flow/index.js +78 -16
- package/lib/flow/replay.d.ts +5 -0
- package/lib/flow/replay.js +55 -0
- package/lib/flow/runtime.d.ts +4 -0
- package/lib/flow/runtime.js +74 -0
- package/lib/flow/step-context.d.ts +7 -0
- package/lib/flow/step-context.js +3 -0
- package/lib/server/flows.d.ts +2 -2
- package/lib/server/flows.js +4 -6
- package/lib/server/index.js +16 -4
- package/lib/server/recorder.js +42 -6
- package/lib/src/ConnectedInspector.d.ts +1 -1
- package/lib/src/ConnectedInspector.js +14 -3
- package/lib/src/CopyFixture.d.ts +22 -0
- package/lib/src/CopyFixture.js +67 -0
- package/lib/src/FlowOverview.js +4 -2
- package/lib/src/JevDevtools.js +1 -1
- package/lib/src/JevDrawer.js +2 -4
- package/lib/src/display-redaction.d.ts +9 -0
- package/lib/src/display-redaction.js +116 -0
- package/lib/src/flow-fixture.d.ts +19 -0
- package/lib/src/flow-fixture.js +40 -0
- package/lib/src/flow-stream.js +9 -0
- package/lib/src/index.d.ts +5 -0
- package/lib/src/index.js +1 -0
- package/lib/src/inspector-styles.js +1 -1
- package/lib/src/inspector.css +207 -267
- package/package.json +2 -2
- package/skills/setup-jev-devtools/SKILL.md +8 -5
- package/skills/setup-jev-devtools/references/flows.md +15 -2
- package/skills/setup-jev-devtools/references/nextjs.md +1 -1
- package/skills/setup-jev-devtools/references/react-node.md +1 -2
- package/skills/setup-jev-devtools/references/verify.md +2 -4
package/lib/src/FlowOverview.js
CHANGED
|
@@ -6,6 +6,7 @@ import { JsonBlock } from "./TraceContent.js";
|
|
|
6
6
|
import { conditionInputs, conditionRequirement, } from "./condition-inputs.js";
|
|
7
7
|
import { formatFlowCondition } from "./flow-condition.js";
|
|
8
8
|
import { TraceDiagram } from "./TraceDiagram.js";
|
|
9
|
+
import { CopyFixtureButton, CopyFixtureReport, useFixtureCopy, } from "./CopyFixture.js";
|
|
9
10
|
import { FlowDetailsPanel } from "./FlowDetailsPanel.js";
|
|
10
11
|
import { DiagramContent } from "./DiagramContent.js";
|
|
11
12
|
// Measure in canvas coordinates: screen rectangles also include the camera zoom.
|
|
@@ -277,6 +278,7 @@ export const FlowOverview = memo(function FlowOverview({ definition, run, traces
|
|
|
277
278
|
collectionViews,
|
|
278
279
|
itemSizes,
|
|
279
280
|
]);
|
|
281
|
+
const fixtureCopy = useFixtureCopy(definition, run, tracesById);
|
|
280
282
|
const { viewport, canvas, zoom, zoomBy, fit, preserveCamera, focusArea } = useDiagramViewport(layout.width, layout.height, run.id, {
|
|
281
283
|
x: layout.left,
|
|
282
284
|
y: 0,
|
|
@@ -319,9 +321,9 @@ export const FlowOverview = memo(function FlowOverview({ definition, run, traces
|
|
|
319
321
|
const trace = step?.traceId
|
|
320
322
|
? traces.find((t) => t.id === step.traceId)
|
|
321
323
|
: undefined;
|
|
322
|
-
return (_jsx("div", { className: `flow-overview-stack ${inline ? "flow-inline-overview" : ""}`, style: inline ? { width: layout.width } : undefined, children: _jsxs("section", { className: "request-detail whole-flow", "aria-label": inline ? "Collection item flow" : "Whole flow", children: [!inline && (_jsxs("header", { className: "detail-header", children: [_jsxs("div", { children: [_jsxs("span", { className: "eyebrow", children: ["Flow run \u00B7 ", run.status] }), _jsx("h2", { children: run.name })] }), _jsxs("div", { children: [run.outcome ? (_jsxs("strong", { children: ["Outcome: ", run.outcome] })) : (run.error ?? "Execution paths"), _jsx("small", { className: "muted", children: run.durationMs !== undefined
|
|
324
|
+
return (_jsx("div", { className: `flow-overview-stack ${inline ? "flow-inline-overview" : ""}`, style: inline ? { width: layout.width } : undefined, children: _jsxs("section", { className: "request-detail whole-flow", "aria-label": inline ? "Collection item flow" : "Whole flow", children: [!inline && (_jsxs("header", { className: "detail-header", children: [_jsxs("div", { children: [_jsxs("span", { className: "eyebrow", children: ["Flow run \u00B7 ", run.status] }), _jsx("h2", { children: run.name })] }), _jsxs("div", { className: "flow-run-summary", children: [run.outcome ? (_jsxs("strong", { children: ["Outcome: ", run.outcome] })) : (run.error ?? "Execution paths"), _jsx("small", { className: "muted", children: run.durationMs !== undefined
|
|
323
325
|
? ` · ${Math.round(run.durationMs)} ms`
|
|
324
|
-
: "" })] })] })), _jsxs("div", { className: "lab-flow-toolbar", children: [!inline && (_jsxs("div", { children: [_jsx("button", { "aria-label": "Zoom flow out", onClick: () => zoomBy(1 / 1.2), children: "\u2212" }), _jsxs("output", { "aria-label": "Flow zoom", children: [zoom, "%"] }), _jsx("button", { "aria-label": "Zoom flow in", onClick: () => zoomBy(1.2), children: "+" }), _jsx("button", { onClick: fit, children: "Fit flow" }), _jsx("button", { disabled: !selected, onClick: () => selectStep(selected), children: "Focus step" })] })), _jsxs("label", { children: ["Step", _jsxs("select", { "aria-label": "Flow step", value: selected, onChange: (e) => selectStep(e.target.value), children: [_jsx("option", { value: "", children: "Select a step" }), definition.nodes.map((n) => (_jsxs("option", { value: n.id, children: [n.title ? `${n.title} (${n.id})` : n.id, " \u00B7", " ", run.steps[n.id]?.status ?? "waiting"] }, n.id)))] })] })] }), _jsxs("div", { className: "flow-workspace", children: [_jsx("div", { className: inline
|
|
326
|
+
: "" }), _jsx(CopyFixtureButton, { control: fixtureCopy })] })] })), !inline && _jsx(CopyFixtureReport, { control: fixtureCopy }), _jsxs("div", { className: "lab-flow-toolbar", children: [!inline && (_jsxs("div", { children: [_jsx("button", { "aria-label": "Zoom flow out", onClick: () => zoomBy(1 / 1.2), children: "\u2212" }), _jsxs("output", { "aria-label": "Flow zoom", children: [zoom, "%"] }), _jsx("button", { "aria-label": "Zoom flow in", onClick: () => zoomBy(1.2), children: "+" }), _jsx("button", { onClick: fit, children: "Fit flow" }), _jsx("button", { disabled: !selected, onClick: () => selectStep(selected), children: "Focus step" })] })), _jsxs("label", { children: ["Step", _jsxs("select", { "aria-label": "Flow step", value: selected, onChange: (e) => selectStep(e.target.value), children: [_jsx("option", { value: "", children: "Select a step" }), definition.nodes.map((n) => (_jsxs("option", { value: n.id, children: [n.title ? `${n.title} (${n.id})` : n.id, " \u00B7", " ", run.steps[n.id]?.status ?? "waiting"] }, n.id)))] })] })] }), _jsxs("div", { className: "flow-workspace", children: [_jsx("div", { className: inline
|
|
325
327
|
? "flow-inline-surface"
|
|
326
328
|
: "flow-overview-viewport diagram-viewport", ref: inline ? undefined : viewport, style: inline ? { height: layout.height } : undefined, tabIndex: inline ? undefined : 0, "aria-label": inline ? "Item flow canvas" : "Flow canvas", role: "region", children: _jsxs("div", { ref: inline ? undefined : canvas, className: "flow-overview-canvas", style: {
|
|
327
329
|
width: layout.width,
|
package/lib/src/JevDevtools.js
CHANGED
|
@@ -33,7 +33,7 @@ export const RequestDetail = memo(function RequestDetail({ trace, }) {
|
|
|
33
33
|
startTransition(() => setTab(name));
|
|
34
34
|
else
|
|
35
35
|
setTab(name);
|
|
36
|
-
}, children: name }, name))) }), _jsx("div", { className: `detail-body ${tab === "Flow" ? "detail-body-flow" : tab === "Questions" ? "detail-body-questions" : ""}`, children: _jsxs(Suspense, { fallback: _jsx("p", { className: "muted", role: "status", children: "Loading questions\u2026" }), children: [trace.error && (_jsxs("div", { role: "alert", className: "error-banner", children: [_jsx("strong", { children: trace.error.name }), " ", trace.error.message] })), trace.captureWarnings.map((w) => (_jsx("p", { className: "warning", children: w }, w))), tab === "Flow" && _jsx(TraceDiagram, { trace: trace }, trace.id), tab === "Questions" && (_jsx(Questions, { trace: trace }, trace.id)), tab === "Context" && (_jsxs(_Fragment, { children: [_jsx("p", { className: "muted", children: "Captured before dispatch. Known credential fields
|
|
36
|
+
}, children: name }, name))) }), _jsx("div", { className: `detail-body ${tab === "Flow" ? "detail-body-flow" : tab === "Questions" ? "detail-body-questions" : ""}`, children: _jsxs(Suspense, { fallback: _jsx("p", { className: "muted", role: "status", children: "Loading questions\u2026" }), children: [trace.error && (_jsxs("div", { role: "alert", className: "error-banner", children: [_jsx("strong", { children: trace.error.name }), " ", trace.error.message] })), trace.captureWarnings.map((w) => (_jsx("p", { className: "warning", children: w }, w))), tab === "Flow" && _jsx(TraceDiagram, { trace: trace }, trace.id), tab === "Questions" && (_jsx(Questions, { trace: trace }, trace.id)), tab === "Context" && (_jsxs(_Fragment, { children: [_jsx("p", { className: "muted", children: "Captured before dispatch without changing SDK data. Known credential fields remain redacted; additional display masking follows the component prop. Captures are size limited." }), findImage(trace.request.state) && (_jsx("img", { className: "context-image", src: findImage(trace.request.state), alt: "Captured context" })), _jsx(JsonBlock, { value: trace.request.state }), trace.request.assets && (_jsx(JsonBlock, { value: trace.request.assets }))] })), tab === "Transport" && (_jsxs(_Fragment, { children: [_jsx("h3", { children: "HTTP attempts" }), _jsx("p", { className: "muted", children: "Attempt duration ends at response headers. Total duration includes SDK processing and retry waits." }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Attempt" }), _jsx("th", { children: "Status" }), _jsx("th", { children: "Duration" })] }) }), _jsx("tbody", { children: trace.attempts.map((a) => (_jsxs("tr", { children: [_jsx("td", { children: a.number }), _jsx("td", { children: a.error || a.status || "Pending" }), _jsx("td", { children: ms(a.durationMs) })] }, a.number))) })] }), !trace.attempts.length && _jsx("p", { children: "No HTTP attempt recorded." })] })), tab === "Raw" && _jsx(JsonBlock, { value: trace })] }) })] })) : (_jsxs("div", { className: "empty-detail", children: [_jsx("span", { className: "empty-symbol", children: "\u21B3" }), _jsx("h2", { children: "Follow a Jev request" }), _jsxs("p", { children: ["Context, parallel questions, typed answers.", _jsx("br", {}), "Run a sample above to see the complete flow."] })] })) }));
|
|
37
37
|
});
|
|
38
38
|
export function JevPanel({ traces, flows = emptyFlows, connection, onClear, }) {
|
|
39
39
|
const [view, setView] = useState("requests");
|
package/lib/src/JevDrawer.js
CHANGED
|
@@ -50,10 +50,8 @@ export function JevDrawer({ children, open, onOpenChange, }) {
|
|
|
50
50
|
}, [open, root]);
|
|
51
51
|
useEffect(() => {
|
|
52
52
|
const host = document.createElement("jev-devtools-root");
|
|
53
|
-
// The
|
|
54
|
-
//
|
|
55
|
-
host.style.cssText =
|
|
56
|
-
"all: initial !important; position: fixed !important; inset: 0 !important; pointer-events: none !important; z-index: 2147483000 !important;";
|
|
53
|
+
// The shadow stylesheet resets the exposed host through :host(), keeping
|
|
54
|
+
// page styles out without an expanded inline reset on the host element.
|
|
57
55
|
const shadow = host.attachShadow({ mode: "open" });
|
|
58
56
|
const style = document.createElement("style");
|
|
59
57
|
style.textContent = inspectorStyles;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Trace } from "./protocol.js";
|
|
2
|
+
import type { FlowDefinition, FlowRun } from "./flow-protocol.js";
|
|
3
|
+
/** One projection cache per mounted inspector. Stream captures are immutable;
|
|
4
|
+
* unchanged rows and nested runs retain identity across unrelated updates. */
|
|
5
|
+
export declare function createDisplayRedactor(): {
|
|
6
|
+
trace: (value: Trace) => Trace;
|
|
7
|
+
run: (value: FlowRun) => FlowRun;
|
|
8
|
+
definition: (value: FlowDefinition) => FlowDefinition;
|
|
9
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Presentation only. Credential and application redaction happen in the server
|
|
2
|
+
// recorder; these personal fields are still present in the received captures.
|
|
3
|
+
const sensitiveKeys = new Set([
|
|
4
|
+
"email",
|
|
5
|
+
"emailaddress",
|
|
6
|
+
"phone",
|
|
7
|
+
"phonenumber",
|
|
8
|
+
"mobile",
|
|
9
|
+
"mobilenumber",
|
|
10
|
+
"address",
|
|
11
|
+
"postaladdress",
|
|
12
|
+
"streetaddress",
|
|
13
|
+
"mailingaddress",
|
|
14
|
+
"ssn",
|
|
15
|
+
"socialsecuritynumber",
|
|
16
|
+
"creditcard",
|
|
17
|
+
"creditcardnumber",
|
|
18
|
+
"cardnumber",
|
|
19
|
+
]);
|
|
20
|
+
function memoize(project) {
|
|
21
|
+
const cache = new WeakMap();
|
|
22
|
+
return (value) => {
|
|
23
|
+
const cached = cache.get(value);
|
|
24
|
+
if (cached)
|
|
25
|
+
return cached;
|
|
26
|
+
const result = project(value);
|
|
27
|
+
cache.set(value, result);
|
|
28
|
+
return result;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// Map entries without interpreting their names. Preserve redacted/truncated
|
|
32
|
+
// scalar placeholders and retain identity when every value is unchanged.
|
|
33
|
+
function mapValues(value, project) {
|
|
34
|
+
if (!value || typeof value !== "object")
|
|
35
|
+
return value;
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
const next = value.map((item, i) => project(item, String(i)));
|
|
38
|
+
return next.every((item, i) => item === value[i]) ? value : next;
|
|
39
|
+
}
|
|
40
|
+
let changed = false;
|
|
41
|
+
const entries = Object.entries(value).map(([key, item]) => {
|
|
42
|
+
const next = project(item, key);
|
|
43
|
+
changed ||= next !== item;
|
|
44
|
+
return [key, next];
|
|
45
|
+
});
|
|
46
|
+
return changed ? Object.fromEntries(entries) : value;
|
|
47
|
+
}
|
|
48
|
+
/** One projection cache per mounted inspector. Stream captures are immutable;
|
|
49
|
+
* unchanged rows and nested runs retain identity across unrelated updates. */
|
|
50
|
+
export function createDisplayRedactor() {
|
|
51
|
+
function fields(value, structural = {}) {
|
|
52
|
+
return mapValues(value, (item, key) => Object.hasOwn(structural, key)
|
|
53
|
+
? structural[key](item)
|
|
54
|
+
: sensitiveKeys.has(key.replace(/[-_]/g, "").toLowerCase())
|
|
55
|
+
? "[redacted]"
|
|
56
|
+
: data(item));
|
|
57
|
+
}
|
|
58
|
+
const objects = memoize((value) => fields(value));
|
|
59
|
+
function data(value) {
|
|
60
|
+
return value && typeof value === "object" ? objects(value) : value;
|
|
61
|
+
}
|
|
62
|
+
const contents = (value) => mapValues(value, data);
|
|
63
|
+
// SDK maps use arbitrary question IDs, category labels and asset references.
|
|
64
|
+
// Mask their contents, not the entry itself because its name resembles PII.
|
|
65
|
+
const question = (value) => fields(value, { criteria: contents });
|
|
66
|
+
const answer = (value) => fields(value, { probabilities: contents, legend: contents });
|
|
67
|
+
const trace = memoize((value) => {
|
|
68
|
+
const request = fields(value.request, {
|
|
69
|
+
questions: (items) => mapValues(items, question),
|
|
70
|
+
assets: contents,
|
|
71
|
+
}), result = fields(value.result, {
|
|
72
|
+
answers: (items) => mapValues(items, answer),
|
|
73
|
+
});
|
|
74
|
+
return request === value.request && result === value.result
|
|
75
|
+
? value
|
|
76
|
+
: { ...value, request, result };
|
|
77
|
+
});
|
|
78
|
+
const run = memoize((value) => {
|
|
79
|
+
let changed = false;
|
|
80
|
+
// Step IDs are structural metadata, not personal-data field names.
|
|
81
|
+
const steps = Object.fromEntries(Object.entries(value.steps).map(([id, step]) => {
|
|
82
|
+
const captured = data(step.data);
|
|
83
|
+
let collection = step.collection;
|
|
84
|
+
if (collection) {
|
|
85
|
+
const items = collection.items.map((item) => {
|
|
86
|
+
const child = item.run && run(item.run);
|
|
87
|
+
return child === item.run ? item : { ...item, run: child };
|
|
88
|
+
});
|
|
89
|
+
if (items.some((item, i) => item !== collection.items[i]))
|
|
90
|
+
collection = { ...collection, items };
|
|
91
|
+
}
|
|
92
|
+
const next = captured === step.data && collection === step.collection
|
|
93
|
+
? step
|
|
94
|
+
: { ...step, data: captured, collection };
|
|
95
|
+
changed ||= next !== step;
|
|
96
|
+
return [id, next];
|
|
97
|
+
}));
|
|
98
|
+
const output = data(value.value);
|
|
99
|
+
return changed || output !== value.value
|
|
100
|
+
? { ...value, steps, value: output }
|
|
101
|
+
: value;
|
|
102
|
+
});
|
|
103
|
+
const definition = memoize((value) => {
|
|
104
|
+
const nodes = value.nodes.map((node) => {
|
|
105
|
+
const rule = data(node.conditionRule);
|
|
106
|
+
const item = node.itemDefinition && definition(node.itemDefinition);
|
|
107
|
+
return rule === node.conditionRule && item === node.itemDefinition
|
|
108
|
+
? node
|
|
109
|
+
: { ...node, conditionRule: rule, itemDefinition: item };
|
|
110
|
+
});
|
|
111
|
+
return nodes.some((node, i) => node !== value.nodes[i])
|
|
112
|
+
? { ...value, nodes }
|
|
113
|
+
: value;
|
|
114
|
+
});
|
|
115
|
+
return { trace, run, definition };
|
|
116
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FlowDefinition, FlowRun } from "./flow-protocol.js";
|
|
2
|
+
import type { Trace } from "./protocol.js";
|
|
3
|
+
/** Jev response bodies keyed by flow step ID, replayed by replayClient from jev-devtools/flow. Map and loop items use `${parentId}/${index}/${innerId}`. */
|
|
4
|
+
export type FlowFixture = {
|
|
5
|
+
version: 1;
|
|
6
|
+
flow: string;
|
|
7
|
+
steps: Record<string, unknown>;
|
|
8
|
+
};
|
|
9
|
+
export type BuiltFlowFixture = {
|
|
10
|
+
fixture: FlowFixture;
|
|
11
|
+
/** Completed jev steps whose capture was evicted, unlinked, or has no result. */
|
|
12
|
+
missing: string[];
|
|
13
|
+
/** Capture warnings from the traces used; redaction or truncation may show in the answers. */
|
|
14
|
+
warnings: string[];
|
|
15
|
+
};
|
|
16
|
+
/** Builds a replay fixture from the captured answers of a run's completed jev steps, including map and loop items. */
|
|
17
|
+
export declare function flowFixture(definition: FlowDefinition, run: FlowRun, traces: ReadonlyMap<string, Trace>): BuiltFlowFixture;
|
|
18
|
+
/** Whether a run, or any of its map and loop items, has a completed jev step. */
|
|
19
|
+
export declare function hasCompletedJev(definition: FlowDefinition, run: FlowRun): boolean;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Builds a replay fixture from the captured answers of a run's completed jev steps, including map and loop items. */
|
|
2
|
+
export function flowFixture(definition, run, traces) {
|
|
3
|
+
const steps = {}, missing = [], warnings = new Set();
|
|
4
|
+
// Item runs reuse bare inner ids; key them by the composed link id.
|
|
5
|
+
const collect = (program, programRun, prefix) => {
|
|
6
|
+
for (const node of program.nodes) {
|
|
7
|
+
const step = programRun.steps[node.id];
|
|
8
|
+
if (node.itemDefinition)
|
|
9
|
+
for (const item of step?.collection?.items ?? [])
|
|
10
|
+
if (item.run)
|
|
11
|
+
collect(node.itemDefinition, item.run, `${prefix}${node.id}/${item.index}/`);
|
|
12
|
+
if (node.kind !== "jev" || step?.status !== "completed")
|
|
13
|
+
continue;
|
|
14
|
+
const trace = step.traceId ? traces.get(step.traceId) : undefined;
|
|
15
|
+
if (!trace?.result) {
|
|
16
|
+
missing.push(prefix + node.id);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
steps[prefix + node.id] = structuredClone(trace.result);
|
|
20
|
+
for (const warning of trace.captureWarnings)
|
|
21
|
+
warnings.add(warning);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
collect(definition, run, "");
|
|
25
|
+
return {
|
|
26
|
+
fixture: { version: 1, flow: definition.name, steps },
|
|
27
|
+
missing,
|
|
28
|
+
warnings: [...warnings],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Whether a run, or any of its map and loop items, has a completed jev step. */
|
|
32
|
+
export function hasCompletedJev(definition, run) {
|
|
33
|
+
return definition.nodes.some((node) => {
|
|
34
|
+
const step = run.steps[node.id];
|
|
35
|
+
if (node.kind === "jev")
|
|
36
|
+
return step?.status === "completed";
|
|
37
|
+
return (!!node.itemDefinition &&
|
|
38
|
+
(step?.collection?.items ?? []).some((item) => !!item.run && hasCompletedJev(node.itemDefinition, item.run)));
|
|
39
|
+
});
|
|
40
|
+
}
|
package/lib/src/flow-stream.js
CHANGED
|
@@ -23,6 +23,15 @@ export function connectFlowStream(url, onUpdate) {
|
|
|
23
23
|
definitions = new Map();
|
|
24
24
|
const current = new EventSource(url + "/flows/events");
|
|
25
25
|
source = current;
|
|
26
|
+
current.addEventListener("open", () => {
|
|
27
|
+
if (!alive || source !== current)
|
|
28
|
+
return;
|
|
29
|
+
// Native reconnect reuses this EventSource. The server starts a fresh
|
|
30
|
+
// snapshot; neither cached definitions nor pending publications survive.
|
|
31
|
+
cancel();
|
|
32
|
+
runs = new Map();
|
|
33
|
+
definitions = new Map();
|
|
34
|
+
});
|
|
26
35
|
current.addEventListener("flows", (event) => {
|
|
27
36
|
if (!alive || source !== current)
|
|
28
37
|
return;
|
package/lib/src/index.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
export type { Trace, Snapshot, StreamSnapshot, TraceDelta, Json, AnswerView, QuestionView, } from "./protocol.js";
|
|
2
|
+
export { flowFixture } from "./flow-fixture.js";
|
|
3
|
+
export type { FlowFixture, BuiltFlowFixture } from "./flow-fixture.js";
|
|
2
4
|
export type JevDevtoolsProps = {
|
|
3
5
|
endpoint?: string;
|
|
4
6
|
/** Opt in explicitly, normally with import.meta.env.DEV. */
|
|
5
7
|
enabled?: boolean;
|
|
6
8
|
defaultOpen?: boolean;
|
|
9
|
+
/** Mask supported personal fields in DevTools views only. Defaults to true.
|
|
10
|
+
* Captures still contain these values; credentials remain server-redacted. */
|
|
11
|
+
redactAdditionalSensitiveData?: boolean;
|
|
7
12
|
};
|
|
8
13
|
/** SSR-safe entry. No requests or browser globals are accessed while disabled. */
|
|
9
14
|
export declare function JevDevtools({ enabled, ...props }: JevDevtoolsProps): import("react").JSX.Element | null;
|
package/lib/src/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { lazy, Suspense, useEffect, useState } from "react";
|
|
4
|
+
export { flowFixture } from "./flow-fixture.js";
|
|
4
5
|
const ConnectedInspector = lazy(() => import("./ConnectedInspector.js"));
|
|
5
6
|
/** SSR-safe entry. No requests or browser globals are accessed while disabled. */
|
|
6
7
|
export function JevDevtools({ enabled = false, ...props }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const inspectorStyles = ".jev-devtools {\n all: initial;\n display: block;\n direction: ltr;\n unicode-bidi: isolate;\n pointer-events: auto;\n color-scheme: dark;\n font:\n 12px system-ui,\n sans-serif;\n color: #eee8ed;\n line-height: 1.5;\n}\n.jev-devtools,\n.jev-devtools * {\n box-sizing: border-box;\n}\n.jev-devtools button,\n.jev-devtools input,\n.jev-devtools select,\n.jev-devtools textarea {\n font: inherit;\n color: inherit;\n border: 1px solid #3b303d;\n border-radius: 5px;\n background: #17121b;\n}\n.jev-devtools button {\n padding: 7px 11px;\n cursor: pointer;\n}\n.jev-devtools button:disabled {\n opacity: 0.45;\n cursor: default;\n}\n.jev-devtools input,\n.jev-devtools select {\n padding: 8px;\n width: 100%;\n}\n.jev-devtools button:hover:not(:disabled) {\n border-color: #e551ba;\n}\n.jev-devtools :is(button, input, select, textarea, summary):focus-visible {\n outline: 2px solid #e551ba;\n outline-offset: 3px;\n}\n.jev-devtools .eyebrow {\n font-size: 10px;\n letter-spacing: 0.12em;\n color: #bc9db5;\n text-transform: uppercase;\n}\n.jev-devtools .jev-inspector {\n height: 100%;\n display: flex;\n color: #eee8ed;\n background: #0d0a0f;\n font:\n 12px \"DM Sans\",\n sans-serif;\n min-height: 0;\n overflow: hidden;\n}\n.jev-devtools .jev-inspector h2 {\n font-size: 15px;\n margin: 0;\n font-weight: 600;\n}\n.jev-devtools .jev-inspector h3 {\n font-size: 13px;\n margin: 0 0 8px;\n}\n.jev-devtools .jev-inspector code,\n.jev-devtools .jev-inspector pre {\n font:\n 11px \"JetBrains Mono\",\n monospace;\n}\n.jev-devtools .jev-inspector pre {\n line-height: 1.7;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n max-height: 460px;\n overflow: auto;\n background: #100d13;\n padding: 16px;\n border: 1px solid #2e2533;\n border-radius: 5px;\n}\n.jev-devtools .jev-inspector .muted {\n color: #a89bac;\n font-size: 11px;\n line-height: 1.6;\n}\n.jev-devtools .request-list {\n flex: 0 0 300px;\n border-right: 1px solid #302634;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n.jev-devtools .request-list > header {\n padding: 17px 14px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n.jev-devtools .request-list h2 span {\n font-size: 11px;\n color: #b796ad;\n margin-left: 5px;\n}\n.jev-devtools .request-list button {\n font-size: 11px;\n}\n.jev-devtools .list-filters {\n display: flex;\n gap: 7px;\n padding: 0 12px 12px;\n}\n.jev-devtools .list-filters input {\n min-width: 0;\n}\n.jev-devtools .list-filters select {\n width: 86px;\n font-size: 11px;\n}\n.jev-devtools .request-items {\n overflow: auto;\n flex: 1;\n}\n.jev-devtools .request-row {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n text-align: left;\n border: 0;\n border-top: 1px solid #251d2a;\n border-radius: 0;\n background: transparent;\n padding: 16px 12px;\n}\n.jev-devtools .request-row.selected {\n background: #251423;\n box-shadow: inset 2px 0 #e551ba;\n}\n.jev-devtools .request-row strong {\n display: block;\n font-size: 12px;\n font-weight: 500;\n}\n.jev-devtools .request-row small {\n display: block;\n font-size: 10px;\n color: #a99aac;\n margin-top: 6px;\n}\n.jev-devtools .row-status {\n font-size: 9px;\n color: #ad9bb0;\n margin-left: auto;\n}\n.jev-devtools .status-dot {\n width: 6px;\n height: 6px;\n display: inline-block;\n border-radius: 50%;\n background: #b09ab7;\n flex-shrink: 0;\n}\n.jev-devtools .status-dot.success {\n background: #b3c79c;\n}\n.jev-devtools .status-dot.pending {\n background: #e551ba;\n}\n.jev-devtools .status-dot.error {\n background: #ee8e85;\n}\n.jev-devtools .request-list footer {\n padding: 12px;\n color: #9e8ea5;\n border-top: 1px solid #302634;\n font-size: 10px;\n display: flex;\n gap: 7px;\n}\n.jev-devtools .request-detail {\n flex: 1;\n min-width: 0;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n.jev-devtools .detail-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 20px;\n padding: 18px 24px 10px;\n}\n.jev-devtools .detail-header h2 {\n margin-top: 6px;\n}\n.jev-devtools .metrics {\n display: flex;\n gap: 24px;\n font:\n 12px \"JetBrains Mono\",\n monospace;\n white-space: nowrap;\n}\n.jev-devtools .metrics small {\n display: block;\n font:\n 9px \"DM Sans\",\n sans-serif;\n color: #97879f;\n margin-top: 6px;\n}\n.jev-devtools .detail-meta {\n display: flex;\n gap: 20px;\n flex-wrap: wrap;\n padding: 0 24px 14px;\n color: #a08aa5;\n}\n.jev-devtools .detail-meta code {\n font-size: 10px;\n}\n.jev-devtools .detail-tabs {\n display: flex;\n gap: 20px;\n border-bottom: 1px solid #302634;\n padding: 0 24px;\n}\n.jev-devtools .detail-tabs button {\n border: 0;\n border-radius: 0;\n background: none;\n padding: 10px 0;\n color: #a89bac;\n font-size: 11px;\n}\n.jev-devtools .detail-tabs button[aria-pressed=\"true\"] {\n box-shadow: inset 0 -2px #e551ba;\n color: #f5c1e6;\n}\n.jev-devtools .detail-body {\n overflow: auto;\n flex: 1;\n min-height: 0;\n padding: 16px 24px 28px;\n background-image: radial-gradient(#342337 0.6px, transparent 0.6px);\n background-size: 16px 16px;\n}\n.jev-devtools .request-flow {\n display: flex;\n align-items: center;\n gap: 40px;\n padding: 14px 0 20px;\n}\n.jev-devtools .state-node {\n position: relative;\n flex: 0 0 160px;\n border: 1px solid #e551ba;\n padding: 20px 15px;\n background: #1f1320;\n border-radius: 6px;\n}\n.jev-devtools .state-node h3 {\n margin-top: 12px;\n}\n.jev-devtools .state-node p {\n color: #b69db3;\n line-height: 1.5;\n}\n.jev-devtools .state-node code {\n font-size: 10px;\n}\n.jev-devtools .state-node:after {\n content: \"\";\n position: absolute;\n left: 100%;\n top: 50%;\n width: 20px;\n border-top: 1px solid #7f416d;\n}\n.jev-devtools .question-branches {\n border-left: 1px solid #7f416d;\n padding-left: 20px;\n display: grid;\n grid-template-columns: repeat(3, minmax(160px, 1fr));\n gap: 12px;\n flex: 1;\n position: relative;\n}\n.jev-devtools .question-node {\n position: relative;\n border: 1px solid #75516c;\n border-radius: 6px;\n padding: 15px;\n background: #110d14;\n min-width: 0;\n}\n.jev-devtools .question-node:before {\n content: \"\";\n position: absolute;\n right: 100%;\n top: 50%;\n width: 21px;\n border-top: 1px solid #7f416d;\n}\n.jev-devtools .question-branches .question-node:not(:first-child):before {\n display: none;\n}\n.jev-devtools .question-node header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n.jev-devtools .question-node header h3 {\n margin: 0;\n overflow-wrap: anywhere;\n}\n.jev-devtools .type {\n font:\n 9px \"JetBrains Mono\",\n monospace;\n color: #e59acc;\n border: 1px solid #5e3654;\n border-radius: 3px;\n padding: 3px 5px;\n}\n.jev-devtools .instructions {\n font-size: 11px;\n color: #b8a6bc;\n line-height: 1.5;\n}\n.jev-devtools .answer-value {\n display: block;\n font-size: 20px;\n font-weight: 500;\n margin: 15px 0;\n color: #f0c7e5;\n}\n.jev-devtools .answer-value small {\n font-size: 10px;\n color: #b5a1ba;\n}\n.jev-devtools .probability {\n margin: 10px 0;\n font-size: 10px;\n}\n.jev-devtools .probability > div:first-child {\n display: flex;\n justify-content: space-between;\n gap: 5px;\n margin-bottom: 5px;\n}\n.jev-devtools .probability b {\n font-weight: 400;\n color: #d8abc9;\n}\n.jev-devtools .bar {\n height: 4px;\n background: #302033;\n border-radius: 2px;\n overflow: hidden;\n}\n.jev-devtools .bar i {\n display: block;\n height: 100%;\n background: #e551ba;\n}\n.jev-devtools .confidence {\n font-size: 10px;\n color: #a68cac;\n border-top: 1px solid #302634;\n padding-top: 10px;\n display: flex;\n justify-content: space-between;\n}\n.jev-devtools .confidence b {\n color: #d1bad2;\n font-weight: 400;\n}\n.jev-devtools details {\n margin-top: 12px;\n font-size: 10px;\n color: #b7a0bd;\n}\n.jev-devtools summary {\n cursor: pointer;\n}\n.jev-devtools .standalone {\n margin-bottom: 14px;\n max-width: 750px;\n}\n.jev-devtools .standalone:before {\n display: none;\n}\n.jev-devtools .standalone .answer {\n max-width: 450px;\n}\n.jev-devtools .box-preview {\n position: relative;\n margin-top: 14px;\n min-height: 80px;\n background: #19121c;\n}\n.jev-devtools .box-preview img {\n width: 100%;\n display: block;\n}\n.jev-devtools .bounding-box {\n position: absolute;\n border: 1.5px solid #e551ba;\n background: #e551ba15;\n}\n.jev-devtools .coordinates {\n display: block;\n font-size: 9px !important;\n line-height: 1.5;\n margin-top: 8px;\n color: #ac93b0;\n}\n.jev-devtools .context-image {\n max-width: 400px;\n width: 100%;\n border: 1px solid #75516c;\n border-radius: 6px;\n}\n.jev-devtools .empty {\n padding: 20px;\n color: #a294a8;\n line-height: 1.7;\n}\n.jev-devtools .empty-detail {\n margin: auto;\n padding: 40px;\n text-align: center;\n color: #b2a0ba;\n}\n.jev-devtools .empty-symbol {\n font-size: 36px;\n color: #e551ba;\n display: block;\n margin-bottom: 20px;\n}\n.jev-devtools .empty-detail p {\n font-size: 12px;\n line-height: 1.8;\n}\n.jev-devtools .error-banner {\n border: 1px solid #874b50;\n background: #31191e;\n padding: 12px;\n line-height: 1.5;\n margin-bottom: 16px;\n}\n.jev-devtools .warning {\n color: #e2b97d;\n}\n.jev-devtools .jev-inspector table {\n border-collapse: collapse;\n width: 100%;\n text-align: left;\n}\n.jev-devtools .jev-inspector th,\n.jev-devtools .jev-inspector td {\n border-bottom: 1px solid #302634;\n padding: 14px;\n}\n.jev-devtools .flow-dot {\n display: none;\n}\n.jev-devtools .pending .flow-dot {\n display: block;\n position: absolute;\n right: -23px;\n top: calc(50% - 3px);\n width: 6px;\n height: 6px;\n background: #e551ba;\n border-radius: 50%;\n animation: jev-inspector-pulse 1s infinite;\n}\n@keyframes jev-inspector-pulse {\n 50% {\n opacity: 0.2;\n transform: scale(0.7);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .jev-devtools .pending .flow-dot {\n animation: none;\n }\n}\n@media (max-width: 1100px) {\n .jev-devtools .question-branches {\n grid-template-columns: 1fr;\n }\n .jev-devtools .question-branches .question-node:not(:first-child):before {\n display: block;\n }\n .jev-devtools .request-flow {\n align-items: flex-start;\n }\n .jev-devtools .state-node {\n margin-top: 45px;\n }\n .jev-devtools .metrics {\n gap: 12px;\n }\n .jev-devtools .request-list {\n flex-basis: 250px;\n }\n}\n@media (max-width: 700px) {\n .jev-devtools .jev-inspector {\n flex-direction: column;\n }\n .jev-devtools .request-list {\n flex-basis: 140px;\n flex-shrink: 0;\n border-right: 0;\n border-bottom: 1px solid #302634;\n }\n .jev-devtools .request-list > header {\n padding: 6px 12px;\n }\n .jev-devtools .request-list footer {\n display: none;\n }\n .jev-devtools .list-filters {\n padding-bottom: 6px;\n }\n .jev-devtools .request-items {\n display: flex;\n }\n .jev-devtools .request-row {\n min-width: 240px;\n padding: 8px 12px;\n }\n .jev-devtools .request-detail {\n min-height: 0;\n }\n .jev-devtools .detail-header {\n padding: 12px;\n }\n .jev-devtools .detail-meta,\n .jev-devtools .detail-tabs {\n padding-left: 12px;\n padding-right: 12px;\n }\n .jev-devtools .detail-body {\n padding: 12px;\n }\n .jev-devtools .metrics {\n display: none;\n }\n .jev-devtools .state-node {\n flex-basis: 115px;\n padding: 12px;\n }\n .jev-devtools .request-flow {\n gap: 25px;\n }\n .jev-devtools .state-node:after {\n width: 12px;\n }\n .jev-devtools .question-branches {\n padding-left: 12px;\n }\n .jev-devtools .question-node:before {\n width: 13px;\n }\n .jev-devtools .question-node {\n padding: 12px;\n }\n}\n\n.jev-devtools .request-flow {\n flex-direction: column;\n align-items: stretch;\n gap: 24px;\n}\n.jev-devtools .state-node {\n flex: auto;\n width: fit-content;\n align-self: center;\n padding: 12px 24px;\n text-align: center;\n margin: 0;\n}\n.jev-devtools .state-node h3 {\n display: inline-block;\n margin: 0 12px;\n}\n.jev-devtools .state-node p {\n display: inline-block;\n margin: 0 12px 0 0;\n font-size: 11px;\n}\n.jev-devtools .state-node .eyebrow {\n display: none;\n}\n.jev-devtools .state-node:after {\n left: 50%;\n top: 100%;\n width: 0;\n height: 24px;\n border-top: 0;\n border-left: 1px solid #7f416d;\n}\n.jev-devtools .question-branches {\n border-left: 0;\n border-top: 1px solid #7f416d;\n padding: 20px 0 0;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n}\n.jev-devtools .question-node:before,\n.jev-devtools .question-branches .question-node:not(:first-child):before {\n display: block;\n right: auto;\n left: 50%;\n top: -21px;\n width: 0;\n height: 20px;\n border-top: 0;\n border-left: 1px solid #7f416d;\n}\n.jev-devtools .standalone:before {\n display: none;\n}\n.jev-devtools .flow-caption {\n margin-top: 0;\n}\n.jev-devtools .pending .flow-dot {\n right: auto;\n left: calc(50% - 3px);\n top: calc(100% + 10px);\n}\n@media (max-width: 900px) {\n .jev-devtools .question-branches {\n grid-template-columns: 1fr;\n }\n .jev-devtools .question-node:before,\n .jev-devtools .question-branches .question-node:not(:first-child):before {\n height: 12px;\n top: -13px;\n }\n .jev-devtools .question-branches .question-node:first-child:before {\n height: 20px;\n top: -21px;\n }\n .jev-devtools .state-node {\n padding: 10px;\n }\n .jev-devtools .state-node p {\n display: block;\n margin: 6px 0;\n }\n .jev-devtools .state-node h3 {\n font-size: 12px;\n }\n}\n\n.jev-devtools.jev-drawer {\n margin: 0;\n padding: 0;\n position: fixed;\n z-index: 1000;\n inset: auto 0 0;\n display: flex;\n flex-direction: column;\n background: #0d0a0f;\n color: #eee8ed;\n border-top: 1px solid #604058;\n box-shadow: 0 -12px 48px #0005;\n font:\n 12px \"DM Sans\",\n sans-serif;\n}\n.jev-devtools.jev-drawer[hidden],\n.jev-devtools.jev-drawer-trigger[hidden] {\n display: none;\n}\n.jev-devtools .jev-drawer-resize {\n position: absolute;\n z-index: 1;\n top: -6px;\n width: 100%;\n height: 12px;\n cursor: ns-resize;\n touch-action: none;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.jev-devtools .jev-drawer-resize span {\n width: 42px;\n height: 3px;\n border-radius: 3px;\n background: #79506f;\n}\n.jev-devtools .jev-drawer-resize:hover span,\n.jev-devtools .jev-drawer-resize:focus-visible span {\n background: #e551ba;\n}\n.jev-devtools .jev-drawer-resize:focus-visible {\n outline: 2px solid #e551ba;\n outline-offset: -2px;\n}\n.jev-devtools .jev-drawer-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex: 0 0 46px;\n padding: 0 16px;\n border-bottom: 1px solid #302634;\n}\n.jev-devtools .jev-drawer-header strong {\n display: flex;\n align-items: center;\n gap: 9px;\n font-weight: 600;\n}\n.jev-devtools .jev-mark {\n color: #e551ba;\n font-size: 21px;\n}\n.jev-devtools .jev-drawer-header > div {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.jev-devtools .jev-drawer-header button {\n background: transparent;\n border-color: transparent;\n font-size: 11px;\n color: #c4afc8;\n}\n.jev-devtools .jev-drawer-header .jev-drawer-close {\n font-size: 22px;\n line-height: 1;\n padding: 4px 8px;\n}\n.jev-devtools .jev-drawer-content {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n.jev-devtools.jev-drawer-trigger {\n position: fixed;\n bottom: 18px;\n right: 18px;\n z-index: 1000;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 10px 16px;\n border: 1px solid #a24487;\n border-radius: 8px;\n cursor: pointer;\n background: #211321;\n color: #f1cbe6;\n font:\n 600 13px \"DM Sans\",\n sans-serif;\n box-shadow: 0 4px 20px #0005;\n}\n.jev-devtools.jev-drawer-trigger span {\n color: #e551ba;\n font-size: 20px;\n}\n/* Baseline cards and authored left-to-right composition from the lab's Jev presets. */\n.jev-devtools .detail-body.detail-body-flow {\n display: flex;\n padding: 0;\n overflow: hidden;\n}\n.jev-devtools .lab-flow {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-width: 0;\n min-height: 0;\n}\n.jev-devtools .lab-flow-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-shrink: 0;\n padding: 12px 16px;\n flex-wrap: wrap;\n}\n.jev-devtools .lab-flow-toolbar label {\n display: flex;\n gap: 10px;\n align-items: center;\n font-size: 11px;\n min-width: 0;\n}\n.jev-devtools .lab-flow-toolbar select {\n width: auto;\n max-width: 240px;\n font-size: 11px;\n}\n.jev-devtools .lab-flow-toolbar > div {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.jev-devtools .lab-flow-toolbar button {\n font-size: 11px;\n}\n.jev-devtools .lab-flow-toolbar output {\n font-size: 11px;\n min-width: 35px;\n text-align: center;\n}\n.jev-devtools .lab-flow-viewport {\n position: relative;\n flex: 1;\n min-height: 100px;\n overflow: hidden;\n background-color: #0d0a0f;\n background-image: radial-gradient(\n rgb(70 52 73 / var(--diagram-grid-opacity, 1))\n calc(0.8px * var(--diagram-grid-weight, 1)),\n transparent calc(0.8px * var(--diagram-grid-weight, 1))\n );\n background-size: 20px 20px;\n border-block: 1px solid #302634;\n cursor: grab;\n touch-action: none;\n user-select: none;\n overscroll-behavior: contain;\n}\n.jev-devtools .lab-flow-viewport[data-panning] {\n cursor: grabbing;\n}\n.jev-devtools .lab-flow-viewport:focus-visible {\n outline: 2px solid #e551ba;\n outline-offset: -2px;\n}\n.jev-devtools .lab-flow-caption {\n flex-shrink: 0;\n padding: 8px 16px;\n margin: 0;\n}\n.jev-devtools .lab-gesture-hint {\n display: block;\n color: #c6a7bd;\n}\n.jev-devtools .lab-flow-canvas {\n position: absolute;\n inset: 0 auto auto 0;\n transform-origin: top left;\n will-change: transform;\n font-family: system-ui, sans-serif;\n color: #f5f3f6;\n}\n.jev-devtools .lab-connections {\n position: absolute;\n inset: 0;\n overflow: visible;\n}\n.jev-devtools .lab-connections path {\n fill: none;\n stroke: #645a68;\n stroke-width: 1;\n}\n.jev-devtools .lab-connections path.active {\n stroke: #968592;\n}\n.jev-devtools .lab-connections text {\n fill: #b7b1bc;\n font:\n 12px ui-monospace,\n monospace;\n}\n.jev-devtools .lab-flow-dot {\n fill: #e551ba;\n}\n.jev-devtools .lab-card {\n position: absolute;\n border: 1.3px solid #f5f3f6;\n border-radius: 14px;\n padding: 16px;\n background: #0d0a0f;\n overflow: hidden;\n}\n.jev-devtools .lab-eyebrow {\n display: block;\n color: #e551ba;\n font:\n 500 10px ui-monospace,\n monospace;\n letter-spacing: 1px;\n margin: 0 0 7px;\n}\n.jev-devtools .lab-card h3 {\n font-size: 16px;\n font-weight: 600;\n line-height: 1.3;\n letter-spacing: -0.2px;\n margin: 0 0 10px;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.jev-devtools .lab-card p {\n font-size: 13px;\n line-height: 1.4;\n margin: 10px 0;\n}\n.jev-devtools .lab-copy {\n display: -webkit-box;\n -webkit-line-clamp: 5;\n -webkit-box-orient: vertical;\n overflow: hidden;\n overflow-wrap: anywhere;\n}\n.jev-devtools .lab-probability {\n margin: 17px 0;\n}\n.jev-devtools .lab-probability > div:first-child {\n display: flex;\n justify-content: space-between;\n gap: 10px;\n margin-bottom: 9px;\n font-size: 15px;\n}\n.jev-devtools .lab-probability span {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.jev-devtools .lab-probability code {\n font:\n 13px ui-monospace,\n monospace;\n}\n.jev-devtools .lab-track {\n height: 7px;\n border-radius: 4px;\n background: #f5f3f61a;\n overflow: hidden;\n}\n.jev-devtools .lab-track i {\n display: block;\n height: 100%;\n border-radius: 4px;\n background: #e551ba;\n}\n.jev-devtools .lab-track i.lab-alternative {\n opacity: 0.35;\n}\n.jev-devtools .lab-card .lab-result {\n font-size: 14px;\n margin-top: 24px;\n}\n.jev-devtools .lab-card .lab-small {\n font-size: 12px;\n color: #b7b1bc;\n margin-top: 20px;\n}\n.jev-devtools .lab-idle {\n opacity: 0.65;\n}\n.jev-devtools .lab-scale {\n position: relative;\n margin-top: 18px;\n border-top: 1px solid #b7b1bc;\n display: flex;\n justify-content: space-between;\n padding-top: 9px;\n}\n.jev-devtools .lab-scale > span {\n position: absolute;\n top: -5px;\n width: 9px;\n height: 9px;\n border-radius: 50%;\n background: #e551ba;\n transform: translateX(-50%);\n}\n.jev-devtools .lab-big {\n display: block;\n font-size: 36px;\n font-weight: 500;\n margin-top: 26px;\n}\n.jev-devtools .lab-endpoints {\n display: flex;\n justify-content: space-between;\n font-size: 12px;\n color: #b7b1bc;\n margin-top: 10px;\n}\n.jev-devtools .lab-image {\n position: relative;\n}\n.jev-devtools .lab-image img {\n display: block;\n width: 100%;\n}\n.jev-devtools .lab-box {\n position: absolute;\n border: 1.5px solid #e551ba;\n background: #e551ba15;\n}\n.jev-devtools .lab-source-image {\n width: 100%;\n max-height: 105px;\n object-fit: contain;\n}\n.jev-devtools .lab-coordinates {\n font-family: ui-monospace, monospace;\n}\n@media (prefers-reduced-motion: reduce) {\n .jev-devtools .lab-flow-dot {\n display: none;\n }\n}\n/* The public TypeSafe mark travels with the package, independent of host assets. */\n.jev-devtools .typesafe-mark {\n display: inline-block;\n flex: 0 0 23px;\n width: 23px;\n height: 32px;\n overflow: hidden;\n line-height: 0;\n}\n.jev-devtools .typesafe-mark img {\n display: block;\n height: 32px;\n width: auto;\n max-width: none;\n}\n\n.jev-devtools .detail-body-questions {\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n.jev-devtools .questions-list {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 180px;\n}\n.jev-devtools .questions-navigation {\n display: flex;\n align-items: end;\n gap: 8px;\n flex-wrap: wrap;\n flex-shrink: 0;\n}\n.jev-devtools .questions-navigation label {\n display: flex;\n align-items: center;\n gap: 8px;\n white-space: nowrap;\n flex: 1;\n min-width: 240px;\n max-width: 480px;\n font-size: 11px;\n color: #bc9db5;\n}\n.jev-devtools .questions-navigation select {\n display: block;\n min-width: 0;\n}\n.jev-devtools .questions-navigation > span {\n align-self: center;\n color: #a89bac;\n}\n.jev-devtools .questions-help {\n margin: 8px 0;\n flex-shrink: 0;\n}\n.jev-devtools .questions-viewport {\n flex: 1;\n min-height: 0;\n overflow: auto;\n overflow-anchor: none;\n scrollbar-gutter: stable;\n padding: 3px;\n}\n.jev-devtools .questions-spacer {\n position: relative;\n width: 100%;\n}\n.jev-devtools .questions-row {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n padding-bottom: 14px;\n}\n.jev-devtools .questions-row .standalone {\n margin-bottom: 0;\n}\n.jev-devtools .questions-viewport:focus-visible,\n.jev-devtools .questions-row article:focus-visible {\n outline: 2px solid #e551ba;\n outline-offset: -2px;\n}\n\n/* Reserve measured card geometry while rapid scrolling uses a light preview. */\n.jev-devtools .questions-row[data-preview=\"true\"] article {\n height: 100%;\n}\n.jev-devtools .question-scroll-preview p {\n margin-top: 16px;\n}\n\n/* The full distribution stays at reading size, outside the zoomable canvas. */\n.jev-devtools .lab-flow-viewport[hidden] {\n display: none;\n}\n.jev-devtools .lab-choice-browser {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n padding: 8px 16px;\n gap: 10px;\n}\n.jev-devtools .lab-choice-controls {\n display: flex;\n gap: 12px;\n align-items: end;\n flex-wrap: wrap;\n font-size: 12px;\n}\n.jev-devtools .lab-choice-controls label {\n display: grid;\n gap: 5px;\n}\n.jev-devtools .lab-choice-table-scroll {\n overflow: auto;\n overscroll-behavior: contain;\n min-height: 0;\n flex: 1;\n}\n.jev-devtools .lab-choice-browser table {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n}\n.jev-devtools .lab-choice-browser caption {\n text-align: left;\n padding: 8px 0;\n color: #aaa0af;\n}\n.jev-devtools .lab-choice-browser th,\n.jev-devtools .lab-choice-browser td {\n padding: 9px 12px;\n border-bottom: 1px solid #302634;\n text-align: left;\n}\n.jev-devtools .lab-choice-browser th {\n overflow-wrap: anywhere;\n max-width: 320px;\n}\n.jev-devtools .lab-choice-browser td {\n font-variant-numeric: tabular-nums;\n}\n.jev-devtools .lab-choice-browser code {\n white-space: normal;\n overflow-wrap: anywhere;\n}\n.jev-devtools .lab-choice-returned {\n display: block;\n font-size: 10px;\n color: #e551ba;\n}\n.jev-devtools .lab-choice-pagination {\n display: flex;\n align-items: center;\n gap: 12px;\n justify-content: space-between;\n font-size: 12px;\n}\n.jev-devtools .lab-choice-remainder button {\n margin-top: 7px;\n}\n\n.jev-devtools .lab-flow-compact .lab-output {\n padding: 12px;\n height: 104px;\n}\n.jev-devtools .lab-flow-compact .lab-output .lab-eyebrow {\n margin-bottom: 6px;\n}\n.jev-devtools .lab-flow-compact .lab-output h3 {\n font-size: 16px;\n margin-bottom: 8px;\n}\n.jev-devtools .lab-flow-compact .lab-output p {\n font-size: 12px;\n margin: 4px 0;\n}\n.jev-devtools .lab-flow-compact .lab-result {\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n overflow-wrap: anywhere;\n}\n.jev-devtools .lab-choice-remainder {\n padding: 12px;\n}\n.jev-devtools .lab-choice-remainder .lab-small {\n margin: 8px 0 0;\n font-size: 11px;\n}\n\n.jev-devtools .detail-body.detail-body-flow {\n flex-direction: column;\n}\n.jev-devtools .detail-body-flow > .warning,\n.jev-devtools .detail-body-flow > .error-banner {\n flex-shrink: 0;\n margin: 6px 16px;\n}\n.jev-devtools .lab-choice-browser {\n overflow: auto;\n}\n.jev-devtools .lab-choice-table-scroll {\n flex: 1 0 110px;\n}\n\n/* Only freshly revealed branches enter; pan/zoom remains on the canvas. */\n.jev-devtools .lab-card-enter {\n animation: jev-card-enter 280ms cubic-bezier(0.2, 0.8, 0.2, 1) backwards;\n}\n.jev-devtools .lab-branch-enter {\n stroke-dasharray: 1;\n animation: jev-branch-enter 280ms ease-out backwards;\n}\n@keyframes jev-card-enter {\n from {\n opacity: 0;\n transform: translateX(-16px) scale(0.96);\n }\n}\n@keyframes jev-branch-enter {\n from {\n opacity: 0;\n stroke-dashoffset: 1;\n }\n to {\n opacity: 1;\n stroke-dashoffset: 0;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .jev-devtools .lab-card-enter,\n .jev-devtools .lab-branch-enter {\n animation: none;\n }\n}\n\n/* Connected requests share one camera and one opt-in full request detail. */\n.whole-flow {\n min-width: 0;\n overflow: hidden;\n}\n.whole-flow > .detail-header,\n.whole-flow > .lab-flow-toolbar {\n flex-shrink: 0;\n}\n.flow-workspace {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n.flow-details-panel {\n flex: none;\n min-width: 0;\n background: #130f17;\n border-top: 1px solid #342a38;\n}\n.flow-details-bar {\n display: flex;\n align-items: center;\n gap: 12px;\n height: 36px;\n padding: 0 12px;\n}\n.jev-devtools .flow-details-bar button {\n flex: none;\n padding: 4px 8px;\n font-size: 11px;\n}\n.flow-details-bar > span {\n color: #b5a6bc;\n font-size: 11px;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.flow-details-body {\n overflow: auto;\n overscroll-behavior: contain;\n scrollbar-gutter: stable;\n}\n.flow-details-resize {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 8px;\n cursor: ns-resize;\n touch-action: none;\n user-select: none;\n}\n.flow-details-resize span {\n width: 40px;\n height: 2px;\n border-radius: 2px;\n background: #6c5874;\n}\n.flow-details-resize:hover,\n.flow-details-resize:focus-visible {\n background: #392239;\n outline: 1px solid #e551ba;\n outline-offset: -1px;\n}\n.flow-overview-viewport {\n position: relative;\n min-height: 0;\n flex: 1 1 0;\n overflow: hidden;\n touch-action: none;\n cursor: grab;\n background-image: radial-gradient(\n rgb(83 67 87 / var(--diagram-grid-opacity, 1))\n calc(1px * var(--diagram-grid-weight, 1)),\n transparent calc(1px * var(--diagram-grid-weight, 1))\n );\n background-size: 20px 20px;\n}\n.flow-overview-viewport[data-panning] {\n cursor: grabbing;\n}\n.flow-overview-canvas {\n position: absolute;\n transform-origin: 0 0;\n}\n.flow-connections {\n position: absolute;\n inset: 0;\n overflow: visible;\n color: #c0b8c4;\n pointer-events: none;\n}\n.flow-step {\n position: absolute;\n width: 220px;\n min-height: 172px;\n overflow-wrap: anywhere;\n display: flex;\n flex-direction: column;\n gap: 8px;\n text-align: left;\n padding: 14px;\n border: 1px solid #736476;\n border-radius: 12px;\n background: #151017;\n color: inherit;\n}\n.flow-step strong {\n white-space: normal;\n width: 100%;\n}\n.flow-step-description {\n overflow-wrap: anywhere;\n font-size: 12px;\n}\n.flow-step.flow-request {\n display: block;\n padding: 0;\n background: #0d0a0f;\n /* Skip offscreen paint/layout while preserving each question/expansion state. */\n content-visibility: auto;\n contain-intrinsic-size: auto 640px;\n}\n.flow-request-heading {\n width: 100%;\n min-height: 64px;\n gap: 20px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n text-align: left;\n padding: 12px 20px;\n border: 0;\n border-bottom: 1px solid #342a38;\n border-radius: 12px 12px 0 0;\n background: transparent;\n color: inherit;\n}\n.flow-request-heading .eyebrow {\n display: block;\n margin-bottom: 4px;\n}\n.jev-devtools .lab-flow-embedded {\n width: 1120px;\n display: block;\n}\n.jev-devtools .lab-flow-surface {\n position: relative;\n width: 1120px;\n}\n.jev-devtools .lab-flow-surface[hidden] {\n display: none;\n}\n.jev-devtools .lab-flow-embedded .lab-flow-canvas {\n will-change: auto;\n}\n.jev-devtools .lab-flow-embedded .lab-choice-browser {\n height: 520px;\n}\n.flow-step.selected {\n outline: 2px solid #e551ba;\n outline-offset: 3px;\n}\n.flow-step[data-status=\"completed\"] {\n border-color: #e551ba;\n}\n.flow-step[data-status=\"running\"] {\n border-color: #e551ba;\n background: #2b1728;\n}\n.flow-step[data-status=\"untaken\"],\n.flow-step[data-status=\"blocked\"] {\n color: #948797;\n border-color: #403746;\n background: #151017;\n}\n.flow-step[data-status=\"error\"] {\n border-color: #f17c78;\n}\n.flow-step[data-status=\"cancelled\"] {\n border-style: dashed;\n}\n.flow-selection {\n padding: 12px 20px;\n border-top: 1px solid #342a38;\n}\n.flow-selection p {\n margin: 6px 0;\n overflow-wrap: anywhere;\n}\n.flow-request-detail {\n min-height: 450px;\n border-top: 1px solid #534357;\n}\n.flow-request-detail > .request-detail {\n min-height: 450px;\n}\n\n.flow-card-heading,\n.flow-card-footer,\n.flow-join-summary,\n.flow-lane {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n width: 100%;\n}\n.flow-card-heading {\n justify-content: flex-start;\n}\n.flow-task .flow-kind-icon {\n border: 1px solid currentColor;\n border-radius: 6px;\n padding: 4px;\n}\n.flow-task-preview {\n display: grid;\n gap: 8px;\n min-width: 0;\n}\n.jev-devtools .flow-task-preview .diagram-content {\n max-height: 280px;\n padding: 8px 10px;\n border: 1px solid #35283b;\n border-radius: 4px;\n background: #100c13;\n}\n.flow-task-preview small {\n color: var(--muted);\n font-size: 11px;\n}\n.flow-task-details {\n display: grid;\n gap: 12px;\n}\n.flow-task-details details {\n min-width: 0;\n}\n.flow-task-details summary {\n cursor: pointer;\n margin-bottom: 8px;\n}\n.flow-task-details .diagram-content {\n max-height: 320px;\n overflow: auto;\n}\n.flow-kind-icon {\n width: 26px;\n height: 26px;\n color: #e551ba;\n flex-shrink: 0;\n}\n.flow-kind-icon svg {\n width: 100%;\n height: 100%;\n}\n.flow-card-heading .eyebrow {\n font-size: 10px;\n}\n.flow-status {\n margin-left: auto;\n font-size: 10px;\n border-radius: 20px;\n padding: 4px 8px;\n background: #342031;\n color: #f0b7e0;\n}\n.flow-step[data-status=\"untaken\"] .flow-status {\n background: #241e28;\n color: #948797;\n}\n.flow-step[data-status=\"untaken\"] .flow-kind-icon {\n color: #948797;\n}\n.flow-card-body > strong {\n white-space: normal;\n font-size: 18px;\n line-height: 1.25;\n overflow-wrap: anywhere;\n}\n.flow-step-description {\n line-height: 1.5;\n color: #b9aebf;\n white-space: pre-wrap;\n}\n.flow-card-footer {\n margin-top: auto;\n padding-top: 10px;\n border-top: 1px solid #342a38;\n font-size: 10px;\n color: #a092a7;\n}\n.flow-card-footer code {\n max-width: 45%;\n white-space: normal;\n overflow-wrap: anywhere;\n}\n.flow-card-footer small {\n text-align: right;\n}\n.flow-join-summary {\n margin-top: 4px;\n font-size: 11px;\n color: #c9b9cd;\n}\n.flow-join-summary > span {\n color: #ef9ed9;\n font-variant-numeric: tabular-nums;\n}\n.flow-lanes {\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n}\n.flow-lane {\n border-radius: 5px;\n background: #211923;\n padding: 6px 8px;\n font-size: 11px;\n min-height: 28px;\n}\n.flow-lane > span {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n.flow-lane > span > span {\n color: #ef9ed9;\n margin-right: 4px;\n}\n.flow-lane small {\n color: #b9aebf;\n}\n.flow-lane-details {\n padding-left: 18px;\n font-size: 12px;\n}\n.flow-request-heading > span:first-child {\n min-width: 0;\n max-width: 80%;\n}\n.flow-request-description {\n display: block;\n white-space: pre-wrap;\n font-size: 12px;\n line-height: 1.5;\n color: #b9aebf;\n margin-top: 5px;\n overflow-wrap: anywhere;\n}\n\n/* Structured context stays within the card; its gestures never move the camera. */\n.jev-devtools .lab-content-card {\n display: flex;\n flex-direction: column;\n padding: 14px;\n}\n.jev-devtools .lab-content-card h3 {\n font-size: 14px;\n margin-bottom: 8px;\n flex-shrink: 0;\n}\n.jev-devtools .lab-content-card .lab-eyebrow {\n font-size: 9px;\n margin-bottom: 5px;\n flex-shrink: 0;\n}\n.jev-devtools .diagram-content {\n min-height: 0;\n flex: 1;\n overflow: auto;\n overscroll-behavior: contain;\n touch-action: pan-y;\n scrollbar-width: thin;\n scrollbar-color: #514256 transparent;\n padding-right: 4px;\n font-size: 12px;\n line-height: 1.5;\n color: #d5cdd9;\n cursor: auto;\n user-select: text;\n}\n.jev-devtools .diagram-content:focus-visible {\n outline: 1px solid #e551ba;\n outline-offset: -1px;\n border-radius: 3px;\n}\n.jev-devtools .diagram-property {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n gap: 8px;\n padding: 5px 0;\n border-bottom: 1px solid #261e2a;\n}\n.jev-devtools .diagram-property-text {\n display: block;\n}\n.jev-devtools .diagram-property-key {\n font:\n 10px/1.5 ui-monospace,\n monospace;\n color: #c8a8c8;\n overflow-wrap: anywhere;\n min-width: 0;\n}\n.jev-devtools .diagram-property-text > .diagram-property-key {\n display: block;\n margin-bottom: 2px;\n}\n.jev-devtools .diagram-text-value {\n display: block;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n.jev-devtools .diagram-text-preview {\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.jev-devtools .diagram-value-number {\n color: #a6d6ca;\n font:\n 11px/1.5 ui-monospace,\n monospace;\n font-variant-numeric: tabular-nums;\n overflow-wrap: anywhere;\n}\n.jev-devtools .diagram-value-boolean {\n color: #c4b1ed;\n font:\n 11px/1.5 ui-monospace,\n monospace;\n}\n.jev-devtools .diagram-value-empty {\n color: #9c8ca4;\n font:\n 10px/1.5 ui-monospace,\n monospace;\n}\n.jev-devtools .diagram-property-disclosure {\n width: 100%;\n display: flex;\n align-items: baseline;\n gap: 5px;\n padding: 6px 0;\n border: 0;\n border-bottom: 1px solid #261e2a;\n border-radius: 0;\n background: transparent;\n text-align: left;\n color: inherit;\n}\n.jev-devtools .diagram-property-disclosure:hover {\n background: #211723;\n}\n.jev-devtools .diagram-property-caret {\n color: #ab8aab;\n flex-shrink: 0;\n}\n.jev-devtools .diagram-property-type {\n color: #9c8ca4;\n font:\n 10px/1.5 ui-monospace,\n monospace;\n margin-left: auto;\n flex-shrink: 0;\n}\n.jev-devtools .diagram-property-children {\n margin-left: 4px;\n padding-left: 9px;\n border-left: 1px solid #49324b;\n}\n.jev-devtools .diagram-content-toggle {\n display: block;\n padding: 3px 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #e9a4d7;\n font-size: 10px;\n text-align: left;\n}\n.jev-devtools .diagram-content-toggle:hover {\n color: #ffd9f3;\n text-decoration: underline;\n}\n\n/* Noul is a probability of true; its two outputs carry p and 1-p.\n Keep the fill opaque, with readable text even at zero probability. */\n.jev-devtools .lab-noul-output {\n border-color: rgb(\n 245 243 246 / calc(0.35 + 0.65 * var(--lab-noul-probability, 1))\n );\n}\n.jev-devtools .lab-noul-output > h3,\n.jev-devtools .lab-noul-output > p {\n opacity: calc(0.65 + 0.35 * var(--lab-noul-probability, 1));\n}\n\n.flow-condition-rule {\n display: block;\n padding: 10px 12px;\n border: 1px solid #49324b;\n border-radius: 6px;\n background: #211723;\n width: 100%;\n}\n.flow-condition-label {\n display: block;\n font-size: 10px;\n color: #ba9dbe;\n margin-bottom: 5px;\n}\n.flow-condition-rule code {\n display: block;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font:\n 12px/1.6 ui-monospace,\n monospace;\n color: #f2d7eb;\n}\n\n.flow-condition-incoming {\n display: block;\n padding-bottom: 10px;\n margin-bottom: 10px;\n border-bottom: 1px solid #49324b;\n}\n.flow-condition-input {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n gap: 12px;\n font-size: 12px;\n padding: 3px 0;\n}\n.flow-condition-input > span {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n.flow-condition-input > b {\n font-size: 17px;\n font-weight: 600;\n color: #f2d7eb;\n overflow-wrap: anywhere;\n white-space: normal;\n max-width: 65%;\n}\n.flow-input-details {\n font-size: 12px;\n}\n.flow-input-details > div {\n display: flex;\n gap: 16px;\n margin: 6px 0;\n}\n.flow-input-details code {\n color: #a092a7;\n margin-left: 8px;\n}\n.flow-input-details dd {\n margin: 0;\n overflow-wrap: anywhere;\n}\n\n.flow-overview-stack {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n min-width: 0;\n overflow: hidden;\n}\n.flow-map-progress {\n display: grid;\n gap: 10px;\n font-size: 14px;\n line-height: 1.5;\n}\n.flow-map-progress small {\n color: #b5a6bc;\n}\n\n.jev-devtools .flow-card-body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n flex: 1;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n}\n.jev-devtools .flow-card-body:hover {\n background: transparent;\n}\n.flow-collection-controls {\n display: flex;\n align-items: end;\n gap: 10px;\n border-top: 1px solid #49324b;\n margin-top: 4px;\n padding-top: 12px;\n}\n.flow-collection-controls label {\n display: grid;\n gap: 6px;\n flex: 1;\n min-width: 0;\n color: #b9aebf;\n font-size: 11px;\n}\n.jev-devtools .flow-collection-controls select {\n width: 100%;\n min-width: 0;\n}\n.jev-devtools .flow-collection-controls button {\n flex: none;\n color: #efb1df;\n}\n.flow-collection-expansion {\n position: absolute;\n width: max-content;\n}\n.flow-item-frame {\n border: 1px solid #64415d;\n border-radius: 12px;\n background: #100c13;\n overflow: hidden;\n}\n.flow-collection-heading {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 24px;\n padding: 16px 20px;\n border-bottom: 1px solid #49324b;\n background: #1c1220;\n}\n.flow-collection-heading h3 {\n margin: 5px 0;\n font-size: 16px;\n}\n.flow-collection-heading small {\n color: #b9aebf;\n}\n.flow-collection-link text {\n fill: #ce9abd;\n font-size: 12px;\n}\n.flow-item-placeholder {\n width: 600px;\n padding: 24px;\n line-height: 1.6;\n}\n.flow-inline-overview,\n.flow-inline-overview > .whole-flow,\n.flow-inline-overview > .whole-flow > .flow-workspace {\n display: block;\n flex: none;\n}\n.flow-inline-surface {\n position: relative;\n}\n\n.flow-item-content {\n min-width: 0;\n animation: flow-item-enter 240ms cubic-bezier(0.22, 1, 0.36, 1) both;\n}\n.flow-item-forward {\n --flow-item-offset: 28px;\n}\n.flow-item-backward {\n --flow-item-offset: -28px;\n}\n@keyframes flow-item-enter {\n from {\n opacity: 0;\n transform: translateX(var(--flow-item-offset));\n }\n to {\n opacity: 1;\n transform: translateX(0);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .flow-item-content {\n animation: none;\n }\n}\n.jev-devtools .flow-item-arrow {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n display: grid;\n place-items: center;\n width: 56px;\n height: 56px;\n padding: 12px;\n margin: 0 auto;\n border: 1px solid #64415d;\n border-radius: 6px;\n background: #211623;\n color: #efa7db;\n}\n.jev-devtools .flow-item-arrow:hover:not(:disabled) {\n background: #382035;\n border-color: #e551ba;\n}\n.flow-item-arrow svg {\n width: 28px;\n height: 28px;\n}\n\n.flow-item-previous {\n left: -76px;\n}\n.flow-item-next {\n right: -76px;\n}\n";
|
|
1
|
+
export const inspectorStyles = "/* Important declarations in the inner shadow context beat page-authored host\n styles, including important ones. Keep the reset here instead of expanding\n the all shorthand into hundreds of inline properties on the host element.\n These qualified host selectors are inert in the public document stylesheet. */\n:host(jev-devtools-root) {\n all: initial !important;\n direction: ltr !important;\n unicode-bidi: isolate !important;\n position: fixed !important;\n inset: 0 !important;\n pointer-events: none !important;\n z-index: 2147483000 !important;\n}\n\n:host(jev-devtools-root)::before,\n:host(jev-devtools-root)::after {\n content: none !important;\n display: none !important;\n}\n\n.jev-devtools {\n all: initial;\n /* all does not reset custom properties. Establish our own inherited defaults;\n cameras and probability cards can still set local values below this root. */\n --diagram-grid-opacity: 1;\n --diagram-grid-weight: 1;\n --lab-noul-probability: 1;\n --flow-item-offset: 0px;\n display: block;\n direction: ltr;\n unicode-bidi: isolate;\n pointer-events: auto;\n color-scheme: dark;\n font:\n 12px system-ui,\n sans-serif;\n color: #eee8ed;\n line-height: 1.5;\n}\n.jev-devtools,\n.jev-devtools * {\n box-sizing: border-box;\n}\n.jev-devtools button,\n.jev-devtools input,\n.jev-devtools select,\n.jev-devtools textarea {\n font: inherit;\n color: inherit;\n border: 1px solid #3b303d;\n border-radius: 5px;\n background: #17121b;\n}\n.jev-devtools button {\n padding: 7px 11px;\n cursor: pointer;\n}\n.jev-devtools button:disabled {\n opacity: 0.45;\n cursor: default;\n}\n.jev-devtools input,\n.jev-devtools select {\n padding: 8px;\n width: 100%;\n}\n.jev-devtools button:hover:not(:disabled) {\n border-color: #e551ba;\n}\n.jev-devtools :is(button, input, select, textarea, summary):focus-visible {\n outline: 2px solid #e551ba;\n outline-offset: 3px;\n}\n.jev-devtools .eyebrow {\n font-size: 10px;\n letter-spacing: 0.12em;\n color: #bc9db5;\n text-transform: uppercase;\n}\n.jev-devtools .jev-inspector {\n height: 100%;\n display: flex;\n color: #eee8ed;\n background: #0d0a0f;\n font:\n 12px \"DM Sans\",\n sans-serif;\n min-height: 0;\n overflow: hidden;\n}\n.jev-devtools .jev-inspector h2 {\n font-size: 15px;\n margin: 0;\n font-weight: 600;\n}\n.jev-devtools .jev-inspector h3 {\n font-size: 13px;\n margin: 0 0 8px;\n}\n.jev-devtools .jev-inspector code,\n.jev-devtools .jev-inspector pre {\n font:\n 11px \"JetBrains Mono\",\n monospace;\n}\n.jev-devtools .jev-inspector pre {\n line-height: 1.7;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n max-height: 460px;\n overflow: auto;\n background: #100d13;\n padding: 16px;\n border: 1px solid #2e2533;\n border-radius: 5px;\n}\n.jev-devtools .jev-inspector .muted {\n color: #a89bac;\n font-size: 11px;\n line-height: 1.6;\n}\n.jev-devtools .request-list {\n flex: 0 0 300px;\n border-right: 1px solid #302634;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n.jev-devtools .request-list > header {\n padding: 17px 14px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n.jev-devtools .request-list h2 span {\n font-size: 11px;\n color: #b796ad;\n margin-left: 5px;\n}\n.jev-devtools .request-list button {\n font-size: 11px;\n}\n.jev-devtools .list-filters {\n display: flex;\n gap: 7px;\n padding: 0 12px 12px;\n}\n.jev-devtools .list-filters input {\n min-width: 0;\n}\n.jev-devtools .list-filters select {\n width: 86px;\n font-size: 11px;\n}\n.jev-devtools .request-items {\n overflow: auto;\n flex: 1;\n}\n.jev-devtools .request-row {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n text-align: left;\n border: 0;\n border-top: 1px solid #251d2a;\n border-radius: 0;\n background: transparent;\n padding: 16px 12px;\n}\n.jev-devtools .request-row.selected {\n background: #251423;\n box-shadow: inset 2px 0 #e551ba;\n}\n.jev-devtools .request-row strong {\n display: block;\n font-size: 12px;\n font-weight: 500;\n}\n.jev-devtools .request-row small {\n display: block;\n font-size: 10px;\n color: #a99aac;\n margin-top: 6px;\n}\n.jev-devtools .row-status {\n font-size: 9px;\n color: #ad9bb0;\n margin-left: auto;\n}\n.jev-devtools .status-dot {\n width: 6px;\n height: 6px;\n display: inline-block;\n border-radius: 50%;\n background: #b09ab7;\n flex-shrink: 0;\n}\n.jev-devtools .status-dot.success {\n background: #b3c79c;\n}\n.jev-devtools .status-dot.pending {\n background: #e551ba;\n}\n.jev-devtools .status-dot.error {\n background: #ee8e85;\n}\n.jev-devtools .request-list footer {\n padding: 12px;\n color: #9e8ea5;\n border-top: 1px solid #302634;\n font-size: 10px;\n display: flex;\n gap: 7px;\n}\n.jev-devtools .request-detail {\n flex: 1;\n min-width: 0;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n.jev-devtools .detail-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 20px;\n padding: 18px 24px 10px;\n}\n.jev-devtools .detail-header h2 {\n margin-top: 6px;\n}\n.jev-devtools .metrics {\n display: flex;\n gap: 24px;\n font:\n 12px \"JetBrains Mono\",\n monospace;\n white-space: nowrap;\n}\n.jev-devtools .metrics small {\n display: block;\n font:\n 9px \"DM Sans\",\n sans-serif;\n color: #97879f;\n margin-top: 6px;\n}\n.jev-devtools .detail-meta {\n display: flex;\n gap: 20px;\n flex-wrap: wrap;\n padding: 0 24px 14px;\n color: #a08aa5;\n}\n.jev-devtools .detail-meta code {\n font-size: 10px;\n}\n.jev-devtools .detail-tabs {\n display: flex;\n gap: 20px;\n border-bottom: 1px solid #302634;\n padding: 0 24px;\n}\n.jev-devtools .detail-tabs button {\n border: 0;\n border-radius: 0;\n background: none;\n padding: 10px 0;\n color: #a89bac;\n font-size: 11px;\n}\n.jev-devtools .detail-tabs button[aria-pressed=\"true\"] {\n box-shadow: inset 0 -2px #e551ba;\n color: #f5c1e6;\n}\n.jev-devtools .detail-body {\n overflow: auto;\n flex: 1;\n min-height: 0;\n padding: 16px 24px 28px;\n background-image: radial-gradient(#342337 0.6px, transparent 0.6px);\n background-size: 16px 16px;\n}\n.jev-devtools .question-node {\n position: relative;\n border: 1px solid #75516c;\n border-radius: 6px;\n padding: 15px;\n background: #110d14;\n min-width: 0;\n}\n/* Retain the legacy question connectors and standalone suppression together.\n Remove only after resolving the narrow-screen visual differences in\n https://github.com/diegoag64/jev-devtools/issues/57. */\n.jev-devtools .question-node:before {\n content: \"\";\n position: absolute;\n right: 100%;\n top: 50%;\n width: 21px;\n border-top: 1px solid #7f416d;\n}\n.jev-devtools .question-branches .question-node:not(:first-child):before {\n display: none;\n}\n.jev-devtools .question-node header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n.jev-devtools .question-node header h3 {\n margin: 0;\n overflow-wrap: anywhere;\n}\n.jev-devtools .type {\n font:\n 9px \"JetBrains Mono\",\n monospace;\n color: #e59acc;\n border: 1px solid #5e3654;\n border-radius: 3px;\n padding: 3px 5px;\n}\n.jev-devtools .answer-value {\n display: block;\n font-size: 20px;\n font-weight: 500;\n margin: 15px 0;\n color: #f0c7e5;\n}\n.jev-devtools .answer-value small {\n font-size: 10px;\n color: #b5a1ba;\n}\n.jev-devtools .probability {\n margin: 10px 0;\n font-size: 10px;\n}\n.jev-devtools .probability > div:first-child {\n display: flex;\n justify-content: space-between;\n gap: 5px;\n margin-bottom: 5px;\n}\n.jev-devtools .probability b {\n font-weight: 400;\n color: #d8abc9;\n}\n.jev-devtools .bar {\n height: 4px;\n background: #302033;\n border-radius: 2px;\n overflow: hidden;\n}\n.jev-devtools .bar i {\n display: block;\n height: 100%;\n background: #e551ba;\n}\n.jev-devtools .confidence {\n font-size: 10px;\n color: #a68cac;\n border-top: 1px solid #302634;\n padding-top: 10px;\n display: flex;\n justify-content: space-between;\n}\n.jev-devtools .confidence b {\n color: #d1bad2;\n font-weight: 400;\n}\n.jev-devtools details {\n margin-top: 12px;\n font-size: 10px;\n color: #b7a0bd;\n}\n.jev-devtools summary {\n cursor: pointer;\n}\n.jev-devtools .standalone {\n margin-bottom: 14px;\n max-width: 750px;\n}\n.jev-devtools .standalone:before {\n display: none;\n}\n.jev-devtools .standalone .answer {\n max-width: 450px;\n}\n.jev-devtools .box-preview {\n position: relative;\n margin-top: 14px;\n min-height: 80px;\n background: #19121c;\n}\n.jev-devtools .box-preview img {\n width: 100%;\n display: block;\n}\n.jev-devtools .bounding-box {\n position: absolute;\n border: 1.5px solid #e551ba;\n background: #e551ba15;\n}\n.jev-devtools .coordinates {\n display: block;\n font-size: 9px !important;\n line-height: 1.5;\n margin-top: 8px;\n color: #ac93b0;\n}\n.jev-devtools .context-image {\n max-width: 400px;\n width: 100%;\n border: 1px solid #75516c;\n border-radius: 6px;\n}\n.jev-devtools .empty {\n padding: 20px;\n color: #a294a8;\n line-height: 1.7;\n}\n.jev-devtools .empty-detail {\n margin: auto;\n padding: 40px;\n text-align: center;\n color: #b2a0ba;\n}\n.jev-devtools .empty-symbol {\n font-size: 36px;\n color: #e551ba;\n display: block;\n margin-bottom: 20px;\n}\n.jev-devtools .empty-detail p {\n font-size: 12px;\n line-height: 1.8;\n}\n.jev-devtools .error-banner {\n border: 1px solid #874b50;\n background: #31191e;\n padding: 12px;\n line-height: 1.5;\n margin-bottom: 16px;\n}\n.jev-devtools .warning {\n color: #e2b97d;\n}\n.jev-devtools .jev-inspector table {\n border-collapse: collapse;\n width: 100%;\n text-align: left;\n}\n.jev-devtools .jev-inspector th,\n.jev-devtools .jev-inspector td {\n border-bottom: 1px solid #302634;\n padding: 14px;\n}\n@media (max-width: 1100px) {\n .jev-devtools .question-branches .question-node:not(:first-child):before {\n display: block;\n }\n .jev-devtools .metrics {\n gap: 12px;\n }\n .jev-devtools .request-list {\n flex-basis: 250px;\n }\n}\n@media (max-width: 700px) {\n .jev-devtools .jev-inspector {\n flex-direction: column;\n }\n .jev-devtools .request-list {\n flex-basis: 140px;\n flex-shrink: 0;\n border-right: 0;\n border-bottom: 1px solid #302634;\n }\n .jev-devtools .request-list > header {\n padding: 6px 12px;\n }\n .jev-devtools .request-list footer {\n display: none;\n }\n .jev-devtools .list-filters {\n padding-bottom: 6px;\n }\n .jev-devtools .request-items {\n display: flex;\n }\n .jev-devtools .request-row {\n min-width: 240px;\n padding: 8px 12px;\n }\n .jev-devtools .detail-header {\n padding: 12px;\n }\n .jev-devtools .detail-meta,\n .jev-devtools .detail-tabs {\n padding-left: 12px;\n padding-right: 12px;\n }\n .jev-devtools .detail-body {\n padding: 12px;\n }\n .jev-devtools .metrics {\n display: none;\n }\n .jev-devtools .question-node:before {\n width: 13px;\n }\n .jev-devtools .question-node {\n padding: 12px;\n }\n}\n.jev-devtools .question-node:before,\n.jev-devtools .question-branches .question-node:not(:first-child):before {\n display: block;\n right: auto;\n left: 50%;\n top: -21px;\n width: 0;\n height: 20px;\n border-top: 0;\n border-left: 1px solid #7f416d;\n}\n.jev-devtools .standalone:before {\n display: none;\n}\n@media (max-width: 900px) {\n .jev-devtools .question-node:before,\n .jev-devtools .question-branches .question-node:not(:first-child):before {\n height: 12px;\n top: -13px;\n }\n .jev-devtools .question-branches .question-node:first-child:before {\n height: 20px;\n top: -21px;\n }\n}\n\n.jev-devtools.jev-drawer {\n margin: 0;\n padding: 0;\n position: fixed;\n z-index: 1000;\n inset: auto 0 0;\n display: flex;\n flex-direction: column;\n background: #0d0a0f;\n color: #eee8ed;\n border-top: 1px solid #604058;\n box-shadow: 0 -12px 48px #0005;\n font:\n 12px \"DM Sans\",\n sans-serif;\n}\n.jev-devtools.jev-drawer[hidden],\n.jev-devtools.jev-drawer-trigger[hidden] {\n display: none;\n}\n.jev-devtools .jev-drawer-resize {\n position: absolute;\n z-index: 1;\n top: -6px;\n width: 100%;\n height: 12px;\n cursor: ns-resize;\n touch-action: none;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.jev-devtools .jev-drawer-resize span {\n width: 42px;\n height: 3px;\n border-radius: 3px;\n background: #79506f;\n}\n.jev-devtools .jev-drawer-resize:hover span,\n.jev-devtools .jev-drawer-resize:focus-visible span {\n background: #e551ba;\n}\n.jev-devtools .jev-drawer-resize:focus-visible {\n outline: 2px solid #e551ba;\n outline-offset: -2px;\n}\n.jev-devtools .jev-drawer-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex: 0 0 46px;\n padding: 0 16px;\n border-bottom: 1px solid #302634;\n}\n.jev-devtools .jev-drawer-header strong {\n display: flex;\n align-items: center;\n gap: 9px;\n font-weight: 600;\n}\n.jev-devtools .jev-drawer-header > div {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.jev-devtools .jev-drawer-header button {\n background: transparent;\n border-color: transparent;\n font-size: 11px;\n color: #c4afc8;\n}\n.jev-devtools .jev-drawer-header .jev-drawer-close {\n font-size: 22px;\n line-height: 1;\n padding: 4px 8px;\n}\n.jev-devtools .jev-drawer-content {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n.jev-devtools.jev-drawer-trigger {\n position: fixed;\n bottom: 18px;\n right: 18px;\n z-index: 1000;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 10px 16px;\n border: 1px solid #a24487;\n border-radius: 8px;\n cursor: pointer;\n background: #211321;\n color: #f1cbe6;\n font:\n 600 13px \"DM Sans\",\n sans-serif;\n box-shadow: 0 4px 20px #0005;\n}\n.jev-devtools.jev-drawer-trigger span {\n color: #e551ba;\n font-size: 20px;\n}\n/* Baseline cards and authored left-to-right composition from the lab's Jev presets. */\n.jev-devtools .detail-body.detail-body-flow {\n display: flex;\n padding: 0;\n overflow: hidden;\n}\n.jev-devtools .lab-flow {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-width: 0;\n min-height: 0;\n}\n.jev-devtools .lab-flow-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-shrink: 0;\n padding: 12px 16px;\n flex-wrap: wrap;\n}\n.jev-devtools .lab-flow-toolbar label {\n display: flex;\n gap: 10px;\n align-items: center;\n font-size: 11px;\n min-width: 0;\n}\n.jev-devtools .lab-flow-toolbar select {\n width: auto;\n max-width: 240px;\n font-size: 11px;\n}\n.jev-devtools .lab-flow-toolbar > div {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.jev-devtools .lab-flow-toolbar button {\n font-size: 11px;\n}\n.jev-devtools .lab-flow-toolbar output {\n font-size: 11px;\n min-width: 35px;\n text-align: center;\n}\n.jev-devtools .lab-flow-viewport {\n position: relative;\n flex: 1;\n min-height: 100px;\n overflow: hidden;\n background-color: #0d0a0f;\n background-image: radial-gradient(\n rgb(70 52 73 / var(--diagram-grid-opacity, 1))\n calc(0.8px * var(--diagram-grid-weight, 1)),\n transparent calc(0.8px * var(--diagram-grid-weight, 1))\n );\n background-size: 20px 20px;\n border-block: 1px solid #302634;\n cursor: grab;\n touch-action: none;\n user-select: none;\n overscroll-behavior: contain;\n}\n.jev-devtools .lab-flow-viewport[data-panning] {\n cursor: grabbing;\n}\n.jev-devtools .lab-flow-viewport:focus-visible {\n outline: 2px solid #e551ba;\n outline-offset: -2px;\n}\n.jev-devtools .lab-flow-caption {\n flex-shrink: 0;\n padding: 8px 16px;\n margin: 0;\n}\n.jev-devtools .lab-gesture-hint {\n display: block;\n color: #c6a7bd;\n}\n.jev-devtools .lab-flow-canvas {\n position: absolute;\n inset: 0 auto auto 0;\n transform-origin: top left;\n will-change: transform;\n font-family: system-ui, sans-serif;\n color: #f5f3f6;\n}\n.jev-devtools .lab-connections {\n position: absolute;\n inset: 0;\n overflow: visible;\n}\n.jev-devtools .lab-connections path {\n fill: none;\n stroke: #645a68;\n stroke-width: 1;\n}\n.jev-devtools .lab-connections path.active {\n stroke: #968592;\n}\n.jev-devtools .lab-connections text {\n fill: #b7b1bc;\n font:\n 12px ui-monospace,\n monospace;\n}\n.jev-devtools .lab-flow-dot {\n fill: #e551ba;\n}\n.jev-devtools .lab-card {\n position: absolute;\n border: 1.3px solid #f5f3f6;\n border-radius: 14px;\n padding: 16px;\n background: #0d0a0f;\n overflow: hidden;\n}\n.jev-devtools .lab-eyebrow {\n display: block;\n color: #e551ba;\n font:\n 500 10px ui-monospace,\n monospace;\n letter-spacing: 1px;\n margin: 0 0 7px;\n}\n.jev-devtools .lab-card h3 {\n font-size: 16px;\n font-weight: 600;\n line-height: 1.3;\n letter-spacing: -0.2px;\n margin: 0 0 10px;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.jev-devtools .lab-card p {\n font-size: 13px;\n line-height: 1.4;\n margin: 10px 0;\n}\n.jev-devtools .lab-copy {\n display: -webkit-box;\n -webkit-line-clamp: 5;\n -webkit-box-orient: vertical;\n overflow: hidden;\n overflow-wrap: anywhere;\n}\n.jev-devtools .lab-probability {\n margin: 17px 0;\n}\n.jev-devtools .lab-probability > div:first-child {\n display: flex;\n justify-content: space-between;\n gap: 10px;\n margin-bottom: 9px;\n font-size: 15px;\n}\n.jev-devtools .lab-probability span {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.jev-devtools .lab-probability code {\n font:\n 13px ui-monospace,\n monospace;\n}\n.jev-devtools .lab-track {\n height: 7px;\n border-radius: 4px;\n background: #f5f3f61a;\n overflow: hidden;\n}\n.jev-devtools .lab-track i {\n display: block;\n height: 100%;\n border-radius: 4px;\n background: #e551ba;\n}\n.jev-devtools .lab-track i.lab-alternative {\n opacity: 0.35;\n}\n.jev-devtools .lab-card .lab-result {\n font-size: 14px;\n margin-top: 24px;\n}\n.jev-devtools .lab-card .lab-small {\n font-size: 12px;\n color: #b7b1bc;\n margin-top: 20px;\n}\n.jev-devtools .lab-idle {\n opacity: 0.65;\n}\n.jev-devtools .lab-scale {\n position: relative;\n margin-top: 18px;\n border-top: 1px solid #b7b1bc;\n display: flex;\n justify-content: space-between;\n padding-top: 9px;\n}\n.jev-devtools .lab-scale > span {\n position: absolute;\n top: -5px;\n width: 9px;\n height: 9px;\n border-radius: 50%;\n background: #e551ba;\n transform: translateX(-50%);\n}\n.jev-devtools .lab-big {\n display: block;\n font-size: 36px;\n font-weight: 500;\n margin-top: 26px;\n}\n.jev-devtools .lab-endpoints {\n display: flex;\n justify-content: space-between;\n font-size: 12px;\n color: #b7b1bc;\n margin-top: 10px;\n}\n.jev-devtools .lab-image {\n position: relative;\n}\n.jev-devtools .lab-image img {\n display: block;\n width: 100%;\n}\n.jev-devtools .lab-box {\n position: absolute;\n border: 1.5px solid #e551ba;\n background: #e551ba15;\n}\n.jev-devtools .lab-source-image {\n width: 100%;\n max-height: 105px;\n object-fit: contain;\n}\n.jev-devtools .lab-coordinates {\n font-family: ui-monospace, monospace;\n}\n@media (prefers-reduced-motion: reduce) {\n .jev-devtools .lab-flow-dot {\n display: none;\n }\n}\n/* The public TypeSafe mark travels with the package, independent of host assets. */\n.jev-devtools .typesafe-mark {\n display: inline-block;\n flex: 0 0 23px;\n width: 23px;\n height: 32px;\n overflow: hidden;\n line-height: 0;\n}\n.jev-devtools .typesafe-mark img {\n display: block;\n height: 32px;\n width: auto;\n max-width: none;\n}\n\n.jev-devtools .detail-body-questions {\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n.jev-devtools .questions-list {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 180px;\n}\n.jev-devtools .questions-navigation {\n display: flex;\n align-items: end;\n gap: 8px;\n flex-wrap: wrap;\n flex-shrink: 0;\n}\n.jev-devtools .questions-navigation label {\n display: flex;\n align-items: center;\n gap: 8px;\n white-space: nowrap;\n flex: 1;\n min-width: 240px;\n max-width: 480px;\n font-size: 11px;\n color: #bc9db5;\n}\n.jev-devtools .questions-navigation select {\n display: block;\n min-width: 0;\n}\n.jev-devtools .questions-navigation > span {\n align-self: center;\n color: #a89bac;\n}\n.jev-devtools .questions-help {\n margin: 8px 0;\n flex-shrink: 0;\n}\n.jev-devtools .questions-viewport {\n flex: 1;\n min-height: 0;\n overflow: auto;\n overflow-anchor: none;\n scrollbar-gutter: stable;\n padding: 3px;\n}\n.jev-devtools .questions-spacer {\n position: relative;\n width: 100%;\n}\n.jev-devtools .questions-row {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n padding-bottom: 14px;\n}\n.jev-devtools .questions-row .standalone {\n margin-bottom: 0;\n}\n.jev-devtools .questions-viewport:focus-visible,\n.jev-devtools .questions-row article:focus-visible {\n outline: 2px solid #e551ba;\n outline-offset: -2px;\n}\n\n/* Reserve measured card geometry while rapid scrolling uses a light preview. */\n.jev-devtools .questions-row[data-preview=\"true\"] article {\n height: 100%;\n}\n.jev-devtools .question-scroll-preview p {\n margin-top: 16px;\n}\n\n/* The full distribution stays at reading size, outside the zoomable canvas. */\n.jev-devtools .lab-flow-viewport[hidden] {\n display: none;\n}\n.jev-devtools .lab-choice-browser {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n padding: 8px 16px;\n gap: 10px;\n}\n.jev-devtools .lab-choice-controls {\n display: flex;\n gap: 12px;\n align-items: end;\n flex-wrap: wrap;\n font-size: 12px;\n}\n.jev-devtools .lab-choice-controls label {\n display: grid;\n gap: 5px;\n}\n.jev-devtools .lab-choice-table-scroll {\n overflow: auto;\n overscroll-behavior: contain;\n min-height: 0;\n}\n.jev-devtools .lab-choice-browser table {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n}\n.jev-devtools .lab-choice-browser caption {\n text-align: left;\n padding: 8px 0;\n color: #aaa0af;\n}\n.jev-devtools .lab-choice-browser th,\n.jev-devtools .lab-choice-browser td {\n padding: 9px 12px;\n border-bottom: 1px solid #302634;\n text-align: left;\n}\n.jev-devtools .lab-choice-browser th {\n overflow-wrap: anywhere;\n max-width: 320px;\n}\n.jev-devtools .lab-choice-browser td {\n font-variant-numeric: tabular-nums;\n}\n.jev-devtools .lab-choice-browser code {\n white-space: normal;\n overflow-wrap: anywhere;\n}\n.jev-devtools .lab-choice-returned {\n display: block;\n font-size: 10px;\n color: #e551ba;\n}\n.jev-devtools .lab-choice-pagination {\n display: flex;\n align-items: center;\n gap: 12px;\n justify-content: space-between;\n font-size: 12px;\n}\n.jev-devtools .lab-choice-remainder button {\n margin-top: 7px;\n}\n\n.jev-devtools .lab-flow-compact .lab-output {\n padding: 12px;\n height: 104px;\n}\n.jev-devtools .lab-flow-compact .lab-output .lab-eyebrow {\n margin-bottom: 6px;\n}\n.jev-devtools .lab-flow-compact .lab-output h3 {\n font-size: 16px;\n margin-bottom: 8px;\n}\n.jev-devtools .lab-flow-compact .lab-output p {\n font-size: 12px;\n margin: 4px 0;\n}\n.jev-devtools .lab-flow-compact .lab-result {\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n overflow-wrap: anywhere;\n}\n.jev-devtools .lab-choice-remainder {\n padding: 12px;\n}\n.jev-devtools .lab-choice-remainder .lab-small {\n margin: 8px 0 0;\n font-size: 11px;\n}\n\n.jev-devtools .detail-body.detail-body-flow {\n flex-direction: column;\n}\n.jev-devtools .detail-body-flow > .warning,\n.jev-devtools .detail-body-flow > .error-banner {\n flex-shrink: 0;\n margin: 6px 16px;\n}\n.jev-devtools .lab-choice-browser {\n overflow: auto;\n}\n.jev-devtools .lab-choice-table-scroll {\n flex: 1 0 110px;\n}\n\n/* Only freshly revealed branches enter; pan/zoom remains on the canvas. */\n.jev-devtools .lab-card-enter {\n animation: jev-card-enter 280ms cubic-bezier(0.2, 0.8, 0.2, 1) backwards;\n}\n.jev-devtools .lab-branch-enter {\n stroke-dasharray: 1;\n animation: jev-branch-enter 280ms ease-out backwards;\n}\n@keyframes jev-card-enter {\n from {\n opacity: 0;\n transform: translateX(-16px) scale(0.96);\n }\n}\n@keyframes jev-branch-enter {\n from {\n opacity: 0;\n stroke-dashoffset: 1;\n }\n to {\n opacity: 1;\n stroke-dashoffset: 0;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .jev-devtools .lab-card-enter,\n .jev-devtools .lab-branch-enter {\n animation: none;\n }\n}\n\n/* Connected requests share one camera and one opt-in full request detail.\n :where scopes these selectors without changing their existing specificity. */\n:where(.jev-devtools) .whole-flow {\n min-width: 0;\n overflow: hidden;\n}\n:where(.jev-devtools) .whole-flow > .detail-header,\n:where(.jev-devtools) .whole-flow > .lab-flow-toolbar {\n flex-shrink: 0;\n}\n:where(.jev-devtools) .flow-workspace {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n:where(.jev-devtools) .flow-details-panel {\n flex: none;\n min-width: 0;\n background: #130f17;\n border-top: 1px solid #342a38;\n}\n:where(.jev-devtools) .flow-details-bar {\n display: flex;\n align-items: center;\n gap: 12px;\n height: 36px;\n padding: 0 12px;\n}\n.jev-devtools .flow-details-bar button {\n flex: none;\n padding: 4px 8px;\n font-size: 11px;\n}\n:where(.jev-devtools) .flow-details-bar > span {\n color: #b5a6bc;\n font-size: 11px;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n:where(.jev-devtools) .flow-details-body {\n overflow: auto;\n overscroll-behavior: contain;\n scrollbar-gutter: stable;\n}\n:where(.jev-devtools) .flow-details-resize {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 8px;\n cursor: ns-resize;\n touch-action: none;\n user-select: none;\n}\n:where(.jev-devtools) .flow-details-resize span {\n width: 40px;\n height: 2px;\n border-radius: 2px;\n background: #6c5874;\n}\n:where(.jev-devtools) .flow-details-resize:hover,\n:where(.jev-devtools) .flow-details-resize:focus-visible {\n background: #392239;\n outline: 1px solid #e551ba;\n outline-offset: -1px;\n}\n:where(.jev-devtools) .flow-overview-viewport {\n position: relative;\n min-height: 0;\n flex: 1 1 0;\n overflow: hidden;\n touch-action: none;\n cursor: grab;\n background-image: radial-gradient(\n rgb(83 67 87 / var(--diagram-grid-opacity, 1))\n calc(1px * var(--diagram-grid-weight, 1)),\n transparent calc(1px * var(--diagram-grid-weight, 1))\n );\n background-size: 20px 20px;\n}\n:where(.jev-devtools) .flow-overview-viewport[data-panning] {\n cursor: grabbing;\n}\n:where(.jev-devtools) .flow-overview-canvas {\n position: absolute;\n transform-origin: 0 0;\n}\n:where(.jev-devtools) .flow-connections {\n position: absolute;\n inset: 0;\n overflow: visible;\n color: #c0b8c4;\n pointer-events: none;\n}\n:where(.jev-devtools) .flow-step {\n position: absolute;\n min-height: 172px;\n overflow-wrap: anywhere;\n display: flex;\n flex-direction: column;\n gap: 8px;\n text-align: left;\n padding: 14px;\n border: 1px solid #736476;\n border-radius: 12px;\n background: #151017;\n color: inherit;\n}\n:where(.jev-devtools) .flow-step strong {\n white-space: normal;\n width: 100%;\n}\n:where(.jev-devtools) .flow-step-description {\n overflow-wrap: anywhere;\n font-size: 12px;\n}\n:where(.jev-devtools) .flow-step.flow-request {\n display: block;\n padding: 0;\n background: #0d0a0f;\n /* Skip offscreen paint/layout while preserving each question/expansion state. */\n content-visibility: auto;\n contain-intrinsic-size: auto 640px;\n}\n:where(.jev-devtools) .flow-request-heading {\n width: 100%;\n min-height: 64px;\n gap: 20px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n text-align: left;\n padding: 12px 20px;\n border: 0;\n border-bottom: 1px solid #342a38;\n border-radius: 12px 12px 0 0;\n background: transparent;\n color: inherit;\n}\n:where(.jev-devtools) .flow-request-heading .eyebrow {\n display: block;\n margin-bottom: 4px;\n}\n.jev-devtools .lab-flow-embedded {\n width: 1120px;\n display: block;\n}\n.jev-devtools .lab-flow-surface {\n position: relative;\n width: 1120px;\n}\n.jev-devtools .lab-flow-surface[hidden] {\n display: none;\n}\n.jev-devtools .lab-flow-embedded .lab-flow-canvas {\n will-change: auto;\n}\n.jev-devtools .lab-flow-embedded .lab-choice-browser {\n height: 520px;\n}\n:where(.jev-devtools) .flow-step.selected {\n outline: 2px solid #e551ba;\n outline-offset: 3px;\n}\n:where(.jev-devtools) .flow-step[data-status=\"completed\"] {\n border-color: #e551ba;\n}\n:where(.jev-devtools) .flow-step[data-status=\"running\"] {\n border-color: #e551ba;\n background: #2b1728;\n}\n:where(.jev-devtools) .flow-step[data-status=\"untaken\"],\n:where(.jev-devtools) .flow-step[data-status=\"blocked\"] {\n color: #948797;\n border-color: #403746;\n background: #151017;\n}\n:where(.jev-devtools) .flow-step[data-status=\"error\"] {\n border-color: #f17c78;\n}\n:where(.jev-devtools) .flow-step[data-status=\"cancelled\"] {\n border-style: dashed;\n}\n:where(.jev-devtools) .flow-selection {\n padding: 12px 20px;\n border-top: 1px solid #342a38;\n}\n:where(.jev-devtools) .flow-selection p {\n margin: 6px 0;\n overflow-wrap: anywhere;\n}\n:where(.jev-devtools) .flow-request-detail {\n min-height: 450px;\n border-top: 1px solid #534357;\n}\n:where(.jev-devtools) .flow-request-detail > .request-detail {\n min-height: 450px;\n}\n\n:where(.jev-devtools) .flow-card-heading,\n:where(.jev-devtools) .flow-card-footer,\n:where(.jev-devtools) .flow-join-summary,\n:where(.jev-devtools) .flow-lane {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n width: 100%;\n}\n:where(.jev-devtools) .flow-card-heading {\n justify-content: flex-start;\n}\n:where(.jev-devtools) .flow-task .flow-kind-icon {\n border: 1px solid currentColor;\n border-radius: 6px;\n padding: 4px;\n}\n:where(.jev-devtools) .flow-task-preview {\n display: grid;\n gap: 8px;\n min-width: 0;\n}\n.jev-devtools .flow-task-preview .diagram-content {\n max-height: 280px;\n padding: 8px 10px;\n border: 1px solid #35283b;\n border-radius: 4px;\n background: #100c13;\n}\n:where(.jev-devtools) .flow-task-preview small {\n color: #a89bac;\n font-size: 11px;\n}\n:where(.jev-devtools) .flow-task-details {\n display: grid;\n gap: 12px;\n}\n:where(.jev-devtools) .flow-task-details details {\n min-width: 0;\n}\n:where(.jev-devtools) .flow-task-details summary {\n cursor: pointer;\n margin-bottom: 8px;\n}\n:where(.jev-devtools) .flow-task-details .diagram-content {\n max-height: 320px;\n overflow: auto;\n}\n:where(.jev-devtools) .flow-kind-icon {\n width: 26px;\n height: 26px;\n color: #e551ba;\n flex-shrink: 0;\n}\n:where(.jev-devtools) .flow-kind-icon svg {\n width: 100%;\n height: 100%;\n}\n:where(.jev-devtools) .flow-card-heading .eyebrow {\n font-size: 10px;\n}\n:where(.jev-devtools) .flow-status {\n margin-left: auto;\n font-size: 10px;\n border-radius: 20px;\n padding: 4px 8px;\n background: #342031;\n color: #f0b7e0;\n}\n:where(.jev-devtools) .flow-step[data-status=\"untaken\"] .flow-status {\n background: #241e28;\n color: #948797;\n}\n:where(.jev-devtools) .flow-step[data-status=\"untaken\"] .flow-kind-icon {\n color: #948797;\n}\n:where(.jev-devtools) .flow-card-body > strong {\n white-space: normal;\n font-size: 18px;\n line-height: 1.25;\n overflow-wrap: anywhere;\n}\n:where(.jev-devtools) .flow-step-description {\n line-height: 1.5;\n color: #b9aebf;\n white-space: pre-wrap;\n}\n:where(.jev-devtools) .flow-card-footer {\n margin-top: auto;\n padding-top: 10px;\n border-top: 1px solid #342a38;\n font-size: 10px;\n color: #a092a7;\n}\n:where(.jev-devtools) .flow-card-footer code {\n max-width: 45%;\n white-space: normal;\n overflow-wrap: anywhere;\n}\n:where(.jev-devtools) .flow-card-footer small {\n text-align: right;\n}\n:where(.jev-devtools) .flow-join-summary {\n margin-top: 4px;\n font-size: 11px;\n color: #c9b9cd;\n}\n:where(.jev-devtools) .flow-join-summary > span {\n color: #ef9ed9;\n font-variant-numeric: tabular-nums;\n}\n:where(.jev-devtools) .flow-lanes {\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n}\n:where(.jev-devtools) .flow-lane {\n border-radius: 5px;\n background: #211923;\n padding: 6px 8px;\n font-size: 11px;\n min-height: 28px;\n}\n:where(.jev-devtools) .flow-lane > span {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n:where(.jev-devtools) .flow-lane > span > span {\n color: #ef9ed9;\n margin-right: 4px;\n}\n:where(.jev-devtools) .flow-lane small {\n color: #b9aebf;\n}\n:where(.jev-devtools) .flow-lane-details {\n padding-left: 18px;\n font-size: 12px;\n}\n:where(.jev-devtools) .flow-request-heading > span:first-child {\n min-width: 0;\n max-width: 80%;\n}\n:where(.jev-devtools) .flow-request-description {\n display: block;\n white-space: pre-wrap;\n font-size: 12px;\n line-height: 1.5;\n color: #b9aebf;\n margin-top: 5px;\n overflow-wrap: anywhere;\n}\n\n/* Structured context stays within the card; its gestures never move the camera. */\n.jev-devtools .lab-content-card {\n display: flex;\n flex-direction: column;\n padding: 14px;\n}\n.jev-devtools .lab-content-card h3 {\n font-size: 14px;\n margin-bottom: 8px;\n flex-shrink: 0;\n}\n.jev-devtools .lab-content-card .lab-eyebrow {\n font-size: 9px;\n margin-bottom: 5px;\n flex-shrink: 0;\n}\n.jev-devtools .diagram-content {\n min-height: 0;\n flex: 1;\n overflow: auto;\n overscroll-behavior: contain;\n touch-action: pan-y;\n scrollbar-width: thin;\n scrollbar-color: #514256 transparent;\n padding-right: 4px;\n font-size: 12px;\n line-height: 1.5;\n color: #d5cdd9;\n cursor: auto;\n user-select: text;\n}\n.jev-devtools .diagram-content:focus-visible {\n outline: 1px solid #e551ba;\n outline-offset: -1px;\n border-radius: 3px;\n}\n.jev-devtools .diagram-property {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n gap: 8px;\n padding: 5px 0;\n border-bottom: 1px solid #261e2a;\n}\n.jev-devtools .diagram-property-text {\n display: block;\n}\n.jev-devtools .diagram-property-key {\n font:\n 10px/1.5 ui-monospace,\n monospace;\n color: #c8a8c8;\n overflow-wrap: anywhere;\n min-width: 0;\n}\n.jev-devtools .diagram-property-text > .diagram-property-key {\n display: block;\n margin-bottom: 2px;\n}\n.jev-devtools .diagram-text-value {\n display: block;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n.jev-devtools .diagram-text-preview {\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.jev-devtools .diagram-value-number {\n color: #a6d6ca;\n font:\n 11px/1.5 ui-monospace,\n monospace;\n font-variant-numeric: tabular-nums;\n overflow-wrap: anywhere;\n}\n.jev-devtools .diagram-value-boolean {\n color: #c4b1ed;\n font:\n 11px/1.5 ui-monospace,\n monospace;\n}\n.jev-devtools .diagram-value-empty {\n color: #9c8ca4;\n font:\n 10px/1.5 ui-monospace,\n monospace;\n}\n.jev-devtools .diagram-property-disclosure {\n width: 100%;\n display: flex;\n align-items: baseline;\n gap: 5px;\n padding: 6px 0;\n border: 0;\n border-bottom: 1px solid #261e2a;\n border-radius: 0;\n background: transparent;\n text-align: left;\n color: inherit;\n}\n.jev-devtools .diagram-property-disclosure:hover {\n background: #211723;\n}\n.jev-devtools .diagram-property-caret {\n color: #ab8aab;\n flex-shrink: 0;\n}\n.jev-devtools .diagram-property-type {\n color: #9c8ca4;\n font:\n 10px/1.5 ui-monospace,\n monospace;\n margin-left: auto;\n flex-shrink: 0;\n}\n.jev-devtools .diagram-property-children {\n margin-left: 4px;\n padding-left: 9px;\n border-left: 1px solid #49324b;\n}\n.jev-devtools .diagram-content-toggle {\n display: block;\n padding: 3px 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #e9a4d7;\n font-size: 10px;\n text-align: left;\n}\n.jev-devtools .diagram-content-toggle:hover {\n color: #ffd9f3;\n text-decoration: underline;\n}\n\n/* Noul is a probability of true; its two outputs carry p and 1-p.\n Keep the fill opaque, with readable text even at zero probability. */\n.jev-devtools .lab-noul-output {\n border-color: rgb(\n 245 243 246 / calc(0.35 + 0.65 * var(--lab-noul-probability, 1))\n );\n}\n.jev-devtools .lab-noul-output > h3,\n.jev-devtools .lab-noul-output > p {\n opacity: calc(0.65 + 0.35 * var(--lab-noul-probability, 1));\n}\n\n:where(.jev-devtools) .flow-condition-rule {\n display: block;\n padding: 10px 12px;\n border: 1px solid #49324b;\n border-radius: 6px;\n background: #211723;\n width: 100%;\n}\n:where(.jev-devtools) .flow-condition-label {\n display: block;\n font-size: 10px;\n color: #ba9dbe;\n margin-bottom: 5px;\n}\n:where(.jev-devtools) .flow-condition-rule code {\n display: block;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font:\n 12px/1.6 ui-monospace,\n monospace;\n color: #f2d7eb;\n}\n\n:where(.jev-devtools) .flow-condition-incoming {\n display: block;\n padding-bottom: 10px;\n margin-bottom: 10px;\n border-bottom: 1px solid #49324b;\n}\n:where(.jev-devtools) .flow-condition-input {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n gap: 12px;\n font-size: 12px;\n padding: 3px 0;\n}\n:where(.jev-devtools) .flow-condition-input > span {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n:where(.jev-devtools) .flow-condition-input > b {\n font-size: 17px;\n font-weight: 600;\n color: #f2d7eb;\n overflow-wrap: anywhere;\n white-space: normal;\n max-width: 65%;\n}\n:where(.jev-devtools) .flow-input-details {\n font-size: 12px;\n}\n:where(.jev-devtools) .flow-input-details > div {\n display: flex;\n gap: 16px;\n margin: 6px 0;\n}\n:where(.jev-devtools) .flow-input-details code {\n color: #a092a7;\n margin-left: 8px;\n}\n:where(.jev-devtools) .flow-input-details dd {\n margin: 0;\n overflow-wrap: anywhere;\n}\n\n:where(.jev-devtools) .flow-overview-stack {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n min-width: 0;\n overflow: hidden;\n}\n:where(.jev-devtools) .flow-map-progress {\n display: grid;\n gap: 10px;\n font-size: 14px;\n line-height: 1.5;\n}\n:where(.jev-devtools) .flow-map-progress small {\n color: #b5a6bc;\n}\n\n.jev-devtools .flow-card-body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n flex: 1;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n}\n.jev-devtools .flow-card-body:hover {\n background: transparent;\n}\n:where(.jev-devtools) .flow-collection-controls {\n display: flex;\n align-items: end;\n gap: 10px;\n border-top: 1px solid #49324b;\n margin-top: 4px;\n padding-top: 12px;\n}\n:where(.jev-devtools) .flow-collection-controls label {\n display: grid;\n gap: 6px;\n flex: 1;\n min-width: 0;\n color: #b9aebf;\n font-size: 11px;\n}\n.jev-devtools .flow-collection-controls select {\n width: 100%;\n min-width: 0;\n}\n.jev-devtools .flow-collection-controls button {\n flex: none;\n color: #efb1df;\n}\n:where(.jev-devtools) .flow-collection-expansion {\n position: absolute;\n width: max-content;\n}\n:where(.jev-devtools) .flow-item-frame {\n border: 1px solid #64415d;\n border-radius: 12px;\n background: #100c13;\n overflow: hidden;\n}\n:where(.jev-devtools) .flow-collection-heading {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 24px;\n padding: 16px 20px;\n border-bottom: 1px solid #49324b;\n background: #1c1220;\n}\n:where(.jev-devtools) .flow-collection-heading h3 {\n margin: 5px 0;\n font-size: 16px;\n}\n:where(.jev-devtools) .flow-collection-heading small {\n color: #b9aebf;\n}\n:where(.jev-devtools) .flow-collection-link text {\n fill: #ce9abd;\n font-size: 12px;\n}\n:where(.jev-devtools) .flow-item-placeholder {\n width: 600px;\n padding: 24px;\n line-height: 1.6;\n}\n:where(.jev-devtools) .flow-inline-overview,\n:where(.jev-devtools) .flow-inline-overview > .whole-flow,\n:where(.jev-devtools) .flow-inline-overview > .whole-flow > .flow-workspace {\n display: block;\n flex: none;\n}\n:where(.jev-devtools) .flow-inline-surface {\n position: relative;\n}\n\n:where(.jev-devtools) .flow-item-content {\n min-width: 0;\n animation: jev-flow-item-enter 240ms cubic-bezier(0.22, 1, 0.36, 1) both;\n}\n:where(.jev-devtools) .flow-item-forward {\n --flow-item-offset: 28px;\n}\n:where(.jev-devtools) .flow-item-backward {\n --flow-item-offset: -28px;\n}\n@keyframes jev-flow-item-enter {\n from {\n opacity: 0;\n transform: translateX(var(--flow-item-offset));\n }\n to {\n opacity: 1;\n transform: translateX(0);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n :where(.jev-devtools) .flow-item-content {\n animation: none;\n }\n}\n.jev-devtools .flow-item-arrow {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n display: grid;\n place-items: center;\n width: 56px;\n height: 56px;\n padding: 12px;\n margin: 0 auto;\n border: 1px solid #64415d;\n border-radius: 6px;\n background: #211623;\n color: #efa7db;\n}\n.jev-devtools .flow-item-arrow:hover:not(:disabled) {\n background: #382035;\n border-color: #e551ba;\n}\n:where(.jev-devtools) .flow-item-arrow svg {\n width: 28px;\n height: 28px;\n}\n\n:where(.jev-devtools) .flow-item-previous {\n left: -76px;\n}\n:where(.jev-devtools) .flow-item-next {\n right: -76px;\n}\n.jev-devtools .flow-run-summary {\n text-align: right;\n}\n.jev-devtools .flow-fixture-button {\n display: block;\n margin: 6px 0 0 auto;\n /* Keep the header still when the shorter confirmation replaces the label. */\n min-width: 96px;\n font-size: 11px;\n transition: background-color 160ms ease, border-color 160ms ease;\n}\n.jev-devtools .flow-fixture-button[data-copied] {\n border-color: #e551ba;\n background: #382035;\n animation: jev-fixture-copied 200ms ease-out;\n}\n@keyframes jev-fixture-copied {\n from {\n transform: scale(0.96);\n }\n to {\n transform: scale(1);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .jev-devtools .flow-fixture-button {\n transition: none;\n }\n .jev-devtools .flow-fixture-button[data-copied] {\n animation: none;\n }\n}\n.jev-devtools .flow-fixture {\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n flex-shrink: 0;\n gap: 4px;\n padding: 0 24px;\n text-align: right;\n}\n.jev-devtools .flow-fixture p {\n margin: 0;\n max-width: 360px;\n font-size: 11px;\n}\n.jev-devtools .flow-fixture details {\n max-width: 360px;\n font-size: 11px;\n}\n.jev-devtools .flow-fixture details ul {\n max-height: 120px;\n margin: 4px 0 0;\n padding: 0;\n overflow: auto;\n list-style: none;\n font-family: \"JetBrains Mono\", monospace;\n overflow-wrap: anywhere;\n}\n.jev-devtools .flow-fixture details ul:focus-visible {\n outline: 2px solid #e551ba;\n outline-offset: 2px;\n}\n.jev-devtools .flow-fixture textarea {\n width: 360px;\n max-width: 100%;\n height: 120px;\n padding: 8px;\n font:\n 11px \"JetBrains Mono\",\n monospace;\n text-align: left;\n}\n";
|