/* ==========================================================================
   Mermaid Chart — diagrams-as-code. Layout mirrors Code Genie: a toolbar, a
   split body (editor | preview), an error bar and a status footer. Uses the
   shared design tokens from protium-ui.css.
   ========================================================================== */

.ms-title { font-weight: 600; color: var(--text); letter-spacing: .2px; }

.ms-main {
  display: flex; flex-direction: column;
  height: calc(100vh - var(--nav-h) - var(--status-h));
  min-height: 0;
}

/* Each mode (Code / Draw) is itself a flex column filling .ms-main */
.ms-mode { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
.ms-mode.pt-hidden { display: none; }

/* Disabled Draw tab in the segmented control */
.pt-segment button:disabled { opacity: .45; cursor: not-allowed; }
.pt-segment button:disabled:hover { color: var(--text-muted); }

/* ---- shape palette (draggable chips, Lucidchart-style) ---------------- */
/* DRAW body: left palette sidebar + canvas (Lucidchart/Miro layout) */
.ms-draw-row { flex: 1 1 auto; display: flex; min-height: 0; position: relative; }
.ms-palette {
  flex: 0 0 168px; display: flex; flex-direction: column; gap: 6px;
  padding: 10px; overflow: auto; background: var(--surface); border-right: 1px solid var(--border);
}
.ms-palette-title { font: 600 11px/1 var(--font-sans); letter-spacing: .4px; text-transform: uppercase; color: var(--text-muted); padding: 2px 2px 6px; }
.ms-chip {
  display: flex; align-items: center; gap: 8px; cursor: grab;
  height: 34px; padding: 0 12px; border-radius: var(--r-md, 8px);
  border: 1px solid var(--border); background: var(--field); color: var(--text);
  font: 500 12.5px/1 var(--font-sans); user-select: none; white-space: nowrap;
  transition: border-color .12s var(--ease), background .12s var(--ease), box-shadow .12s var(--ease);
}
.ms-chip:hover { border-color: var(--accent); background: var(--surface); box-shadow: 0 1px 6px rgba(37,99,235,.12); }
.ms-chip:active { cursor: grabbing; }
/* tiny shape glyph to hint each chip's look */
.ms-chip-glyph { width: 16px; height: 12px; flex: 0 0 16px; border: 1.5px solid #2563eb; background: #eff6ff; }
.cg-rect { border-radius: 2px; }
.cg-round { border-radius: 5px; }
.cg-stadium { border-radius: 999px; }
.cg-subroutine { border-left-width: 3px; border-right-width: 3px; border-radius: 1px; }
.cg-cylinder { border-radius: 50% / 30%; }
.cg-circle { width: 13px; height: 13px; flex-basis: 13px; border-radius: 50%; }
.cg-diamond { width: 11px; height: 11px; flex-basis: 11px; transform: rotate(45deg); border-radius: 1px; }
.cg-hexagon { clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%); }
.cg-asymmetric { clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 30% 50%); }

/* ---- DRAW canvas (React Flow) ----------------------------------------- */
/* Kept LIGHT in both themes — matches the preview canvas convention. The
   React Flow pane fills the area below the draw toolbar. */
.ms-rf {
  flex: 1 1 auto; min-height: 0; min-width: 0;
  /* dots come from React Flow's <Background variant="dots"> (pan/zoom aware) */
  background: #ffffff;
}

/* V2 SHAPE SYSTEM: the bundle renders each node as
   <div class="rf-node rf-<shape>"> containing an SVG shape body
   (.rf-shape-svg — polygon/path/ellipse sized to the label) plus an upright,
   React-escaped .rf-label layered above it. The div itself is a transparent
   hit-box; all visuals (fill, border, shadow, selection glow) live on the SVG,
   so diamonds/circles/hexagons are crisp real geometry at any size. */
.rf-node {
  position: relative; box-sizing: border-box; cursor: grab;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: none; padding: 0;
}
.rf-node:active { cursor: grabbing; }
.rf-shape-svg {
  position: absolute; inset: 0; overflow: visible; display: block;
  filter: drop-shadow(0 1.5px 3px rgba(15, 23, 42, .13));
  transition: filter .14s var(--ease);
}
/* subtle hover lift so boxes feel tactile (Lucidchart-style affordance) */
.react-flow__node:hover .rf-node:not(.is-sel) .rf-shape-svg {
  filter: drop-shadow(0 3px 7px rgba(15, 23, 42, .18));
}
/* <br/> FIX: labels arrive with real newlines (normalised from mermaid's
   <br/>); pre-line makes them wrap instead of rendering one huge line.
   IMPORTANT: this font MUST match the bundle's text measurer (LABEL_FONT),
   and --wrap must match SHAPE_WRAP per shape, so the drawn label wraps
   exactly like the measured one and always fits inside the geometry. */
.rf-label {
  position: relative; z-index: 2; text-align: center;
  font: 500 13px/1.45 'Inter Tight', system-ui, sans-serif; color: #0f172a;
  white-space: pre-line; overflow-wrap: break-word; word-break: break-word;
  max-width: min(var(--wrap, 260px), 100%);
}
.rf-node { --wrap: 260px; }
.rf-node.rf-subroutine { --wrap: 230px; }
.rf-node.rf-cylinder { --wrap: 210px; }
.rf-node.rf-stadium { --wrap: 220px; }
.rf-node.rf-asymmetric { --wrap: 230px; }
.rf-node.rf-hexagon { --wrap: 190px; }
.rf-node.rf-diamond { --wrap: 150px; }
.rf-node.rf-circle { --wrap: 110px; }
/* Diamonds size ~1:1; when a label is too long for ~3 lines even at the
   smaller font, the bundle sets an inline max-width + this clamp so text is
   truncated with an ellipsis (full text stays in the inspector + title tip).
   The bundle sets inline max-width/font-size; here we cap the line count. */
.rf-label.rf-label-clamp {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden; white-space: normal;
}
/* cylinder: label sits below the top rim; asymmetric: clear the left notch */
.rf-node.rf-cylinder .rf-label { padding-top: 14px; }
.rf-node.rf-asymmetric .rf-label { padding-left: 10px; }
/* Selection: a confident accent glow on the geometry itself (works for every
   shape — no rectangular ring around a diamond). */
.rf-node.is-sel .rf-shape-svg {
  filter: drop-shadow(0 0 1.5px rgba(37, 99, 235, .95))
          drop-shadow(0 0 7px rgba(37, 99, 235, .40))
          drop-shadow(0 2px 4px rgba(15, 23, 42, .14));
}

/* Handles hidden until the box is hovered/selected, so the body is the clear
   drag target and connecting (drag from a dot) is deliberate.
   IMPORTANT: React Flow marks source handles `.connectionindicator`, which sets
   `pointer-events: all` on them. With opacity:0 alone the invisible 10px dots on
   each edge still hit-test, so pressing near a node edge starts a *connection*
   instead of *moving* the node — that's the "dragging felt buggy" report. Force
   `pointer-events:none` while hidden so the body is the unambiguous drag target;
   restore `pointer-events:all` only once the dots are revealed (hover/selected),
   keeping deliberate connect-by-dragging intact. */
/* ---- connect hit-areas (item 3): full-side EDGE strips ------------------
   Each source handle is rendered as a thin strip running the full length of a
   side, so a connection can be started by grabbing ANYWHERE along that edge —
   not just a tiny dot. Hidden + pointer-events:none until the node is hovered/
   selected, so the BODY remains the unambiguous MOVE target; only on hover do
   the strips light up and become grabbable. A small visible dot is drawn via
   ::after for affordance. The target handle (rf-h-target) covers the whole node
   so released connections / onConnectEnd can land anywhere on the box. */
.rf-h {
  background: transparent; border: none; border-radius: 0;
  opacity: 0; pointer-events: none !important;
  transition: opacity .12s var(--ease), background .12s var(--ease);
  z-index: 5;
}
/* strip geometry per side — thin band hugging each edge (override RF inline) */
.rf-h-t, .rf-h-b { width: 100% !important; height: 12px !important; left: 0 !important; transform: none !important; min-width: 0 !important; }
.rf-h-t { top: -2px !important; } .rf-h-b { bottom: -2px !important; top: auto !important; }
.rf-h-l, .rf-h-r { width: 12px !important; height: 100% !important; top: 0 !important; transform: none !important; min-height: 0 !important; }
.rf-h-l { left: -2px !important; } .rf-h-r { right: -2px !important; left: auto !important; }
/* visible affordance dot centered on each strip — a crisp, clearly-grabbable
   "connection point" (Lucidchart/Miro style). Bigger + white halo so it reads as
   an obvious target on hover; grows on its own hover for clear "grab here" intent. */
.rf-h::after {
  content: ""; position: absolute; width: 11px; height: 11px; border-radius: 50%;
  background: #2563eb; border: 2.5px solid #fff;
  box-shadow: 0 0 0 1.5px rgba(37,99,235,.55), 0 1px 3px rgba(15,23,42,.25);
  transition: transform .1s var(--ease), background .1s var(--ease);
}
.rf-h-t::after, .rf-h-b::after { left: 50%; top: 50%; transform: translate(-50%, -50%); }
.rf-h-l::after, .rf-h-r::after { left: 50%; top: 50%; transform: translate(-50%, -50%); }
/* reveal on hover/selected: strips become grabbable and the dots show.
   cursor:crosshair across the WHOLE strip (not just the tiny dot) so the entire
   side reads as "grab to connect". */
.rf-node:hover .rf-h, .react-flow__node:hover .rf-h, .react-flow__node.selected .rf-h {
  opacity: 1; pointer-events: all !important; cursor: crosshair;
}
/* hovering a strip: tint it and pop the dot so it's unmistakably the grab point */
.rf-node:hover .rf-h:hover, .react-flow__node:hover .rf-h:hover {
  background: rgba(37,99,235,.12); cursor: crosshair;
}
.rf-node:hover .rf-h:hover::after, .react-flow__node:hover .rf-h:hover::after {
  transform: translate(-50%, -50%) scale(1.35); background: #1d4ed8;
}

/* ---- connection-drag drop-target highlighting -------------------------- */
/* While a connection is being dragged (wrapper gets .rf-connecting from
   entry.jsx onConnectStart/End), EVERY box advertises that it can receive the
   edge (dots shown), and the box currently under the pointer lights up green so
   the user can SEE where the edge will land. Combined with the generous 90px
   auto-connect threshold, dropping near a box reliably connects. */
.rf-connecting .rf-h { opacity: 1; }
.rf-connecting .react-flow__node:hover .rf-shape-svg,
.rf-connecting .rf-node:hover .rf-shape-svg {
  filter: drop-shadow(0 0 1.5px rgba(22, 163, 74, .95))
          drop-shadow(0 0 8px rgba(22, 163, 74, .5));
}
/* whole canvas shows crosshair during a connection drag for clear intent */
.rf-connecting .react-flow__pane { cursor: crosshair; }
/* whole-node target handle: invisible, sits under the body, accepts drops */
.rf-h-target {
  width: 100% !important; height: 100% !important; top: 0 !important; left: 0 !important;
  transform: none !important; min-width: 0 !important; min-height: 0 !important;
  background: transparent; border: none; border-radius: 8px; opacity: 0;
  pointer-events: none !important; z-index: 0;
}

/* ---- inline label editing (item 5) ------------------------------------ */
/* now a <textarea> so multi-line labels can be edited (Shift+Enter = newline) */
.rf-label-input {
  font: 500 13px/1.45 'Inter Tight', system-ui, sans-serif; color: #0f172a; text-align: center;
  border: 1.5px solid #2563eb; border-radius: 6px; background: #fff;
  padding: 3px 7px; width: calc(100% - 16px); min-width: 82px; box-sizing: border-box; outline: none;
  resize: none; overflow: hidden; display: block;
  box-shadow: 0 2px 10px rgba(37, 99, 235, .18);
}
/* While editing, the input must be the unambiguous focus/click target: lift it
   above the connection handles and disable their pointer-events so a click can't
   land on a handle (starting a connection drag) instead of the field. */
.rf-label-input { position: relative; z-index: 10; pointer-events: auto; }
.rf-node.is-editing .rf-h,
.rf-node.is-editing .rf-h-target { pointer-events: none !important; opacity: 0 !important; }

/* ---- orthogonal edge labels (Yes/No etc.), centered on the elbow path ----
   Rendered via EdgeLabelRenderer as an HTML chip so it sits crisply on the
   right-angle midpoint, regardless of solid/dotted/thick line style. */
.rf-edge-label {
  font: 600 11px 'Inter Tight', system-ui, sans-serif; color: #475569;
  background: #fff; border: 1px solid #cbd5e1; border-radius: 999px;
  padding: 2px 9px; line-height: 1.4; white-space: nowrap;
  box-shadow: 0 1px 3px rgba(15,23,42,.10); user-select: none;
}
/* Lucidchart-style Yes/No edge coding (auto, from the label text). */
.rf-edge-label.rf-edge-yes { color: #15803d; border-color: #86efac; background: #f0fdf4; }
.rf-edge-label.rf-edge-no  { color: #b91c1c; border-color: #fca5a5; background: #fef2f2; }

/* ---- auto-generated legend overlay -------------------------------------
   FIXED to the canvas viewport bottom-right, stacked just ABOVE the minimap
   (minimap is 104px tall + corner margin, so bottom:128px clears it with a
   gap). position:absolute inside .ms-rf-wrap => never scales with zoom, never
   pans, never overlaps a side panel (the inspector is a separate flex column). */
.rf-legend {
  position: absolute; right: 12px; bottom: 128px; top: auto; left: auto;
  z-index: 6; width: max-content; max-width: 240px;
  /* round-4 item 2: SOLID backdrop so the legend reads as a floating overlay
     card and never ghosts over canvas content beneath it. */
  background: #ffffff; border: 1px solid #dbe3ec; border-radius: 12px;
  box-shadow: 0 8px 24px -6px rgba(15,23,42,.26), 0 2px 6px rgba(15,23,42,.12);
  padding: 10px 13px; font: 500 12px/1.5 'Inter Tight', system-ui, sans-serif;
  color: #334155;
}
.rf-legend[hidden] { display: none; }
.rf-legend-title {
  font: 700 10px/1 'Inter Tight', system-ui, sans-serif; letter-spacing: .5px;
  text-transform: uppercase; color: #94a3b8; margin-bottom: 8px;
}
.rf-legend-sec + .rf-legend-sec { margin-top: 9px; padding-top: 9px; border-top: 1px solid #eef2f6; }
/* rows never wrap vertically — single line each */
.rf-legend-row { display: flex; align-items: center; gap: 8px; padding: 2px 0; white-space: nowrap; }
.rf-legend-sw { width: 15px; height: 12px; border-radius: 3px; flex: 0 0 15px; border: 1.5px solid; }
.rf-legend-sw-diamond { transform: rotate(45deg) scale(.82); border-radius: 2px; }
.rf-legend-sw-round { border-radius: 7px; }
.rf-legend-line { width: 16px; height: 0; flex: 0 0 16px; border-top: 2.5px solid; border-radius: 2px; }
.rf-legend-lbl { color: #475569; white-space: nowrap; }

/* ---- reaflow-style hover "+ add connected node" affordance (item 3) ------
   A small round button anchored to the node's bottom-right. Hidden until the
   node is hovered; clicking adds a connected child + opens inline rename. */
.rf-add-child {
  position: absolute; right: -11px; bottom: -11px; z-index: 11;
  width: 22px; height: 22px; border-radius: 50%;
  border: 1.5px solid #2563eb; background: #2563eb; color: #fff;
  font: 700 15px/1 var(--font-sans); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transform: scale(.6); pointer-events: none;
  transition: opacity .12s ease, transform .12s ease;
  box-shadow: 0 2px 6px rgba(37,99,235,.35);
}
.rf-node:hover .rf-add-child,
.react-flow__node:hover .rf-add-child,
.react-flow__node.selected .rf-add-child {
  opacity: 1; transform: scale(1); pointer-events: all;
}
.rf-add-child:hover { background: #1d4ed8; transform: scale(1.12); }
/* non-rect shapes: tuck the "+" toward the geometry so it doesn't float in
   the empty corner of the bounding box */
.rf-node.rf-diamond .rf-add-child,
.rf-node.rf-circle .rf-add-child,
.rf-node.rf-hexagon .rf-add-child { right: 12%; bottom: 6%; }
/* don't show "+" while editing the label */
.rf-node.is-editing .rf-add-child { display: none; }

/* ---- React Flow chrome: edges, Controls, MiniMap ----------------------
   The official @xyflow stylesheet (vendor/reactflow.css) IS loaded, but its
   default theme is tuned for a grey canvas. On our WHITE canvas the controls
   (#fefefe bg, #eee borders) and minimap nodes (#e2e2e2) almost vanish, and
   the default edge stroke (#b1b1b7) is faint. We tune the documented CSS
   variables + a few element rules so edges read crisply and the bottom-left
   Controls and bottom-right MiniMap look like proper React Flow chrome. */
.ms-rf .react-flow {
  /* crisper, slightly darker edges + arrowheads (Lucidchart-like) */
  --xy-edge-stroke-default: #64748b;
  --xy-edge-stroke-selected-default: #2563eb;
  /* controls: white buttons, real border + shadow so they sit ON the canvas */
  --xy-controls-button-background-color-default: #ffffff;
  --xy-controls-button-background-color-hover-default: #eff6ff;
  --xy-controls-button-color-default: #334155;
  --xy-controls-button-color-hover-default: #2563eb;
  --xy-controls-button-border-color-default: #e2e8f0;
  --xy-controls-box-shadow-default: 0 2px 10px rgba(15, 23, 42, .14);
  /* minimap: white bg, clearly visible node fill + viewport mask */
  --xy-minimap-background-color-default: #ffffff;
  --xy-minimap-node-background-color-default: #bfdbfe;
  --xy-minimap-node-stroke-color-default: #2563eb;
  --xy-minimap-mask-background-color-default: rgba(37, 99, 235, .10);
  --xy-minimap-mask-stroke-color-default: rgba(37, 99, 235, .45);
}
/* crisper default edge weight with rounded joins (matches the router's
   rounded elbows) */
.ms-rf .react-flow__edge-path { stroke-width: 1.75; stroke-linecap: round; }
.ms-rf .react-flow__edge.selected .react-flow__edge-path { stroke-width: 2.25; }
/* give the Controls + MiniMap panels a rounded card look */
.ms-rf .react-flow__controls { border-radius: 10px; overflow: hidden; }
.ms-rf .react-flow__controls-button { border-bottom-color: #e2e8f0; }
.ms-rf .react-flow__minimap {
  border: 1px solid #e2e8f0; border-radius: 10px;
  box-shadow: 0 2px 10px rgba(15, 23, 42, .14);
}

/* ---- empty-state hint over the canvas (item 8) ------------------------- */
/* The hint is a SIBLING of #rf inside .ms-rf-wrap (React Flow owns #rf's
   children, so the hint can't live inside it). The wrapper is the flex cell;
   #rf fills it and the hint overlays it, centered. Toggled via inline display
   by studio.js based on node count. */
.ms-rf-wrap { flex: 1 1 auto; min-height: 0; min-width: 0; position: relative; display: flex; }
.ms-rf-wrap .ms-rf { flex: 1 1 auto; }
.rf-empty-hint {
  display: none; position: absolute; inset: 0; z-index: 4; pointer-events: none;
  align-items: center; justify-content: center; text-align: center; padding: 24px;
  color: #94a3b8; font: 500 14px/1.7 var(--font-sans);
}

/* ---- helper alignment guides (React Flow "Helper Lines" pattern) -------- */
.rf-helper-line {
  background: #f43f5e; z-index: 6;
  box-shadow: 0 0 0 .5px rgba(244,63,94,.35);
}

/* ---- node resize handles (NodeResizer) ---------------------------------- */
.ms-rf .react-flow__resize-control.handle,
.ms-rf .rf-resize-handle {
  width: 9px; height: 9px; border-radius: 2.5px;
  background: #fff; border: 1.5px solid #2563eb;
  box-shadow: 0 1px 2px rgba(15,23,42,.2);
}
.ms-rf .rf-resize-line { border-color: rgba(37,99,235,.55); border-width: 1px; }

/* ---- selection context toolbar (NodeToolbar) ---------------------------- */
.rf-ntb {
  display: flex; align-items: center; gap: 5px;
  padding: 6px 8px; border-radius: 10px;
  background: #ffffff; border: 1px solid #e2e8f0;
  box-shadow: 0 8px 24px -6px rgba(15,23,42,.22), 0 2px 6px rgba(15,23,42,.10);
}
.rf-ntb-sw {
  width: 18px; height: 18px; padding: 0; border-radius: 5px; cursor: pointer;
  border: 1.5px solid #2563eb; transition: transform .1s ease, box-shadow .1s ease;
}
.rf-ntb-sw:hover { transform: scale(1.15); box-shadow: 0 0 0 2px rgba(37,99,235,.18); }
.rf-ntb-sw-reset {
  background: #fff; border: 1.5px dashed #94a3b8; color: #64748b;
  font: 700 12px/1 var(--font-sans); display: inline-flex; align-items: center; justify-content: center;
}
.rf-ntb-sw-custom {
  position: relative; overflow: hidden; display: inline-flex;
  border: 1.5px solid #e2e8f0; background:
    conic-gradient(from 0deg, #ef4444, #f59e0b, #22c55e, #06b6d4, #6366f1, #a855f7, #ef4444);
}
.rf-ntb-sw-custom input[type=color] {
  position: absolute; inset: -4px; width: calc(100% + 8px); height: calc(100% + 8px);
  border: none; padding: 0; background: transparent; cursor: pointer; opacity: 0;
}
.rf-ntb-sep { width: 1px; height: 18px; background: #e2e8f0; margin: 0 3px; }
.rf-ntb-btn {
  height: 24px; padding: 0 9px; border-radius: 6px; cursor: pointer;
  border: 1px solid #e2e8f0; background: #fff; color: #334155;
  font: 600 11.5px/1 var(--font-sans); white-space: nowrap;
  transition: background .1s ease, border-color .1s ease, color .1s ease;
}
.rf-ntb-btn:hover { background: #eff6ff; border-color: #bfdbfe; color: #1d4ed8; }
.rf-ntb-btn-danger:hover { background: #fef2f2; border-color: #fecaca; color: #dc2626; }

/* ---- snap-to-grid toggle ------------------------------------------------ */
.ms-snap.is-on {
  background: var(--accent-soft, #dbeafe); color: var(--accent, #2563eb);
  border-color: var(--accent, #2563eb);
}

/* ---- align / distribute cluster ----------------------------------------- */
.ms-align {
  display: inline-flex; align-items: center; gap: 2px;
  height: 34px; padding: 0 5px; border-radius: var(--r-md, 8px);
  border: 1px solid var(--border); background: var(--field);
}
.ms-align-btn {
  width: 26px; height: 26px; padding: 3px; border: none; border-radius: 6px;
  background: transparent; color: var(--text-muted); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .1s ease, color .1s ease;
}
.ms-align-btn:hover { background: var(--accent-soft, #dbeafe); color: var(--accent, #2563eb); }
.ms-align-btn svg {
  width: 16px; height: 16px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.ms-align-btn svg rect { fill: currentColor; fill-opacity: .18; }
.ms-align-sep { width: 1px; height: 18px; background: var(--border); margin: 0 3px; }

/* ---- toolbar ----------------------------------------------------------- */
.ms-toolbar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 16px; background: var(--surface); border-bottom: 1px solid var(--border);
}
.ms-toolbar .sep { width: 1px; height: 22px; background: var(--border); margin: 0 2px; }
.ms-toolbar .spacer { flex: 1 1 auto; }

/* Export trio (PNG / SVG / PDF) grouped as one cohesive, labelled cluster so the
   three download actions read as a set, set apart from the file actions. */
.ms-export-grp {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 8px 4px 10px; border-radius: 10px;
  border: 1px solid var(--border-faint); background: var(--field);
}
.ms-grp-label {
  font: 600 10px/1 var(--font-sans); letter-spacing: .5px; text-transform: uppercase;
  color: var(--text-faint); margin-right: 2px; user-select: none;
}

/* ---- DRAW color control (FEATURE 2): preset swatches + reset + custom ---- */
.ms-color {
  display: inline-flex; align-items: center; gap: 5px;
  height: 34px; padding: 0 8px 0 10px; border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--field);
}
.ms-color-label {
  font: 600 10px/1 var(--font-sans); letter-spacing: .5px; text-transform: uppercase;
  color: var(--text-faint); margin-right: 2px; user-select: none;
}
.ms-sw {
  width: 20px; height: 20px; padding: 0; border-radius: 5px; cursor: pointer;
  background: var(--sw-fill, #eff6ff); border: 1.5px solid var(--sw-stroke, #2563eb);
  transition: transform .1s var(--ease), box-shadow .1s var(--ease);
}
.ms-sw:hover { transform: scale(1.12); box-shadow: 0 0 0 2px rgba(37,99,235,.18); }
.ms-sw-reset {
  background: #fff; border: 1.5px dashed #94a3b8; color: #64748b;
  font: 700 13px/1 var(--font-sans); display: inline-flex; align-items: center; justify-content: center;
}
.ms-sw-custom {
  position: relative; overflow: hidden; padding: 0;
  border: 1.5px solid var(--border); background:
    conic-gradient(from 0deg, #ef4444, #f59e0b, #22c55e, #06b6d4, #6366f1, #a855f7, #ef4444);
}
.ms-sw-custom input[type=color] {
  position: absolute; inset: -4px; width: calc(100% + 8px); height: calc(100% + 8px);
  border: none; padding: 0; background: transparent; cursor: pointer; opacity: 0;
}

.ms-select {
  height: 34px; padding: 0 30px 0 12px; border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--field); color: var(--text);
  font: 500 13px/1 var(--font-sans); cursor: pointer; appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2390a0b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat; background-position: right 8px center;
}
.ms-select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }

/* file-open is a <label> styled as a button; hide the native input */
#btn-open { cursor: pointer; }

.ms-status { display: flex; align-items: center; gap: 10px; }
.ms-meta { color: var(--text-faint); font: 500 12px/1 var(--font-mono); white-space: nowrap; }

/* ---- body: editor | grip | preview ------------------------------------ */
.ms-body { flex: 1 1 auto; display: flex; min-height: 0; }

.ms-cm { flex: 1 1 0; min-width: 280px; overflow: hidden; position: relative; }
.ms-cm .CodeMirror { height: 100%; font: 13px/1.6 var(--font-mono); }

.ms-grip {
  flex: 0 0 6px; cursor: col-resize; background: var(--border-faint);
  transition: background .15s var(--ease);
}
.ms-grip:hover, .ms-grip.is-active { background: var(--accent); }

.ms-preview {
  flex: 1 1 0; min-width: 320px; display: flex; flex-direction: column;
  background: var(--surface-2); border-left: 1px solid var(--border);
}
.ms-preview-head {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px; border-bottom: 1px solid var(--border); background: var(--surface);
}
.ms-preview-title { font: 600 12px/1 var(--font-sans); letter-spacing: .4px; text-transform: uppercase; color: var(--text-muted); }
.ms-preview-head .spacer { flex: 1 1 auto; }
/* Zoom controls as a tidy segmented cluster sitting in the preview header */
.ms-zoom {
  display: flex; align-items: center; gap: 2px;
  padding: 3px; border-radius: 9px;
  border: 1px solid var(--border-faint); background: var(--field);
}
.ms-zoom .pt-btn { min-width: 30px; justify-content: center; font-weight: 600; }
/* live zoom-level readout sitting between the − / + buttons */
.ms-zoom-level {
  min-width: 42px; text-align: center; padding: 0 4px;
  font: 600 11.5px/1 var(--font-mono); color: var(--text-muted);
  letter-spacing: .2px; user-select: none; white-space: nowrap;
}

/* the stage holds the rendered SVG; svg-pan-zoom drives pan & wheel-zoom.
   Kept LIGHT in both themes: Mermaid's default theme draws dark edges/arrows,
   which vanish on a dark canvas — and a white canvas matches the exported image.
   The diagram is auto-fit + centered on every render (see fitAndFrame() in
   studio.js) so it reads as a centered document with margins, not a static SVG
   stranded in a corner. A subtle inset shadow frames the canvas as a surface.
   touch-action:none keeps wheel / pinch zoom on the canvas instead of letting
   the page scroll hijack it. */
.ms-stage {
  flex: 1 1 auto; min-height: 0; position: relative; overflow: hidden;
  touch-action: none;
  background:
    radial-gradient(circle at 1px 1px, #e2e8f0 1px, transparent 0) 0 0 / 22px 22px,
    #ffffff;
}
/* soft inner vignette so the canvas reads as a framed surface, not a flat fill */
.ms-stage::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 1;
  box-shadow: inset 0 0 0 1px rgba(15,23,42,.05), inset 0 14px 32px -22px rgba(15,23,42,.18);
}
.ms-stage #render { width: 100%; height: 100%; display: block; position: relative; z-index: 0; }
.ms-stage svg { width: 100%; height: 100%; display: block; cursor: grab; }
.ms-stage svg:active { cursor: grabbing; }

/* empty / placeholder */
.ms-stage.is-empty::after {
  content: "Your diagram will appear here.";
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: #94a3b8; font: 500 14px/1 var(--font-sans);
}

/* ---- error bar --------------------------------------------------------- */
.ms-error {
  display: none; align-items: center; gap: 8px;
  padding: 8px 16px; background: var(--bad-soft); border-top: 1px solid var(--bad-border);
  color: var(--bad); font: 500 12.5px/1.5 var(--font-mono); white-space: pre-wrap;
}
.ms-error.is-show { display: flex; }
.ms-error svg { width: 16px; height: 16px; flex: 0 0 16px; }

/* ---- CodeMirror theme: .cm-s-protium (shared with Code Genie) ---------- */
.cm-s-protium.CodeMirror { background: var(--field); color: #d4d4d4; }
.cm-s-protium .CodeMirror-gutters { background: var(--field); border-right: 1px solid var(--border); }
.cm-s-protium .CodeMirror-linenumber { color: var(--text-faint); }
.cm-s-protium .CodeMirror-cursor { border-left: 1.5px solid #aed6ff; }
.cm-s-protium .CodeMirror-activeline-background { background: rgba(255,255,255,0.03); }
.cm-s-protium .CodeMirror-selected { background: var(--accent-soft) !important; }
.cm-s-protium .CodeMirror-focused .CodeMirror-selected { background: var(--accent-soft) !important; }
.cm-s-protium .cm-string { color: #ce9178; }
.cm-s-protium .cm-keyword { color: #c586c0; }
.cm-s-protium .cm-atom { color: #569cd6; }
.cm-s-protium .cm-number { color: #b5cea8; }
.cm-s-protium .cm-operator { color: #4ec9b0; }
.cm-s-protium .cm-variable-2 { color: #9cdcfe; }
.cm-s-protium .cm-comment { color: #6a9955; }
.cm-s-protium .cm-error { color: var(--bad); }

/* =========================================================================
   RIGHT INSPECTOR PANEL (Figma/Lucidchart-style properties rail)
   ========================================================================= */
.ms-inspector {
  flex: 0 0 264px; display: flex; flex-direction: column; min-height: 0;
  background: var(--surface); border-left: 1px solid var(--border);
  transition: flex-basis .18s var(--ease), transform .18s var(--ease);
}
.ms-inspector.is-collapsed { flex-basis: 0; overflow: hidden; border-left: none; }
.ms-insp-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid var(--border);
}
.ms-insp-title { font: 700 11px/1 var(--font-sans); letter-spacing: .5px; text-transform: uppercase; color: var(--text-muted); }
.ms-insp-collapse, .ms-insp-reopen {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 7px; cursor: pointer;
  border: 1px solid var(--border); background: var(--field); color: var(--text-muted);
}
.ms-insp-collapse:hover, .ms-insp-reopen:hover { color: var(--accent); border-color: var(--accent); }
.ms-insp-collapse svg, .ms-insp-reopen svg { width: 15px; height: 15px; }
.ms-insp-reopen {
  position: absolute; top: 10px; right: 10px; z-index: 7;
  width: 30px; height: 30px; background: #fff;
  box-shadow: 0 2px 8px rgba(15,23,42,.14);
}
/* round-4 item 4 BUG FIX: the author `display:inline-flex` above overrides the
   UA `[hidden]{display:none}` rule, so the "hidden" reopen button still
   rendered ON TOP of the collapse chevron (same corner, z-index 7) and
   swallowed every click — the panel could never collapse. Re-assert hidden. */
.ms-insp-reopen[hidden] { display: none; }
/* item 4: when a node/edge is selected while the panel is COLLAPSED, the handle
   pulses to signal "properties available here" — it does NOT auto-expand. */
.ms-insp-reopen.is-pulsing {
  animation: inspPulse .5s var(--ease) 0s 3;
  border-color: var(--accent); color: var(--accent);
}
@keyframes inspPulse {
  0%, 100% { box-shadow: 0 2px 8px rgba(15,23,42,.14); transform: scale(1); }
  50% { box-shadow: 0 0 0 4px rgba(37,99,235,.30), 0 2px 8px rgba(15,23,42,.18); transform: scale(1.12); }
}
.ms-insp-body { flex: 1 1 auto; overflow: auto; padding: 14px; }
.ms-insp-group { margin-bottom: 16px; }
.ms-insp-group:last-child { margin-bottom: 0; }
.ms-insp-label { font: 600 10.5px/1 var(--font-sans); letter-spacing: .4px; text-transform: uppercase; color: var(--text-faint); margin-bottom: 7px; }
.ms-insp-selinfo {
  display: flex; align-items: center; gap: 9px; padding: 10px 11px; border-radius: 9px;
  background: var(--field); border: 1px solid var(--border-faint); margin-bottom: 16px;
}
.ms-insp-selinfo .ms-insp-badge {
  width: 26px; height: 22px; border-radius: 5px; flex: 0 0 26px; border: 2px solid var(--accent); background: #eff6ff;
}
/* addendum: long node names wrap then clamp to 2 lines with an ellipsis; the
   full text is exposed on hover via a native title tooltip (set in studio.js). */
.ms-insp-selinfo .ms-insp-selname {
  font: 600 12.5px/1.3 var(--font-sans); color: var(--text);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; overflow-wrap: break-word; word-break: break-word;
}
.ms-insp-selinfo { align-items: flex-start; }
.ms-insp-selinfo .ms-insp-badge { margin-top: 1px; }
.ms-insp-selrole { font: 500 11px/1 var(--font-sans); color: var(--text-faint); margin-top: 2px; }
.ms-insp-swatches { display: flex; flex-wrap: wrap; gap: 6px; }
.ms-insp-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.ms-insp-act {
  flex: 1 1 auto; min-width: 72px; height: 32px; border-radius: 7px; cursor: pointer;
  border: 1px solid var(--border); background: var(--field); color: var(--text);
  font: 600 12px/1 var(--font-sans);
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  transition: background .1s ease, border-color .1s ease, color .1s ease;
}
.ms-insp-act:hover { background: var(--accent-soft, #dbeafe); border-color: var(--accent); color: var(--accent); }
.ms-insp-act.is-danger:hover { background: #fef2f2; border-color: #fecaca; color: #dc2626; }
.ms-insp-empty { text-align: center; color: var(--text-faint); font: 500 12.5px/1.6 var(--font-sans); padding: 22px 6px; }
.ms-insp-empty svg { width: 34px; height: 34px; stroke: var(--border); margin: 0 auto 10px; display: block; }
.ms-insp-empty kbd {
  font: 600 11px/1 var(--font-mono); background: var(--field); border: 1px solid var(--border);
  border-radius: 4px; padding: 1px 5px; color: var(--text-muted);
}
.ms-insp-body .ms-select { width: 100%; box-sizing: border-box; }

/* =========================================================================
   TEMPLATE GALLERY (modal, client-side, no CDN)
   ========================================================================= */
.tpl-overlay {
  position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center;
  background: rgba(15,23,42,.46); backdrop-filter: blur(3px); padding: 28px;
  animation: tplFade .16s var(--ease);
}
.tpl-overlay[hidden] { display: none; }
@keyframes tplFade { from { opacity: 0; } to { opacity: 1; } }
.tpl-modal {
  width: min(940px, 96vw); max-height: 88vh; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border); border-radius: 16px;
  box-shadow: 0 24px 64px -12px rgba(15,23,42,.5); overflow: hidden;
  animation: tplPop .18s var(--ease);
}
@keyframes tplPop { from { transform: translateY(8px) scale(.99); opacity: 0; } to { transform: none; opacity: 1; } }
.tpl-head { display: flex; align-items: flex-start; justify-content: space-between; padding: 20px 22px 14px; }
.tpl-title { margin: 0; font: 700 19px/1.2 var(--font-sans); color: var(--text); }
.tpl-sub { margin: 4px 0 0; font: 500 13px/1.4 var(--font-sans); color: var(--text-muted); }
.tpl-close {
  width: 32px; height: 32px; border-radius: 8px; cursor: pointer; flex: 0 0 32px;
  border: 1px solid var(--border); background: var(--field); color: var(--text-muted);
  display: inline-flex; align-items: center; justify-content: center;
}
.tpl-close:hover { color: var(--bad); border-color: var(--bad-border); }
.tpl-close svg { width: 17px; height: 17px; }
.tpl-toolbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding: 0 22px 14px; }
.tpl-search { position: relative; flex: 1 1 220px; }
.tpl-search svg { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); width: 16px; height: 16px; stroke: var(--text-faint); pointer-events: none; }
.tpl-search input {
  width: 100%; box-sizing: border-box; height: 38px; padding: 0 12px 0 34px;
  border-radius: 9px; border: 1px solid var(--border); background: var(--field);
  color: var(--text); font: 500 13px/1 var(--font-sans); outline: none;
}
.tpl-search input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.tpl-cats { display: flex; gap: 6px; flex-wrap: wrap; }
.tpl-cat {
  height: 32px; padding: 0 12px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--border); background: var(--field); color: var(--text-muted);
  font: 600 12px/1 var(--font-sans); transition: all .1s ease;
}
.tpl-cat:hover { border-color: var(--accent); color: var(--accent); }
.tpl-cat.is-active { background: var(--accent); border-color: var(--accent); color: #fff; }
.tpl-grid {
  flex: 1 1 auto; overflow: auto; padding: 4px 22px 22px;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 14px; align-content: start;
}
.tpl-card {
  display: flex; flex-direction: column; cursor: pointer; text-align: left;
  border: 1px solid var(--border); border-radius: 12px; background: var(--field);
  overflow: hidden; transition: transform .12s var(--ease), box-shadow .12s var(--ease), border-color .12s var(--ease);
}
.tpl-card:hover { transform: translateY(-3px); border-color: var(--accent); box-shadow: 0 10px 24px -8px rgba(37,99,235,.35); }
.tpl-thumb {
  height: 116px; background: radial-gradient(circle at 1px 1px, #e2e8f0 1px, transparent 0) 0 0 / 14px 14px, #fbfdff;
  border-bottom: 1px solid var(--border-faint); display: block;
}
.tpl-thumb svg { width: 100%; height: 100%; display: block; }
.tpl-card-body { padding: 10px 12px 12px; }
.tpl-card-name { font: 600 13.5px/1.25 var(--font-sans); color: var(--text); }
.tpl-card-desc { margin-top: 3px; font: 500 11.5px/1.4 var(--font-sans); color: var(--text-faint); }
.tpl-empty { grid-column: 1 / -1; text-align: center; color: var(--text-faint); font: 500 13px/1.6 var(--font-sans); padding: 40px 0; }

@media (max-width: 760px) {
  .ms-body { flex-direction: column; }
  .ms-grip { display: none; }
  .ms-cm, .ms-preview { min-width: 0; }
  .ms-preview { border-left: none; border-top: 1px solid var(--border); }
  .ms-inspector { display: none; }
}
