/*
 * Flow canvas styling.
 * All colours come from the OQLIS theme tokens defined in
 * assets/css/themes/OQLIS-dark.css (:root / [data-theme="dark"]),
 * so the editor follows the user's light/dark preference automatically.
 */

/* Fill the viewport from the bottom of the fixed breadcrumb (45px) down to
   the bottom of the screen. main-content has 15px top padding (which we keep
   so the wrap clears the breadcrumb) and we zero the bottom padding so the
   wrap reaches the screen edge. */
.flow-editor-content {
    padding-bottom: 0 !important;
    margin-bottom: 0 !important;
}

.flow-editor-wrap {
    display: flex;
    flex-direction: row;
    height: calc(100vh - 60px);
    min-height: 0;
    border: 1px solid var(--oqlis-border);
    border-bottom: 0;
    border-left: 0;
    border-right: 0;
    background: var(--oqlis-surface);
    color: var(--oqlis-text);
}

/* ---------- Palette ---------- */
.flow-palette {
    width: 240px;
    background: var(--oqlis-surface-alt);
    border-right: 1px solid var(--oqlis-border);
    padding: 12px;
    overflow-y: auto;
}

.flow-palette .palette-title {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--oqlis-text-muted);
    letter-spacing: 0.5px;
    margin-bottom: 10px;
}

/* Group headers — divide the palette into Data / Compute / Control
   flow / Outbound / Composition / Observability. Slightly smaller,
   muted, with a hairline divider above to separate visually from the
   previous group's items. */
.flow-palette .palette-group {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--oqlis-text-muted);
    letter-spacing: 0.6px;
    margin-top: 18px;
    margin-bottom: 8px;
    padding-top: 10px;
    border-top: 1px solid var(--oqlis-border);
}
/* First group sits flush under the palette title — no top divider. */
.flow-palette .palette-group:first-of-type {
    margin-top: 6px;
    padding-top: 0;
    border-top: none;
}

.palette-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px;
    margin-bottom: 8px;
    background: var(--oqlis-surface);
    border: 1px solid var(--oqlis-border);
    border-radius: 6px;
    color: var(--oqlis-text);
    cursor: grab;
    user-select: none;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.palette-item:hover {
    border-color: var(--oqlis-btn-info-border);
    box-shadow: 0 1px 4px var(--oqlis-drop-shadow);
}

.palette-item .icon {
    font-size: 20px;
    color: var(--oqlis-btn-info-border);
    flex-shrink: 0;
}

.palette-item strong {
    display: block;
    font-size: 13px;
    color: var(--oqlis-text);
}

.palette-item small {
    color: var(--oqlis-text-muted);
    font-size: 11px;
    line-height: 1.3;
}

.palette-footer {
    margin-top: 20px;
    padding-top: 12px;
    border-top: 1px dashed var(--oqlis-border);
    color: var(--oqlis-text-muted);
}

/* ---------- Canvas area ---------- */
.flow-canvas-area {
    flex: 1;
    display: flex;
    flex-direction: column;
    position: relative;
    background:
        radial-gradient(circle, var(--oqlis-border) 1px, transparent 1px) 0 0 / 20px 20px,
        var(--oqlis-surface);
}

.flow-toolbar {
    padding: 8px 12px;
    border-bottom: 1px solid var(--oqlis-border);
    background: var(--oqlis-surface-alt);
    color: var(--oqlis-text);
    display: flex;
    align-items: center;
    gap: 6px;
    z-index: 2;
}

.flow-toolbar-sep {
    width: 1px;
    height: 22px;
    background: var(--oqlis-border);
    margin: 0 6px;
}

.flow-save-status {
    font-size: 12px;
    color: var(--oqlis-text-muted);
    margin-left: 8px;
}

/* Save status pinned to the far right of the flex toolbar — the
   auto left-margin consumes all the free space before it, so it
   sits against the right edge while the buttons stay left. */
.flow-save-status-right {
    margin-left: auto;
}

/* Wire gradient stops — drives the source → target colour ramp on every
 * connection so flow direction is visible at a glance. Keep these as
 * hex values (not CSS vars) because some browsers don't resolve
 * variables inside SVG <stop> elements consistently. Override here if
 * you want to retheme; the JS doesn't care.
 *
 * Default scheme: a cool blue at the OUTPUT end ramping to a warm amber
 * at the INPUT end — complementary on the colour wheel so direction
 * reads at arm's length even on dense fan-in flows. The cool→warm
 * cue mirrors the "data leaves cool, arrives warm" mental model and
 * is colour-blind friendly (blue↔amber is the strongest accessible
 * pair, distinguishable under most colour-vision deficiencies). */
.flow-wire-stop-source { stop-color: #3b82f6; stop-opacity: 1; }   /* vivid blue       */
.flow-wire-stop-target { stop-color: #14b8a6; stop-opacity: 1; }   /* turquoise-green  */

/* Context-wire stops — used by connections feeding input_2. Blue → purple
   so a context wire reads as a different "channel" from the trigger flow
   even when the dashed stroke is hard to see at low zoom. The blue source
   matches the trigger gradient on purpose: every wire LEAVES a node in the
   same blue, and only the destination tone tells you whether you're
   landing on a trigger (green) or context (purple) port. */
.flow-wire-stop-source-ctx { stop-color: #3b82f6; stop-opacity: 1; }   /* vivid blue       */
.flow-wire-stop-target-ctx { stop-color: #a855f7; stop-opacity: 1; }   /* vivid purple     */

/* Schedule picker modal — one labelled checkbox row per schedule. The
 * meta hint sits to the right of the name to help the user pick the right
 * cadence without bouncing back to the schedule editor. */
.flow-schedule-list {
    max-height: 360px;
    overflow-y: auto;
    border: 1px solid var(--oqlis-border);
    border-radius: 4px;
    padding: 4px;
    background: var(--oqlis-surface);
}
.flow-schedule-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    margin: 0;
    border-radius: 3px;
    cursor: pointer;
    font-weight: normal;
}
.flow-schedule-row + .flow-schedule-row { border-top: 1px solid var(--oqlis-border); }
.flow-schedule-row:hover { background: var(--oqlis-surface-alt); }
.flow-schedule-check { margin: 0; }
.flow-schedule-name { flex: 1; color: var(--oqlis-text); }
.flow-schedule-meta {
    font-size: 11px;
    color: var(--oqlis-text-muted);
    font-family: monospace;
}

#drawflow {
    flex: 1;
    position: relative;
    overflow: hidden;
    background: transparent;
}
/* Force the precanvas's scale to pivot from (0, 0). Drawflow ships with no
 * transform-origin override, so the browser default of 50% 50% sneaks in —
 * which means at non-100% zoom the content drifts sideways relative to where
 * (canvas_x, canvas_y, zoom) suggest, breaking palette drop placement and
 * the fit-to-view math. Pinning the origin makes those formulae consistent. */
#drawflow > .drawflow,
#drawflow .parent-drawflow > .drawflow {
    transform-origin: 0 0;
}

/* ---------- Drawflow library overrides ---------- */
.drawflow .drawflow-node {
    background: var(--oqlis-surface-alt);
    border: 1px solid var(--oqlis-border);
    color: var(--oqlis-text);
    border-radius: 8px;
    padding: 0;
    min-width: 220px;
    box-shadow: 0 2px 6px var(--oqlis-drop-shadow);
}

/* Drawflow's default CSS sets .drawflow-node.selected { background: red }.
   Reset it to the normal node surface and use a subtle ring to indicate
   selection — same visual weight as hover, not a full-bleed colour swap. */
/* Disabled nodes: dimmed + diagonal stripe + DISABLED chip in the header.
 * The pseudo-element sits inside the node so it scales with zoom. */
.drawflow .drawflow-node.flow-node-disabled {
    opacity: 0.55;
    background:
        repeating-linear-gradient(
            135deg,
            transparent 0,
            transparent 10px,
            rgba(127, 127, 127, 0.08) 10px,
            rgba(127, 127, 127, 0.08) 20px
        ),
        var(--oqlis-surface-alt);
}
.drawflow .drawflow-node.flow-node-disabled::after {
    content: 'DISABLED';
    position: absolute;
    left: 0;
    right: 0;
    bottom: -22px;
    width: max-content;
    margin: 0 auto;
    padding: 1px 6px;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.6px;
    background: var(--oqlis-text-muted);
    color: var(--oqlis-surface);
    border-radius: 3px;
    line-height: 1.2;
    text-align: center;
    pointer-events: none;
}

/* Step button — pulses while step mode is active so it's obvious the
   flow is under manual node-by-node control. The .flow-step-active
   class is toggled by the canvas JS on start/finish of a stepping run. */
#flowStepBtn.flow-step-active {
    animation: flow-step-pulse 1.3s ease-in-out infinite;
}
@keyframes flow-step-pulse {
    0%, 100% { box-shadow: 0 0 0 0 var(--oqlis-btn-warning-border); }
    50%      { box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.45); }
}

.drawflow .drawflow-node.selected {
    background: var(--oqlis-surface);
    border-color: var(--oqlis-btn-info-border);
    box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.25), 0 2px 8px var(--oqlis-drop-shadow);
}

/* Multi-select outline — a node included in a marquee / shift-click
   group selection. Distinct, heavier ring than the single .selected
   state so a group reads clearly. */
.drawflow .drawflow-node.flow-node-multiselected {
    border-color: var(--oqlis-btn-info-border);
    box-shadow: 0 0 0 2px var(--oqlis-btn-info-border), 0 0 10px rgba(33, 150, 243, 0.35);
}

/* Marquee box-select rubber band. Fixed-positioned overlay drawn on
   the document body so it isn't subject to the canvas transform. */
.flow-marquee {
    position: fixed;
    z-index: 9999;
    pointer-events: none;
    border: 1px solid var(--oqlis-btn-info-border, #3b82f6);
    background: rgba(59, 130, 246, 0.12);
    border-radius: 2px;
}

/* Alignment guide lines — shown while dragging a node when an edge or
   centre lines up with another node's. Dashed + semi-transparent so
   they read as a subtle hint rather than a hard rule. Fixed-position
   (drawn on body, converted from canvas coords), never intercept
   pointer events. The dash is built from a repeating-linear-gradient
   since a 1px div can't use border-style: dashed cleanly. */
.flow-align-guide {
    position: fixed;
    z-index: 9998;
    pointer-events: none;
    display: none;
    opacity: 0.55;
}
.flow-align-guide-v {
    width: 1px;
    background: repeating-linear-gradient(to bottom,
        #ec4899 0, #ec4899 4px, transparent 4px, transparent 9px);
}
.flow-align-guide-h {
    height: 1px;
    background: repeating-linear-gradient(to right,
        #ec4899 0, #ec4899 4px, transparent 4px, transparent 9px);
}

/* Live run state — classes stamped on #node-N by paintCanvasRunState(). */
.drawflow .drawflow-node.flow-run-state-running {
    border-color: var(--oqlis-btn-success-border);
    box-shadow: 0 0 0 2px var(--oqlis-btn-success-border), 0 0 14px var(--oqlis-btn-success-border);
    animation: flow-run-pulse 1.4s ease-in-out infinite;
}

.drawflow .drawflow-node.flow-run-state-waiting {
    border-color: var(--oqlis-btn-warning-border);
    box-shadow: 0 0 0 2px var(--oqlis-btn-warning-border);
}
.drawflow .drawflow-node.flow-run-state-completed {
    border-color: var(--oqlis-btn-success-border);
}
.drawflow .drawflow-node.flow-run-state-failed {
    border-color: var(--oqlis-btn-danger-border);
    box-shadow: 0 0 0 2px var(--oqlis-btn-danger-border);
}
@keyframes flow-run-pulse {
    0%, 100% { box-shadow: 0 0 0 2px var(--oqlis-btn-success-border), 0 0 8px  var(--oqlis-btn-success-border); }
    50%      { box-shadow: 0 0 0 2px var(--oqlis-btn-success-border), 0 0 18px var(--oqlis-btn-success-border); }
}

/* Connection wires
 *
 * --wire-stroke is set per-path by the canvas JS to a per-connection
 * `url(#flow-wire-grad-...)` reference, so each wire renders with its
 * own source → target gradient. The fallback (--oqlis-btn-info-border)
 * keeps the original solid colour for any path that hasn't been styled
 * yet (e.g. a brand-new connection mid-drag, before applyWireGradients
 * has run for it).
 *
 * Run-state rules below (.flow-wire-running etc.) DON'T use the var —
 * they set stroke directly with higher selector specificity, so a live
 * run still shows green/red/yellow flat colours rather than the idle
 * gradient. */
.drawflow .connection .main-path {
    stroke: var(--wire-stroke, var(--oqlis-btn-info-border));
    stroke-width: 3px;
}
.drawflow .connection .main-path:hover {
    stroke: var(--oqlis-link-hover);
}
.drawflow .connection .point {
    stroke: var(--oqlis-btn-info-border);
    fill: var(--oqlis-surface);
}

/* Live run state on edges — paintCanvasRunState() stamps these classes on
   the .connection element. Source-of-truth: connections leaving a running
   node animate as a moving dashed line to show flow direction. */
.drawflow .connection.flow-wire-running .main-path {
    stroke: var(--oqlis-btn-success-border);
    stroke-width: 3px;
    stroke-dasharray: 10 6;
    /* The path is drawn from source → target, so a NEGATIVE dashoffset
       animation moves the dashes in that same direction (towards the
       target). */
    animation: flow-wire-march 0.7s linear infinite;
    filter: drop-shadow(0 0 4px var(--oqlis-btn-success-border));
}
.drawflow .connection.flow-wire-completed .main-path {
    stroke: var(--oqlis-btn-success-border);
    stroke-width: 3px;
}
.drawflow .connection.flow-wire-failed .main-path {
    stroke: var(--oqlis-btn-danger-border);
    stroke-width: 3px;
    stroke-dasharray: 4 4;
}
@keyframes flow-wire-march {
    from { stroke-dashoffset:   0; }
    to   { stroke-dashoffset: -16; }  /* dasharray total = 10 + 6 */
}

/* Input / output ports */
.drawflow .drawflow-node .input,
.drawflow .drawflow-node .output {
    background: var(--oqlis-surface);
    border: 2px solid var(--oqlis-btn-info-border);
}
.drawflow .drawflow-node .input:hover,
.drawflow .drawflow-node .output:hover {
    background: var(--oqlis-btn-info-border);
}

/* Node-id badge — small chip in the top-right corner of every node
   showing the graph id (e.g. "#5"). Used when authoring downstream
   template references that include the upstream's id, like
   {{context.5.previous_answer}} in an Email Action body. Theme-aware
   via the same CSS custom properties as the rest of the canvas. */
.drawflow .drawflow-node .flow-node-id-badge {
    position: absolute;
    bottom: 6px;
    right: 8px;
    font-size: 10px;
    font-weight: 600;
    line-height: 1;
    padding: 3px 6px;
    border-radius: 3px;
    background: var(--oqlis-surface-muted, #e9e9e9);
    color: var(--oqlis-text-muted, #6b6b6b);
    border: 1px solid var(--oqlis-border, #d0d0d0);
    pointer-events: auto;  /* keep the title-tooltip discoverable */
    user-select: text;     /* user can copy the id straight off the chip */
    z-index: 2;
}

/* Port tooltip — shown on hover via [data-tooltip] attribute set by
   ensureInputTooltips() in flow-canvas.js. Uses a ::after pseudo so it
   renders instantly on hover (no native-title hover-delay), positioned
   to the LEFT of the port circle (cursor lands on the port; eye reads
   left into the bubble). pointer-events:none means the tooltip itself
   never intercepts a connection-drag started on the port. The high
   z-index + drop-shadow lifts it above neighbouring nodes when ports
   are densely packed.

   Theme-aware via OQLIS CSS custom properties:
     --oqlis-surface-alt → bg (sits a half-step off the page surface
                               so the bubble reads as elevated in both
                               light and dark themes)
     --oqlis-text        → text colour
     --oqlis-border      → 1px outline so the bubble has definition
                           against any underlying node colour
   Hard-coded fallbacks kick in only if the OQLIS theme stylesheet
   hasn't loaded — picked to be readable on both light + dark pages. */
.drawflow .drawflow-node .input[data-tooltip]:hover::after {
    content: attr(data-tooltip);
    position: absolute;
    right: 100%;
    top: 50%;
    transform: translate(-10px, -50%);
    background: var(--oqlis-surface-alt, #f2f2f2);
    color: var(--oqlis-text, #1f2937);
    border: 1px solid var(--oqlis-border, #d0d0d0);
    padding: 7px 10px;
    border-radius: 4px;
    font-size: 12px;
    line-height: 1.4;
    font-weight: 400;
    width: 240px;
    white-space: normal;
    z-index: 1000;
    pointer-events: none;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
}
.drawflow .drawflow-node .input[data-tooltip]:hover::before {
    content: '';
    position: absolute;
    right: 100%;
    top: 50%;
    transform: translate(-3px, -50%);
    width: 0;
    height: 0;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
    border-left: 6px solid var(--oqlis-border, #d0d0d0);
    z-index: 1001;
    pointer-events: none;
}

/* Context input port (input_2). Visually downplayed vs. the trigger
   port (input_1) — dashed border + muted colour — so the canvas reads
   "this is a secondary, best-effort input" at a glance. The runner
   doesn't gate execution on connections to this port (see
   flow_runner::executeNodeRun); whatever upstreams happen to be
   completed at firing time are merged into $input['context']. */
.drawflow .drawflow-node .input.input_2 {
    background: var(--oqlis-surface);
    border: 2px dashed #94a3b8;  /* slate-400 — muted, neutral grey */
    opacity: 0.85;
}
.drawflow .drawflow-node .input.input_2:hover {
    background: #94a3b8;
    opacity: 1;
}

/* Context wires (connections feeding input_2). Dashed stroke + lower
   opacity so the trigger flow visually dominates. The colour gradient
   still applies — see applyWireGradients() — but the dashed pattern
   makes context links unmistakable in fan-in patterns. */
.drawflow .connection.input_2 .main-path {
    stroke-dasharray: 6 4;
    opacity: 0.7;
}
.drawflow .connection.input_2 .main-path:hover {
    opacity: 1;
}
/* Run-state classes (running / completed / failed) override the dash
   so a live context wire still shows the marching/solid stroke
   alongside its trigger siblings — the dashed pattern is only the
   idle-state cue. */
.drawflow .connection.input_2.flow-wire-running .main-path,
.drawflow .connection.input_2.flow-wire-completed .main-path,
.drawflow .connection.input_2.flow-wire-failed .main-path {
    opacity: 1;
}

/* Delete button (appears on node/connection selection) */
.drawflow-delete {
    background: var(--oqlis-btn-danger);
    color: var(--oqlis-text);
    border: 1px solid var(--oqlis-btn-danger-border);
    box-shadow: 0 2px 6px var(--oqlis-drop-shadow);
}

/* ---------- Node internals ---------- */
.flow-node-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--oqlis-border);
    font-size: 12px;
    font-weight: 600;
    color: var(--oqlis-text);
    text-transform: uppercase;
    letter-spacing: 0.3px;
    background: var(--oqlis-surface);
    border-radius: 8px 8px 0 0;
}

.flow-node-header .icon {
    font-size: 16px;
}

/* Unify step has no matching s7 glyph — inline SVG uses currentColor so it
   inherits the parent's colour (palette uses info-border, node header uses
   parameter-border). */
.flow-icon-unify {
    display: inline-block;
    fill: currentColor;
    vertical-align: middle;
    flex-shrink: 0;
}
.palette-item .flow-icon-unify { width: 20px; height: 20px; margin-right: 4px; }
.flow-node-header .flow-icon-unify { width: 14px; height: 14px; margin-right: 8px; position: relative; top: -1px; }

/* Component node — inline SVG (4 shapes); inherits header/palette colour. */
.flow-icon-component {
    display: inline-block;
    vertical-align: middle;
    flex-shrink: 0;
    color: currentColor;
}
.palette-item .flow-icon-component { width: 20px; height: 20px; margin-right: 4px; }
.flow-node-header .flow-icon-component { width: 14px; height: 14px; margin-right: 8px; position: relative; top: -1px; }

/* Flex row so the icon never overlaps the unify job name, regardless of length. */
.flow-node-unify-target {
    display: flex;
    align-items: center;
    gap: 8px;
}
.flow-node-unify-target .flow-icon-unify { width: 14px; height: 14px; }

.flow-node-body {
    padding: 10px 12px;
    font-size: 12px;
    color: var(--oqlis-text);
}

.flow-node-body .muted {
    color: var(--oqlis-text-muted);
    font-style: italic;
}

/* Per-type accent — drives only the header icon/title hue. */
.flow-node-explore-question .flow-node-header { color: var(--oqlis-btn-info-border); }
.flow-node-llm              .flow-node-header { color: var(--oqlis-btn-primary-border); }
.flow-node-decision         .flow-node-header { color: var(--oqlis-btn-warning-border); }
.flow-node-unify-step       .flow-node-header { color: var(--oqlis-btn-parameter-border); }
.flow-node-action           .flow-node-header { color: var(--oqlis-btn-success-border); }

/* Section label inside a node body — small uppercase tag above each list. */
.flow-node-section-label {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    color: var(--oqlis-text-muted);
    margin-bottom: 4px;
}

/* Explore list on the Explore Question node */
.flow-node-explore-list {
    list-style: none;
    padding: 0;
    margin: 0;
}
.flow-node-explore-list li {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 2px 0;
    font-size: 12px;
    color: var(--oqlis-text);
}
.flow-node-explore-list li .icon {
    font-size: 12px;
    color: var(--oqlis-btn-info-border);
    flex-shrink: 0;
}

/* Branch list + colour-coded legend on the Decision node */
.flow-node-branch-list {
    list-style: none;
    padding: 0;
    margin: 0;
}
.flow-node-branch-list li {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 3px 0;
    font-size: 12px;
    color: var(--oqlis-text);
}
.flow-branch-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
    box-shadow: 0 0 0 2px var(--oqlis-surface-alt);
}

/* ---------- Run sidebar ---------- */
.flow-run-sidebar {
    width: 320px;
    background: var(--oqlis-surface-alt);
    border-left: 1px solid var(--oqlis-border);
    color: var(--oqlis-text);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.flow-run-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 12px;
    border-bottom: 1px solid var(--oqlis-border);
}

.flow-run-badge {
    display: inline-block;
    padding: 2px 8px;
    margin-left: 8px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    border-radius: 10px;
    background: var(--oqlis-surface);
    border: 1px solid var(--oqlis-border);
}
.flow-run-badge.status-running            { background: var(--oqlis-btn-info);    border-color: var(--oqlis-btn-info-border); }
.flow-run-badge.status-pending            { background: var(--oqlis-btn-default); }
.flow-run-badge.status-waiting_unify,
.flow-run-badge.status-waiting_approval,
.flow-run-badge.status-waiting_llm        { background: var(--oqlis-btn-warning); border-color: var(--oqlis-btn-warning-border); }
.flow-run-badge.status-completed          { background: var(--oqlis-btn-success); border-color: var(--oqlis-btn-success-border); }
.flow-run-badge.status-failed,
.flow-run-badge.status-cancelled          { background: var(--oqlis-btn-danger);  border-color: var(--oqlis-btn-danger-border); }
.flow-run-badge.status-paused             { background: var(--oqlis-btn-warning); border-color: var(--oqlis-btn-warning-border); }
.flow-run-badge.status-stepping           { background: var(--oqlis-btn-info);    border-color: var(--oqlis-btn-info-border); }

.flow-run-meta {
    padding: 8px 12px;
    font-size: 11px;
    color: var(--oqlis-text-muted);
    border-bottom: 1px solid var(--oqlis-border);
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.flow-run-nodes {
    flex: 1;
    padding: 8px;
    overflow-y: auto;
}

.flow-run-node {
    background: var(--oqlis-surface);
    border: 1px solid var(--oqlis-border);
    border-radius: 6px;
    padding: 8px 10px;
    margin-bottom: 6px;
    font-size: 12px;
}

.flow-run-node-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-weight: 600;
}

.flow-run-node .pill {
    font-size: 10px;
    text-transform: uppercase;
    padding: 1px 6px;
    border-radius: 10px;
    background: var(--oqlis-surface-muted);
}
.flow-run-node.status-running   .pill { background: var(--oqlis-btn-info);    color: var(--oqlis-text); }
.flow-run-node.status-waiting   .pill { background: var(--oqlis-btn-warning); color: var(--oqlis-text); }
.flow-run-node.status-completed .pill { background: var(--oqlis-btn-success); color: var(--oqlis-text); }
.flow-run-node.status-failed    .pill { background: var(--oqlis-btn-danger);  color: var(--oqlis-text); }

.flow-run-node-body {
    margin-top: 6px;
    color: var(--oqlis-text-muted);
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 120px;
    overflow: auto;
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 11px;
}

.flow-run-error {
    padding: 10px 12px;
    font-size: 12px;
    color: var(--oqlis-text);
    background: var(--oqlis-btn-danger);
    border-top: 1px solid var(--oqlis-btn-danger-border);
}

.flow-run-footer {
    padding: 8px 12px;
    border-top: 1px solid var(--oqlis-border);
    display: flex;
    justify-content: flex-end;
}

/* ---------- Inspect button + click-to-open panel on completed nodes ---------- */
.flow-node-inspect-btn {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 22px;
    height: 22px;
    padding: 0;
    background: var(--oqlis-surface);
    border: 1px solid var(--oqlis-border);
    color: var(--oqlis-text-muted);
    border-radius: 4px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 4;
    transition: color 0.15s, border-color 0.15s, box-shadow 0.15s;
}
.flow-node-inspect-btn:hover {
    color: var(--oqlis-btn-info-border);
    border-color: var(--oqlis-btn-info-border);
    box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.15);
}
.flow-node-inspect-btn .icon { font-size: 13px; line-height: 1; }

/* Power toggle: always pinned to the top-right of every node so the user
 * can disable / re-enable the node in one click without opening the modal.
 * When the inspect button (post-run) is also present, it shifts left to
 * sit beside the power button. */
.flow-node-power-btn {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 22px;
    height: 22px;
    padding: 0;
    background: var(--oqlis-surface);
    border: 1px solid var(--oqlis-border);
    color: var(--oqlis-text-muted);
    border-radius: 4px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 4;
    transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.flow-node-power-btn:hover {
    color: var(--oqlis-text);
    border-color: var(--oqlis-text-muted);
}
.flow-node-power-btn .icon { font-size: 13px; line-height: 1; }
.drawflow .drawflow-node.flow-node-disabled .flow-node-power-btn {
    background: var(--oqlis-btn-danger);
    border-color: var(--oqlis-btn-danger-border);
    color: #fff;
    opacity: 1; /* full strength even though the node body is dimmed */
}
/* When both buttons are present, slide the inspect button left of the power
 * button. The power button stays pinned to the corner — it's the toggle the
 * user always wants in the same spot. */
.drawflow-node:has(.flow-node-power-btn) .flow-node-inspect-btn { right: 34px; }

.flow-node-tooltip {
    position: fixed;
    z-index: 9999;
    width: 380px;
    max-height: 60vh;
    overflow: auto;
    padding: 10px 12px;
    background: var(--oqlis-surface-alt);
    color: var(--oqlis-text);
    border: 1px solid var(--oqlis-border);
    border-radius: 6px;
    box-shadow: 0 6px 20px var(--oqlis-drop-shadow);
    font-size: 12px;
    /* Interactive — the user clicks to open and scrolls inside it. */
    pointer-events: auto;
}
.flow-node-tooltip .flow-tip-title {
    font-weight: 600;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    margin-bottom: 8px;
    color: var(--oqlis-text);
}
.flow-node-tooltip .flow-tip-title .status-completed { color: var(--oqlis-btn-success-border); }
.flow-node-tooltip .flow-tip-title .status-failed    { color: var(--oqlis-btn-danger-border); }
.flow-node-tooltip .flow-tip-title .status-running   { color: var(--oqlis-btn-info-border); }
.flow-node-tooltip .flow-tip-section-label {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    color: var(--oqlis-text-muted);
    margin: 6px 0 3px;
}
.flow-node-tooltip .flow-tip-payload {
    margin: 0;
    padding: 8px 10px;
    background: var(--oqlis-surface);
    border: 1px solid var(--oqlis-border);
    border-radius: 4px;
    font-size: 12px;
    line-height: 1.5;
    word-break: break-word;
    max-height: 260px;
    overflow: auto;
}
.flow-node-tooltip .flow-tip-text {
    white-space: pre-wrap;
    color: var(--oqlis-text);
}
.flow-node-tooltip .flow-tip-html {
    color: var(--oqlis-text);
    line-height: 1.5;
}
.flow-node-tooltip .flow-tip-html p { margin: 0 0 8px; }
.flow-node-tooltip .flow-tip-html p:last-child { margin-bottom: 0; }
.flow-node-tooltip .flow-tip-html ul,
.flow-node-tooltip .flow-tip-html ol { margin: 0 0 8px; padding-left: 20px; }
.flow-node-tooltip .flow-tip-html li + li { margin-top: 2px; }
.flow-node-tooltip .flow-tip-html a { color: var(--oqlis-btn-info-border); }
.flow-node-tooltip .flow-tip-html h1,
.flow-node-tooltip .flow-tip-html h2,
.flow-node-tooltip .flow-tip-html h3,
.flow-node-tooltip .flow-tip-html h4 {
    margin: 8px 0 4px;
    font-size: 13px;
    font-weight: 600;
}
.flow-node-tooltip .flow-tip-html img { max-width: 100%; height: auto; }
.flow-node-tooltip .flow-tip-html table {
    border-collapse: collapse;
    width: 100%;
    margin: 4px 0 8px;
    font-size: 11px;
}
.flow-node-tooltip .flow-tip-html th,
.flow-node-tooltip .flow-tip-html td {
    border: 1px solid var(--oqlis-border);
    padding: 4px 6px;
    text-align: left;
}
.flow-node-tooltip .flow-tip-text + .flow-tip-muted { margin-top: 6px; }
.flow-node-tooltip .flow-tip-muted {
    color: var(--oqlis-text-muted);
    font-size: 11px;
    font-style: italic;
}
.flow-node-tooltip .flow-tip-scalar {
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 11px;
    color: var(--oqlis-text);
}
.flow-node-tooltip .flow-tip-explore-name {
    font-weight: 600;
    font-size: 11px;
    color: var(--oqlis-text);
    margin: 6px 0 4px;
}
.flow-node-tooltip .flow-tip-explore-name:first-child { margin-top: 0; }
.flow-node-tooltip .flow-tip-rows-meta {
    font-size: 11px;
    color: var(--oqlis-text-muted);
    margin-bottom: 4px;
}
.flow-node-tooltip .flow-tip-table-wrap {
    overflow: auto;
    border: 1px solid var(--oqlis-border);
    border-radius: 4px;
}
.flow-node-tooltip .flow-tip-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 11px;
}
.flow-node-tooltip .flow-tip-table th,
.flow-node-tooltip .flow-tip-table td {
    padding: 4px 8px;
    border-bottom: 1px solid var(--oqlis-border);
    text-align: left;
    vertical-align: top;
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.flow-node-tooltip .flow-tip-table th {
    background: var(--oqlis-surface-alt);
    font-weight: 600;
    color: var(--oqlis-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.3px;
    font-size: 10px;
    position: sticky;
    top: 0;
}
.flow-node-tooltip .flow-tip-table tr:last-child td { border-bottom: 0; }
.flow-node-tooltip .flow-tip-kv {
    margin: 0;
    display: grid;
    grid-template-columns: minmax(80px, max-content) 1fr;
    gap: 2px 10px;
}
.flow-node-tooltip .flow-tip-kv dt {
    font-weight: 600;
    color: var(--oqlis-text-muted);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    padding-top: 2px;
}
.flow-node-tooltip .flow-tip-kv dd {
    margin: 0;
    min-width: 0;
}
.flow-node-tooltip .flow-tip-list {
    margin: 0;
    padding-left: 18px;
}
.flow-node-tooltip .flow-tip-list li + li { margin-top: 4px; }
.flow-node-tooltip .flow-tip-error {
    margin-top: 8px;
    padding: 6px 8px;
    background: var(--oqlis-btn-danger);
    border: 1px solid var(--oqlis-btn-danger-border);
    border-radius: 4px;
    color: var(--oqlis-text);
    white-space: pre-wrap;
}

/* Component node — field mapping table */
.flow-cp-mappings { border: 1px solid var(--oqlis-border); border-radius: 4px; max-height: 280px; overflow: auto; }
.flow-cp-mapping-row { display: grid; grid-template-columns: minmax(120px, 1fr) 2fr 70px; gap: 8px; align-items: center; padding: 6px 8px; border-bottom: 1px solid var(--oqlis-border); font-size: 12px; }
.flow-cp-mapping-row:last-child { border-bottom: 0; }
.flow-cp-mapping-row code { background: transparent; padding: 0; color: var(--oqlis-text-muted); font-size: 11px; }
.flow-cp-mapping-row .form-control { padding: 4px 8px; height: 28px; font-size: 12px; }
.flow-cp-mapping-key { display: flex; align-items: center; gap: 6px; justify-content: center; color: var(--oqlis-text-muted); font-size: 11px; }
.flow-cp-mapping-key.hidden { visibility: hidden; }
.flow-cp-mapping-uneditable { color: var(--oqlis-text-muted); font-style: italic; }
