/*
 * Production stylesheet for editor-v7. Merged on 2026-05-13 from
 * static/css/editor-mockup-v2.css (base) + the production overlay rules
 * (originally in this file). Mockup file is the design iteration surface
 * per CLAUDE.md; production owns this file independently. Re-port
 * deliberately when mockup changes.
 *
 * Section 1: Base styles (ported from editor-mockup-v2.css)
 * Section 2: Production overlay rules
 */

/* =========================================================== */
/* Section 1 — Base styles (ported from editor-mockup-v2.css)  */
/* =========================================================== */

/* ═══════════════════════════════════════════════════════════ */
/* Editor mockup — revised, decluttered                         */
/* ═══════════════════════════════════════════════════════════ */

/* Design tokens (colors, typography, spacing, radii) live in
 * static/css/design-tokens.css, generated from DESIGN.md via
 * `bun run design:export`. This file only defines implementation
 * variables that aren't part of the design system itself. */

:root {
  /* Derived tokens — opacity-adjusted variants of design colors.
   * color-mix() evaluates against whatever --accent / --wire resolves to
   * in the active theme, so these tints adapt automatically when the
   * user cycles Darkest → Dark → Medium → Light. */
  --accent-dim: color-mix(in oklab, var(--accent) 12%, transparent);
  --accent-tint-subtle: color-mix(in oklab, var(--accent) 4%, transparent);
  --accent-tint: color-mix(in oklab, var(--accent) 6%, transparent);
  --accent-ring: color-mix(in oklab, var(--accent) 10%, transparent);
  --accent-pill: color-mix(in oklab, var(--accent) 14%, transparent);
  --accent-border: color-mix(in oklab, var(--accent) 30%, transparent);

  --wire-dim: color-mix(in oklab, var(--wire) 45%, transparent);
  --wire-tint-subtle: color-mix(in oklab, var(--wire) 5%, transparent);
  --wire-tint: color-mix(in oklab, var(--wire) 10%, transparent);
  --wire-pill: color-mix(in oklab, var(--wire) 12%, transparent);

  /* Layout — editor-specific chrome dimensions */
  --rail-w: 56px;
  --topbar-h: 48px;

  /* Motion — not part of the design token spec */
  --dur-fast: 0.12s;
  --dur: 0.2s;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

body {
  font-family: var(--font-ui);
  background: var(--bg-root);
  color: var(--text-primary);
  -webkit-font-smoothing: antialiased;
  display: flex;
  overflow: hidden;
}

button {
  font-family: inherit;
  border: none;
  background: none;
  color: inherit;
  cursor: pointer;
}

/* Visually hidden but exposed to screen readers. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Keyboard focus ring — visible on every theme, never for mouse users.
 * Uses the active theme's accent so it stays on-brand Darkest → Light. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Remove the ring when the element already carries its own focus style
 * (inline rename, palette input, drawer search). */
.node-title:focus-visible,
.palette-input:focus-visible,
.drawer-search input:focus-visible,
.prompt-input:focus-visible {
  outline: none;
}

/* ═══════════════════════════════════════════════════════════ */
/* Icon rail                                                    */
/* ═══════════════════════════════════════════════════════════ */

.rail {
  width: var(--rail-w);
  min-width: var(--rail-w);
  background: var(--bg-rail);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 12px 0 14px;
  height: 100vh;
}

.rail-logo {
  width: 36px;
  height: 36px;
  border-radius: 9px;
  background: linear-gradient(
    140deg,
    var(--accent-bright) 0%,
    var(--accent) 100%
  );
  display: grid;
  place-items: center;
  color: var(--accent-ink);
  font-weight: 700;
  font-size: 15px;
  text-decoration: none;
  margin-bottom: 18px;
  box-shadow: 0 2px 10px rgba(202, 138, 4, 0.25);
}

.rail-logo-mark {
  font-family: var(--font-ui);
  letter-spacing: -0.02em;
}

.rail-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  align-items: center;
}

.rail-btn {
  width: 38px;
  height: 38px;
  border-radius: 9px;
  display: grid;
  place-items: center;
  color: var(--text-muted);
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
  position: relative;
}

.rail-btn:hover {
  background: rgba(255, 255, 255, 0.04);
  color: var(--text-primary);
}

.rail-btn.is-active {
  background: var(--accent-dim);
  color: var(--accent-bright);
}

.rail-btn.is-active::before {
  content: "";
  position: absolute;
  left: -12px;
  top: 8px;
  bottom: 8px;
  width: 2px;
  border-radius: 2px;
  background: var(--accent-bright);
}

.rail-divider {
  width: 20px;
  height: 1px;
  background: var(--border);
  margin: 10px 0;
}

.rail-bottom {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: center;
}

.rail-avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--bg-elevated);
  border: 1px solid var(--border-accent);
  color: var(--text-secondary);
  font-size: 12px;
  font-weight: 600;
  display: grid;
  place-items: center;
}

.rail-avatar:hover {
  border-color: var(--accent);
  color: var(--text-primary);
}

/* ═══════════════════════════════════════════════════════════ */
/* Tooltips — portalled singleton (see editor-mockup.js)        */
/*                                                              */
/* A single #floating-tooltip element lives directly under      */
/* <body>. JS positions it with getBoundingClientRect() each    */
/* time a [data-tip] trigger is hovered/focused, so it escapes  */
/* every ancestor's overflow:hidden / clip-path / transform.    */
/* Same pattern Bootstrap uses (via Popper) and Radix/Headless  */
/* UI use (via Floating UI).                                    */
/*                                                              */
/* The declarative API on triggers stays the same:              */
/*   data-tip="Next page"      — tooltip text                   */
/*   data-tip-pos="top|bottom|left|right" — preferred placement */
/* Auto-flip handles viewport collisions.                       */
/* ═══════════════════════════════════════════════════════════ */

#floating-tooltip {
  position: fixed;
  top: 0;
  left: 0;
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-size: 11px;
  font-weight: 500;
  padding: 5px 9px;
  border-radius: 5px;
  border: 1px solid var(--border-accent);
  white-space: nowrap;
  pointer-events: none;
  z-index: 9999;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity var(--dur-fast);
}

#floating-tooltip.is-visible {
  opacity: 1;
}

/* ═══════════════════════════════════════════════════════════ */
/* Workspace layout                                             */
/* ═══════════════════════════════════════════════════════════ */

.workspace {
  flex: 1;
  height: 100vh;
  display: flex;
  flex-direction: column;
  position: relative;
  min-width: 0;
}

/* ═══════════════════════════════════════════════════════════ */
/* Top bar                                                      */
/* ═══════════════════════════════════════════════════════════ */

.topbar {
  height: var(--topbar-h);
  background: var(--bg-topbar);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: nowrap;
  gap: 12px;
  padding: 0 14px 0 10px;
  flex-shrink: 0;
  z-index: 10;
  min-width: 0;
}

.topbar-left {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  flex: 1 1 auto;
  overflow: hidden;
}

.back-btn {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: 7px;
  color: var(--text-muted);
  text-decoration: none;
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
}

.back-btn:hover {
  background: var(--bg-elevated);
  color: var(--text-primary);
}

.breadcrumb {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  min-width: 0;
  flex-wrap: nowrap;
  white-space: nowrap;
  overflow: hidden;
}

.breadcrumb-project {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: -0.01em;
  padding: 4px 8px 4px 8px;
  margin: 0 -2px;
  border-radius: 6px;
  cursor: pointer;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
}

.breadcrumb-project svg {
  flex-shrink: 0;
}

.breadcrumb-project:hover,
.breadcrumb-project[aria-expanded="true"] {
  background: var(--bg-elevated);
}

.breadcrumb-project svg {
  color: var(--text-muted);
  transition: transform var(--dur-fast);
}

.breadcrumb-project[aria-expanded="true"] svg {
  transform: rotate(180deg);
}

/* ═══════════════════════════════════════════════════════════ */
/* Project menu (dropdown from breadcrumb)                      */
/* ═══════════════════════════════════════════════════════════ */

.topbar-left {
  position: relative;
}

.project-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 40px;
  min-width: 240px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-accent);
  border-radius: 10px;
  box-shadow: var(--shadow-modal);
  padding: 6px;
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.pm-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
  border-radius: 6px;
  font-size: 13px;
  color: var(--text-secondary);
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
  text-align: left;
  width: 100%;
}

.pm-item:hover {
  background: var(--bg-card);
  color: var(--text-primary);
}

.pm-item svg {
  color: var(--text-muted);
  flex-shrink: 0;
}

.pm-item:hover svg {
  color: var(--text-secondary);
}

.pm-item span {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
}

.pm-item kbd {
  font-family: var(--font-mono);
  font-size: 10px;
  padding: 1px 5px;
  background: var(--bg-rail);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text-muted);
}

.pm-item--danger {
  color: #f87171;
}

.pm-item--danger svg {
  color: #f87171;
}

.pm-item--danger:hover {
  background: rgba(239, 68, 68, 0.1);
  color: #fca5a5;
}

.pm-item--danger:hover svg {
  color: #fca5a5;
}

.pm-divider {
  height: 1px;
  background: var(--border);
  margin: 4px -2px;
}

.breadcrumb-sep {
  color: var(--text-dim);
  flex-shrink: 0;
}

.breadcrumb-meta {
  color: var(--text-muted);
  font-size: 12px;
  font-family: var(--font-mono);
  flex-shrink: 0;
}

.status-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ready);
  box-shadow: 0 0 6px rgba(92, 184, 92, 0.6);
  margin-left: 4px;
  flex-shrink: 0;
}

/* Save indicator — Lucide icon-driven, three states (saving / saved /
 * error). Replaces .status-dot for the topbar's persist signal. */
.save-indicator {
  display: inline-grid;
  place-items: center;
  margin-left: 6px;
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  color: var(--text-muted);
}

.save-indicator--saving {
  color: var(--text-muted);
  animation: save-spin 0.9s linear infinite;
}

.save-indicator--saved {
  color: var(--ready);
}

.save-indicator--error {
  color: var(--err, #ef4444);
}

@keyframes save-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Transient overlay banner — used for project-forked, etc.
 * Bottom-anchored, self-dismissing. */
.editor-banner {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 14px;
  border-radius: 10px;
  border: 1px solid var(--border, #2a2a2a);
  background: var(--bg-elevated, #1a1a1a);
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.6);
  z-index: 200;
  font-size: 13px;
  color: var(--text, #ddd);
  animation: editor-banner-rise 200ms ease-out;
}

.editor-banner-message {
  flex: 1 1 auto;
}

.editor-banner-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}

.editor-banner-undo {
  padding: 4px 10px;
  border-radius: 6px;
  border: 1px solid var(--border, #2a2a2a);
  background: transparent;
  color: var(--text, #ddd);
  font-size: 12px;
  cursor: pointer;
}

.editor-banner-undo:hover {
  background: var(--bg-hover, #222);
}

.editor-banner-close {
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted, #888);
  border: 0;
  cursor: pointer;
}

@keyframes editor-banner-rise {
  from {
    opacity: 0;
    transform: translate(-50%, 12px);
  }
  to {
    opacity: 1;
    transform: translate(-50%, 0);
  }
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

.tb-icon {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: 7px;
  color: var(--text-muted);
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
}

.tb-icon:hover {
  background: var(--bg-elevated);
  color: var(--text-primary);
}

.tb-divider {
  width: 1px;
  height: 18px;
  background: var(--border-accent);
  margin: 0 6px;
}

.tb-btn {
  font-size: 12.5px;
  font-weight: 500;
  padding: 6px 12px;
  border-radius: 7px;
  color: var(--text-secondary);
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
}

.tb-btn:hover {
  background: var(--bg-elevated);
  color: var(--text-primary);
}

.tb-btn.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
}

.tb-btn.btn-primary:hover {
  background: var(--accent-bright);
}

/* ═══════════════════════════════════════════════════════════ */
/* Canvas                                                       */
/* ═══════════════════════════════════════════════════════════ */

/* ADR-010 CANVAS-002: .canvas is the fixed viewport; .canvas-content is
 * the transformed world layer hosting every node and the wire SVG. */
.canvas {
  flex: 1;
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(circle, rgba(255, 255, 255, 0.025) 1px, transparent 1px),
    var(--bg-canvas);
  background-size: 24px 24px;
  background-position: 0 0;
  /* Animate the background to follow pan/zoom — keeps the dot grid
   * locked to world coords instead of sliding under the cards.
   * --pan-x / --pan-y / --zoom are written by viewport-controller. */
  background-position: var(--pan-x, 0) var(--pan-y, 0);
}

.canvas-content {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  transform-origin: 0 0;
  transform: translate(var(--pan-x, 0px), var(--pan-y, 0px))
    scale(var(--zoom, 1));
  will-change: transform;
}

.wire-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  /* World-space SVG: large enough to host wires far from the origin
   * without clipping. overflow:visible lets paths extend past these
   * bounds anyway. */
  width: 1px;
  height: 1px;
  overflow: visible;
}

.wire {
  fill: none;
  stroke: var(--wire);
  stroke-width: 1.5;
  opacity: 0.55;
  filter: drop-shadow(0 0 3px rgba(34, 211, 238, 0.35));
}

/* Per-composer wire stroke colors. Default .wire is cyan (Scene). */
.wire--character {
  stroke: var(--type-character);
  filter: drop-shadow(0 0 3px rgba(202, 138, 4, 0.35));
}

.wire--scene {
  stroke: var(--type-scene);
}

.wire--place {
  stroke: var(--type-place);
  filter: drop-shadow(0 0 3px rgba(45, 212, 191, 0.35));
}

.wire--object {
  stroke: var(--type-object);
  filter: drop-shadow(0 0 3px rgba(167, 139, 250, 0.35));
}

.wire--design {
  stroke: var(--type-design);
  filter: drop-shadow(0 0 3px rgba(251, 113, 133, 0.35));
}

.wire--audio {
  stroke: var(--type-audio);
  filter: drop-shadow(0 0 3px rgba(192, 132, 252, 0.35));
}

/* Blocked: target node is waiting — data is not flowing through yet. */
.wire--blocked {
  stroke-dasharray: 5 5;
  opacity: 0.45;
  animation: wire-flow 1.2s linear infinite;
}

@keyframes wire-flow {
  to {
    stroke-dashoffset: -10;
  }
}

@media (prefers-reduced-motion: reduce) {
  .wire--blocked {
    animation: none;
  }
}

/* ═══════════════════════════════════════════════════════════ */
/* Node card                                                    */
/* ═══════════════════════════════════════════════════════════ */

.node {
  --node-accent: var(--type-scene);
  position: absolute;
  width: 290px;
  /* Signature treatment: a barely-there composer-type wash at the top edge.
   * Linear gradient fades from ~14% of the type color to transparent over
   * the first ~120px. Layers on top of bg-card so the rest of the card
   * stays clean. */
  background: linear-gradient(
      180deg,
      color-mix(in oklab, var(--node-accent) 14%, transparent),
      transparent 120px
    )
    var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  z-index: 2;
  box-shadow: var(--shadow-card), var(--highlight-top);
  transition:
    border-color var(--dur),
    transform var(--dur);
  /* No overflow:hidden — it would clip ::after tooltips on children.
   * The background gradient + border-radius together honor rounded
   * corners natively, so clipping isn't needed. */
}

/* Per-composer type color for the top-edge wash. Drives the card's
 * --node-accent; the gradient above inherits from it. */
.node--character {
  --node-accent: var(--type-character);
}
.node--scene {
  --node-accent: var(--type-scene);
}
.node--place {
  --node-accent: var(--type-place);
}
.node--object {
  --node-accent: var(--type-object);
}
.node--design {
  --node-accent: var(--type-design);
}
.node--audio {
  --node-accent: var(--type-audio);
}

.node:hover {
  border-color: var(--border-bright);
  transform: translateY(-1px);
}

/* Positions — chosen so the SVG paths align neatly */
.node--pos-1 {
  top: 150px;
  left: 120px;
}
.node--pos-2 {
  top: 460px;
  left: 120px;
}
.node--pos-3 {
  top: 130px;
  left: 720px;
}
.node--pos-4 {
  top: 460px;
  left: 720px;
}
.node--pos-5 {
  top: 310px;
  left: 1270px;
}

/* Header */
.node-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 10px 10px 12px;
  border-bottom: 1px solid var(--border-subtle);
}

.node-badge {
  width: 22px;
  height: 22px;
  border-radius: 5px;
  background: var(--accent-dim);
  color: var(--accent-bright);
  font-size: 10px;
  font-weight: 700;
  font-family: var(--font-mono);
  letter-spacing: 0.02em;
  display: grid;
  place-items: center;
  flex-shrink: 0;
}

.node-badge--scene {
  background: var(--wire-pill);
  color: var(--wire);
}

/* The wrap carries the tooltip (via data-tip) and the flex sizing;
 * the h3 inside handles its own ellipsis truncation without clipping
 * the tooltip pseudo-element that lives on the wrap. */
.node-title-wrap {
  flex: 1;
  min-width: 0;
  display: flex;
}

.node-title {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  flex: 1;
  min-width: 0;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Inline rename: click the title to edit. Subtle hover, clear focus. */
.node-title[contenteditable] {
  cursor: text;
  padding: 2px 6px;
  margin: -2px -6px;
  border-radius: 5px;
  outline: none;
  transition:
    background var(--dur-fast),
    box-shadow var(--dur-fast);
}

.node-title[contenteditable]:hover {
  background: rgba(255, 255, 255, 0.04);
}

.node-title[contenteditable]:focus {
  background: var(--bg-root);
  box-shadow: 0 0 0 1px var(--accent);
  overflow: visible;
  text-overflow: clip;
}

.node-status {
  font-size: 9.5px;
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 4px;
  flex-shrink: 0;
}

.node-status--ready {
  color: var(--ready);
  background: rgba(92, 184, 92, 0.12);
}

.node-status--waiting {
  color: var(--waiting);
  background: rgba(161, 161, 170, 0.08);
}

/* Prominent run button in the header */
.node-run {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 6px;
  background: var(--accent);
  color: var(--accent-ink);
  flex-shrink: 0;
  margin-left: 2px;
  transition:
    background var(--dur-fast),
    transform var(--dur-fast),
    box-shadow var(--dur-fast);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.node-run:hover {
  background: var(--accent-bright);
  transform: translateY(-1px);
  box-shadow: 0 3px 10px rgba(234, 179, 8, 0.4);
}

.node-run:active {
  transform: translateY(0);
}

.node-run[disabled] {
  background: var(--bg-elevated);
  color: var(--text-dim);
  cursor: not-allowed;
  box-shadow: none;
}

.node-run[disabled]:hover {
  transform: none;
  background: var(--bg-elevated);
  box-shadow: none;
}

/* Overflow menu — hidden by default, revealed on node hover */
.node-menu {
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border-radius: 5px;
  color: var(--text-muted);
  flex-shrink: 0;
  opacity: 0;
  transition:
    background var(--dur-fast),
    color var(--dur-fast),
    opacity var(--dur-fast);
}

.node:hover .node-menu,
.node-menu:focus {
  opacity: 1;
}

.node-menu:hover {
  background: var(--bg-elevated);
  color: var(--text-primary);
}

/* Drag handle — 6-dot grip. Same chrome as node-menu, grab cursor. */
.node-move {
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border-radius: 5px;
  color: var(--text-muted);
  flex-shrink: 0;
  opacity: 0;
  cursor: grab;
  transition:
    background var(--dur-fast),
    color var(--dur-fast),
    opacity var(--dur-fast);
}

.node:hover .node-move,
.node-move:focus-visible {
  opacity: 1;
}

.node-move:hover {
  background: var(--bg-elevated);
  color: var(--text-primary);
}

.node-move:active {
  cursor: grabbing;
}

/* Preview */
.node-preview {
  padding: 12px;
}

/* Status + action row — between preview and body */
.node-stat {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 12px;
  border-top: 1px solid var(--border-subtle);
  background: rgba(255, 255, 255, 0.012);
  min-height: 44px;
  box-sizing: border-box;
}

.node-stat-label {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 10.5px;
  font-family: inherit;
  letter-spacing: 0.01em;
  color: var(--text-muted);
}

.node-stat-label--waiting {
  color: var(--text-secondary);
}

.node-stat-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--waiting);
  box-shadow: 0 0 5px rgba(161, 161, 170, 0.4);
  animation: pulse-wait 2s ease-in-out infinite;
}

@keyframes pulse-wait {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.4;
  }
}

.node-thumb {
  width: 100%;
  aspect-ratio: 16 / 10;
  border-radius: 8px;
  border: 1px solid var(--border-subtle);
}

.node-thumb--maren {
  background:
    radial-gradient(circle at 60% 40%, #78716c, transparent 55%),
    linear-gradient(135deg, #292524, #0c0a09);
}

.node-thumb--solveig {
  background:
    radial-gradient(circle at 50% 45%, #fde68a, transparent 50%),
    linear-gradient(135deg, #3f3f46, #18181b);
}

.node-thumb--shore {
  background: linear-gradient(
    180deg,
    #fcd34d 0%,
    #fb923c 20%,
    #1e293b 50%,
    #020617 100%
  );
}

/* Empty preview — dashed box with just a label */
.node-preview--empty {
  padding: 24px 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  font-size: 11px;
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: repeating-linear-gradient(
    -45deg,
    transparent 0 8px,
    rgba(255, 255, 255, 0.015) 8px 9px
  );
  margin: 12px;
  border: 1px dashed var(--border-accent);
  border-radius: 8px;
  aspect-ratio: 16 / 10;
}

/* Body — wraps text + chips below the preview */
.node-body {
  padding: 0 12px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.node-text {
  font-size: 12px;
  color: var(--text-secondary);
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.node-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.chip {
  font-size: 10.5px;
  font-weight: 500;
  padding: 3px 8px;
  border-radius: 5px;
  background: var(--bg-elevated);
  color: var(--text-secondary);
  border: 1px solid var(--border-accent);
  white-space: nowrap;
}

/* Overflow count chip */
.chip--more {
  background: transparent;
  color: var(--text-muted);
  border-color: var(--border);
  font-family: var(--font-mono);
  font-size: 10px;
}

/* ═══════════════════════════════════════════════════════════ */
/* Input ports — wire drop targets                              */
/* ═══════════════════════════════════════════════════════════ */

.node-inputs {
  border-top: 1px solid var(--border-subtle);
  padding: 6px 0 8px;
  background: rgba(255, 255, 255, 0.015);
}

.input-port {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 12px;
  cursor: pointer;
  transition: background var(--dur-fast);
}

.input-port:hover {
  background: var(--wire-tint-subtle);
}

.input-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 1.5px solid var(--border-accent);
  background: var(--bg-card);
  flex-shrink: 0;
  transition:
    border-color var(--dur-fast),
    background var(--dur-fast),
    box-shadow var(--dur-fast);
}

.input-port:hover .input-dot {
  border-color: var(--wire);
}

.input-port.is-wired .input-dot {
  background: var(--wire);
  border-color: var(--wire);
  box-shadow: 0 0 5px rgba(34, 211, 238, 0.5);
}

.input-label {
  flex: 1;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.input-port.is-wired .input-label {
  color: var(--text-secondary);
}

.input-src {
  font-family: inherit;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--wire);
  background: var(--wire-tint);
  padding: 2px 7px;
  border-radius: 4px;
  max-width: 110px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 0;
  letter-spacing: -0.005em;
}

/* ═══════════════════════════════════════════════════════════ */
/* Output port — mirrors input port but in accent gold          */
/* ═══════════════════════════════════════════════════════════ */

.node-foot {
  border-top: 1px solid var(--border-subtle);
  padding: 6px 0;
  background: rgba(255, 255, 255, 0.015);
}

.output-port {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 12px;
  cursor: grab;
  transition: background var(--dur-fast);
}
/* Output dot lives on the right edge so wires exit cleanly out the */
/* card's right side, matching standard node-graph convention       */
/* (Figma / ComfyUI / Blender / Unreal Blueprint). The label keeps  */
/* its left-alignment via flex order; the dot is forced last.       */
.output-port .output-label {
  order: 1;
}
.output-port .output-src {
  order: 2;
}
.output-port .output-dot {
  order: 3;
}

.output-port:hover {
  background: var(--accent-tint);
}

.output-port:active {
  cursor: grabbing;
}

.output-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 1.5px solid var(--border-accent);
  background: var(--bg-card);
  flex-shrink: 0;
  box-sizing: border-box;
  transition:
    border-color var(--dur-fast),
    background var(--dur-fast),
    box-shadow var(--dur-fast);
}

.output-port:hover .output-dot {
  border-color: var(--accent);
}

.output-port.is-wired .output-dot {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 5px rgba(234, 179, 8, 0.5);
}

.output-label {
  flex: 1;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.output-port.is-wired .output-label {
  color: var(--text-secondary);
}

.output-src {
  font-family: inherit;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--accent-bright);
  background: var(--accent-dim);
  padding: 2px 7px;
  border-radius: 4px;
  max-width: 150px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 0;
  letter-spacing: -0.005em;
}

/* ═══════════════════════════════════════════════════════════ */
/* Floating Add button                                          */
/* ═══════════════════════════════════════════════════════════ */

.fab {
  position: absolute;
  right: 24px;
  bottom: 24px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 18px 12px 14px;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
  font-size: 13px;
  border-radius: 999px;
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.4),
    0 10px 28px rgba(202, 138, 4, 0.35);
  transition:
    background var(--dur-fast),
    transform var(--dur-fast),
    box-shadow var(--dur);
  z-index: 20;
}

.fab:hover {
  background: var(--accent-bright);
  transform: translateY(-2px);
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.4),
    0 14px 36px rgba(234, 179, 8, 0.45);
}

/* ═══════════════════════════════════════════════════════════ */
/* Minimap                                                      */
/* ═══════════════════════════════════════════════════════════ */

.minimap {
  position: absolute;
  right: 24px;
  bottom: 90px;
  width: 180px;
  height: 108px;
  background: rgba(10, 10, 12, 0.85);
  backdrop-filter: blur(8px);
  border: 1px solid var(--border);
  border-radius: 8px;
  z-index: 10;
  overflow: hidden;
}

.minimap-node {
  position: absolute;
  width: 22px;
  height: 14px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-accent);
  border-radius: 2px;
}

.minimap-node--1 {
  top: 18%;
  left: 8%;
}
.minimap-node--2 {
  top: 52%;
  left: 8%;
}
.minimap-node--3 {
  top: 14%;
  left: 44%;
}
.minimap-node--4 {
  top: 50%;
  left: 44%;
}
.minimap-node--5 {
  top: 34%;
  left: 78%;
  border-color: var(--wire-dim);
}

.minimap-viewport {
  position: absolute;
  top: 10%;
  left: 5%;
  width: 60%;
  height: 75%;
  border: 1px solid var(--accent);
  border-radius: 3px;
  background: var(--accent-tint-subtle);
  pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════ */
/* Zoom controls                                                */
/* ═══════════════════════════════════════════════════════════ */

.zoom-ctl {
  position: absolute;
  left: 24px;
  bottom: 24px;
  display: flex;
  align-items: center;
  gap: 2px;
  background: rgba(10, 10, 12, 0.85);
  backdrop-filter: blur(8px);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 4px;
  z-index: 10;
}

.zoom-btn {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 5px;
  color: var(--text-secondary);
  font-size: 14px;
  font-weight: 500;
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
}

.zoom-btn:hover {
  background: var(--bg-elevated);
  color: var(--text-primary);
}

.zoom-val {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-muted);
  padding: 0 8px;
  min-width: 48px;
  text-align: center;
}

/* ═══════════════════════════════════════════════════════════ */
/* Pan / zoom cursor states (ADR-010 CANVAS-003)                */
/* ═══════════════════════════════════════════════════════════ */

body.is-space-pan .canvas {
  cursor: grab;
}
body.is-panning .canvas {
  cursor: grabbing;
}
body.is-panning .canvas-content {
  /* While panning, suppress pointer events on cards so a stray
   * pointermove can't trigger a card hover/drag mid-pan. */
  pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════ */
/* Outline drawer                                               */
/* ═══════════════════════════════════════════════════════════ */

.drawer {
  width: 260px;
  min-width: 260px;
  background: var(--bg-rail);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
}

.drawer-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 14px 10px;
  flex-shrink: 0;
}

.drawer-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: -0.01em;
}

.drawer-count {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--text-muted);
  background: var(--bg-elevated);
  padding: 2px 7px;
  border-radius: 999px;
  line-height: 1.3;
}

.drawer-close,
.drawer-add {
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border-radius: 5px;
  color: var(--text-muted);
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
}

.drawer-close:hover,
.drawer-add:hover {
  background: var(--bg-elevated);
  color: var(--text-primary);
}

/* Group the add + close buttons on the right side of the drawer head.
 * `.drawer-add` carries the auto margin so the pair is pushed right and
 * stays adjacent through the parent's flex gap. */
.drawer-add {
  margin-left: auto;
}

/* Drop-zone overlay shown while an OS file drag is hovering the
 * library drawer body. Covers the body area; the underlying list fades
 * to ~30% opacity so the affordance is unambiguous. */
.drawer-body {
  position: relative;
}

.drawer-body--drop-over > .lh-list,
.drawer-body--drop-over > .drawer-empty {
  opacity: 0.3;
  pointer-events: none;
}

.drawer-drop-overlay {
  position: absolute;
  inset: 6px;
  display: grid;
  place-items: center;
  border: 2px dashed var(--accent, #6366f1);
  border-radius: 10px;
  background: color-mix(in srgb, var(--accent, #6366f1) 8%, transparent);
  z-index: 2;
  pointer-events: none;
}

.drawer-drop-overlay-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  color: var(--text-primary);
}

.drawer-drop-overlay-text {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
}

/* Inline error toast shown above the drawer footer when an upload
 * fails (bad mime type, too large, FileReader error). Dismissed by
 * the × button or replaced on the next upload attempt. */
.drawer-error {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 10px 8px;
  padding: 8px 10px;
  font-size: 12px;
  color: var(--text-warn, #f59e0b);
  background: var(--bg-warn, rgba(245, 158, 11, 0.08));
  border: 1px solid var(--border-warn, rgba(245, 158, 11, 0.3));
  border-radius: 6px;
}

.drawer-error-text {
  flex: 1;
  min-width: 0;
}

.drawer-error-dismiss {
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  border-radius: 4px;
  color: inherit;
  flex-shrink: 0;
}

.drawer-error-dismiss:hover {
  background: color-mix(in srgb, var(--text-warn, #f59e0b) 12%, transparent);
}

/* Search */
.drawer-search {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 10px 8px;
  padding: 7px 10px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 7px;
  color: var(--text-muted);
  transition: border-color var(--dur-fast);
}

.drawer-search:focus-within {
  border-color: var(--border-accent);
  color: var(--text-secondary);
}

.drawer-search input {
  flex: 1;
  background: none;
  border: none;
  outline: none;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
  min-width: 0;
}

.drawer-search input::placeholder {
  color: var(--text-dim);
}

/* Body (scrollable) */
.drawer-body {
  flex: 1;
  overflow-y: auto;
  padding: 4px 10px 10px;
}

.drawer-body::-webkit-scrollbar {
  width: 6px;
}

.drawer-body::-webkit-scrollbar-track {
  background: transparent;
}

.drawer-body::-webkit-scrollbar-thumb {
  background: var(--border-accent);
  border-radius: 3px;
}

/* Groups */
.outline-group + .outline-group {
  margin-top: 10px;
}

.outline-group-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 6px 4px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.outline-group-count {
  color: var(--text-dim);
  font-weight: 400;
}

.outline-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.outline-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 6px;
  cursor: pointer;
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
}

.outline-item:hover {
  background: var(--bg-elevated);
}

.outline-item.is-selected {
  background: var(--accent-dim);
}

.outline-item.is-selected .outline-name {
  color: var(--accent-bright);
}

.outline-badge {
  width: 20px;
  height: 20px;
  border-radius: 4px;
  background: var(--accent-dim);
  color: var(--accent-bright);
  font-size: 9px;
  font-weight: 700;
  font-family: var(--font-mono);
  display: grid;
  place-items: center;
  flex-shrink: 0;
}

.outline-badge--scene {
  background: var(--wire-pill);
  color: var(--wire);
}

.outline-name {
  font-size: 12px;
  color: var(--text-secondary);
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.outline-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
}

.outline-dot--ready {
  background: var(--ready);
  box-shadow: 0 0 5px rgba(92, 184, 92, 0.5);
}

.outline-dot--waiting {
  background: var(--text-dim);
}

/* Footer — hosts the sort button (left) and pager (right). Footer
   tooltips appear above (drawer tooltips default to below, which would
   overflow past the drawer edge when the footer sits at the bottom). */
.drawer-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 10px;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}

.drawer-foot-hint {
  font-size: 11px;
  color: var(--text-muted);
  font-family: var(--font-mono);
}

/* ═══════════════════════════════════════════════════════════ */
/* Drawer tabs + sort dropdown (filter bar)                     */
/* ═══════════════════════════════════════════════════════════ */

.drawer-tabs {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 8px 8px 10px;
}

.drawer-tabs-list {
  display: flex;
  flex: 1;
  min-width: 0;
  gap: 2px;
  overflow-x: auto;
  scrollbar-width: none;
}

.drawer-tabs-list::-webkit-scrollbar {
  display: none;
}

.drawer-tab {
  font-family: inherit;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--text-muted);
  padding: 5px 10px;
  border-radius: 6px;
  white-space: nowrap;
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
}

.drawer-tab:hover {
  color: var(--text-secondary);
  background: var(--bg-elevated);
}

.drawer-tab.is-active {
  background: var(--accent-dim);
  color: var(--accent-bright);
}

/* Sort button + popover menu */
.drawer-sort-wrap {
  position: relative;
  flex-shrink: 0;
}

.drawer-sort {
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border-radius: 6px;
  color: var(--text-muted);
  background: transparent;
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
}

.drawer-sort:hover {
  background: var(--bg-elevated);
  color: var(--text-secondary);
}

.drawer-sort[aria-expanded="true"] {
  background: var(--accent-dim);
  color: var(--accent-bright);
}

.drawer-sort-menu {
  position: absolute;
  bottom: calc(100% + 4px);
  left: 0;
  min-width: 148px;
  padding: 4px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-accent);
  border-radius: 8px;
  box-shadow: var(--shadow-modal);
  z-index: 40;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.drawer-sort-menu[hidden] {
  display: none;
}

.drawer-sort-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 5px;
  font-size: 11.5px;
  color: var(--text-secondary);
  cursor: pointer;
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
}

.drawer-sort-item:hover {
  background: var(--bg-surface);
  color: var(--text-primary);
}

.drawer-sort-item.is-selected {
  color: var(--accent-bright);
}

.drawer-sort-check {
  width: 10px;
  height: 10px;
  display: grid;
  place-items: center;
  opacity: 0;
  color: var(--accent-bright);
}

.drawer-sort-item.is-selected .drawer-sort-check {
  opacity: 1;
}

/* ═══════════════════════════════════════════════════════════ */
/* Drawer pager                                                 */
/* ═══════════════════════════════════════════════════════════ */

.drawer-pager {
  display: flex;
  align-items: center;
  gap: 8px;
}

.drawer-pager-btn {
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border-radius: 5px;
  color: var(--text-secondary);
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  transition:
    background var(--dur-fast),
    color var(--dur-fast),
    border-color var(--dur-fast);
}

.drawer-pager-btn:hover:not(:disabled) {
  background: var(--bg-surface);
  border-color: var(--border-accent);
  color: var(--text-primary);
}

.drawer-pager-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.drawer-pager-label {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-secondary);
  min-width: 44px;
  text-align: center;
}

.drawer-pager-label em {
  font-style: normal;
  color: var(--text-dim);
  padding: 0 2px;
}

/* ═══════════════════════════════════════════════════════════ */
/* Unified list items (Library + History)                       */
/* B·72 pattern: 72px thumb + stacked label/meta inside a soft  */
/* bordered card. Same DOM template renders in both drawers —   */
/* library items carry lib-thumb--N gradients and a type label, */
/* history items carry history-thumb--N gradients + timestamp.  */
/* ═══════════════════════════════════════════════════════════ */

.lh-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.lh-item {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px;
  border-radius: 10px;
  cursor: pointer;
  transition:
    background var(--dur-fast),
    border-color var(--dur-fast);
}

.lh-item:hover {
  background: var(--bg-surface);
  border-color: var(--border-accent);
}

.lh-item:active {
  cursor: grabbing;
}

.lh-item.is-selected {
  border-color: var(--accent);
  background: color-mix(in oklab, var(--accent) 10%, var(--bg-elevated));
}

.lh-item.is-selected .lh-name {
  color: var(--accent-bright);
}

.lh-thumb {
  width: 72px;
  height: 72px;
  border-radius: 7px;
  border: 1px solid var(--border);
  flex-shrink: 0;
  background-color: var(--bg-elevated);
  position: relative;
  overflow: hidden;
}

/* Real-bytes thumbnail. Same box as .lh-thumb, but the <img> fills it
 * and crops to cover. Inherits border + radius + overflow so the image
 * is clipped to the rounded corners. */
.lh-thumb--img {
  display: block;
  object-fit: cover;
  /* Some browsers default img to inline-block baseline alignment with
   * a 4px gap below; force block to remove the gap. */
}

.lh-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.lh-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.lh-name {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.lh-meta {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-muted);
  letter-spacing: 0.02em;
}

/* Hover-revealed delete affordance. Hidden by default so the row reads
 * clean; appears on row hover or when the button itself is focused so
 * keyboard users can still reach it. */
.lh-item-delete {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  opacity: 0;
  transition:
    opacity var(--dur-fast),
    background var(--dur-fast),
    color var(--dur-fast);
}

.lh-item:hover .lh-item-delete,
.lh-item-delete:focus-visible {
  opacity: 1;
}

.lh-item-delete:hover {
  background: color-mix(in oklab, var(--danger, #ef4444) 18%, transparent);
  color: var(--danger, #ef4444);
}

/* Armed: first click flipped the × to a check; the button stays visible
 * (no opacity rule needed) so the user has a clear, full-opacity target
 * for the confirming second click. */
.lh-item-delete.is-armed,
.lh-item:hover .lh-item-delete.is-armed {
  opacity: 1;
  background: var(--danger, #ef4444);
  color: #fff;
}

.lh-item-delete.is-armed:hover {
  filter: brightness(1.08);
}

/* ─── Library thumbnail gradients ─── */

.lib-thumb--1 {
  background:
    radial-gradient(circle at 55% 45%, #a8a29e, transparent 45%),
    linear-gradient(135deg, #44403c, #0c0a09);
}
.lib-thumb--2 {
  background:
    radial-gradient(circle at 50% 40%, #fde68a, transparent 45%),
    linear-gradient(135deg, #52525b, #1c1917);
}
.lib-thumb--3 {
  background: linear-gradient(
    180deg,
    #fcd34d 0%,
    #fb923c 25%,
    #1e293b 55%,
    #020617 100%
  );
}
.lib-thumb--4 {
  background:
    radial-gradient(circle at 50% 60%, #fcd34d, transparent 55%),
    linear-gradient(135deg, #451a03, #1c1917);
}
.lib-thumb--5 {
  background:
    radial-gradient(circle at 30% 40%, #475569, transparent 50%),
    linear-gradient(135deg, #0f172a, #020617);
}
.lib-thumb--6 {
  background: linear-gradient(180deg, #64748b 0%, #1e293b 50%, #020617 100%);
}
.lib-thumb--7 {
  background:
    radial-gradient(circle at 65% 55%, #fbbf24, transparent 45%),
    linear-gradient(135deg, #292524, #0c0a09);
}
.lib-thumb--8 {
  background: linear-gradient(
    180deg,
    #fde68a 0%,
    #fb923c 30%,
    #be123c 55%,
    #18181b 100%
  );
}

/* ─── History group headers + thumbnail gradients ─── */

.history-group + .history-group {
  margin-top: 10px;
}

.history-group-head {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 6px 8px 6px;
}

.history-thumb--1 {
  background: linear-gradient(
    180deg,
    #fcd34d 0%,
    #fb923c 25%,
    #1e293b 55%,
    #020617 100%
  );
}
.history-thumb--2 {
  background: linear-gradient(
    180deg,
    #fed7aa 0%,
    #f97316 30%,
    #1e293b 60%,
    #020617 100%
  );
}
.history-thumb--3 {
  background:
    radial-gradient(circle at 50% 40%, #fde68a, transparent 45%),
    linear-gradient(135deg, #52525b, #1c1917);
}
.history-thumb--4 {
  background:
    radial-gradient(circle at 55% 45%, #a8a29e, transparent 45%),
    linear-gradient(135deg, #44403c, #0c0a09);
}
.history-thumb--5 {
  background:
    radial-gradient(circle at 60% 45%, #d6d3d1, transparent 45%),
    linear-gradient(135deg, #44403c, #0c0a09);
}
.history-thumb--6 {
  background:
    radial-gradient(circle at 55% 55%, #fbbf24, transparent 45%),
    linear-gradient(135deg, #292524, #0c0a09);
}
.history-thumb--7 {
  background:
    radial-gradient(circle at 45% 35%, #fef3c7, transparent 45%),
    linear-gradient(135deg, #3f3f46, #18181b);
}

/* ─── Version tag chip (used inside history items) ─── */

.history-tag {
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--text-secondary);
  background: transparent;
  padding: 1px 5px;
  border-radius: 3px;
  border: 1px solid var(--border-accent);
  flex-shrink: 0;
}

/* ═══════════════════════════════════════════════════════════ */
/* Command palette                                              */
/* ═══════════════════════════════════════════════════════════ */

.palette-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(4, 4, 6, 0.55);
  backdrop-filter: blur(3px);
  z-index: 100;
  animation: palette-fade var(--dur) ease-out;
}

.palette {
  position: fixed;
  top: 14vh;
  left: 50%;
  transform: translateX(-50%);
  width: min(640px, calc(100vw - 48px));
  max-height: 70vh;
  background: var(--bg-elevated);
  border: 1px solid var(--border-accent);
  border-radius: 14px;
  box-shadow: var(--shadow-modal);
  display: flex;
  flex-direction: column;
  z-index: 101;
  overflow: hidden;
  animation: palette-slide var(--dur) cubic-bezier(0.2, 0.9, 0.3, 1);
}

@keyframes palette-fade {
  from {
    opacity: 0;
  }
}

@keyframes palette-slide {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(-8px) scale(0.98);
  }
}

/* Head */
.palette-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 14px 12px;
  border-bottom: 1px solid var(--border);
  color: var(--text-muted);
}

.palette-input {
  flex: 1;
  background: none;
  border: none;
  outline: none;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 15px;
  min-width: 0;
}

.palette-input::placeholder {
  color: var(--text-dim);
}

.palette-input::-webkit-search-cancel-button,
.palette-input::-webkit-search-decoration {
  appearance: none;
  -webkit-appearance: none;
}

.palette-esc {
  font-family: var(--font-mono);
  font-size: 10px;
  padding: 3px 7px;
  background: var(--bg-rail);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text-muted);
}

/* Body (scrollable) */
.palette-body {
  flex: 1;
  overflow-y: auto;
  padding: 6px 8px 8px;
}

.palette-body::-webkit-scrollbar {
  width: 8px;
}

.palette-body::-webkit-scrollbar-track {
  background: transparent;
}

.palette-body::-webkit-scrollbar-thumb {
  background: var(--border-accent);
  border-radius: 4px;
  border: 2px solid var(--bg-elevated);
}

.palette-group + .palette-group {
  margin-top: 6px;
}

.palette-group-head {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 8px 10px 4px;
}

.palette-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.palette-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 10px;
  border-radius: 8px;
  cursor: pointer;
  transition: background var(--dur-fast);
}

.palette-item:hover {
  background: var(--bg-card);
}

.palette-item.is-selected {
  background: var(--accent-dim);
}

.palette-item.is-selected .palette-name {
  color: var(--accent-bright);
}

.palette-badge {
  width: 28px;
  height: 28px;
  border-radius: 6px;
  background: var(--accent-dim);
  color: var(--accent-bright);
  font-size: 10.5px;
  font-weight: 700;
  font-family: var(--font-mono);
  display: grid;
  place-items: center;
  flex-shrink: 0;
}

.palette-badge--scene {
  background: var(--wire-pill);
  color: var(--wire);
}

.palette-badge--place {
  background: rgba(45, 212, 191, 0.12);
  color: #2dd4bf;
}

.palette-badge--object {
  background: rgba(139, 92, 246, 0.14);
  color: #a78bfa;
}

.palette-badge--design {
  background: rgba(244, 63, 94, 0.12);
  color: #fb7185;
}

.palette-badge--audio {
  background: rgba(168, 85, 247, 0.14);
  color: #c084fc;
}

.palette-meta {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.palette-name {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: -0.005em;
}

.palette-desc {
  font-size: 11.5px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.palette-pill {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--accent-pill);
  color: var(--accent-bright);
  border: 1px solid var(--accent-border);
  flex-shrink: 0;
}

.palette-return {
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 2px 8px;
  background: var(--bg-rail);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text-muted);
  flex-shrink: 0;
}

/* Footer */
.palette-foot {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 10px 14px;
  border-top: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.2);
}

.palette-hint {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  color: var(--text-muted);
}

.palette-hint--right {
  margin-left: auto;
}

.palette-hint kbd {
  font-family: var(--font-mono);
  font-size: 10px;
  padding: 1px 5px;
  background: var(--bg-rail);
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: 3px;
  color: var(--text-secondary);
}

/* ═══════════════════════════════════════════════════════════ */
/* Port type colors — dot + pill take the source composer's hue */
/* Applied to both .input-port and .output-port. Cyan (Scene)   */
/* falls through to the default is-wired rules.                 */
/* ═══════════════════════════════════════════════════════════ */

/* Character — gold */
.input-port.is-character.is-wired .input-dot,
.output-port.is-character.is-wired .output-dot {
  background: var(--type-character);
  border-color: var(--type-character);
  box-shadow: 0 0 5px rgba(202, 138, 4, 0.5);
}

.input-port.is-character.is-wired .input-src,
.output-port.is-character.is-wired .output-src {
  color: var(--accent-bright);
  background: var(--accent-dim);
}

/* Scene — cyan (matches default .is-wired). Explicit for clarity. */
.input-port.is-scene.is-wired .input-dot,
.output-port.is-scene.is-wired .output-dot {
  background: var(--type-scene);
  border-color: var(--type-scene);
  box-shadow: 0 0 5px rgba(34, 211, 238, 0.5);
}

.input-port.is-scene.is-wired .input-src,
.output-port.is-scene.is-wired .output-src {
  color: var(--type-scene);
  background: var(--wire-tint);
}

/* Place — teal */
.input-port.is-place.is-wired .input-dot,
.output-port.is-place.is-wired .output-dot {
  background: var(--type-place);
  border-color: var(--type-place);
  box-shadow: 0 0 5px rgba(45, 212, 191, 0.5);
}

.input-port.is-place.is-wired .input-src,
.output-port.is-place.is-wired .output-src {
  color: var(--type-place);
  background: rgba(45, 212, 191, 0.1);
}

/* Object — violet */
.input-port.is-object.is-wired .input-dot,
.output-port.is-object.is-wired .output-dot {
  background: var(--type-object);
  border-color: var(--type-object);
  box-shadow: 0 0 5px rgba(167, 139, 250, 0.5);
}

.input-port.is-object.is-wired .input-src,
.output-port.is-object.is-wired .output-src {
  color: var(--type-object);
  background: rgba(167, 139, 250, 0.12);
}

/* Design — rose */
.input-port.is-design.is-wired .input-dot,
.output-port.is-design.is-wired .output-dot {
  background: var(--type-design);
  border-color: var(--type-design);
  box-shadow: 0 0 5px rgba(251, 113, 133, 0.5);
}

.input-port.is-design.is-wired .input-src,
.output-port.is-design.is-wired .output-src {
  color: var(--type-design);
  background: rgba(251, 113, 133, 0.12);
}

/* Audio — purple */
.input-port.is-audio.is-wired .input-dot,
.output-port.is-audio.is-wired .output-dot {
  background: var(--type-audio);
  border-color: var(--type-audio);
  box-shadow: 0 0 5px rgba(192, 132, 252, 0.5);
}

.input-port.is-audio.is-wired .input-src,
.output-port.is-audio.is-wired .output-src {
  color: var(--type-audio);
  background: rgba(192, 132, 252, 0.12);
}

/* Hover affordances for each type variant */
.input-port.is-character:hover .input-dot,
.output-port.is-character:hover .output-dot {
  border-color: var(--type-character);
}

.input-port.is-place:hover .input-dot,
.output-port.is-place:hover .output-dot {
  border-color: var(--type-place);
}

.input-port.is-object:hover .input-dot,
.output-port.is-object:hover .output-dot {
  border-color: var(--type-object);
}

.input-port.is-design:hover .input-dot,
.output-port.is-design:hover .output-dot {
  border-color: var(--type-design);
}

.input-port.is-audio:hover .input-dot,
.output-port.is-audio:hover .output-dot {
  border-color: var(--type-audio);
}

/* ═══════════════════════════════════════════════════════════ */
/* Thumbnail lightbox — click any library or history item to   */
/* inspect provenance in a Tweakpane-style property sidebar.   */
/* Shares shadow/backdrop tokens with .palette so it feels     */
/* native next to the command palette.                         */
/* ═══════════════════════════════════════════════════════════ */

.lightbox-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(4, 4, 6, 0.55);
  backdrop-filter: blur(3px);
  z-index: 100;
  animation: palette-fade var(--dur) ease-out;
}

.lightbox {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(960px, calc(100vw - 48px));
  height: min(640px, calc(100vh - 96px));
  background: var(--bg-elevated);
  border: 1px solid var(--border-accent);
  border-radius: 14px;
  box-shadow: var(--shadow-modal);
  display: grid;
  grid-template-columns: 1fr 320px;
  z-index: 101;
  overflow: hidden;
  animation: lightbox-slide var(--dur) cubic-bezier(0.2, 0.9, 0.3, 1);
}

@keyframes lightbox-slide {
  from {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.98);
  }
}

/* Preview pane — checker backdrop + centered gradient image */
.lightbox-preview {
  position: relative;
  display: grid;
  place-items: center;
  padding: 28px;
  background: var(--bg-rail);
  background-image:
    linear-gradient(
      45deg,
      color-mix(in oklab, var(--text-primary) 4%, transparent) 25%,
      transparent 25%
    ),
    linear-gradient(
      -45deg,
      color-mix(in oklab, var(--text-primary) 4%, transparent) 25%,
      transparent 25%
    ),
    linear-gradient(
      45deg,
      transparent 75%,
      color-mix(in oklab, var(--text-primary) 4%, transparent) 75%
    ),
    linear-gradient(
      -45deg,
      transparent 75%,
      color-mix(in oklab, var(--text-primary) 4%, transparent) 75%
    );
  background-size: 20px 20px;
  background-position:
    0 0,
    0 10px,
    10px -10px,
    -10px 0;
  border-right: 1px solid var(--border);
}

.lightbox-image {
  width: 100%;
  max-width: 520px;
  aspect-ratio: 1 / 1;
  border-radius: 10px;
  border: 1px solid var(--border-accent);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
  /* background is set by a lib-thumb--N / history-thumb--N class applied in JS */
}

/* Property sidebar */
.lightbox-props {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--bg-elevated);
}

.lightbox-head {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 14px 14px 12px;
  border-bottom: 1px solid var(--border);
}

.lightbox-head-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.lightbox-kicker {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-bright);
}

.lightbox-title {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.lightbox-close {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-muted);
  cursor: pointer;
  transition: all var(--dur-fast);
}

.lightbox-close:hover {
  color: var(--text-primary);
  border-color: var(--border-accent);
  background: var(--bg-rail);
}

/* Property rows — Tweakpane-style 2-column grid, rows share the
   same label column so values align across the whole panel.     */
.lightbox-rows {
  flex: 1;
  overflow-y: auto;
  padding: 6px 0;
}

.lightbox-rows::-webkit-scrollbar {
  width: 8px;
}

.lightbox-rows::-webkit-scrollbar-track {
  background: transparent;
}

.lightbox-rows::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 4px;
}

.lightbox-section {
  padding: 4px 0;
}

.lightbox-section + .lightbox-section {
  border-top: 1px solid var(--border);
  margin-top: 4px;
}

.lightbox-section-head {
  padding: 10px 14px 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.lightbox-row {
  display: grid;
  grid-template-columns: 92px 1fr;
  align-items: center;
  gap: 10px;
  padding: 6px 14px;
  min-height: 26px;
}

.lightbox-row:hover {
  background: color-mix(in oklab, var(--accent) 4%, transparent);
}

.lightbox-row-label {
  font-size: 11px;
  color: var(--text-muted);
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.lightbox-row-value {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

/* editable name/tag values behave like node titles */
.lightbox-row-value[contenteditable] {
  font-family: inherit;
  font-size: 12.5px;
  padding: 2px 5px;
  margin: -2px -5px;
  border-radius: 4px;
  border: 1px solid transparent;
  outline: none;
  cursor: text;
}

.lightbox-row-value[contenteditable]:hover {
  border-color: var(--border);
}

.lightbox-row-value[contenteditable]:focus-visible {
  border-color: var(--accent);
  background: var(--bg-rail);
}

/* colored dot prefix for type/domain rows */
.lightbox-row-dot {
  width: 8px;
  height: 8px;
  border-radius: 2px;
  flex-shrink: 0;
}

.lightbox-row-dot--character {
  background: var(--type-character);
}
.lightbox-row-dot--scene {
  background: var(--type-scene);
}
.lightbox-row-dot--place {
  background: var(--type-place);
}
.lightbox-row-dot--object {
  background: var(--type-object);
}
.lightbox-row-dot--design {
  background: var(--type-design);
}
.lightbox-row-dot--audio {
  background: var(--type-audio);
}
.lightbox-row-dot--style,
.lightbox-row-dot--people {
  background: var(--accent);
}

.lightbox-row-pill {
  font-family: var(--font-mono);
  font-size: 10px;
  padding: 2px 6px;
  border-radius: 3px;
  background: var(--accent-dim);
  color: var(--accent-bright);
  border: 1px solid var(--border);
}

.lightbox-row-muted {
  color: var(--text-muted);
}

/* Footer actions */
.lightbox-foot {
  display: flex;
  gap: 8px;
  padding: 10px 14px;
  border-top: 1px solid var(--border);
}

.lightbox-action {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 7px 10px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-secondary);
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  transition: all var(--dur-fast);
}

.lightbox-action:hover {
  color: var(--text-primary);
  border-color: var(--border-accent);
  background: var(--bg-rail);
}

.lightbox-action--danger {
  color: var(--type-design);
}

.lightbox-action--danger:hover {
  color: var(--type-design);
  border-color: var(--type-design);
  background: color-mix(in oklab, var(--type-design) 10%, transparent);
}

/* Two-step delete: armed state flips the button to a solid destructive
 * surface so the second click clearly differs from the first. */
.lightbox-action--danger.is-armed,
.lightbox-action--danger.is-armed:hover {
  color: #fff;
  border-color: var(--type-design);
  background: var(--type-design);
}

/* Narrow viewports stack the panes */
@media (max-width: 720px) {
  .lightbox {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr auto;
    height: min(720px, calc(100vh - 32px));
    width: calc(100vw - 32px);
  }

  .lightbox-preview {
    border-right: none;
    border-bottom: 1px solid var(--border);
  }

  .lightbox-props {
    max-height: 40vh;
  }
}

/* ═══════════════════════════════════════════════════════════════ */
/* v2 overrides — see docs/DESIGN-RULES.md                          */
/* ═══════════════════════════════════════════════════════════════ */

/* ── MODAL-001 ── Shared modal backdrop                             */
/* A single scrim dims drawers + canvas while any modal is open.    */
/* The existing palette-backdrop and lightbox-backdrop elements     */
/* become thin aliases that just toggle this one. The scrim sits    */
/* above drawers (z:70) and below every modal surface (z:90).       */
.modal-scrim {
  position: fixed;
  inset: 0;
  background: rgba(8, 10, 14, 0.5);
  backdrop-filter: blur(2px);
  z-index: 70;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur) ease;
}
.modal-scrim.is-visible {
  opacity: 1;
  pointer-events: auto;
}
/* Keep the legacy per-modal backdrops invisible in v2 — the scrim */
/* replaces them. They still receive click-to-dismiss via JS.       */
.palette-backdrop,
.lightbox-backdrop {
  background: transparent;
  backdrop-filter: none;
}
/* Modal surfaces above their backdrops AND the scrim.            */
/* Original .palette and .lightbox already declare z-index: 101    */
/* — do not lower them here, that puts them under their            */
/* (invisible) backdrops at z:100 which would eat all clicks.      */

/* ── LIGHTBOX-001 ── Skeleton state                                 */
.lightbox-image.is-skeleton {
  background:
    linear-gradient(
      90deg,
      transparent 0%,
      rgba(255, 255, 255, 0.06) 50%,
      transparent 100%
    ),
    repeating-conic-gradient(
      rgba(255, 255, 255, 0.025) 0% 25%,
      transparent 0% 50%
    ),
    var(--bg-elevated);
  background-size:
    200% 100%,
    16px 16px,
    auto;
  animation: lb-shimmer 1.4s ease-in-out infinite;
}
@keyframes lb-shimmer {
  0% {
    background-position:
      -100% 0,
      0 0,
      0 0;
  }
  100% {
    background-position:
      200% 0,
      0 0,
      0 0;
  }
}
.lightbox-skeleton-row {
  display: grid;
  grid-template-columns: 92px 1fr;
  gap: 12px;
  padding: 6px 14px;
  align-items: center;
}
.lightbox-skeleton-bar {
  height: 10px;
  border-radius: 3px;
  background: linear-gradient(
    90deg,
    var(--bg-elevated) 0%,
    color-mix(in oklab, var(--text-secondary) 10%, var(--bg-elevated)) 50%,
    var(--bg-elevated) 100%
  );
  background-size: 200% 100%;
  animation: lb-shimmer 1.4s ease-in-out infinite;
}
.lightbox-skeleton-bar--sm {
  width: 60%;
}
.lightbox-skeleton-bar--md {
  width: 80%;
}
.lightbox-skeleton-bar--lg {
  width: 100%;
}
.lightbox-section.is-skeleton .lightbox-section-head {
  width: 60px;
  height: 8px;
  border-radius: 2px;
  background: var(--bg-elevated);
  color: transparent;
}
/* Export/Delete disabled while skeleton shows */
.lightbox-action:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* ── ACCENT-001 ── Tame the default wire + port treatment          */
/* Default wires are dim; only selection lights them up.             */
.wire {
  opacity: 0.28;
  filter: none;
  stroke-width: 1.5;
  transition:
    opacity var(--dur),
    stroke-width var(--dur),
    filter var(--dur);
}
.wire--character {
  /* Match the ochre family but desaturate so it stops competing     */
  /* with Run All + selection.                                       */
  stroke: color-mix(in oklab, var(--type-character) 65%, #8b8578);
}
.wire--blocked {
  opacity: 0.45;
}
/* Port dots default: neutral when wired, bright only on highlight.  */
.input-port.is-wired .input-dot,
.output-port.is-wired .output-dot {
  box-shadow: none;
  background: color-mix(in oklab, var(--wire) 70%, var(--bg-card));
  border-color: color-mix(in oklab, var(--wire) 70%, var(--border));
}
.input-port.is-character.is-wired .input-dot,
.output-port.is-character.is-wired .output-dot {
  background: color-mix(in oklab, var(--type-character) 60%, var(--bg-card));
  border-color: color-mix(in oklab, var(--type-character) 60%, var(--border));
}

/* ── SELECT-001 ── Node selection highlights wires                  */
.node.is-selected {
  border-color: var(--node-accent);
  box-shadow:
    0 0 0 1px var(--node-accent),
    0 0 20px -4px color-mix(in oklab, var(--node-accent) 60%, transparent),
    var(--shadow-card);
}
.node.is-selected .node-head {
  border-bottom-color: color-mix(
    in oklab,
    var(--node-accent) 30%,
    var(--border-subtle)
  );
}
/* Port rings amplify on the selected node to signal the wire joint. */
.node.is-selected .input-port.is-wired .input-dot,
.node.is-selected .output-port.is-wired .output-dot {
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--node-accent) 25%, transparent);
}

/* A highlighted wire comes from / goes to the selected node. */
.wire.is-highlighted {
  opacity: 0.95;
  stroke-width: 2;
  filter: drop-shadow(
    0 0 4px color-mix(in oklab, currentColor 70%, transparent)
  );
}
.wire--character.is-highlighted {
  stroke: var(--type-character);
  color: var(--type-character);
}
.wire--scene.is-highlighted {
  stroke: var(--type-scene);
  color: var(--type-scene);
}

/* When any node is selected, dim every non-highlighted wire further */
/* so the selected subgraph reads as foreground.                     */
.canvas.has-selection .wire:not(.is-highlighted) {
  opacity: 0.14;
}
.canvas.has-selection .node:not(.is-selected) {
  opacity: 0.82;
}

/* Deselect affordance on canvas background. */
.canvas {
  cursor: default;
}

/* ═══════════════════════════════════════════════════════════════ */
/* Right rail + node editor drawer (DRAWER-002)                     */
/* ═══════════════════════════════════════════════════════════════ */

.drawer--node {
  width: 420px;
  min-width: 420px;
  border-left: 1px solid var(--border);
  border-right: none;
  background: var(--bg-rail);
}

/* Collapsed = drawer fully hidden; the page-edge handle reopens it. */
.drawer--node[data-collapsed="true"] {
  display: none;
}

/* Edge handle — appears at the right viewport edge while the drawer  */
/* is collapsed. Doubles as the reopen affordance.                    */
.drawer-edge-handle {
  position: fixed;
  top: 50%;
  right: 0;
  transform: translateY(-50%);
  width: 22px;
  height: 64px;
  border: 1px solid var(--border);
  border-right: none;
  border-radius: var(--radius-md) 0 0 var(--radius-md);
  background: var(--bg-card);
  color: var(--text-secondary);
  display: grid;
  place-items: center;
  z-index: 60;
  transition:
    background var(--dur-fast),
    color var(--dur-fast),
    width var(--dur-fast);
}
.drawer-edge-handle:hover {
  width: 28px;
  background: var(--bg-elevated);
  color: var(--text-primary);
}

/* Header */
.ned-head {
  gap: 8px;
  padding: 12px 12px 12px 14px;
  border-bottom: 1px solid var(--border-subtle);
  align-items: center;
}
.ned-h-badge {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border-radius: 5px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  display: grid;
  place-items: center;
}
.ned-h-title {
  flex: 1;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
  outline: none;
  cursor: text;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ned-h-title:focus-visible {
  outline: none;
  background: var(--bg-elevated);
  border-radius: 3px;
  padding: 0 4px;
  margin: 0 -4px;
}
.ned-h-version {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--bg-elevated);
  padding: 2px 6px;
  border-radius: 3px;
  flex-shrink: 0;
}
.ned-h-menu {
  width: 24px;
  height: 24px;
  border-radius: 5px;
  color: var(--text-muted);
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.ned-h-menu:hover {
  color: var(--text-secondary);
  background: var(--bg-elevated);
}

/* Body */
.ned-body {
  flex: 1;
  overflow-y: auto;
  padding: 14px 14px 18px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* Empty state */
.ned-empty {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 60px 28px;
  color: var(--text-muted);
}
.ned-empty-icon {
  width: 48px;
  height: 48px;
  border: 1px dashed var(--border-subtle);
  border-radius: var(--radius-md);
  display: grid;
  place-items: center;
  margin-bottom: 14px;
  color: var(--text-muted);
}
.ned-empty-title {
  font-size: 13px;
  color: var(--text-secondary);
  margin: 0 0 4px;
  font-weight: 500;
}
.ned-empty-hint {
  font-size: 11.5px;
  margin: 0;
  line-height: 1.45;
}

/* Drawer state machine. data-state drives which body block is visible. */
.drawer--node[data-state="empty"] .ned-content,
.drawer--node[data-state="empty"] .ned-references,
.drawer--node[data-state="empty"] .ned-generate,
.drawer--node[data-state="empty"] .ned-cta,
.drawer--node[data-state="empty"] .ned-history-section,
.drawer--node[data-state="empty"] .ned-h-badge {
  display: none;
}
.drawer--node[data-state="empty"] .ned-h-title {
  color: var(--text-muted);
  font-style: italic;
  cursor: default;
}
.drawer--node[data-state="active"] .ned-empty {
  display: none;
}

/* Segment block */
.ned-segment {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 10px 12px 12px;
}
.ned-segment-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 8px;
}
.ned-segment-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.ned-segment-meta {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}
.ned-segment-meta--empty {
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.ned-segment-text {
  width: 100%;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  font-family: inherit;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-primary);
  resize: vertical;
  min-height: 56px;
  outline: none;
  margin-bottom: 8px;
  box-sizing: border-box;
}
.ned-segment-text:focus-visible {
  border-color: var(--border-accent);
  outline: none;
}

.ned-segment-empty {
  padding: 12px 14px;
  border: 1px dashed var(--border-subtle);
  border-radius: var(--radius-sm);
  text-align: center;
  font-size: 11.5px;
  color: var(--text-muted);
  margin-bottom: 8px;
  line-height: 1.45;
}

.ned-presets {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.ned-chip {
  font-family: inherit;
  font-size: 10.5px;
  letter-spacing: -0.005em;
  padding: 3px 9px;
  border-radius: 999px;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-secondary);
  transition:
    background var(--dur-fast),
    border-color var(--dur-fast),
    color var(--dur-fast);
}
.ned-chip:hover {
  background: var(--bg-elevated);
  color: var(--text-primary);
}
.ned-chip.is-active {
  background: var(--accent-tint);
  border-color: var(--accent-border);
  color: var(--accent-bright);
}

/* Wired-reference list */
.ned-refs {
  display: flex;
  flex-direction: column;
  gap: 4px;
  list-style: none;
  padding: 0;
  margin: 0;
}
.ned-ref {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 8px;
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  cursor: pointer;
  transition: background var(--dur-fast);
}
.ned-ref:hover {
  background: color-mix(in oklab, var(--type-character) 8%, var(--bg-elevated));
}
.ned-ref-thumb {
  width: 28px;
  height: 28px;
  border-radius: 5px;
  flex-shrink: 0;
  background: var(--bg-card);
}
.ned-ref-name {
  font-size: 12px;
  flex: 1;
  color: var(--text-primary);
}
.ned-ref-tag {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.04em;
  color: var(--type-character);
  background: color-mix(in oklab, var(--type-character) 12%, transparent);
  padding: 2px 6px;
  border-radius: 3px;
  flex-shrink: 0;
}

/* Generate block */
.ned-generate {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 12px;
}
.ned-generate-head {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin-bottom: 10px;
}
.ned-section-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.ned-generate-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 8px;
}
.ned-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.ned-field-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.ned-select {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: 6px 8px;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 11.5px;
  cursor: pointer;
}
.ned-select:focus-visible {
  border-color: var(--border-accent);
  outline: none;
}

/* CTA row sits outside the Provider panel — primary action stays  */
/* visually distinct from panel-local controls.                    */
.ned-cta {
  display: flex;
  gap: 6px;
  align-items: center;
}
.ned-run {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: linear-gradient(
    180deg,
    var(--accent-bright) 0%,
    var(--accent) 100%
  );
  color: var(--accent-ink);
  font-weight: 600;
  font-size: 12px;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  letter-spacing: -0.005em;
}
.ned-run kbd {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 500;
  background: rgba(0, 0, 0, 0.18);
  padding: 1px 5px;
  border-radius: 3px;
  letter-spacing: 0.04em;
}
.ned-run:hover {
  filter: brightness(1.05);
}

.ned-icon {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  color: var(--text-secondary);
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.ned-icon:hover {
  color: var(--text-primary);
  background: color-mix(in oklab, var(--text-primary) 8%, var(--bg-elevated));
}

/* History list — uses .lh-list / .lh-item styling from the Library and */
/* History drawers. Only the section frame is bespoke.                   */
.ned-history-section {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ned-history-head {
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.ned-history-count {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-muted);
  letter-spacing: 0.04em;
}

/* Responsive: stack drawer below canvas on narrow viewports. */
@media (max-width: 1024px) {
  .drawer--node {
    width: 100%;
    min-width: 0;
    border-left: none;
    border-top: 1px solid var(--border);
  }
  .drawer-edge-handle {
    display: none;
  }
}

/* Canvas toast — short ephemeral feedback ("Added X to canvas"). */
#canvas-toast {
  position: fixed;
  bottom: 28px;
  left: 50%;
  transform: translate(-50%, 12px);
  background: var(--bg-card);
  border: 1px solid var(--border-accent);
  color: var(--text-primary);
  font-size: 12.5px;
  padding: 8px 14px;
  border-radius: 999px;
  box-shadow: var(--shadow-card);
  opacity: 0;
  pointer-events: none;
  z-index: 65;
  transition:
    opacity var(--dur) ease,
    transform var(--dur) ease;
}
#canvas-toast.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* Hover/focus affordance on clickable artifact thumbs. */
.lh-thumb,
.node-thumb,
.ned-ref-thumb {
  transition:
    transform var(--dur-fast),
    box-shadow var(--dur-fast);
}
.lh-thumb:hover,
.node-thumb:hover,
.ned-ref-thumb:hover {
  box-shadow: 0 0 0 2px var(--border-accent);
}
.lh-thumb:focus-visible,
.node-thumb:focus-visible,
.ned-ref-thumb:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--accent);
}

/* References pane — port rows mirroring the canvas node card.       */
.ned-port-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
}
.ned-port-list--out {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px dashed var(--border-subtle);
}
.ned-port-list:empty {
  display: none;
}
.ned-port-list--out:empty {
  border-top: none;
  margin: 0;
  padding: 0;
}
/* Reuse the input-port / output-port atoms inside the inspector.    */
.ned-port-list .input-port,
.ned-port-list .output-port {
  padding: 5px 4px;
  cursor: pointer;
}
.ned-port-list .input-port:hover,
.ned-port-list .output-port:hover {
  background: var(--bg-elevated);
  border-radius: 4px;
}

/* ═══════════════════════════════════════════════════════════════ */
/* Settings dialog — provider registry (MODAL-001)                  */
/* ═══════════════════════════════════════════════════════════════ */

.settings-backdrop {
  position: fixed;
  inset: 0;
  background: transparent;
  z-index: 100;
}
.settings {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(720px, calc(100vw - 48px));
  max-height: min(640px, calc(100vh - 48px));
  background: var(--bg-elevated);
  border: 1px solid var(--border-accent);
  border-radius: 14px;
  box-shadow: var(--shadow-modal);
  display: grid;
  grid-template-rows: auto 1fr auto;
  z-index: 101;
  animation: settings-slide var(--dur) cubic-bezier(0.2, 0.9, 0.3, 1);
  overflow: hidden;
}
@keyframes settings-slide {
  from {
    opacity: 0;
    transform: translate(-50%, calc(-50% + 8px)) scale(0.98);
  }
}

.settings-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border-subtle);
}
.settings-title {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
  flex: 1;
}
.settings-close {
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  color: var(--text-muted);
  border-radius: 5px;
  flex-shrink: 0;
}
.settings-close:hover {
  color: var(--text-primary);
  background: var(--bg-card);
}

.settings-body {
  display: grid;
  grid-template-columns: 240px 1fr;
  min-height: 0;
}

/* Left: provider list */
.settings-providers {
  list-style: none;
  margin: 0;
  padding: 12px 8px;
  border-right: 1px solid var(--border-subtle);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.settings-provider {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  border: 1px solid transparent;
  transition: background var(--dur-fast);
}
.settings-provider:hover {
  background: var(--bg-card);
}
.settings-provider.is-selected {
  background: var(--bg-card);
  border-color: var(--border);
}
.settings-provider-radio {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 1.5px solid var(--border-accent);
  background: var(--bg-elevated);
  flex-shrink: 0;
}
.settings-provider.is-selected .settings-provider-radio {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: inset 0 0 0 2px var(--bg-elevated);
}
.settings-provider-meta {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.settings-provider-label {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.settings-provider-id {
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--text-muted);
  letter-spacing: 0.04em;
}
.settings-provider-flag {
  font-family: var(--font-mono);
  font-size: 11px;
  flex-shrink: 0;
}
.settings-provider.is-default .settings-provider-flag {
  color: var(--accent-bright);
}
.settings-provider.is-unconfigured .settings-provider-flag {
  color: var(--text-muted);
}

/* Right: provider detail */
.settings-detail {
  padding: 18px 20px 20px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.settings-detail-title {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
}
.settings-detail-id {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-muted);
  letter-spacing: 0.04em;
  margin: -8px 0 4px;
}
.settings-row {
  display: grid;
  grid-template-columns: 80px 1fr;
  align-items: center;
  gap: 12px;
  padding: 6px 0;
  border-top: 1px solid var(--border-subtle);
}
.settings-row--block {
  grid-template-columns: 1fr;
  align-items: stretch;
}
.settings-row:first-of-type {
  border-top: none;
}
.settings-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.settings-value {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--text-primary);
}
.settings-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-muted);
  flex-shrink: 0;
}
.settings-dot[data-state="ok"] {
  background: #22c55e;
}
.settings-dot[data-state="error"] {
  background: #f87171;
}
.settings-dot[data-state="pending"] {
  background: var(--accent-bright);
  animation: settings-pulse 1s ease-in-out infinite;
}
@keyframes settings-pulse {
  50% {
    opacity: 0.4;
  }
}

.settings-key-wrap {
  display: flex;
  align-items: stretch;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.settings-key-wrap:focus-within {
  border-color: var(--border-accent);
}
.settings-key-input {
  flex: 1;
  background: transparent;
  border: none;
  outline: none;
  padding: 8px 10px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-primary);
  letter-spacing: 0.02em;
  min-width: 0;
}
.settings-key-toggle {
  width: 32px;
  border-left: 1px solid var(--border-subtle);
  color: var(--text-muted);
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.settings-key-toggle:hover {
  color: var(--text-primary);
  background: var(--bg-elevated);
}

.settings-model-select {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
}
.settings-model-select:focus-visible {
  outline: none;
  border-color: var(--border-accent);
}
.settings-model-select:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.settings-actions {
  display: flex;
  gap: 8px;
  margin-top: 8px;
  flex-wrap: wrap;
}
.settings-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 11.5px;
  color: var(--text-primary);
  letter-spacing: -0.005em;
}
.settings-action:hover {
  background: var(--bg-elevated);
  border-color: var(--border-accent);
}
.settings-action:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.settings-action--default[aria-pressed="true"] {
  background: var(--accent-tint);
  border-color: var(--accent-border);
  color: var(--accent-bright);
}

.settings-foot {
  display: flex;
  justify-content: flex-end;
  padding: 12px 16px;
  border-top: 1px solid var(--border-subtle);
}
.settings-done {
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
  font-size: 12px;
  padding: 8px 18px;
  border-radius: var(--radius-sm);
}
.settings-done:hover {
  background: var(--accent-bright);
}

/* Responsive: stack panes on narrow viewports */
@media (max-width: 640px) {
  .settings-body {
    grid-template-columns: 1fr;
  }
  .settings-providers {
    border-right: none;
    border-bottom: 1px solid var(--border-subtle);
    max-height: 200px;
  }
}

/* Node dragging affordance — header is the drag surface. */
.node-head {
  cursor: grab;
  user-select: none;
}
.node-head:active,
.node.is-dragging .node-head {
  cursor: grabbing;
}
/* Children that own their own input keep their normal cursor. */
.node-head [contenteditable],
.node-head button.node-menu,
.node-head button.node-run {
  cursor: text;
}
.node-head button.node-menu,
.node-head button.node-run {
  cursor: pointer;
}
.node-move {
  cursor: grab;
}
.node.is-dragging {
  /* Subtle visual feedback while dragging — no transform animation */
  /* on .node hover during a drag.                                  */
  box-shadow:
    0 8px 28px -6px rgba(0, 0, 0, 0.45),
    var(--shadow-card);
  opacity: 0.96;
  transition: none;
}

/* ═══════════════════════════════════════════════════════════════ */
/* Force [hidden] to actually hide                                   */
/* The .palette / .lightbox / .settings rules use display:flex/grid  */
/* which have equal specificity to the UA `[hidden] { display:none } */
/* rule. In source order, our author rule wins, so `hidden=true` in  */
/* JS doesn't visually hide the dialog. Force it.                    */
/* ═══════════════════════════════════════════════════════════════ */
[hidden] {
  display: none !important;
}

/* =========================================================== */
/* Section 2 — Production overlay rules                        */
/* =========================================================== */

/*
 * Production overlay for editor-v7. Loaded *after* the mockup stylesheet
 * so component-specific overrides win without editing the mockup. Per
 * CLAUDE.md "Mockup UX Conventions" the mockup files stay untouched
 * until a deliberate port to /src/ — this file is that overlay.
 */

/* Node-card thumbnail is a click target for the artifact-dialog
 * (lightbox-001). Magnify cursor signals "click to inspect" — same
 * affordance the .lh-item rows already offer in the library/history
 * drawers. Stays as cursor:zoom-in (not :pointer) to differentiate
 * from button-style click targets like .node-run. */
.node-thumb {
  cursor: zoom-in;
}

/* Run-status label in .node-stat (left of the run button). Mirrors the
 * existing .node-stat-label--waiting layout (glyph + text) so the row
 * carries one consistent shape across running / ok / blocked / error.
 * Shape (●/▲/✕) is the primary signal; color is secondary for a11y. */
.node-stat-glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 10px;
  height: 10px;
  margin-right: 6px;
  font-size: 11px;
  line-height: 1;
}
.node-stat-label--ok {
  color: var(--accent-success, #4ade80);
}
.node-stat-label--blocked {
  color: var(--accent-warn, #f59e0b);
}
.node-stat-label--error {
  color: var(--accent-error, #ef4444);
}

/* Failed-run overlay inside .node-preview. Replaces the empty thumb
 * gradient when the latest Generation is blocked/error AND no
 * successful artifact exists for the node. When a prior success
 * exists, only the pip changes — the image stays. */
.node-preview {
  position: relative;
}
.node-failed {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 16px;
  text-align: center;
  background: var(--bg-elevated, rgba(0, 0, 0, 0.4));
  border-radius: 6px;
  pointer-events: none;
}
.node-failed-glyph {
  font-size: 22px;
  line-height: 1;
}
.node-failed--blocked .node-failed-glyph {
  color: var(--accent-warn, #f59e0b);
}
.node-failed--error .node-failed-glyph {
  color: var(--accent-error, #ef4444);
}
.node-failed-headline {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
}
.node-failed-message {
  margin: 0;
  font-size: 11px;
  line-height: 1.4;
  color: var(--text-muted);
  max-width: 240px;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Artifact dialog: when the artifact has real `data:` bytes, the
 * preview swaps from a gradient div to an <img>. The base
 * .lightbox-image rule from the mockup sets aspect-ratio + sizing;
 * we just need object-fit so the image fills the square without
 * distortion (mockup didn't ship this rule because it never had a
 * real <img> variant). */
.lightbox-image--bytes {
  object-fit: cover;
  background: var(--bg-elevated, #0f0f0f);
}

/* Authority drawer — descriptions can be paragraph-long (Getty AAT
 * scope notes regularly hit 300+ chars). Clamp to keep rows compact;
 * the artifact-dialog provides the full-detail view when needed. */
.drawer--authority .lh-list .lh-meta {
  white-space: normal;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.4;
  max-height: calc(2 * 1.4em);
}

.drawer--authority .lh-item {
  align-items: flex-start;
}

.drawer--authority .authority-thumb {
  flex: 0 0 auto;
  width: 72px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-elevated, rgba(255, 255, 255, 0.04));
  border-radius: 8px;
}

.drawer--authority .authority-source-badge {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-muted);
  text-transform: none;
  letter-spacing: 0.02em;
}

.drawer-warn {
  margin: 8px 16px;
  padding: 8px 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-warn, #f59e0b);
  border: 1px solid var(--border-warn, rgba(245, 158, 11, 0.3));
  border-radius: 6px;
}

.drawer-note {
  margin: 8px 16px;
  padding: 8px 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-muted);
  border: 1px dashed var(--border, rgba(255, 255, 255, 0.1));
  border-radius: 6px;
}

/* Empty / loading copy inside .drawer-body. Used by every drawer
 * (outline, library, history, node, authority) for "no results",
 * "loading", and "type a query" states. The mockup HTML never renders
 * these strings — they only appear at runtime — so the mockup CSS
 * doesn't ship a rule. Keeps the message visually distinct from the
 * .lh-list rows it replaces: muted, padded, line-height generous
 * enough for a 2-line wrap. */
.drawer-empty {
  margin: 0;
  padding: 16px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-muted);
}

/* Settings modal — multi-provider variants the mockup CSS doesn't cover.
 * Star action toggles per-capability default; muted note replaces the
 * image-model dropdown for providers without `capabilities.image`;
 * error variant of .settings-value carries the red Test-connection
 * message body. */
.settings-action--star {
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
}

/* Node-drawer Editor Pane — subject-text override. Sits above the
 * read-only Ports/Provenance sections. The textarea grows vertically
 * via `rows`; the hint is muted and small so the surface stays calm. */
.node-editor-subject {
  width: 100%;
  box-sizing: border-box;
  margin: 8px 0 0;
  padding: 8px 10px;
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: 4px;
  font: inherit;
  font-size: 13px;
  line-height: 1.5;
  resize: vertical;
  min-height: 64px;
}

.node-editor-subject:focus {
  outline: none;
  border-color: var(--accent-default, var(--accent));
}

.node-editor-subject::placeholder {
  color: var(--text-muted);
  font-style: italic;
}

.node-editor-hint {
  margin: 6px 0 0;
  font-size: 11px;
  line-height: 1.4;
  color: var(--text-muted);
}

/* Per-port guidance row — sits inside .outline-list as a second
 * <li> immediately after each input port. Indented to align under
 * the port's .outline-name (badge is ~32px + gap). Output ports do
 * not render this row. */
.port-guidance {
  list-style: none;
  margin: 0 0 6px;
  padding: 4px 0 0 44px;
}

.port-guidance-text {
  width: 100%;
  box-sizing: border-box;
  padding: 6px 8px;
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: 3px;
  font: inherit;
  font-size: 12px;
  line-height: 1.4;
  resize: vertical;
  min-height: 40px;
}

.port-guidance-text:focus {
  outline: none;
  border-color: var(--accent-default, var(--accent));
}

.port-guidance-text::placeholder {
  color: var(--text-muted);
  font-style: italic;
}

.settings-action--star.is-active {
  background: var(--accent-default, #f59e0b);
  color: var(--bg-base, #0a0a0a);
  border-color: transparent;
}

.settings-value--muted {
  color: var(--text-muted);
  font-style: italic;
}

.settings-value--error {
  color: var(--text-error, #ef4444);
  word-break: break-word;
}

/* INPUT add-zone — mirrors `.input-port`'s row geometry from the
 * mockup (padding, dot dimensions, label font), so the four rows in
 * .node-inputs read with one consistent rhythm. The only visual
 * distinction is the dashed dot border ("nothing connected yet") and
 * a hover-revealed suggestion span. A wire-drop mints a fresh Port
 * typed to the source. Type check is bypassed at this target —
 * universal escape hatch from 1:1 type matching (see prompt 014). */
.input-port--add {
  display: flex;
  align-items: center;
  gap: 8px;
  position: relative;
  padding: 4px 12px;
  cursor: copy;
  color: var(--text-muted);
}

/* Dashed variant of `.input-dot`: same 10×10 + 1.5px border so wired
 * and unwired rows have identical heights and dot centers align
 * column-to-column across all input rows. */
.input-port--add .input-dot--empty {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 1.5px dashed currentColor;
  background: transparent;
  flex-shrink: 0;
  box-sizing: border-box;
}

/* Suggestion hint — collapsed until the node is hovered. Matches
 * `.input-label`'s font/size/casing/letter-spacing from the mockup
 * so the row continues to read as one line; opacity 0.7 lets the
 * actual label win the eye. */
.input-port-hint {
  display: none;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
  opacity: 0.7;
  margin-left: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.node:hover .input-port-hint {
  display: inline;
}

.input-port--add.is-wire-target {
  background: color-mix(in oklab, var(--accent, #f59e0b) 12%, transparent);
  color: var(--accent, #f59e0b);
}

.input-port--add.is-wire-target .input-dot--empty {
  border-style: solid;
}

/* Per-input × button. Hidden by default; revealed on hover of the
 * input row. Click cascades to graphRemovePort which also drops any
 * wire touching this port. */
.input-port {
  position: relative;
}

.input-port-remove {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  margin: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 3px;
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  visibility: hidden;
  transition:
    color 80ms ease,
    border-color 80ms ease,
    background 80ms ease;
}

.input-port:hover .input-port-remove {
  visibility: visible;
}

.input-port-remove:hover {
  color: var(--accent-error, #ef4444);
  border-color: var(--accent-error, #ef4444);
  background: color-mix(in oklab, var(--accent-error, #ef4444) 8%, transparent);
}

.input-port-remove:focus-visible {
  outline: none;
  visibility: visible;
  border-color: var(--accent, #f59e0b);
  color: var(--accent, #f59e0b);
}

/* Inspect drawer × button — same idiom as node-card's input-port-remove
 * but always visible (the drawer is the secondary path for users who
 * find the on-card × too small to hit). Sits flush-right of the
 * outline-dot on input port rows. */
.outline-port-remove {
  margin-left: auto;
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 3px;
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  transition:
    color 80ms ease,
    border-color 80ms ease,
    background 80ms ease;
}

.outline-port-remove:hover {
  color: var(--accent-error, #ef4444);
  border-color: var(--accent-error, #ef4444);
  background: color-mix(in oklab, var(--accent-error, #ef4444) 8%, transparent);
}

.outline-port-remove:focus-visible {
  outline: none;
  border-color: var(--accent, #f59e0b);
  color: var(--accent, #f59e0b);
}

/* CORS / proxy-required warning shown above the Status row when a
 * non-browser-callable provider is selected. Yellow / advisory tone:
 * the key is configurable but won't work in BYOK browser mode. */
.settings-warn {
  margin: 0 0 12px 0;
  padding: 10px 12px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-warn, #f59e0b);
  background: var(--bg-warn, rgba(245, 158, 11, 0.08));
  border: 1px solid var(--border-warn, rgba(245, 158, 11, 0.3));
  border-radius: 6px;
}

/* Account dialog — identity header. Reuses .settings* shell otherwise. */
.account-identity {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 4px 0 16px 0;
  border-bottom: 1px solid var(--border, rgba(255, 255, 255, 0.08));
  margin-bottom: 16px;
}

.account-avatar-lg {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  font-weight: 600;
  background: var(--accent, #6366f1);
  color: var(--text-on-accent, #ffffff);
  flex: 0 0 auto;
}

.account-identity-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

/* Artifact dialog — prompt-text row carries a truncated preview plus a
 * small clipboard button. The base .lightbox-row-value rule whites-space:
 * nowrap + ellipsis; for the prompt row we keep that single-line preview
 * but flex the copy button into the right edge of the value column. */
.lightbox-row-value--copyable {
  justify-content: space-between;
}

.lightbox-row-text {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1 1 auto;
}

.lightbox-row-copy {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  margin: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text-muted);
  cursor: pointer;
  transition:
    color 80ms ease,
    border-color 80ms ease,
    background 80ms ease;
}

.lightbox-row-copy:hover {
  color: var(--text-primary);
  border-color: var(--border);
  background: var(--bg-rail);
}

.lightbox-row-copy:focus-visible {
  outline: none;
  border-color: var(--accent);
  color: var(--accent);
}

/* Guided drag — when an output is being dragged, mute every input port
 * that doesn't accept the source's type, and glow the ports that do
 * (plus every add-zone, since add-zones mint a port to fit). The
 * default rule (no .is-drag-match, not an add-zone) mutes; positive
 * flags overrule via specificity. Driven by `body.is-wire-dragging`,
 * which `wire-create.ts:enterDragMode` adds at pointerdown and
 * `clearState` strips at pointerup / pointercancel / teardown. */
body.is-wire-dragging .input-port:not(.input-port--add):not(.is-drag-match) {
  opacity: 0.3;
  pointer-events: none;
}

/* Matched typed ports get the strong glow — the primary "drop here" signal. */
body.is-wire-dragging .is-drag-match {
  outline: 1px solid var(--accent, #f59e0b);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Add-zones get a subtler signal — they're the fallback ("you can also
 * drop here, the system will mint a port to fit"), so the dashed dot
 * just shifts to the accent color rather than the whole row outlining.
 * Keeps the canvas readable when many nodes are visible at once. */
body.is-wire-dragging .input-port--add .input-dot--empty {
  border-color: var(--accent, #f59e0b);
}

/* Source node — fade its own input area so the user can't self-loop
 * and so visual attention stays on the *other* nodes' targets. The
 * compatibleTarget gate rejects drops here regardless, but the visual
 * mute prevents the user from trying. */
body.is-wire-dragging .is-drag-source-node .input-port {
  opacity: 0.3;
  pointer-events: none;
}
body.is-wire-dragging .is-drag-source-node .input-port--add .input-dot--empty {
  border-color: currentColor;
}

/* Tooltips are noise during a drag: the user's intent is set, no
 * need to surface labels of incidental hovers. The portalled
 * #floating-tooltip is the only tooltip surface. */
body.is-wire-dragging #floating-tooltip {
  display: none;
}

/* ── Library drag ─────────────────────────────────────────────────────
 * Mouse-based drag of a library / history thumbnail onto an input
 * port. The same is-wire-dragging-style mute is applied to ports that
 * aren't valid drop targets (only unwired input ports accept drops);
 * the active hover gets a strong glow via `.is-library-target`.
 *
 * Driven by `body.is-library-dragging`, added at the threshold-crossed
 * moment in library-drag.ts and stripped on pointerup/cancel. */
body.is-library-dragging {
  cursor: grabbing;
}

/* Floating ghost — fixed to the viewport, follows the pointer via a
 * transform set on every pointermove. 64×64 keeps it small enough to
 * not occlude the drop target. */
.library-drag-ghost {
  position: fixed;
  top: 0;
  left: 0;
  width: 64px;
  height: 64px;
  pointer-events: none;
  z-index: 9999;
  border-radius: 6px;
  overflow: hidden;
  box-shadow: var(--shadow-modal, 0 8px 24px rgba(0, 0, 0, 0.4));
  opacity: 0.85;
  transform: translate(-9999px, -9999px);
}
.library-drag-ghost .lh-thumb {
  width: 100%;
  height: 100%;
  border-radius: 6px;
}

/* During a library drag: every non-wired input port AND every add-zone
 * is a valid drop target. Add-zones mint a new typed port on drop
 * (typed to the dragged item's pre-resolved ConceptType); existing
 * ports just accept the wire. Only `.is-wired` ports are muted —
 * they already have an upstream source and silently refuse overwrites.
 *
 * Two layers of signal: a subtle dashed ring on every valid candidate
 * (so the user sees options at drag start, before hovering anything),
 * and a stronger solid outline on the actively hovered candidate via
 * `.is-library-target`. Mirrors the static + dynamic split in
 * wire-create (`.is-drag-match` static / `.is-wire-target` dynamic). */
body.is-library-dragging .input-port.is-wired {
  opacity: 0.3;
  pointer-events: none;
}
body.is-library-dragging .input-port[data-port-id]:not(.is-wired),
body.is-library-dragging .input-port--add[data-node-id] {
  outline: 1px dashed
    var(
      --accent-border,
      color-mix(in oklab, var(--accent, #f59e0b) 30%, transparent)
    );
  outline-offset: 2px;
  border-radius: 2px;
}
body.is-library-dragging .input-port.is-library-target {
  outline: 1px solid var(--accent, #f59e0b);
  outline-offset: 2px;
  border-radius: 2px;
}
body.is-library-dragging #floating-tooltip {
  display: none;
}

/* ── Reference node card ──────────────────────────────────────────────
 * Reference cards carry a library/uploaded image as a wire payload —
 * no inputs, no body text, no Run. The thumb fills the card; the
 * footer holds a single output port that wires downstream. */
.node--reference {
  min-height: auto;
}
.node--reference .node-preview--reference {
  /* Drop the failed-hero overlay padding the generator preview reserves. */
  padding: 0;
}
.node--reference .node-thumb--reference {
  /* Stronger preview: the thumbnail IS the card's content. */
  aspect-ratio: 1 / 1;
  background-color: var(--bg-elevated, #1c1c1c);
  background-size: cover;
  background-position: center;
  border-radius: 4px;
}

/* ──────────────────────────────────────────────────────────────── */
/* Node status row — refined treatment.                              */
/* Run button is always right-aligned (no left→right flip when the   */
/* status label appears). Label adopts the card's mono uppercase     */
/* inspector vocabulary. Spinner is a rotating ring, not a 7px dot.  */
/* ──────────────────────────────────────────────────────────────── */
.node-stat {
  justify-content: flex-end;
  padding: 10px 12px;
  gap: 8px;
}
.node-stat-label {
  margin-right: auto;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.node-stat-glyph {
  width: 18px;
  height: 18px;
  margin-right: 0;
  border-radius: 50%;
  background: color-mix(in oklab, currentColor 14%, transparent);
}
.node-stat-label--waiting {
  color: var(--text-secondary);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-size: 10px;
  font-family: var(--font-mono);
}

/* Ok state: the green check already says "this ran successfully" —
   the "READY" word is redundant. Hide the text but keep the glyph
   visible and the parent's aria-label / tooltip intact. Blocked /
   Failed still render their text because the word is the signal. */
.node-stat-label--ok {
  font-size: 0;
}
.node-stat-label--ok .node-stat-glyph {
  font-size: 10px;
}

/* Rotating ring spinner — replaces the pulsing 7px dot. Same DOM
   node and class as the mockup; just visually beefier. */
.node-stat-dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: transparent;
  border: 1.5px solid color-mix(in oklab, var(--waiting) 22%, transparent);
  border-top-color: var(--waiting);
  box-shadow: none;
  animation: node-stat-spin 0.85s linear infinite;
}
@keyframes node-stat-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Run button — slightly larger touch target, vertical gradient,
   thin accent halo so the amber reads as an intentional CTA rather
   than a flat swatch. */
.node-run {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  background: linear-gradient(180deg, var(--accent-bright), var(--accent));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    0 2px 6px -1px rgba(0, 0, 0, 0.35),
    0 0 0 1px color-mix(in oklab, var(--accent) 35%, transparent);
}
.node-run:hover {
  transform: translateY(-1px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.28),
    0 6px 16px -3px color-mix(in oklab, var(--accent) 55%, transparent),
    0 0 0 1px color-mix(in oklab, var(--accent) 55%, transparent);
}
.node-run[disabled] {
  background: var(--bg-elevated);
  box-shadow: inset 0 0 0 1px var(--border-subtle);
}
.node-run[disabled]:hover {
  box-shadow: inset 0 0 0 1px var(--border-subtle);
}

/* ═══════════════════════════════════════════════════════════ */
/* Fullscreen canvas (Phase 1 — CSS-only chrome hide).          */
/* Toggled by main.ts via [data-canvas-fullscreen] on <html>.   */
/* ═══════════════════════════════════════════════════════════ */

html[data-canvas-fullscreen] editor-rail,
html[data-canvas-fullscreen] editor-topbar,
html[data-canvas-fullscreen] drawer-outline,
html[data-canvas-fullscreen] drawer-library,
html[data-canvas-fullscreen] drawer-history,
html[data-canvas-fullscreen] drawer-node,
html[data-canvas-fullscreen] drawer-authority {
  display: none;
}

html[data-canvas-fullscreen] .workspace {
  width: 100vw;
}
