/*
 * automation.css — Automations Builder page + canvas.
 *
 * Everything is built on tokens.css variables so light / dark / RTL come for
 * free. Page chrome (top bar, panels, modals) flips with the rest of the site;
 * the canvas itself stays LTR because workflows read left → right.
 *
 * Naming: `.au-` prefix for everything automation-specific.
 */

:root {
  --au-grid: rgba(15, 17, 23, 0.06);
  --au-grid-strong: rgba(15, 17, 23, 0.10);
  --au-canvas-bg: #fbfbfc;
  --au-edge: #b6bcc6;
  --au-node-bg: #ffffff;
  --au-port: #c2c8d2;
  --au-topbar-h: 132px;
}
body.dark-mode {
  --au-grid: rgba(255, 255, 255, 0.05);
  --au-grid-strong: rgba(255, 255, 255, 0.09);
  --au-canvas-bg: #0d0f14;
  --au-edge: #3a4150;
  --au-node-bg: #161922;
  --au-port: #444c5c;
}

/* ── Operations / Blueprint console accent (AMBER) ──────────────────────────────
   The automation builder's single live accent. The canvas already styled
   nodes/edges with var(--au-accent, …) but the page never defined it — so the
   warm amber canvas was paired with blue chrome. Defining it here on the page
   body unifies both. Per-node category colours are still set inline by canvas.js
   (var(--au-accent) is overridden on each card); this page value only governs the
   builder's own chrome + control-flow/loop accents that read it without an inline
   override. The edge-hover follows the accent so a connecting wire highlights amber. */
body.au-body {
  --au-accent: #f59e0b;
  --au-accent-strong: #d97706;
  --au-accent-soft: color-mix(in srgb, #f59e0b 12%, transparent);
  --au-accent-ring: color-mix(in srgb, #f59e0b 30%, transparent);
  --au-edge-hover: var(--au-accent);
}
body.dark-mode.au-body {
  /* Lift the amber so it stays legible on the dark canvas/surfaces. */
  --au-accent: #fbbf24;
  --au-accent-strong: #f59e0b;
  --au-accent-soft: color-mix(in srgb, #fbbf24 16%, transparent);
  --au-accent-ring: color-mix(in srgb, #fbbf24 34%, transparent);
}

/* The page is a fixed-height app shell: header, top bar, then the flexible
   stage. overflow hidden keeps the canvas the only scroll surface. */
html, body { height: 100%; }
body.au-body {
  margin: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
}
.au-chrome { position: sticky; top: 0; z-index: 60; flex: 0 0 auto; }
.au-chrome .dp-header { position: static; }
/* Compact, consistent header credit meter (matches the other builder pages —
   those rules live inside coding.html's <style>, so this page needs its own). */
.au-chrome .dp-credit-meter {
  height: 32px; min-width: 104px; max-width: 148px; padding: 0 10px;
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface); color: var(--fg);
  font-size: 11px; font-weight: 800; line-height: 1; white-space: nowrap;
  flex: 0 0 auto; box-shadow: var(--shadow-sm);
}
.au-chrome .dp-credit-meter strong { font-size: 12px; line-height: 1; }
.au-chrome .dp-credit-meter small {
  min-width: 0; overflow: hidden; text-overflow: ellipsis;
  color: var(--fg-muted); font-size: 9.5px; font-weight: 700; line-height: 1;
}
@media (max-width: 720px) {
  .au-chrome .dp-credit-meter { min-width: 58px; max-width: 84px; padding: 0 7px; }
  .au-chrome .dp-credit-meter small { max-width: 40px; }
}

/* ── Top bar ──────────────────────────────────────────────────────────────── */
.au-topbar {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--s-4);
  align-items: end;
  padding: var(--s-4) clamp(12px, 3vw, 28px);
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  z-index: 40;
}
.au-topbar-main { display: flex; flex-direction: column; gap: var(--s-3); min-width: 0; }
.au-title-row { display: flex; align-items: center; gap: var(--s-3); min-width: 0; }
.au-title-icon {
  width: 34px; height: 34px; flex: 0 0 auto;
  display: grid; place-items: center;
  border-radius: 9px;
  background: linear-gradient(135deg, var(--au-accent-strong), var(--au-accent));
  color: #fff;
  box-shadow: 0 4px 14px var(--au-accent-ring);
}
.au-title-icon svg { width: 19px; height: 19px; }
.au-title-input {
  flex: 1 1 auto; min-width: 0;
  border: 1px solid transparent;
  background: transparent;
  color: var(--fg);
  font: 700 clamp(16px, 2.4vw, 22px)/1.1 var(--font-body);
  letter-spacing: -0.02em;
  padding: 6px 10px;
  border-radius: var(--r-input);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.au-title-input:hover { background: var(--surface-2); }
.au-title-input:focus { outline: none; background: var(--surface-2); border-color: var(--border-strong); }
.au-title-input::placeholder { color: var(--fg-subtle); font-weight: 600; }

/* Prompt row: platform segmented control + textarea + Generate. */
.au-prompt-row { display: flex; gap: var(--s-3); align-items: stretch; flex-wrap: wrap; }
.au-platforms {
  position: relative; /* anchor for the sliding indicator */
  display: inline-flex;
  gap: 3px;
  padding: 3px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-input);
  flex: 0 0 auto;
  align-self: stretch;
}
/* Sliding pill that animates to the active segment. Sits behind the labels;
   the active segment's own background is dropped so this reads as the fill. */
.au-seg-indicator {
  position: absolute;
  top: 3px; left: 0; bottom: 3px;
  width: 0;
  border-radius: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  opacity: 0;
  pointer-events: none;
  z-index: 0;
  transition: transform .28s cubic-bezier(.4, 0, .2, 1), opacity var(--dur-fast) var(--ease);
}
.au-seg {
  position: relative; /* keep label above the indicator */
  z-index: 1;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0 11px; height: 100%;
  min-height: 38px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--fg-muted);
  font: 600 12.5px/1 var(--font-body);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.au-seg-logo { display: inline-flex; opacity: .75; transition: opacity var(--dur-fast) var(--ease); }
.au-seg:hover { color: var(--fg); }
.au-seg.is-active {
  /* Background/box-shadow now come from the sliding indicator behind it. */
  color: var(--au-accent-strong);
  border-color: transparent;
}
.au-seg.is-active .au-seg-logo { opacity: 1; }
.au-seg:active { transform: translateY(1px); }
/* If the indicator can't position (e.g. no JS), fall back to a solid fill. */
.au-seg-indicator:not([style*="opacity: 1"]) ~ .au-seg.is-active {
  background: var(--surface);
  border-color: var(--border);
  box-shadow: var(--shadow-sm);
}
@media (prefers-reduced-motion: reduce) {
  .au-seg-indicator { transition: opacity .01ms; }
}

/* The field is a FIXED-height slot in the row (one collapsed line). Its height
   never changes, so the platform picker and Generate button beside it never
   move no matter how much is typed — the textarea grows as a floating panel
   anchored to this box (see .is-expanded below), not by stretching the row. */
.au-prompt-field {
  position: relative;
  flex: 1 1 320px;
  min-width: 220px;
  height: var(--au-prompt-h, 44px);
}
.au-prompt {
  /* Collapsed: fill the fixed slot exactly. Absolutely positioned so its height
     is driven by JS without participating in the row's flex sizing. */
  position: absolute;
  top: 0; left: 0; right: 0;
  height: var(--au-prompt-h, 44px);
  resize: none;
  /* JS (App._autoGrowPrompt) grows the height with the content up to this
     ceiling, then the textarea scrolls internally. Keep the cap here too so a
     long paste can't blow out the panel before JS runs. */
  max-height: 40vh;
  overflow-y: auto;
  padding: 11px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-input);
  background: var(--surface-2);
  color: var(--fg);
  font: 500 14px/1.45 var(--font-body);
  box-sizing: border-box;
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.au-prompt:focus { outline: none; border-color: var(--au-accent); background: var(--surface); box-shadow: 0 0 0 3px var(--au-accent-ring); }
.au-prompt::placeholder { color: var(--fg-subtle); }

/* Inline hint shown when Generate is pressed with an empty description. */
.au-prompt-empty-hint {
  position: absolute;
  top: calc(100% + 4px);
  left: 2px;
  z-index: 5;
  font: 600 12px/1.4 var(--font-body);
  color: var(--dp-orange);
}
.au-prompt-empty-hint[hidden] { display: none; }

/* Expanded: the textarea becomes a floating window. Still anchored to the
   field's box (same left/right/top) but allowed to grow DOWNWARD past the row.
   Because it's absolutely positioned and the slot keeps its fixed height, the
   row height — and therefore the siblings — are completely unaffected. The
   raised z-index + solid surface + shadow make it read as a distinct panel
   floating over the canvas/toolbar below. JS sets the inline height. */
.au-prompt-field.is-expanded .au-prompt {
  z-index: 50;
  background: var(--surface);
  border-color: var(--au-accent);
  border-radius: var(--r-card, 12px);
  box-shadow: 0 0 0 3px var(--au-accent-ring), 0 18px 44px -12px rgba(15, 17, 23, .35);
}
body.dark-mode .au-prompt-field.is-expanded .au-prompt {
  box-shadow: 0 0 0 3px var(--au-accent-ring), 0 20px 48px -10px rgba(0, 0, 0, .6);
}

.au-generate {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 0 18px;
  min-height: 40px;
  border: none;
  border-radius: var(--r-input);
  background: var(--au-accent-strong);
  color: var(--on-primary);
  font: 700 14px/1 var(--font-body);
  cursor: pointer;
  box-shadow: 0 4px 14px var(--au-accent-ring);
  transition: background var(--dur) var(--ease), transform var(--dur-fast) var(--ease), box-shadow var(--dur) var(--ease);
}
.au-generate:hover { background: var(--au-accent); box-shadow: 0 6px 20px var(--au-accent-ring); }
.au-generate:active { transform: translateY(1px); }
.au-generate:disabled { opacity: .6; cursor: progress; }
.au-generate svg { width: 17px; height: 17px; }
.au-cost-pill {
  display: inline-flex; align-items: center;
  padding: 2px 7px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.22);
  font: 800 10.5px/1 var(--font-mono);
  letter-spacing: .02em;
}

/* ── Stage (canvas + drawers) ────────────────────────────────────────────────── */
.au-stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  overflow: hidden;
}
.au-canvas-wrap { position: relative; flex: 1 1 auto; min-width: 0; }

/* ── Toolbar (floating over canvas) ───────────────────────────────────────────── */
.au-toolbar {
  position: absolute;
  top: var(--s-4);
  left: 50%;
  transform: translateX(-50%);
  z-index: 18;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 5px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(10px) saturate(1.2);
  box-shadow: var(--shadow-pop);
}
.au-toolbar.is-disabled { opacity: .55; pointer-events: none; }
.au-tb-sep { width: 1px; height: 22px; margin: 0 3px; background: var(--border); }
.au-tb-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  border: none;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--fg-muted);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.au-tb-btn svg { width: 18px; height: 18px; }
.au-tb-btn:hover { background: var(--surface-2); color: var(--fg); }
.au-tb-btn.is-active { background: var(--au-accent-soft); color: var(--au-accent-strong); }
.au-tb-btn:active { transform: scale(.92); }
.au-tb-btn:disabled { opacity: .4; cursor: default; }
.au-tb-btn.au-tb-primary { color: var(--au-accent-strong); }

/* Tooltip on hover via data-tip. */
.au-tb-btn[data-tip] { position: relative; }
.au-tb-btn[data-tip]::after {
  content: attr(data-tip);
  position: absolute; top: calc(100% + 8px); left: 50%; transform: translateX(-50%) translateY(-4px);
  padding: 4px 8px;
  border-radius: 6px;
  background: var(--fg);
  color: var(--bg);
  font: 600 11px/1 var(--font-body);
  white-space: nowrap;
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
  z-index: 5;
}
.au-tb-btn[data-tip]:hover::after { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ── Validation issues chip (non-blocking guidance) ───────────────────────────────
 * A small affordance pinned to the TOP-RIGHT corner of the canvas stage, clear
 * of the centred floating toolbar so it's always fully visible (never tucked
 * under the button row). When the graph has lightweight validity hints (no
 * trigger, disconnected steps, dangling edge) it shows a count; clicking it
 * pops a panel that drops DOWN-and-LEFT from the chip so it stays in view. It
 * never blocks editing or export — purely a nudge. Hidden when the graph is
 * clean of a graph entirely. In RTL it mirrors to the top-LEFT corner. */
.au-validity {
  position: absolute;
  top: var(--s-4);
  right: var(--s-4);
  left: auto;
  transform: none;
  z-index: 17;
  display: none;
}
.au-validity.is-shown { display: block; }
html[dir="rtl"] .au-validity { right: auto; left: var(--s-4); }
.au-validity-btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 11px 5px 9px;
  border: 1px solid color-mix(in srgb, var(--dp-orange) 45%, var(--border));
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  backdrop-filter: blur(10px) saturate(1.2);
  color: var(--fg);
  font: 700 11.5px/1 var(--font-body);
  cursor: pointer;
  box-shadow: var(--shadow-pop);
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.au-validity-btn:hover { border-color: var(--dp-orange); background: var(--surface); }
.au-validity-btn:active { transform: translateY(1px); }
.au-validity-btn[aria-expanded="true"] { border-color: var(--dp-orange); background: var(--surface); }
.au-validity-dot {
  display: inline-grid; place-items: center;
  width: 17px; height: 17px; flex: 0 0 auto;
  color: var(--dp-orange);
}
.au-validity-dot svg { width: 15px; height: 15px; }
.au-validity-count {
  display: inline-grid; place-items: center;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: var(--r-pill);
  background: var(--dp-orange); color: #fff;
  font: 800 10px/1 var(--font-mono);
}
/* All-clear state: a calm green tick, no count. */
.au-validity.is-clean .au-validity-btn {
  border-color: color-mix(in srgb, #16a34a 40%, var(--border));
  color: var(--fg-muted);
}
.au-validity.is-clean .au-validity-dot { color: #16a34a; }
.au-validity.is-clean .au-validity-count { display: none; }

/* The popover drops down from the chip and is anchored to its RIGHT edge, so it
   opens leftward into the canvas and never runs off the stage's right side. */
.au-validity-pop {
  position: absolute; top: calc(100% + 8px); right: 0; left: auto;
  transform: translateY(-4px);
  width: min(320px, calc(100vw - 28px)); max-width: 360px;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
  box-shadow: var(--shadow-pop);
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.au-validity.is-open .au-validity-pop { opacity: 1; pointer-events: auto; transform: translateY(0); }
/* RTL: the chip sits top-left, so its popover opens rightward (anchored left). */
html[dir="rtl"] .au-validity-pop { right: auto; left: 0; }
.au-validity-item {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 7px 8px; border-radius: 9px;
  font: 500 12px/1.45 var(--font-body); color: var(--fg);
}
.au-validity-item + .au-validity-item { margin-top: 2px; }
.au-validity-item::before {
  content: ''; flex: 0 0 auto; margin-top: 5px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--dp-orange);
}
.au-validity-ok { color: var(--fg-muted); }
.au-validity-ok::before { background: #16a34a; }

/* ── Canvas gesture hint (onboarding) ─────────────────────────────────────────────
 * A soft, on-brand card in the BOTTOM-LEFT of the canvas (clear of the centred
 * extend bar) that teaches the three mouse/touch gestures with gentle looping
 * micro-animations: drag a node to move, drag a port to connect, click an edge
 * to remove. Shown once (JS gates on localStorage), dismissible via the ×, and
 * auto-fades after the user performs a gesture or ~12s. Reduced-motion users get
 * the same card with the motion silenced. RTL mirrors it to the bottom-right. */
.au-hint {
  position: absolute;
  left: var(--s-4);
  bottom: 88px;
  z-index: 19;
  width: max-content; max-width: min(260px, calc(100vw - 28px));
  padding: 11px 13px 12px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: blur(10px) saturate(1.2);
  box-shadow: var(--shadow-pop);
  opacity: 0;
  transform: translateY(8px) scale(.98);
  transform-origin: bottom left;
  pointer-events: none;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.au-hint.is-shown { opacity: 1; transform: none; pointer-events: auto; }
html[dir="rtl"] .au-hint { left: auto; right: var(--s-4); transform-origin: bottom right; }

.au-hint-close {
  position: absolute; top: 6px; right: 6px;
  width: 22px; height: 22px;
  display: inline-grid; place-items: center;
  border: none; border-radius: 50%;
  background: transparent; color: var(--fg-subtle);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.au-hint-close svg { width: 13px; height: 13px; }
.au-hint-close:hover { background: var(--surface-2); color: var(--fg); }
html[dir="rtl"] .au-hint-close { right: auto; left: 6px; }

.au-hint-head { display: flex; align-items: center; gap: 7px; margin: 0 18px 9px 0; }
html[dir="rtl"] .au-hint-head { margin: 0 0 9px 18px; }
.au-hint-spark { display: inline-flex; color: var(--dp-blue); }
.au-hint-spark svg { width: 15px; height: 15px; }
.au-hint-title { font: 800 11px/1 var(--font-body); letter-spacing: .04em; text-transform: uppercase; color: var(--fg-muted); }

.au-hint-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.au-hint-item { display: flex; align-items: center; gap: 9px; }
.au-hint-glyph {
  flex: 0 0 auto;
  width: 44px; height: 28px;
  display: inline-grid; place-items: center;
  border-radius: 8px;
  background: var(--surface-2);
  color: var(--dp-blue);
}
.au-hint-glyph svg { width: 44px; height: 28px; overflow: visible; }
.au-hint-text { font: 600 12px/1.3 var(--font-body); color: var(--fg); }

/* Glyph 1 — "Drag to move": the little card slides side-to-side, the cursor
   trailing just behind it, so the gesture reads at a glance. */
.au-hint-card {
  fill: color-mix(in srgb, var(--dp-blue) 16%, transparent);
  stroke: var(--dp-blue); stroke-width: 1.6;
  animation: au-hint-slide 2.4s var(--ease) infinite;
}
.au-hint-cursor { color: var(--fg-muted); animation: au-hint-slide 2.4s var(--ease) infinite; }

/* Glyph 2 — "Drag a port to connect": the wire draws from the left dot to the
   right on a loop (dash sweep), the destination dot pulsing as it lands. */
.au-hint-wire {
  stroke: var(--dp-blue); stroke-width: 1.8; stroke-linecap: round;
  stroke-dasharray: 100; stroke-dashoffset: 100;
  animation: au-hint-draw 2.6s var(--ease) infinite;
}
.au-hint-dot { fill: var(--surface); stroke: var(--dp-blue); stroke-width: 1.8; }
.au-hint-dot-b { transform-origin: 33px 14px; animation: au-hint-pop 2.6s var(--ease) infinite; }

/* Glyph 3 — "Click an edge to remove": a steady edge with an × badge that
   pulses, mirroring the canvas's delete affordance. */
.au-hint-edge { stroke: var(--au-edge); stroke-width: 1.8; stroke-linecap: round; }
.au-hint-x { transform-origin: 22px 14px; animation: au-hint-pulse 2.2s var(--ease) infinite; }
.au-hint-x circle { fill: var(--surface); stroke: var(--dp-orange); stroke-width: 1.6; }
.au-hint-x path { stroke: var(--dp-orange); stroke-linecap: round; }

@keyframes au-hint-slide {
  0%, 100% { transform: translateX(-4px); }
  50%      { transform: translateX(5px); }
}
@keyframes au-hint-draw {
  0%, 12%  { stroke-dashoffset: 100; }
  55%, 100% { stroke-dashoffset: 0; }
}
@keyframes au-hint-pop {
  0%, 55%  { transform: scale(1); }
  68%      { transform: scale(1.5); }
  82%, 100% { transform: scale(1); }
}
@keyframes au-hint-pulse {
  0%, 100% { transform: scale(1); opacity: .85; }
  50%      { transform: scale(1.18); opacity: 1; }
}

/* Reduced motion: keep the card and the static glyphs, silence the loops and
   land each animation in its "resolved" frame (wire fully drawn). */
@media (prefers-reduced-motion: reduce) {
  .au-hint { transition: opacity .01ms; transform: none; }
  .au-hint-card, .au-hint-cursor, .au-hint-dot-b, .au-hint-x { animation: none !important; }
  .au-hint-wire { animation: none !important; stroke-dashoffset: 0; }
}

/* ── Canvas ───────────────────────────────────────────────────────────────────── */
.au-canvas {
  position: absolute; inset: 0;
  overflow: hidden;
  /* Own all touch gestures: pan / drag / pinch are handled in canvas.js, so the
     browser must not also scroll or zoom the page while interacting. */
  touch-action: none;
  background-color: var(--au-canvas-bg);
  /* Dual dot grid: fine + coarse, drawn with radial gradients. */
  background-image:
    radial-gradient(var(--au-grid-strong) 1.3px, transparent 1.3px),
    radial-gradient(var(--au-grid) 1px, transparent 1px);
  background-size: 120px 120px, 24px 24px;
  background-position: 0 0, 0 0;
  cursor: grab;
  opacity: 0; pointer-events: none;
}
.au-canvas.is-shown { opacity: 1; pointer-events: auto; }
.au-canvas.is-panning { cursor: grabbing; }
.au-canvas.is-connecting { cursor: crosshair; }
.au-world { position: absolute; top: 0; left: 0; transform-origin: 0 0; will-change: transform; }
.au-edges { position: absolute; top: 0; left: 0; width: 6000px; height: 6000px; overflow: visible; pointer-events: none; }
.au-nodes { position: absolute; top: 0; left: 0; }

/* Edges */
.au-edge-group { pointer-events: none; }
.au-edge { pointer-events: auto; }
.au-edge-hit { fill: none; stroke: transparent; stroke-width: 18; cursor: pointer; }
.au-edge-line {
  fill: none;
  stroke: var(--au-edge);
  stroke-width: 2;
  transition: stroke var(--dur-fast) var(--ease), stroke-width var(--dur-fast) var(--ease);
}
.au-edge:hover .au-edge-line { stroke: var(--au-edge-hover); stroke-width: 2.6; }
/* Electric flow: a short bright dash that travels source → target like current
   in a wire. Tinted per-edge (inline stroke = source accent) with a soft glow.
   Subtle by design and non-interactive so it never blocks edge clicks. */
.au-edge-flow {
  fill: none;
  stroke: var(--dp-blue);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-dasharray: 5 150;
  stroke-dashoffset: 155;
  opacity: .55;
  pointer-events: none;
  filter: drop-shadow(0 0 2px currentColor);
  animation: au-edge-flow 2.4s linear infinite;
}
.au-edge:hover .au-edge-flow { opacity: .8; }
@keyframes au-edge-flow { to { stroke-dashoffset: 0; } }
.au-edge-label {
  fill: var(--fg-muted);
  font: 600 11px var(--font-body);
  paint-order: stroke;
  stroke: var(--au-canvas-bg);
  stroke-width: 4px;
}
.au-drag-wire {
  fill: none;
  stroke: var(--dp-blue);
  stroke-width: 2.4;
  stroke-dasharray: 5 5;
  pointer-events: none;
  animation: au-dash 0.5s linear infinite;
}
@keyframes au-dash { to { stroke-dashoffset: -10; } }
.au-edge-del { opacity: 0; cursor: pointer; transition: opacity var(--dur-fast) var(--ease); pointer-events: auto; }
.au-edge-del circle { fill: var(--surface); stroke: var(--border-strong); stroke-width: 1; }
.au-edge-del path { stroke: var(--dp-orange); stroke-width: 1.6; stroke-linecap: round; }
.au-edge:hover .au-edge-del { opacity: 1; }
/* Touch has no hover: a tapped edge is "armed" so its delete button shows,
   mirroring the hover reveal. Slightly larger hit target for fingers. */
.au-edge.is-armed .au-edge-del { opacity: 1; }
.au-edge.is-armed .au-edge-del circle { fill: var(--dp-orange); r: 11; }
.au-edge.is-armed .au-edge-del path { stroke: #fff; }
.au-edge-del:hover circle { fill: var(--dp-orange); }
.au-edge-del:hover path { stroke: #fff; }

/* Node cards */
.au-node {
  position: absolute;
  width: 220px;
  box-sizing: border-box;
  background: var(--au-node-bg);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow-card);
  cursor: grab;
  user-select: none;
  transition: box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.au-node::before {
  content: '';
  position: absolute; left: 0; top: 12px; bottom: 12px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--au-accent);
}
.au-node:hover { border-color: var(--au-accent); box-shadow: var(--shadow-card-hover); transform: translateY(-2px); }
.au-node.is-dragging { cursor: grabbing; box-shadow: var(--shadow-pop); z-index: 5; transform: none; }
.au-node.is-selected { border-color: var(--au-accent); box-shadow: 0 0 0 2px var(--au-accent), var(--shadow-card-hover); }
/* A soft, slow ring that breathes around the selected card. */
.au-node.is-selected::after {
  content: '';
  position: absolute; inset: -4px;
  border-radius: 18px;
  pointer-events: none;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--au-accent) 55%, transparent);
  opacity: 0;
  animation: au-node-ring 2.2s var(--ease) infinite;
}
@keyframes au-node-ring {
  0%, 100% { opacity: 0; transform: scale(.99); }
  50% { opacity: .7; transform: scale(1); }
}
.au-node.is-drop-target { border-color: var(--dp-blue); box-shadow: 0 0 0 2px var(--dp-blue), var(--shadow-card-hover); }
.au-node-new { animation: au-node-pop 1.5s var(--ease); }
@keyframes au-node-pop {
  0% { box-shadow: 0 0 0 0 var(--dp-blue-ring); }
  20% { box-shadow: 0 0 0 8px var(--dp-blue-ring); }
  100% { box-shadow: var(--shadow-card); }
}
/* Staggered entrance when a fresh graph renders. --i is the node index. */
.au-node-enter {
  animation: au-node-enter .42s var(--ease) both;
  animation-delay: calc(var(--i, 0) * 40ms);
}
@keyframes au-node-enter {
  from { opacity: 0; transform: translateY(8px) scale(.96); }
  to   { opacity: 1; transform: none; }
}

.au-node-body { display: flex; align-items: center; gap: 11px; padding: 13px 14px 13px 16px; }
.au-node-chip {
  flex: 0 0 auto;
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border-radius: 10px;
  color: var(--au-accent);
  background: color-mix(in srgb, var(--au-accent) 12%, transparent);
}
.au-node-text { min-width: 0; flex: 1 1 auto; }
.au-node-label {
  font: 650 12.5px/1.25 var(--font-body);
  color: var(--fg);
  letter-spacing: -0.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.au-node-sub {
  margin-top: 2px;
  font: 500 10px/1.3 var(--font-body);
  color: var(--fg-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.au-node-kind {
  position: absolute; top: 8px; right: 10px;
  font: 700 8.5px/1 var(--font-mono);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--au-accent);
  opacity: .65;
}

/* Ports */
.au-port {
  position: absolute;
  top: 50%;
  width: 13px; height: 13px;
  margin-top: -6.5px;
  border-radius: 50%;
  background: var(--au-node-bg);
  border: 2px solid var(--au-port);
  transition: border-color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
  z-index: 2;
}
.au-port-in { left: -7px; }
.au-port-out { right: -7px; cursor: crosshair; }
.au-node:hover .au-port { border-color: var(--au-accent); }
.au-port-out:hover { background: var(--dp-blue); border-color: var(--dp-blue); transform: scale(1.25); }
.au-port-in { pointer-events: none; }

/* Icons: brand marks bring their own fills and must not be clipped or recoloured;
   stroke glyphs inherit currentColor from the chip. A consistent box keeps every
   mark optically the same size. */
.au-ico { display: block; }
.au-node-chip .au-ico, .au-subnode-chip .au-ico { overflow: visible; }

/* ── AI-agent cluster (agent card + labelled bottom ports) ───────────────────────
 * An AI-agent node renders larger and carries a rail of labelled bottom ports
 * (Chat Model / Memory / Tool / Output Parser). Sub-nodes hang beneath it as
 * compact chips joined by dashed links — mirroring the n8n cluster canvas. */
.au-node-agent {
  width: 260px;
  border-radius: 16px;
  /* A faint accent wash + stronger spine so the agent reads as the hub. */
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--au-accent) 8%, var(--au-node-bg)), var(--au-node-bg) 60%);
  box-shadow: var(--shadow-card), 0 0 0 1px color-mix(in srgb, var(--au-accent) 22%, transparent);
}
.au-node-agent::before { top: 14px; bottom: 14px; width: 4px; }
.au-node-agent .au-node-body { padding: 15px 16px 14px 18px; }
.au-node-agent .au-node-label { font-size: 13.5px; font-weight: 700; }
.au-agent-chip {
  width: 42px; height: 42px;
  border-radius: 12px;
  color: #fff;
  background: linear-gradient(135deg, var(--au-accent), color-mix(in srgb, var(--au-accent) 65%, #fff 0%));
  box-shadow: 0 4px 12px color-mix(in srgb, var(--au-accent) 45%, transparent);
}
/* Brand chips (e.g. the robot agent mark) already carry their own colour, so we
   give them a neutral plate rather than tinting the glyph white. */
.au-agent-chip { background: linear-gradient(135deg, color-mix(in srgb, var(--au-accent) 16%, var(--surface)), var(--surface)); }

/* Bottom port rail: evenly spaced labelled stubs sitting on the agent's lower
   edge. Each stub is a small dot (the dashed link lands here) above a caption. */
.au-agent-rail {
  display: flex;
  justify-content: space-around;
  align-items: flex-start;
  gap: 2px;
  padding: 0 6px 6px;
  margin-top: -2px;
}
.au-agent-port {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
}
.au-agent-port-dot {
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--au-node-bg);
  border: 2px solid var(--au-accent);
  /* Pull the dot down so it straddles the card edge where links arrive. */
  margin-bottom: 1px;
  box-shadow: 0 1px 3px rgba(15,17,23,.12);
}
.au-agent-port-label {
  font: 700 8.5px/1.1 var(--font-body);
  letter-spacing: .01em;
  color: var(--fg-muted);
  text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 100%;
}

/* ── Sub-node chips (chat model / memory / tool / parser) ─────────────────────── */
.au-subnode {
  width: 168px;
  border-radius: 13px;
  cursor: grab;
  background: var(--au-node-bg);
}
/* Sub-node chips read calmer than main cards: thinner spine, top-anchored port. */
.au-subnode::before { top: 10px; bottom: 10px; width: 3px; }
.au-subnode-body { display: flex; align-items: center; gap: 9px; padding: 9px 11px 9px 13px; }
.au-subnode-chip {
  flex: 0 0 auto;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 9px;
  color: var(--au-accent);
  background: color-mix(in srgb, var(--au-accent) 13%, transparent);
}
.au-subnode-text { min-width: 0; flex: 1 1 auto; }
.au-subnode-label {
  font: 650 11.5px/1.2 var(--font-body);
  color: var(--fg);
  letter-spacing: -0.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.au-subnode-cap {
  margin-top: 1px;
  font: 700 8px/1.1 var(--font-mono);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--au-accent);
  opacity: .8;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The sub-node's upward output port sits centred on its TOP edge. */
.au-port-sub-out {
  position: absolute;
  top: -7px; left: 50%;
  margin-left: -6.5px; margin-top: 0;
  width: 13px; height: 13px;
  border-radius: 50%;
  background: var(--au-node-bg);
  border: 2px solid var(--au-accent);
  z-index: 2;
  pointer-events: none; /* sub-links aren't user-drawn from the chip */
}

/* ── Sub-node dashed links (chip top → agent bottom port) ─────────────────────── */
.au-sub-group { pointer-events: none; }
.au-sub-edge { pointer-events: auto; }
.au-sub-line {
  fill: none;
  stroke: var(--dp-blue);
  stroke-width: 1.8;
  stroke-dasharray: 5 4;
  opacity: .75;
  transition: stroke-width var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
.au-sub-edge:hover .au-sub-line { stroke-width: 2.4; opacity: 1; }
/* A gentle travelling dash so the sub-link feels alive without competing with
   the brighter main-flow current. */
.au-sub-flow {
  fill: none;
  stroke: var(--dp-blue);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray: 3 120;
  stroke-dashoffset: 123;
  opacity: .5;
  filter: drop-shadow(0 0 1.5px currentColor);
  animation: au-sub-flow 2.8s linear infinite;
}
@keyframes au-sub-flow { to { stroke-dashoffset: 0; } }

/* ── errorPolicy badge ───────────────────────────────────────────────────────────
 * A tiny shield/retry chip in a card's top-left corner marking a step that has
 * retry / continue-on-fail handling. Decorative; the title carries the detail. */
.au-node-badge {
  position: absolute; top: -7px; left: -7px;
  width: 18px; height: 18px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--dp-blue) 45%, var(--border));
  color: var(--dp-blue);
  box-shadow: var(--shadow-sm);
  z-index: 3;
  pointer-events: auto;
}
.au-node-badge svg { display: block; }
/* On agent cards the spine is thicker — nudge the badge so it clears the corner. */
.au-node-agent .au-node-badge { top: -7px; left: -7px; }
html[dir="rtl"] .au-node-badge { left: auto; right: -7px; }

/* ── Loop node (two labelled output ports: Loop / Done) ───────────────────────────
 * A loop renders as a normal card but exposes two right-edge outputs stacked
 * vertically: Loop (upper, the per-item body) and Done (lower, the
 * continuation). The y-ratios match _portPoint() in canvas.js (0.28 / 0.72). */
.au-node-loop { /* shares .au-node sizing; accent comes from --au-accent (amber) */ }
.au-node-loop .au-port-loop { top: 28%; }
.au-node-loop .au-port-done { top: 72%; }
.au-node-loop .au-port-loop,
.au-node-loop .au-port-done {
  right: -7px;
  background: var(--au-node-bg);
  border-color: var(--au-accent);
}
.au-node-loop:hover .au-port-loop,
.au-node-loop:hover .au-port-done { border-color: var(--au-accent); }
/* A little caption beside each port so the two outputs read like n8n's loop. */
.au-port-tag {
  position: absolute; right: 16px; top: 50%;
  transform: translateY(-50%);
  padding: 1px 6px;
  border-radius: var(--r-pill);
  font: 800 8px/1.35 var(--font-mono);
  letter-spacing: .04em; text-transform: uppercase;
  white-space: nowrap;
  background: color-mix(in srgb, var(--au-accent) 14%, var(--surface));
  color: var(--au-accent);
  border: 1px solid color-mix(in srgb, var(--au-accent) 35%, transparent);
  pointer-events: none;
}
.au-port-tag-loop { color: var(--au-accent); }
.au-port-tag-done {
  background: color-mix(in srgb, var(--fg-muted) 12%, var(--surface));
  color: var(--fg-muted);
  border-color: color-mix(in srgb, var(--fg-muted) 30%, transparent);
}

/* Loop body + back edges: dashed amber so the cycle reads apart from the solid
   forward flow. The back-edge (returning into the loop) is dimmer still. */
.au-edge-loopbody .au-edge-line {
  stroke: var(--au-accent, #d97706);
  stroke-dasharray: 6 5;
}
.au-edge-loopbody .au-edge-flow { stroke: var(--au-accent, #d97706); }
.au-edge-loopbody:hover .au-edge-line { stroke: var(--au-accent, #d97706); }
.au-edge-back .au-edge-line { opacity: .85; stroke-dasharray: 4 5; }
.au-edge-back .au-edge-flow { opacity: .4; }

/* ── Sticky notes ─────────────────────────────────────────────────────────────────
 * A soft parchment panel that annotates the canvas. No ports, no execution; it
 * sits BEHIND the executable cards (lower z-index + earlier in DOM). Draggable
 * and selectable like any node. params.width/height set its box; params.color
 * (via --au-note-color) tints it. */
.au-note {
  --au-note-color: #fde68a;            /* parchment amber (light default) */
  --au-note-ink: #6b5512;
  position: absolute;
  z-index: 0;                          /* behind regular cards (which sit above) */
  box-sizing: border-box;
  padding: 14px 15px 16px;
  border-radius: 10px;
  border: 1px solid color-mix(in srgb, var(--au-note-color) 70%, #b8860b 12%);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--au-note-color) 92%, #fff),
      color-mix(in srgb, var(--au-note-color) 80%, #fff 0%));
  color: var(--au-note-ink);
  box-shadow: 0 6px 18px -8px rgba(120, 90, 10, .45), 0 1px 0 rgba(255,255,255,.5) inset;
  cursor: grab;
  user-select: none;
  overflow: hidden;
  transition: box-shadow var(--dur) var(--ease), transform var(--dur-fast) var(--ease), border-color var(--dur) var(--ease);
}
/* The accent spine that every .au-node draws would clash with the paper — drop
   it, and neutralise the breathing selection ring's accent to the note hue. */
.au-note::before { content: none; }
.au-note:hover {
  transform: translateY(-1px);
  box-shadow: 0 10px 24px -8px rgba(120, 90, 10, .55), 0 1px 0 rgba(255,255,255,.5) inset;
  border-color: color-mix(in srgb, var(--au-note-color) 55%, #b8860b 30%);
}
.au-note.is-dragging { cursor: grabbing; box-shadow: var(--shadow-pop); z-index: 1; transform: none; }
.au-note.is-selected {
  border-color: color-mix(in srgb, var(--au-note-color) 40%, #b8860b 45%);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--au-note-color) 60%, #b8860b 30%), 0 10px 24px -8px rgba(120,90,10,.5);
}
.au-note.is-selected::after { content: none; }   /* skip the accent breathing ring */
/* A folded dog-ear in the top-right corner sells the "sticky note" read. */
.au-note-fold {
  position: absolute; top: 0; right: 0;
  width: 18px; height: 18px;
  background: linear-gradient(225deg, color-mix(in srgb, var(--au-note-color) 55%, #000 12%) 0 50%, transparent 50%);
  border-bottom-left-radius: 4px;
}
.au-note-body {
  font: 500 12.5px/1.5 var(--font-body);
  white-space: normal; word-break: break-word;
  max-height: 100%;
}
.au-note-line { min-height: .75em; }
.au-note-line.is-blank { height: .5em; }
.au-note-empty { font-style: italic; opacity: .6; }
/* When a custom colour is supplied, derive a readable ink from it. The default
   light parchment already pairs with the dark ink above. */
.au-note-tinted { --au-note-ink: #3a2f08; }

/* Dark mode: a warm, dimmer parchment that still reads as "paper, not card". */
body.dark-mode .au-note {
  --au-note-color: #4a3f1e;
  --au-note-ink: #f2e6c2;
  border-color: color-mix(in srgb, var(--au-note-color) 60%, #000 20%);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--au-note-color) 88%, #000 0%),
      color-mix(in srgb, var(--au-note-color) 96%, #000 8%));
  box-shadow: 0 8px 22px -10px rgba(0,0,0,.6), 0 1px 0 rgba(255,255,255,.05) inset;
}
body.dark-mode .au-note-tinted { --au-note-ink: #fbf3da; }
body.dark-mode .au-note-fold {
  background: linear-gradient(225deg, color-mix(in srgb, var(--au-note-color) 55%, #000 30%) 0 50%, transparent 50%);
}

/* ── Empty / skeleton / error states ──────────────────────────────────────────── */
.au-state {
  position: absolute; inset: 0;
  display: none;
  z-index: 12;
}
.au-state.is-shown { display: flex; }
.au-empty {
  flex-direction: column; align-items: center; justify-content: safe center;
  text-align: center;
  padding: 24px;
  overflow-y: auto;
  background:
    radial-gradient(circle at 50% 30%, var(--dp-blue-soft), transparent 55%),
    var(--au-canvas-bg);
  background-image:
    radial-gradient(circle at 50% 30%, var(--dp-blue-soft), transparent 55%),
    radial-gradient(var(--au-grid) 1px, transparent 1px);
  background-size: auto, 24px 24px;
}
.au-empty-art {
  width: 76px; height: 76px;
  display: grid; place-items: center;
  border-radius: 22px;
  background: linear-gradient(135deg, var(--au-accent-strong), var(--au-accent));
  color: #fff;
  box-shadow: 0 10px 30px var(--au-accent-ring);
  margin-bottom: var(--s-5);
}
.au-empty-art svg { width: 38px; height: 38px; }
.au-empty h2 { margin: 0 0 var(--s-3); font-size: clamp(1.3rem, 3vw, 1.9rem); letter-spacing: -0.03em; }
.au-empty p { margin: 0 0 var(--s-6); max-width: 46ch; color: var(--fg-muted); line-height: 1.6; }
.au-examples { display: flex; flex-direction: column; gap: 8px; width: min(520px, 100%); }
.au-example-chip {
  text-align: left;
  padding: 11px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
  color: var(--fg);
  font: 500 13px/1.4 var(--font-body);
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), background var(--dur) var(--ease);
}
.au-example-chip::before { content: '✦'; color: var(--dp-blue); margin-right: 8px; }
.au-example-chip:hover { border-color: var(--dp-blue); transform: translateY(-2px); box-shadow: var(--shadow-card); background: linear-gradient(135deg, var(--surface), var(--dp-blue-soft)); }

/* Explore Templates: a single prominent button in the empty state. Clicking it
   opens the templates side drawer (styled further down). Sits under the example
   chips with a touch of breathing room. */
.au-templates-cta {
  display: inline-flex; align-items: center; gap: 9px;
  margin-top: var(--s-5);
  padding: 11px 18px;
  border: 1px solid color-mix(in srgb, var(--dp-blue) 35%, var(--border));
  border-radius: var(--r-pill);
  background: linear-gradient(135deg, var(--surface), var(--dp-blue-soft));
  color: var(--dp-blue);
  font: 700 13.5px/1 var(--font-body);
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), background var(--dur) var(--ease);
}
.au-templates-cta:hover {
  border-color: var(--dp-blue);
  transform: translateY(-2px);
  box-shadow: var(--shadow-card);
}
.au-templates-cta:active { transform: translateY(0); }
.au-templates-cta-ico { display: inline-flex; }
.au-templates-cta-ico svg { width: 17px; height: 17px; }

/* ── Templates drawer (right-side panel; full-width bottom sheet on mobile) ─────
 * A slide-in drawer listing template categories and cards. Mirrors the
 * inspector / JSON-sheet drawer language: a dimming backdrop, a surface panel
 * with a sticky header and a scrollable body. Clicking a card prefills the
 * prompt + platform and closes the drawer (handled in app.js). */
.au-templates-backdrop {
  position: fixed; inset: 0; z-index: 1190;
  background: rgba(15, 17, 23, 0.5);
  backdrop-filter: blur(3px);
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur) var(--ease);
}
.au-templates-backdrop.is-open { opacity: 1; pointer-events: auto; }
.au-templates-drawer {
  position: fixed; top: 0; right: 0; bottom: 0;
  z-index: 1200;
  width: min(440px, 92vw);
  display: flex; flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: -18px 0 44px -16px rgba(15, 17, 23, .4);
  transform: translateX(102%);
  transition: transform var(--dur) var(--ease);
}
.au-templates-drawer.is-open { transform: translateX(0); }
body.dark-mode .au-templates-drawer { box-shadow: -18px 0 48px -14px rgba(0, 0, 0, .6); }
.au-templates-head {
  flex: 0 0 auto;
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  padding: 18px 18px 14px 20px;
  border-bottom: 1px solid var(--border);
}
.au-templates-head-text { min-width: 0; }
.au-templates-head h3 { margin: 0; font-size: 1.1rem; letter-spacing: -0.02em; color: var(--fg); }
.au-templates-sub { margin: 4px 0 0; font: 500 12px/1.45 var(--font-body); color: var(--fg-muted); }
.au-templates-body { flex: 1 1 auto; overflow-y: auto; padding: 14px 16px 24px; }

.au-tpl-section + .au-tpl-section { margin-top: var(--s-5); }
.au-tpl-section-title {
  margin: 0 0 9px; padding: 0 2px;
  font: 700 10.5px/1 var(--font-mono); letter-spacing: .12em; text-transform: uppercase;
  color: var(--fg-subtle);
}
.au-tpl-grid { display: flex; flex-direction: column; gap: 8px; }
.au-tpl-card {
  display: flex; align-items: center; gap: 10px; text-align: left;
  padding: 11px 13px;
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--surface); color: var(--fg);
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), background var(--dur) var(--ease);
}
.au-tpl-card:hover {
  border-color: var(--dp-blue); transform: translateY(-1px);
  box-shadow: var(--shadow-card);
  background: linear-gradient(135deg, var(--surface), var(--dp-blue-soft));
}
.au-tpl-card:active { transform: translateY(0); }
.au-tpl-card:focus-visible { outline: 2px solid var(--dp-blue); outline-offset: 2px; }
.au-tpl-card-main { min-width: 0; flex: 1 1 auto; }
.au-tpl-card-title {
  display: block;
  font: 700 13px/1.3 var(--font-body); color: var(--fg);
  letter-spacing: -0.01em;
}
.au-tpl-card-desc {
  display: block; margin-top: 2px;
  font: 500 11.5px/1.4 var(--font-body); color: var(--fg-muted);
}
.au-tpl-card-badge {
  flex: 0 0 auto;
  padding: 3px 8px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--fg-muted);
  border: 1px solid var(--border);
  font: 700 9.5px/1 var(--font-mono); letter-spacing: .04em; text-transform: lowercase;
}
.au-tpl-card:hover .au-tpl-card-badge { border-color: color-mix(in srgb, var(--dp-blue) 40%, var(--border)); color: var(--dp-blue); }

/* The badge column: recommended platform on top, a subtle "all platforms"
   reassurance underneath — the recommendation is a default, not a constraint. */
.au-tpl-card-tags {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}
.au-tpl-card-all {
  font: 600 9px/1 var(--font-mono);
  letter-spacing: .03em;
  text-transform: lowercase;
  color: var(--fg-muted);
  opacity: .65;
  white-space: nowrap;
}
.au-tpl-card:hover .au-tpl-card-all { opacity: 1; color: var(--dp-blue); }

/* RTL: drawer slides in from the LEFT and its inner edge/shadow flip. */
html[dir="rtl"] .au-templates-drawer {
  right: auto; left: 0;
  border-left: 0; border-right: 1px solid var(--border);
  box-shadow: 18px 0 44px -16px rgba(15, 17, 23, .4);
  transform: translateX(-102%);
}
html[dir="rtl"] .au-templates-drawer.is-open { transform: translateX(0); }
html[dir="rtl"] .au-tpl-card { text-align: right; }

/* Skeleton — a faint pre-laid graph that shimmers while we generate. */
.au-skeleton {
  align-items: center; justify-content: center;
  background: var(--au-canvas-bg);
  background-image: radial-gradient(var(--au-grid) 1px, transparent 1px);
  background-size: 24px 24px;
  flex-direction: column;
  gap: var(--s-6);
}
.au-skel-flow { display: flex; align-items: center; gap: 0; }
.au-skel-node {
  width: 150px; height: 58px;
  border-radius: 14px;
  background: linear-gradient(100deg, var(--surface-2) 30%, var(--surface) 50%, var(--surface-2) 70%);
  background-size: 200% 100%;
  border: 1px solid var(--border);
  animation: au-shimmer 1.3s ease-in-out infinite;
}
.au-skel-link { width: 46px; height: 2px; background: var(--border-strong); }
.au-skel-node:nth-child(3) { animation-delay: .15s; }
.au-skel-node:nth-child(5) { animation-delay: .3s; }
@keyframes au-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
.au-skel-label { display: inline-flex; align-items: center; gap: 10px; color: var(--fg-muted); font: 600 14px/1 var(--font-body); }
.au-skel-spinner {
  width: 18px; height: 18px;
  border: 2.5px solid var(--border-strong);
  border-top-color: var(--dp-blue);
  border-radius: 50%;
  animation: au-spin .8s linear infinite;
}
@keyframes au-spin { to { transform: rotate(360deg); } }

.au-error {
  flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: 24px;
  background: var(--au-canvas-bg);
}
.au-error-art {
  width: 60px; height: 60px; display: grid; place-items: center;
  border-radius: 18px; background: var(--dp-orange-soft); color: var(--dp-orange);
  margin-bottom: var(--s-4);
}
.au-error-art svg { width: 30px; height: 30px; }
.au-error h2 { margin: 0 0 var(--s-2); font-size: 1.3rem; }
.au-error-msg { margin: 0 0 var(--s-5); max-width: 44ch; color: var(--fg-muted); line-height: 1.55; }

/* ── Warnings banner ──────────────────────────────────────────────────────────── */
.au-warnings {
  position: absolute; left: 50%; bottom: 96px; transform: translateX(-50%) translateY(12px);
  z-index: 22;
  width: min(640px, calc(100% - 32px));
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.au-warnings.is-open { opacity: 1; transform: translateX(-50%) translateY(0); pointer-events: auto; }
.au-warn-inner {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 12px 12px 14px;
  border: 1px solid var(--dp-orange);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow-pop);
}
.au-warn-icon { color: var(--dp-orange); flex: 0 0 auto; margin-top: 1px; }
.au-warn-icon svg { width: 17px; height: 17px; }
.au-warn-list { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.au-warn-line { font: 500 12.5px/1.45 var(--font-body); color: var(--fg); }

/* ── AI extend box ────────────────────────────────────────────────────────────── */
.au-extend {
  position: absolute; left: 50%; bottom: var(--s-4); transform: translateX(-50%);
  z-index: 20;
  width: min(640px, calc(100% - 32px));
  display: flex; align-items: center; gap: 8px;
  padding: 7px 7px 7px 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: blur(10px) saturate(1.2);
  box-shadow: var(--shadow-pop);
}
.au-extend-spark { color: var(--au-accent-strong); flex: 0 0 auto; display: inline-flex; }
.au-extend-spark svg { width: 18px; height: 18px; }
.au-extend-input {
  flex: 1 1 auto; min-width: 0;
  border: none; background: transparent; color: var(--fg);
  font: 500 13.5px/1.4 var(--font-body);
}
.au-extend-input:focus { outline: none; }
.au-extend-input::placeholder { color: var(--fg-subtle); }
.au-extend-btn {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 0 14px; height: 34px;
  border: none; border-radius: var(--r-pill);
  background: var(--au-accent-strong); color: var(--on-primary);
  font: 700 12.5px/1 var(--font-body);
  cursor: pointer;
  transition: background var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.au-extend-btn:hover { background: var(--au-accent); }
.au-extend-btn:active { transform: translateY(1px); }
.au-extend-btn:disabled { opacity: .6; cursor: progress; }
.au-extend-btn.is-loading { position: relative; color: transparent; }
.au-extend-btn.is-loading::after {
  content: ''; position: absolute; inset: 0; margin: auto;
  width: 15px; height: 15px;
  border: 2px solid rgba(255,255,255,.5); border-top-color: #fff;
  border-radius: 50%; animation: au-spin .7s linear infinite;
}
.au-extend-cost {
  flex: 0 0 auto;
  padding: 0 8px; height: 22px;
  display: inline-flex; align-items: center;
  border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--fg-muted);
  font: 800 10px/1 var(--font-mono); letter-spacing: .02em;
}

/* The extend box and warnings only make sense once a graph is loaded. */
.au-stage:not([data-state="loaded"]) .au-extend { display: none; }

/* ── Inspector drawer ─────────────────────────────────────────────────────────── */
.au-inspector {
  flex: 0 0 0;
  width: 0;
  border-left: 1px solid var(--border);
  background: var(--surface);
  overflow: hidden;
  display: flex; flex-direction: column;
  transition: width var(--dur) var(--ease), flex-basis var(--dur) var(--ease);
  z-index: 24;
}
.au-inspector.is-open { flex-basis: 320px; width: 320px; }
.au-insp-head {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 14px 12px 18px;
  border-bottom: 1px solid var(--border);
}
.au-insp-title { font: 700 14px/1 var(--font-body); letter-spacing: -0.01em; }
.au-insp-body { flex: 1 1 auto; overflow-y: auto; padding: 16px 18px 28px; }
.au-insp-preview {
  display: flex; align-items: center; gap: 11px;
  padding: 12px; margin-bottom: var(--s-5);
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--surface-2);
}
.au-insp-chip {
  width: 38px; height: 38px; flex: 0 0 auto;
  display: grid; place-items: center; border-radius: 10px;
  color: var(--au-accent); background: color-mix(in srgb, var(--au-accent) 14%, transparent);
}
.au-insp-preview-label { font: 650 13px/1.2 var(--font-body); }
.au-insp-preview-kind { margin-top: 2px; font: 700 9.5px/1 var(--font-mono); letter-spacing: .08em; text-transform: uppercase; color: var(--au-accent); }

.au-field { display: block; margin-bottom: var(--s-4); }
.au-field-label { display: block; margin-bottom: 6px; font: 600 11px/1 var(--font-body); letter-spacing: .02em; text-transform: uppercase; color: var(--fg-muted); }
.au-input {
  width: 100%; box-sizing: border-box;
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: var(--r-input);
  background: var(--surface-2);
  color: var(--fg);
  font: 500 13px/1.4 var(--font-body);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.au-input:focus { outline: none; border-color: var(--au-accent); background: var(--surface); box-shadow: 0 0 0 3px var(--au-accent-ring); }
.au-select { cursor: pointer; appearance: none; background-image: none; padding-right: 28px; }
.au-textarea { resize: vertical; min-height: 60px; }

.au-params-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.au-params-head .au-field-label { margin-bottom: 0; }
.au-mini-btn {
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface); color: var(--au-accent-strong);
  font: 700 11px/1 var(--font-body); padding: 5px 9px; cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.au-mini-btn:hover { border-color: var(--au-accent); background: var(--au-accent-soft); }
.au-param-rows { display: flex; flex-direction: column; gap: 6px; }
.au-param-row { display: grid; grid-template-columns: 1fr 1fr auto; gap: 6px; align-items: center; }
.au-param-key, .au-param-val { padding: 7px 9px; font-size: 12.5px; }
.au-param-empty { font: 500 12px/1.4 var(--font-body); color: var(--fg-subtle); padding: 4px 0; }
.au-param-del { width: 30px; height: 30px; flex: 0 0 auto; }

.au-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; color: var(--fg-muted);
  border-radius: 8px; cursor: pointer; padding: 4px;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.au-icon-btn svg { width: 16px; height: 16px; }
.au-icon-btn:hover { background: var(--surface-2); color: var(--fg); }

.au-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 9px 14px; border-radius: var(--r-input);
  font: 650 13px/1 var(--font-body); cursor: pointer; border: 1px solid transparent;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), transform var(--dur-fast) var(--ease), color var(--dur) var(--ease);
}
.au-btn:active { transform: translateY(1px); }
.au-btn-outline { background: var(--surface); border-color: var(--border); color: var(--fg); }
.au-btn-outline:hover { border-color: var(--border-strong); background: var(--surface-2); }
.au-btn-danger { width: 100%; margin-top: var(--s-4); background: transparent; border-color: color-mix(in srgb, var(--dp-orange) 45%, transparent); color: var(--dp-orange); }
.au-btn-danger:hover { background: var(--dp-orange); color: #fff; border-color: var(--dp-orange); }

/* ── JSON drawer (bottom sheet) ──────────────────────────────────────────────── */
.au-json-drawer {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 0;
  z-index: 30;
  background: var(--surface);
  border-top: 1px solid var(--border);
  box-shadow: 0 -12px 32px rgba(15,17,23,.12);
  overflow: hidden;
  transition: height var(--dur) var(--ease);
  display: flex; flex-direction: column;
}
.au-json-drawer.is-open { height: min(46%, 420px); }
.au-json-head {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 16px; border-bottom: 1px solid var(--border);
}
.au-json-head h3 { margin: 0; font: 700 13px/1 var(--font-body); }
.au-json-cols { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--border); }
.au-json-col { display: flex; flex-direction: column; min-height: 0; background: var(--surface); }
.au-json-col-head { display: flex; align-items: center; justify-content: space-between; padding: 8px 14px; border-bottom: 1px solid var(--border); }
.au-json-col-head span { font: 600 11px/1 var(--font-mono); letter-spacing: .04em; text-transform: uppercase; color: var(--fg-muted); }
.au-json-area {
  flex: 1 1 auto; min-height: 0;
  width: 100%; box-sizing: border-box;
  border: none; resize: none;
  padding: 12px 14px;
  background: var(--surface-2);
  color: var(--fg);
  font: 500 12px/1.6 var(--font-mono);
  tab-size: 2;
}
.au-json-area:focus { outline: none; }
.au-json-area[readonly] { color: var(--fg-muted); }
.au-chip-btn {
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface); color: var(--fg);
  font: 700 10.5px/1 var(--font-mono); letter-spacing: .05em; text-transform: uppercase;
  padding: 6px 10px; cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.au-chip-btn:hover { border-color: var(--au-accent); background: var(--au-accent-soft); color: var(--au-accent-strong); }
.au-chip-btn.au-chip-primary { background: var(--au-accent-strong); color: #fff; border-color: var(--au-accent-strong); }
.au-chip-btn.au-chip-primary:hover { background: var(--au-accent); color: #fff; }

/* ── Overlays / modals ───────────────────────────────────────────────────────── */
.au-overlay {
  position: fixed; inset: 0; z-index: 1200;
  display: none; align-items: center; justify-content: center;
  padding: 20px;
  background: rgba(15, 17, 23, 0.5);
  backdrop-filter: blur(3px);
}
.au-overlay.is-open { display: flex; animation: au-fade .2s var(--ease); }
@keyframes au-fade { from { opacity: 0; } to { opacity: 1; } }
.au-modal {
  width: min(520px, 100%);
  max-height: min(80vh, 640px);
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 18px;
  box-shadow: var(--shadow-pop);
  overflow: hidden;
  animation: au-modal-in .22s var(--ease);
}
@keyframes au-modal-in { from { opacity: 0; transform: translateY(12px) scale(.98); } to { opacity: 1; transform: none; } }
.au-modal-head { display: flex; align-items: center; justify-content: space-between; padding: 16px 18px; border-bottom: 1px solid var(--border); }
.au-modal-title { margin: 0; font-size: 1.05rem; letter-spacing: -0.02em; }
.au-open-list { overflow-y: auto; padding: 10px; }
.au-open-loading, .au-open-empty { padding: 28px 16px; text-align: center; color: var(--fg-muted); font-size: 13.5px; }
.au-open-item { display: flex; align-items: center; gap: 6px; padding: 4px; border-radius: 12px; transition: background var(--dur-fast) var(--ease); }
.au-open-item:hover { background: var(--surface-2); }
.au-open-load {
  flex: 1 1 auto; min-width: 0; text-align: left;
  display: flex; flex-direction: column; gap: 3px;
  border: none; background: transparent; cursor: pointer; padding: 8px 10px; color: var(--fg);
}
.au-open-name { font: 650 13.5px/1.2 var(--font-body); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.au-open-meta { font: 500 11.5px/1 var(--font-mono); color: var(--fg-muted); text-transform: capitalize; }
.au-open-del { flex: 0 0 auto; }
.au-open-del:hover { color: var(--dp-orange); }

.au-install-body { padding: 18px 20px 22px; overflow-y: auto; }
.au-install-banner {
  padding: 11px 13px; margin-bottom: var(--s-4);
  border: 1px solid color-mix(in srgb, var(--dp-orange) 40%, transparent);
  border-radius: 12px; background: var(--dp-orange-soft);
  color: var(--fg); font: 500 12.5px/1.5 var(--font-body);
}
.au-install-name { margin: 0 0 var(--s-3); font-size: 1rem; letter-spacing: -0.01em; }
.au-install-steps { margin: 0 0 var(--s-4); padding-left: 22px; display: flex; flex-direction: column; gap: 9px; }
.au-install-steps li { font: 500 13.5px/1.5 var(--font-body); color: var(--fg); }
.au-install-steps li::marker { color: var(--dp-blue); font-weight: 700; }
.au-install-doc { display: inline-flex; }

/* ── Message log (modal) ──────────────────────────────────────────────────────── */
/* Reuses the shared overlay/modal shell; only the header actions + list rows are
   bespoke. Each row mirrors a banner line, prefixed with the time it was shown. */
.au-log-actions { display: inline-flex; align-items: center; gap: 8px; }
.au-log-body { overflow-y: auto; padding: 8px; }
.au-log-item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 12px; border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface-2);
}
.au-log-item + .au-log-item { margin-top: 6px; }
/* Warnings get an amber spine so they read like the banner they came from. */
.au-log-warning { border-left: 3px solid var(--dp-orange); }
.au-log-time {
  flex: 0 0 auto; margin-top: 1px;
  font: 700 10.5px/1.4 var(--font-mono); letter-spacing: .03em;
  color: var(--fg-subtle); font-variant-numeric: tabular-nums;
}
.au-log-text { flex: 1 1 auto; min-width: 0; font: 500 12.5px/1.5 var(--font-body); color: var(--fg); word-break: break-word; }

/* RTL: flip the warning spine to the trailing edge. */
html[dir="rtl"] .au-log-warning { border-left: 1px solid var(--border); border-right: 3px solid var(--dp-orange); }

/* ── Responsive ──────────────────────────────────────────────────────────────── */
/*
 * Mobile (≤768px): the top bar collapses into a compact header so the canvas
 * gets the bulk of the viewport. The platform control scrolls horizontally on
 * its own row (never clipping Pipedream / Activepieces), and the prompt shares a
 * row with Generate. Drawers, the JSON sheet, the AI-extend bar and overlays all
 * become full-width bottom sheets. Touch panning/zoom is handled in canvas.js.
 */
@media (max-width: 768px) {
  /* Single column; tighter gutters so we reclaim width for controls. */
  .au-topbar {
    grid-template-columns: 1fr;
    gap: var(--s-2);
    padding: var(--s-3) clamp(10px, 3vw, 16px);
    padding-left: max(clamp(10px, 3vw, 16px), env(safe-area-inset-left));
    padding-right: max(clamp(10px, 3vw, 16px), env(safe-area-inset-right));
  }
  .au-topbar-main { gap: var(--s-2); }
  .au-title-input { font-size: 17px; padding: 4px 8px; }

  /* The prompt row wraps: platforms own the first line (scrollable), then the
     prompt textarea and Generate share the next line. min-width:0 everywhere so
     no child can impose its intrinsic width and blow out the row. */
  .au-prompt-row { flex-wrap: wrap; align-items: stretch; gap: var(--s-2); }
  .au-platforms {
    flex: 1 1 100%;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    align-self: auto;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }
  .au-platforms::-webkit-scrollbar { display: none; }
  /* Segments must keep their natural size so the row actually overflows (and
     scrolls) instead of squashing labels. */
  .au-seg { flex: 0 0 auto; }
  .au-prompt-field { flex: 1 1 180px; min-width: 0; }
  /* Still expands into a floating panel on phones, but caps lower so the
     on-screen keyboard and canvas stay usable; JS respects this ceiling via
     getComputedStyle on max-height. The collapsed slot stays a fixed 44px. */
  .au-prompt { max-height: 34vh; }
  .au-generate { flex: 0 0 auto; min-width: 0; padding: 0 14px; }

  /* The floating toolbar sits a touch lower (clears the compact header), scrolls
     horizontally, and keeps tap targets ≥40px. */
  .au-toolbar {
    top: var(--s-3);
    gap: 0;
    padding: 4px;
    max-width: calc(100% - 20px);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }
  .au-toolbar::-webkit-scrollbar { display: none; }
  .au-tb-btn { width: 44px; height: 44px; flex: 0 0 auto; }
  .au-tb-sep { flex: 0 0 auto; }
  /* Tooltips would be clipped by the scroll container and aren't useful on
     touch — drop them on mobile. */
  .au-tb-btn[data-tip]::after { display: none; }

  /* On phones the toolbar spans nearly the full width, so the chip drops just
     BELOW it (still pinned to the right edge, top-left in RTL) where it stays
     fully visible and clear of the scrolling button row. */
  .au-validity { top: calc(var(--s-3) + 52px); right: 10px; }
  html[dir="rtl"] .au-validity { right: auto; left: 10px; }
  .au-validity-pop { width: min(72vw, 320px); max-width: none; }

  /* The gesture hint lifts above the full-width extend bar + warnings stack and
     hugs the left gutter (right in RTL). Wording already covers touch ("Tap an
     edge…" reads fine for the cut row). */
  .au-hint { left: 10px; bottom: calc(118px + env(safe-area-inset-bottom)); max-width: min(240px, calc(100vw - 24px)); }
  html[dir="rtl"] .au-hint { left: auto; right: 10px; }

  /* Inspector becomes a full-width bottom sheet, docked to the bottom of the
     stage. Its RESTING styles alone are always correct — closed slides off-screen
     via translateY, open clears it — so the panel lands in the right place with no
     dependence on transition/animation frames advancing. Height is fixed (no
     min()-height interpolation, which is unreliable across engines). */
  .au-inspector {
    position: absolute;
    left: 0; right: 0; bottom: 0; top: auto;
    width: auto; flex-basis: auto;
    height: min(70vh, 460px);
    border-left: 0; border-top: 1px solid var(--border);
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -12px 32px rgba(15,17,23,.18);
  }
  .au-inspector:not(.is-open) { transform: translateY(102%); pointer-events: none; }
  .au-inspector.is-open { width: auto; flex-basis: auto; transform: translateY(0); }
  .au-insp-body { padding-bottom: max(28px, env(safe-area-inset-bottom)); }

  /* JSON sheet: a full-width bottom sheet with a fixed height that slides via
     transform. The resting states alone are correct (closed off-screen, open at
     0) so it can't get stuck collapsed the way an animated 0→auto height can.
     Single column, stacked. */
  .au-json-drawer {
    height: min(64%, 460px);
    transform: translateY(102%);
    transition: none;
  }
  .au-json-drawer.is-open { height: min(64%, 460px); transform: translateY(0); }
  .au-json-cols { grid-template-columns: 1fr; grid-template-rows: 1fr 1fr; }

  /* Templates drawer becomes a full-width bottom sheet, matching the other
     panels. It slides up from the bottom (closed off-screen, open at 0) so it
     never gets stuck the way an animated height can. RTL keeps the same vertical
     motion — no horizontal flip needed for a bottom sheet. */
  .au-templates-drawer {
    top: auto; left: 0; right: 0; bottom: 0;
    width: auto;
    height: min(82vh, 620px);
    border-left: 0; border-top: 1px solid var(--border);
    border-radius: 18px 18px 0 0;
    box-shadow: 0 -14px 36px -12px rgba(15, 17, 23, .32);
    transform: translateY(102%);
  }
  .au-templates-drawer.is-open { transform: translateY(0); }
  html[dir="rtl"] .au-templates-drawer {
    left: 0; right: 0; border-right: 0; border-top: 1px solid var(--border);
    box-shadow: 0 -14px 36px -12px rgba(15, 17, 23, .32);
    transform: translateY(102%);
  }
  html[dir="rtl"] .au-templates-drawer.is-open { transform: translateY(0); }
  .au-templates-body { padding-bottom: max(24px, env(safe-area-inset-bottom)); }

  /* AI-extend bar + warnings span the full width (minus a small gutter) and
     respect the home-indicator safe area. */
  .au-extend {
    width: calc(100% - 20px);
    left: 50%;
    bottom: max(var(--s-3), env(safe-area-inset-bottom));
    gap: 6px;
    padding: 6px 6px 6px 12px;
  }
  .au-extend-cost { display: none; }
  .au-warnings { width: calc(100% - 20px); bottom: calc(64px + env(safe-area-inset-bottom)); }

  /* Modals dock to the bottom as full-width sheets instead of floating centred.
     We drop the transform-based entrance (animation: none) so the sheet always
     rests flush at the bottom — the backdrop still fades in via au-fade. */
  .au-overlay { align-items: flex-end; padding: 0; }
  .au-modal {
    width: 100%;
    max-height: 86vh;
    border-radius: 18px 18px 0 0;
    animation: none;
  }
  .au-install-body, .au-open-list, .au-log-body { padding-bottom: max(22px, env(safe-area-inset-bottom)); }
}

/* ── Setup checklist + deploy (How-to-install modal) ─────────────────────────── */
.au-setup, .au-deploy {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.au-setup-title { margin: 0 0 4px; font-size: 14px; font-weight: 700; }
.au-setup-sub { margin: 0 0 10px; font-size: 12.5px; color: var(--fg-muted); }
.au-setup-rows { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; }
.au-setup-row { display: flex; align-items: center; gap: 10px; }
.au-setup-token {
  flex: 0 0 auto;
  min-width: 150px;
  font: 11.5px/1.4 var(--font-mono, ui-monospace, monospace);
  color: var(--dp-blue);
  background: var(--dp-blue-soft);
  padding: 3px 8px;
  border-radius: 7px;
}
.au-setup-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 34px;
  padding: 0 10px;
  font-size: 13px;
  color: var(--fg);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 9px;
}
.au-setup-input:focus { outline: none; border-color: var(--dp-blue); box-shadow: 0 0 0 3px var(--dp-blue-ring); }
.au-setup-apply, .au-deploy-btn {
  height: 34px; padding: 0 14px;
  font-size: 13px; font-weight: 600;
  color: #fff; background: var(--dp-blue);
  border: 0; border-radius: 9px; cursor: pointer;
}
.au-setup-apply:hover, .au-deploy-btn:hover { filter: brightness(1.06); }
.au-setup-apply:disabled, .au-deploy-btn:disabled { opacity: .6; cursor: default; }
.au-deploy-row { display: flex; gap: 8px; flex-wrap: wrap; }
.au-deploy-row .au-setup-input { flex: 1 1 200px; }
.au-deploy-result { margin-top: 10px; font-size: 12.5px; color: var(--fg-muted); }
.au-deploy-result a { color: var(--dp-blue); font-weight: 600; }
.au-install-est, .au-validity-est {
  margin-top: 10px;
  font-size: 12px;
  color: var(--fg-muted);
  background: var(--surface-2, rgba(127,127,127,.07));
  padding: 7px 10px;
  border-radius: 8px;
}
.au-validity-est { margin-top: 4px; }

/* Import row in the Open dialog. */
.au-open-import { padding: 10px 16px 0; }
.au-open-import-btn { width: 100%; }

/* Multi-turn extend memory chip. */
.au-extend-memory {
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 700;
  color: var(--dp-blue);
  background: var(--dp-blue-soft);
  padding: 2px 8px;
  border-radius: 999px;
  cursor: default;
}

/* ── Dry run (simulate) ──────────────────────────────────────────────────────
   The sim panel is a floating log (bottom-left) that fills as the run walks the
   canvas; node marks show the active / visited steps. Sample data only — the
   panel header says so, and nothing real is ever called. */
.au-sim-panel {
  position: fixed;
  left: 14px;
  bottom: calc(76px + env(safe-area-inset-bottom));
  width: min(360px, calc(100vw - 28px));
  max-height: min(46vh, 420px);
  display: none;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 18px 44px -18px rgba(15, 17, 23, .4);
  overflow: hidden;
  z-index: 60;
}
.au-sim-panel.is-open { display: flex; }
.au-sim-head {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 10px 10px 14px;
  border-bottom: 1px solid var(--border);
}
.au-sim-title { font-weight: 700; font-size: 13.5px; }
.au-sim-note { font-size: 11.5px; color: var(--fg-muted); margin-inline-end: auto; }
.au-sim-list { overflow-y: auto; padding: 8px 10px 10px; display: flex; flex-direction: column; gap: 6px; }
.au-sim-row {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 7px 9px;
  animation: au-sim-in .18s ease both;
}
@keyframes au-sim-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.au-sim-row-head { display: flex; align-items: center; gap: 7px; min-width: 0; }
.au-sim-idx {
  flex: 0 0 auto; width: 18px; height: 18px; border-radius: 50%;
  background: var(--dp-blue-soft); color: var(--dp-blue);
  font-size: 10.5px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
}
.au-sim-label { font-size: 12.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.au-sim-branch {
  flex: 0 0 auto; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  color: var(--dp-blue); background: var(--dp-blue-soft);
  padding: 1px 6px; border-radius: 999px;
}
.au-sim-svc { flex: 0 0 auto; margin-inline-start: auto; font-size: 10.5px; color: var(--fg-muted); }
.au-sim-sample {
  margin: 6px 0 0; padding: 5px 7px;
  font: 11px/1.5 var(--font-mono, ui-monospace, monospace);
  color: var(--fg-muted);
  background: var(--surface-2, rgba(127,127,127,.07));
  border-radius: 7px;
  white-space: pre-wrap; word-break: break-word;
  max-height: 72px; overflow: hidden;
}
.au-sim-done { font-size: 12px; color: var(--fg-muted); padding: 4px 2px 0; }

/* Canvas marks: the executing node glows blue, finished steps keep a calm
   green edge until the run is closed. */
.au-node.is-sim-active {
  box-shadow: 0 0 0 3px var(--dp-blue-ring), 0 10px 26px -12px rgba(37, 99, 235, .45);
  border-color: var(--dp-blue);
}
.au-node.is-sim-visited { border-color: #34a06d; }
.au-node.is-sim-visited::before { background: #34a06d; }

/* Tighter pass for small phones. */
@media (max-width: 480px) {
  .au-title-icon { width: 30px; height: 30px; }
  .au-title-icon svg { width: 17px; height: 17px; }
  .au-title-input { font-size: 16px; }
  /* Stack prompt above Generate so the textarea gets full width; Generate is a
     comfortable full-width tap target underneath. Here the field and Generate
     are stacked vertically (not a horizontal row), so there's no sibling to
     protect from horizontal drift — instead of floating the panel DOWN over the
     Generate button beneath it, we let the textarea grow in normal flow and push
     the full-width button down. That's the natural mobile behaviour and keeps
     Generate fully tappable. The fixed-slot/float trick is reserved for the
     wider bands where the controls actually share a row. */
  .au-prompt-field { flex: 1 1 100%; height: auto; }
  /* Back to in-flow: width:100% is required here because, unlike the absolute
     collapsed/expanded states, a static textarea has no left/right anchor to
     stretch it and would otherwise shrink to its intrinsic `cols` width. */
  .au-prompt { position: static; width: 100%; height: auto; min-height: var(--au-prompt-h, 44px); }
  .au-prompt-field.is-expanded .au-prompt {
    /* Grow in flow; keep the focus ring but drop the heavy floating shadow and
       raised stacking since it's not overlaying anything here. */
    z-index: auto;
    box-shadow: 0 0 0 3px var(--dp-blue-ring);
    border-radius: var(--r-input);
  }
  .au-generate { flex: 1 1 100%; justify-content: center; }
  .au-seg { padding: 0 10px; min-height: 44px; }
  .au-seg-label { white-space: nowrap; }
  /* On the smallest phones the gesture hint would crowd the canvas next to the
     extend bar — hide it. The gestures are still discoverable, and the chip /
     toolbar remain. */
  .au-hint { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
  /* Fully silence the looping ambience (no travelling current, no breathing ring). */
  .au-edge-flow { animation: none !important; opacity: 0 !important; }
  .au-sub-flow { animation: none !important; opacity: 0 !important; }
  .au-node.is-selected::after { animation: none !important; opacity: 0 !important; }
  .au-node:hover { transform: none !important; }
}

@media (pointer: coarse), (max-width: 720px) {
  .au-title-input,
  .au-icon-btn,
  .au-chip-btn,
  .au-extend-btn,
  .au-json-tab {
    min-width: 40px;
    min-height: 40px;
    touch-action: manipulation;
  }
}

/* RTL: the site keeps the page LTR (i18n product decision), but if a future
   change flips dir we keep panels/modals sensible. The canvas always reads
   left → right because automation flows are inherently directional. */
html[dir="rtl"] .au-inspector { border-left: 0; border-right: 1px solid var(--border); }
html[dir="rtl"] .au-node::before { left: auto; right: 0; border-radius: 3px 0 0 3px; }
html[dir="rtl"] .au-canvas { direction: ltr; }

/* ── Fix-errors banner ─────────────────────────────────────────────────────────────
 * A prominent, persistent panel pinned just under the floating toolbar. It lists
 * every validity issue with a Fix button: structural issues fix instantly & free
 * (green), AI issues repair via the model and cost credits (blue, .is-ai). The
 * same issues are mirrored as per-node "Fix this" badges (.au-node-issue). Shown
 * only when the loaded graph has issues. */
.au-errors {
  position: absolute;
  top: calc(var(--s-4) + 52px);
  left: 50%;
  transform: translateX(-50%) translateY(-6px);
  z-index: 16;
  width: min(620px, calc(100% - 32px));
  max-height: min(46%, 360px);
  display: flex; flex-direction: column;
  border: 1px solid color-mix(in srgb, var(--dp-orange) 45%, var(--border));
  border-radius: 14px;
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter: blur(12px) saturate(1.2);
  box-shadow: var(--shadow-pop);
  opacity: 0; pointer-events: none;
  overflow: hidden;
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.au-errors.is-open { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
.au-errors.is-busy { pointer-events: none; opacity: .65; }
.au-errors-inner { display: flex; flex-direction: column; min-height: 0; }
.au-errors-head {
  display: flex; align-items: center; gap: 9px;
  padding: 10px 10px 10px 13px;
  border-bottom: 1px solid var(--border);
}
.au-errors-icon { display: inline-flex; color: var(--dp-orange); }
.au-errors-icon svg { width: 16px; height: 16px; }
.au-errors-title { font: 800 12.5px/1 var(--font-body); color: var(--fg); flex: 1 1 auto; }
.au-errors-fixall {
  border: none; border-radius: var(--r-pill);
  padding: 7px 14px;
  background: var(--dp-orange); color: #fff;
  font: 800 12px/1 var(--font-body); cursor: pointer;
  transition: filter var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.au-errors-fixall:hover { filter: brightness(1.06); }
.au-errors-fixall:active { transform: translateY(1px); }
.au-errors-close {
  width: 26px; height: 26px; flex: 0 0 auto;
  display: inline-grid; place-items: center;
  border: none; border-radius: 50%;
  background: transparent; color: var(--fg-subtle); cursor: pointer;
}
.au-errors-close svg { width: 13px; height: 13px; }
.au-errors-close:hover { background: var(--surface-2); color: var(--fg); }
.au-errors-list { overflow-y: auto; padding: 6px; display: flex; flex-direction: column; gap: 4px; }
.au-errors-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 6px 6px 10px;
  border-radius: 9px;
  background: var(--surface-2);
}
.au-errors-row.au-errors-error { box-shadow: inset 3px 0 0 var(--dp-orange); }
.au-errors-msg {
  flex: 1 1 auto; text-align: left;
  border: none; background: transparent; cursor: pointer;
  font: 500 12px/1.4 var(--font-body); color: var(--fg);
  padding: 2px 0;
}
.au-errors-msg:hover { color: var(--dp-blue); text-decoration: underline; }
html[dir="rtl"] .au-errors-msg { text-align: right; }
.au-errors-fix {
  flex: 0 0 auto;
  border: 1px solid color-mix(in srgb, #16a34a 45%, var(--border));
  border-radius: var(--r-pill);
  padding: 5px 12px;
  background: color-mix(in srgb, #16a34a 12%, var(--surface));
  color: #15803d;
  font: 800 11px/1 var(--font-body); cursor: pointer;
  white-space: nowrap;
  transition: filter var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.au-errors-fix:hover { filter: brightness(1.04); }
.au-errors-fix:active { transform: translateY(1px); }
.au-errors-fix.is-ai {
  border-color: color-mix(in srgb, var(--dp-blue) 45%, var(--border));
  background: color-mix(in srgb, var(--dp-blue) 12%, var(--surface));
  color: var(--dp-blue);
}

/* Per-node "Fix this error" badge + outline on the offending card. */
.au-node.has-issue {
  border-color: color-mix(in srgb, var(--dp-orange) 60%, var(--au-accent));
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--dp-orange) 35%, transparent), var(--shadow-card);
}
.au-node-issue {
  position: absolute; top: -9px; left: -9px; z-index: 6;
  width: 22px; height: 22px; padding: 0;
  display: inline-grid; place-items: center;
  border: 2px solid var(--surface);
  border-radius: 50%;
  background: var(--dp-orange); color: #fff;
  cursor: pointer;
  box-shadow: var(--shadow-card);
  transition: transform var(--dur-fast) var(--ease), filter var(--dur-fast) var(--ease);
}
.au-node-issue:hover { transform: scale(1.12); filter: brightness(1.05); }
html[dir="rtl"] .au-node-issue { left: auto; right: -9px; }

@media (prefers-reduced-motion: reduce) {
  .au-errors { transition: none; }
}

/* ── Upload your automation (import entry) ─────────────────────────────────────── */
.au-upload-cta {
  display: inline-flex; align-items: center; gap: 9px;
  margin-top: var(--s-3);
  padding: 10px 18px;
  border: 1px solid color-mix(in srgb, var(--dp-orange) 32%, var(--border));
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--fg);
  font: 700 13px/1 var(--font-body);
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.au-upload-cta:hover { border-color: var(--dp-orange); transform: translateY(-2px); box-shadow: var(--shadow-card); }
.au-upload-cta:active { transform: translateY(0); }
.au-upload-cta-ico { display: inline-flex; color: var(--dp-orange); }
.au-upload-cta-ico svg { width: 17px; height: 17px; }
.au-upload-hint { margin: 10px auto 0; max-width: 440px; color: var(--fg-subtle); font: 500 12px/1.5 var(--font-body); }

/* Drag-and-drop affordance: a dashed overlay when a file is dragged onto the stage. */
.au-stage.is-drop::after {
  content: 'Drop your workflow JSON to import';
  position: absolute; inset: 10px; z-index: 40;
  display: grid; place-items: center;
  border: 2px dashed var(--dp-blue);
  border-radius: 16px;
  background: color-mix(in srgb, var(--dp-blue) 10%, var(--surface));
  color: var(--dp-blue);
  font: 800 15px/1 var(--font-body);
  pointer-events: none;
}

/* ===== Automations identity v26 — Operations / Blueprint console =====
 * The personality layer. Everything above sets structure + the unified amber
 * accent; this block (later → wins) gives the page its instrument-panel voice:
 * a squared tactile RUN key, a thin amber status rail across the top bar, a
 * blueprint dot-grid canvas, and a schematic empty state whose examples read as
 * monospace technical tags. CSS-only — no DOM the JS reads is touched; only new
 * decoration + pseudo-elements + re-skins of existing selectors. Token-safe so
 * light / dark / RTL all hold. */

/* ── RUN key — the Generate button reads like a physical hardware key ──────────
 * Squared (not the shared rounded glow capsule), with a faint top inner highlight
 * and a darker amber bottom edge so it sits proud of the bar; pressing it depresses
 * firmly. The mono cost-pill is kept (it's part of the instrument read). */
.au-body .au-generate {
  border-radius: 9px;
  /* Dark espresso ink on amber — the high-contrast (~9:1) reading conventional
     for amber/caution keys, and it makes the key feel physical. White on amber
     was ~2:1 and failed WCAG AA. The svg + cost pill inherit this via currentColor. */
  color: #2a1c02;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 16%, var(--au-accent)) 0%,
      var(--au-accent-strong) 52%,
      color-mix(in srgb, #000 8%, var(--au-accent-strong)) 100%);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #fff 38%, transparent),
    inset 0 -2px 0 color-mix(in srgb, #000 22%, transparent),
    0 3px 0 color-mix(in srgb, #000 30%, var(--au-accent-strong)),
    0 6px 14px var(--au-accent-ring);
  letter-spacing: .01em;
  transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur) var(--ease);
}
.au-body .au-generate:hover {
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 20%, var(--au-accent)) 0%,
      var(--au-accent) 52%,
      color-mix(in srgb, #000 6%, var(--au-accent-strong)) 100%);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #fff 42%, transparent),
    inset 0 -2px 0 color-mix(in srgb, #000 22%, transparent),
    0 3px 0 color-mix(in srgb, #000 30%, var(--au-accent-strong)),
    0 8px 18px var(--au-accent-ring);
}
/* Press: the key travels down onto its bottom edge — the 3px stand-off collapses. */
.au-body .au-generate:active {
  transform: translateY(2px);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #fff 28%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #000 18%, transparent),
    0 1px 0 color-mix(in srgb, #000 30%, var(--au-accent-strong)),
    0 3px 8px var(--au-accent-ring);
}
.au-body .au-generate:disabled { transform: none; }
/* Tighten the cost pill into a square-cornered mono readout to match the key. */
.au-body .au-cost-pill {
  border-radius: 5px;
  /* A pale LCD readout chip — crisp dark digits (inherited espresso ink) on a
     light face, so the credit count stays legible against the amber key. */
  background: color-mix(in srgb, #fff 80%, var(--au-accent));
  padding: 2px 7px;
}

/* ── Status rail — a control-panel cue across the top bar ──────────────────────
 * A hairline amber rail along the bar's top edge, plus a small live status dot
 * beside the title that breathes (silenced under reduced-motion). Reads as a
 * powered-on console without adding chrome height. */
.au-body .au-topbar {
  border-top: 2px solid var(--au-accent-strong);
  background-image: linear-gradient(180deg, var(--au-accent-soft), transparent 14px);
}
.au-body .au-title-row { position: relative; }
.au-body .au-title-icon { position: relative; }
.au-body .au-title-icon::after {
  content: '';
  position: absolute; top: -3px; right: -3px;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--au-accent);
  border: 1.5px solid var(--surface);
  box-shadow: 0 0 0 0 var(--au-accent-ring);
  animation: au-status-pulse 2.4s var(--ease) infinite;
}
html[dir="rtl"] .au-body .au-title-icon::after { right: auto; left: -3px; }
@keyframes au-status-pulse {
  0%   { box-shadow: 0 0 0 0 var(--au-accent-ring); }
  70%  { box-shadow: 0 0 0 6px color-mix(in srgb, var(--au-accent) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--au-accent) 0%, transparent); }
}

/* ── Mono technical micro-labels ──────────────────────────────────────────────
 * The small section labels already use Geist Mono in places (JSON cols, port
 * tags, node kind). Lift the platform segment labels into the same uppercase
 * mono register so the control row reads as instrument labels, not chrome. */
.au-body .au-seg-label {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.au-body .au-seg.is-active .au-seg-label { font-weight: 500; }

/* ── Blueprint canvas — enrich the dot grid into a faint schematic ────────────
 * Keep --au-canvas-bg + the existing dual dot grid (defined on .au-canvas), and
 * layer a faint crosshatch of fine rules over it so the surface reads like
 * engineering paper. Lines are derived from the grid token so they auto-tune in
 * dark mode and never compete with the nodes. */
.au-body .au-canvas {
  background-image:
    radial-gradient(var(--au-grid-strong) 1.3px, transparent 1.3px),
    radial-gradient(var(--au-grid) 1px, transparent 1px),
    linear-gradient(to right, var(--au-grid) 1px, transparent 1px),
    linear-gradient(to bottom, var(--au-grid) 1px, transparent 1px);
  background-size:
    120px 120px,
    24px 24px,
    120px 120px,
    120px 120px;
}

/* ── Schematic empty state ────────────────────────────────────────────────────
 * The node glyph sits framed in a faint blueprint plate; the radial wash warms to
 * amber; the example items become squared monospace technical TAGS that light up
 * amber on hover. Copy text is untouched — only its styling reads as instrument
 * panel. */
.au-body .au-empty {
  background:
    radial-gradient(circle at 50% 28%, var(--au-accent-soft), transparent 55%),
    var(--au-canvas-bg);
  background-image:
    radial-gradient(circle at 50% 28%, var(--au-accent-soft), transparent 55%),
    linear-gradient(to right, var(--au-grid) 1px, transparent 1px),
    linear-gradient(to bottom, var(--au-grid) 1px, transparent 1px);
  background-size: auto, 24px 24px, 24px 24px;
}
/* Frame the node glyph in a blueprint plate with corner ticks. */
.au-body .au-empty-art {
  border-radius: 16px;
  position: relative;
  background:
    linear-gradient(135deg, var(--au-accent-strong), var(--au-accent));
}
.au-body .au-empty-art::before {
  content: '';
  position: absolute; inset: -10px;
  border-radius: 20px;
  border: 1px dashed var(--au-accent-ring);
  pointer-events: none;
}
.au-body .au-empty h2 { letter-spacing: -0.03em; }
/* Examples → technical tags. The ✦ bullet becomes a mono caret prefix. */
.au-body .au-examples { gap: 7px; }
.au-body .au-example-chip {
  border-radius: 6px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  font: 500 12.5px/1.4 var(--font-mono);
  letter-spacing: -0.005em;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--au-accent) 0%, transparent);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), background var(--dur) var(--ease);
}
.au-body .au-example-chip::before {
  content: '›_';
  color: var(--au-accent-strong);
  font-family: var(--font-mono);
  font-weight: 600;
  margin-right: 9px;
  opacity: .85;
}
.au-body .au-example-chip:hover {
  border-color: var(--au-accent);
  transform: translateY(-1px);
  background: var(--au-accent-soft);
  box-shadow: inset 0 0 0 1px var(--au-accent-ring), var(--shadow-sm);
}
/* Templates CTA → amber, squared a touch tighter to match the console language. */
.au-body .au-templates-cta {
  border-color: color-mix(in srgb, var(--au-accent) 38%, var(--border));
  background: linear-gradient(135deg, var(--surface), var(--au-accent-soft));
  color: var(--au-accent-strong);
}
.au-body .au-templates-cta:hover { border-color: var(--au-accent); }

/* ── Misc chrome accents that still read blue → amber ─────────────────────────
 * The example/template hover washes, node "new" pop ring, drop affordance and a
 * few inspector touchpoints used --dp-blue purely as the builder accent. Re-skin
 * to amber so nothing reads split-brain. (Genuinely-blue category nodes keep
 * their inline --au-accent; this only governs the page's own chrome.) */
.au-body .au-tpl-card:hover {
  border-color: var(--au-accent);
  background: linear-gradient(135deg, var(--surface), var(--au-accent-soft));
}
.au-body .au-tpl-card:focus-visible { outline-color: var(--au-accent); }
.au-body .au-tpl-card:hover .au-tpl-card-badge { border-color: color-mix(in srgb, var(--au-accent) 40%, var(--border)); color: var(--au-accent-strong); }
.au-body .au-tpl-card:hover .au-tpl-card-all { color: var(--au-accent-strong); }
.au-body .au-node-new { animation: au-node-pop-amber 1.5s var(--ease); }
@keyframes au-node-pop-amber {
  0%   { box-shadow: 0 0 0 0 var(--au-accent-ring); }
  20%  { box-shadow: 0 0 0 8px var(--au-accent-ring); }
  100% { box-shadow: var(--shadow-card); }
}
.au-body .au-stage.is-drop::after {
  border-color: var(--au-accent);
  background: color-mix(in srgb, var(--au-accent) 10%, var(--surface));
  color: var(--au-accent-strong);
}

/* Templates drawer + install/setup/deploy + sim/log + gesture hint + connect
 * affordances — every remaining surface where --dp-blue was used purely as the
 * builder's accent, re-skinned to amber. Functional canvas wires (the live
 * "current" flow) stay as-is; here we only retint the chrome a user reads as the
 * builder's brand. */
.au-body .au-templates-cta:active { transform: translateY(0); }
.au-body .au-tpl-card:focus-visible { outline-color: var(--au-accent); }
.au-body .au-mini-btn,
.au-body .au-deploy-result a,
.au-body .au-extend-memory { color: var(--au-accent-strong); }
.au-body .au-extend-memory { background: var(--au-accent-soft); }
.au-body .au-install-steps li::marker { color: var(--au-accent-strong); }
.au-body .au-install-banner {
  border-color: color-mix(in srgb, var(--au-accent) 40%, transparent);
  background: var(--au-accent-soft);
}
.au-body .au-setup-token { color: var(--au-accent-strong); background: var(--au-accent-soft); }
.au-body .au-setup-input:focus { border-color: var(--au-accent); box-shadow: 0 0 0 3px var(--au-accent-ring); }
.au-body .au-setup-apply,
.au-body .au-deploy-btn { background: var(--au-accent-strong); }
.au-body .au-setup-apply:hover,
.au-body .au-deploy-btn:hover { background: var(--au-accent); filter: none; }
/* Dry-run / sim panel reads amber-active (the running step). */
.au-body .au-sim-idx,
.au-body .au-sim-branch { background: var(--au-accent-soft); color: var(--au-accent-strong); }
.au-body .au-node.is-sim-active {
  box-shadow: 0 0 0 3px var(--au-accent-ring), 0 10px 26px -12px color-mix(in srgb, var(--au-accent-strong) 45%, transparent);
  border-color: var(--au-accent);
}
/* Gesture-hint card + the connect wire/dot affordances follow the accent so the
 * "drag to connect" demo reads as the same amber current the canvas uses. */
.au-body .au-hint-spark { color: var(--au-accent-strong); }
.au-body .au-hint-card { fill: var(--au-accent-soft); stroke: var(--au-accent); }
.au-body .au-hint-wire { stroke: var(--au-accent); }
.au-body .au-hint-dot { stroke: var(--au-accent); }
.au-body .au-port-out:hover { background: var(--au-accent); border-color: var(--au-accent); }
.au-body .au-node.is-drop-target { border-color: var(--au-accent); box-shadow: 0 0 0 2px var(--au-accent), var(--shadow-card-hover); }
/* errorPolicy badge + AI-fix button: amber so the builder's own affordances match. */
.au-body .au-node-badge { border-color: color-mix(in srgb, var(--au-accent) 45%, var(--border)); color: var(--au-accent-strong); }
.au-body .au-errors-msg:hover { color: var(--au-accent-strong); }
.au-body .au-errors-fix.is-ai {
  border-color: color-mix(in srgb, var(--au-accent) 45%, var(--border));
  background: color-mix(in srgb, var(--au-accent) 12%, var(--surface));
  color: var(--au-accent-strong);
}
/* "Building your automation…" skeleton spinner — the most prominent moment of the
 * flow. Its base rule still spun --dp-blue against the otherwise all-amber console;
 * re-point the lit arc to the accent so the generate skeleton reads single-brand. */
.au-body .au-skel-spinner { border-top-color: var(--au-accent); }

/* Reduced motion: silence the status dot's pulse (it lands solid). */
@media (prefers-reduced-motion: reduce) {
  .au-body .au-title-icon::after { animation: none !important; }
}
