/* ============================================================
   Reusable components: buttons, inputs, blocks, connections.
   Buttons inherit the "raw-crystal-viridian" mineral look from
   the AirWanderer reference.
   ============================================================ */

/* ----- Buttons ----- */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 7px 14px;
  font-family: 'EB Garamond', Georgia, serif;
  font-weight: 500;
  font-size: 13px;
  letter-spacing: 0.3px;
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.10);
  cursor: pointer;
  user-select: none;
  transition: all 0.25s ease;
  color: #f8fff8;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  box-shadow:
    0 2px 6px rgba(0, 0, 0, 0.12),
    0 1px 2px rgba(0, 0, 0, 0.08),
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    inset 0 -1px 0 rgba(0, 0, 0, 0.10);
  /* Crystal viridian background — derived from raw-crystal-viridian-1 */
  background:
    linear-gradient(35deg,
      transparent 0%,
      rgba(255, 255, 255, 0.18) 6.7%,
      transparent 7.5%,
      transparent 21%,
      rgba(255, 255, 255, 0.22) 21.4%,
      transparent 22.2%,
      transparent 36%,
      rgba(255, 255, 255, 0.13) 36.9%,
      transparent 37.7%
    ),
    linear-gradient(125deg,
      transparent 0%,
      rgba(255, 255, 255, 0.16) 9.8%,
      transparent 10.6%,
      transparent 26%,
      rgba(255, 255, 255, 0.20) 26.5%,
      transparent 27.3%
    ),
    radial-gradient(ellipse 13px 7px at 30% 35%, rgba(0, 0, 0, 0.13) 0%, transparent 70%),
    radial-gradient(ellipse 10px 5px at 75% 15%, rgba(255, 255, 255, 0.09) 0%, transparent 75%),
    linear-gradient(180deg, rgb(45, 125, 85) 0%, rgb(35, 105, 70) 48.8%, rgb(25, 85, 55) 100%);
}

.btn:hover {
  transform: translateY(-1px);
  box-shadow:
    0 4px 10px rgba(0, 0, 0, 0.16),
    0 2px 4px rgba(0, 0, 0, 0.10),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
  filter: brightness(1.04);
}
.btn:active { transform: translateY(0); filter: brightness(0.95); }
.btn:disabled, .btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none !important;
  filter: none !important;
}

/* Quiet — flat low-emphasis */
.btn.btn-quiet {
  color: var(--text);
  text-shadow: none;
  background: #fff;
  border: 1px solid var(--border);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}
.btn.btn-quiet:hover { background: #f4f8f6; border-color: var(--accent-3); color: var(--accent); }

/* Danger */
.btn.btn-danger {
  background: linear-gradient(145deg, #c45656, #a64545);
  border-color: rgba(180, 60, 60, 0.4);
}

.btn.btn-sm {
  padding: 4px 10px;
  font-size: 12px;
}
.btn.btn-icon {
  padding: 6px 8px;
  min-width: 28px;
  font-size: 13px;
}

/* ----- Inputs ----- */
.field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
.field label {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.6px;
}
.field .hint { font-size: 11.5px; color: var(--text-muted); margin-top: -2px; }

.input, .select, .textarea,
.ext-inspector-input {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 7px 10px;
  font-size: 13px;
  color: var(--text);
  width: 100%;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.input:focus, .select:focus, .textarea:focus,
.ext-inspector-input:focus {
  outline: none;
  border-color: var(--accent-3);
  box-shadow: 0 0 0 2px rgba(98, 175, 139, 0.18);
}
.textarea,
textarea.ext-inspector-input {
  resize: vertical;
  min-height: 70px;
  line-height: 1.45;
  font-family: inherit;
}

/* Phase 10 Slice 2 — custom select chevron.
   Native browser chevrons render inconsistently across Chrome /
   Firefox / Safari and ignore the accent palette. Replace with an
   inline-SVG arrow tinted to match `--text-muted`. Scoped to
   genuine `<select>` elements only — applying this to a broad
   .ext-inspector-input selector would also affect text inputs
   and textareas. */
.select,
select.ext-inspector-input {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%236b7a73' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 10px 6px;
  padding-right: 28px;
}

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text);
  margin: 6px 0;
  cursor: pointer;
  user-select: none;
}
.checkbox-row input[type="checkbox"] { accent-color: var(--accent-2); }

.row { display: flex; gap: 8px; }
.row > * { flex: 1; }

/* ----- Block (canvas card) ----- */
.block {
  position: absolute;
  width: 220px;
  background: #fff;
  border-radius: 10px;
  border: 1px solid var(--border);
  box-shadow: var(--shadow-soft);
  cursor: grab;
  transition: box-shadow 0.2s ease, transform 0.05s ease, border-color 0.2s ease;
  user-select: none;
  z-index: 2;
}
.block:hover { box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12); }
.block.selected {
  border-color: var(--accent-2);
  box-shadow: 0 0 0 2px rgba(67, 145, 109, 0.25), var(--shadow-medium);
}
.block.primary-selection {
  /* Slightly stronger outline so the user can tell which selected
     block the inspector is currently bound to. */
  box-shadow: 0 0 0 3px rgba(67, 145, 109, 0.45), var(--shadow-medium);
}
.block.dragging { cursor: grabbing; box-shadow: 0 12px 24px rgba(0, 0, 0, 0.18); }

.block-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, #fafcfb, #f3f7f5);
  border-radius: 10px 10px 0 0;
}
.block-title {
  font-weight: 600;
  font-size: 13px;
  color: var(--accent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
}
.block-type-badge {
  font-size: 9.5px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  background: rgba(67, 145, 109, 0.10);
  color: var(--accent-2);
  padding: 1px 6px;
  border-radius: 10px;
  font-weight: 600;
}

.block-body {
  padding: 8px 10px;
  font-size: 11.5px;
  color: var(--text-muted);
}
.block-body .meta { font-size: 11px; }
.block-body .meta strong { color: var(--text); font-weight: 500; }

.block-output-preview {
  margin-top: 6px;
  background: #f7faf8;
  border: 1px solid #e6ede9;
  border-radius: 6px;
  padding: 6px 8px;
  font-size: 11px;
  line-height: 1.4;
  color: #4b5058;
  max-height: 56px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: pre-wrap;
}

.block-status {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10.5px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 10px;
  font-weight: 600;
  background: #eef0ee;
  color: var(--text-muted);
}
.block-status::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.block-status.s-running { color: var(--st-running); background: rgba(224, 164, 55, 0.12); }
.block-status.s-running::before { animation: pulseDot 1.2s infinite ease-in-out; }
.block-status.s-needs_review { color: var(--st-needs-review); background: rgba(204, 146, 55, 0.12); }
.block-status.s-completed,
.block-status.s-approved { color: var(--st-completed); background: rgba(46, 142, 93, 0.12); }
.block-status.s-failed { color: var(--st-failed); background: rgba(176, 72, 72, 0.12); }
.block-status.s-stopped,
.block-status.s-skipped { color: var(--st-stopped); background: rgba(107, 107, 107, 0.10); }
/* Template (For Each Item original) — visually distinct from
   "not started" so users don't mistake it for a runnable step. */
.block-status.s-template {
  color: #5b3da9;
  background: rgba(139, 92, 246, 0.10);
  border: 1px solid rgba(139, 92, 246, 0.30);
}

/* Block whose ``disabled_by_repeat_group`` is set — e.g. the For
   Each Item original/template. Stays readable and editable, but
   clearly marked as a template so it doesn't read as a normal
   executable step. Uses a dashed purple border + faint tinted
   background (matching the group frame) instead of heavy opacity
   reduction — earlier opacity 0.55 looked broken rather than
   intentional. */
.block.is-template-disabled {
  border-style: dashed;
  border-color: #c4b5fd;
  background:
    linear-gradient(180deg, rgba(243, 239, 255, 0.6), rgba(237, 233, 254, 0.4));
}
.block.is-template-disabled .run-indicator { display: none; }
.block.is-template-disabled .block-status.s-template::before {
  /* Quiet the leading dot — the TEMPLATE pill is enough signal. */
  display: none;
}

@keyframes pulseDot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

/* Block running: pulsing border + visible spinner. */
.block.is-running {
  border-color: var(--st-running);
  animation: blockRunPulse 1.6s ease-in-out infinite;
}
.block.is-needs-review { border-color: var(--st-needs-review); }
.block.is-failed       { border-color: var(--st-failed); }
.block.is-completed    { border-color: var(--st-completed); }

@keyframes blockRunPulse {
  0%, 100% {
    box-shadow:
      0 0 0 0 rgba(224, 164, 55, 0.30),
      var(--shadow-soft);
  }
  50% {
    box-shadow:
      0 0 0 6px rgba(224, 164, 55, 0.0),
      0 0 14px rgba(224, 164, 55, 0.45);
  }
}

/* Spinner in the block header — only visible while running. */
.run-indicator {
  display: none;
  margin-right: 4px;
  color: var(--st-running);
  align-items: center;
  justify-content: center;
}
.block.is-running .run-indicator {
  display: inline-flex;
  animation: spin 1.2s linear infinite;
}
@keyframes spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Connection handles. Hidden by default to keep the canvas calm; the
   block reveals them on hover, focus, or while it's selected so users
   only see the affordance when they want to wire something up. */
.handle {
  position: absolute;
  width: 12px;
  height: 12px;
  opacity: 0;
  pointer-events: none;
  border-radius: 50%;
  background: #fff;
  border: 2px solid var(--accent-2);
  z-index: 3;
  cursor: crosshair;
  transition: opacity 0.12s ease, transform 0.15s ease, background 0.15s ease;
}
.block:hover .handle,
.block.selected .handle,
.block.primary-selection .handle,
.block.dragging .handle,
.block.is-connecting .handle {
  opacity: 1;
  pointer-events: auto;
}
.handle:hover { transform: scale(1.25); background: var(--accent-3); }
.handle.handle-in  { left: -7px;  top: 50%; transform: translateY(-50%); }
.handle.handle-out { right: -7px; top: 50%; transform: translateY(-50%); }
.handle.handle-out.connecting { background: var(--accent-2); transform: translateY(-50%) scale(1.3); }

.icon-btn {
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 2px 4px;
  font-size: 14px;
  color: var(--text-muted);
  border-radius: 4px;
  line-height: 1;
}
.icon-btn:hover { background: rgba(0, 0, 0, 0.06); color: var(--text); }
.icon-btn:focus-visible {
  outline: 2px solid var(--accent-2, #43916d);
  outline-offset: 2px;
  background: rgba(67, 145, 109, 0.07);
  color: var(--text);
}

/* ----- Tags / pills ----- */
.tag {
  display: inline-block;
  font-size: 10.5px;
  background: #eef3f0;
  color: var(--accent);
  padding: 2px 7px;
  border-radius: 10px;
  font-weight: 500;
}

/* Section heading inside drawer panels — lighter than before so the
   inspector feels less crowded and the inputs/text get the visual weight. */
.section-title {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 18px 0 6px;
  padding: 0 0 3px;
  border-bottom: 1px dashed rgba(0, 0, 0, 0.08);
}
.section-title:first-child { margin-top: 0; }
.section-title.type-input  { color: #1d4f6c; border-bottom-color: rgba(45, 121, 158, 0.30); }
.section-title.type-output { color: #3b2a72; border-bottom-color: rgba(94, 73, 168, 0.30); }

/* ----- Input / Output blocks (coloured accents) ----- */

/* Tones — teal-blue for input (distinct from running-amber),
   indigo for output (distinct from failed-red). */
:root {
  --c-input: #2d799e;
  --c-input-soft: #c5dbe8;
  --c-input-bg: #e8f2f8;
  --c-output: #5e49a8;
  --c-output-soft: #d6cdef;
  --c-output-bg: #ece6f7;
  --c-trigger: #d68a1c;
  --c-generate: #138c6c;
  --c-generate-soft: #b9e2d4;
  --c-generate-bg: #e3f4ee;
}

/* Subtler accents — left bar + soft tinted header, no aggressive gradient. */
.block.type-input { border-left: 3px solid var(--c-input); }
.block.type-input .block-header { background: #e8f2f8; }
.block.type-input .block-title { color: #1d4f6c; }
.block.type-input .block-type-badge {
  background: rgba(45, 121, 158, 0.18);
  color: #1d4f6c;
}
.block.type-input .handle { border-color: var(--c-input); }

.block.type-output { border-left: 3px solid var(--c-output); }
.block.type-output .block-header { background: #ece6f7; }
.block.type-output .block-title { color: #3b2a72; }
.block.type-output .block-type-badge {
  background: rgba(94, 73, 168, 0.18);
  color: #3b2a72;
}
.block.type-output .handle { border-color: var(--c-output); }

.block.type-generate { border-left: 3px solid var(--c-generate); }
.block.type-generate .block-header { background: var(--c-generate-bg); }
.block.type-generate .block-title { color: #0d5c47; }
.block.type-generate .block-type-badge {
  background: rgba(19, 140, 108, 0.18);
  color: #0d5c47;
}
.block.type-generate .handle { border-color: var(--c-generate); }

/* Connection colouring by source / kind. */
.connection-path.from-input  { stroke: var(--c-input); }
.connection-path.from-output { stroke: var(--c-output); }
.connection-path.kind-trigger {
  stroke: var(--c-trigger);
  stroke-dasharray: 6 4;
  animation: dashFlow 1.4s linear infinite;
}

/* Palette buttons coloured to match. */
.btn.btn-input {
  background: linear-gradient(145deg, #3a8db0, #1f6a8d);
  border-color: rgba(45, 121, 158, 0.4);
}
.btn.btn-output {
  background: linear-gradient(145deg, #7563bf, #4d3d92);
  border-color: rgba(80, 60, 145, 0.4);
}
.btn.btn-generate {
  background: linear-gradient(145deg, #1aa97e, #0d6c52);
  border-color: rgba(19, 140, 108, 0.4);
}

/* Floating kind picker shown above the "+ Generate" palette button. */
.kind-menu {
  position: fixed;
  z-index: 50;
  min-width: 280px;
  max-width: 340px;
  display: flex;
  flex-direction: column;
  padding: 4px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow-medium);
}
.kind-menu-section-header {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: #64748b;
  padding: 8px 10px 4px;
}
.kind-menu-section-header:first-child { padding-top: 4px; }
.kind-menu-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
  padding: 8px 10px;
  font-size: 13px;
  color: var(--text);
  background: transparent;
  border: none;
  border-radius: 6px;
  cursor: pointer;
}
.kind-menu-item:hover  { background: var(--surface, #f4f6f8); }
.kind-menu-item:focus-visible {
  outline: 2px solid var(--primary, #047857);
  outline-offset: -2px;
}
.kind-menu-label { font-weight: 500; }
.kind-menu-desc  { font-size: 11px; color: #64748b; line-height: 1.35; }

/* =====================================================================
   PLANFLOW — THE BLOCK-PLACING MENU (palette bar + Generate kind menu)
   Owner brief, 2026-08-03: "we have the menu to place blocks on canvas
   ... I would not make it all white and grey, but would still use
   colors for the blocks types to differentiate them."

   Scope: EVERY rule below is under `.aw-newblocks` (the body class
   canvas.init stamps when the ?newblocks flag is on). Flag off, this
   whole section matches nothing and the mineral-gradient buttons above
   are exactly what they were. The markup hooks (.pf-pal__badge /
   __label / __caret) are also only emitted under the flag — app.js
   decoratePalette() returns early when PlanFlowBlocks.isEnabled() is
   false — so flag-off is inert in BOTH the DOM and the cascade.

   RESTYLE ONLY. Same four items, same order, same click behaviour.

   ---- where every value comes from (all MEASURED, not guessed) ----
   Bar surface = the shipped PlanFlow chrome surface, read off the live
   .wf-bar with getComputedStyle (evidence `palette-cardvocab.json`,
   key .wfBar; the whole measured report is `palette-contrast.md`):
     background rgba(255,255,255,.56) · border rgba(255,255,255,.70)
     blur(20px) saturate(180%) brightness(1.03) · radius 16px
     inset 0 1px 0 rgba(255,255,255,.6), 0 10px 30px rgba(55,72,64,.14)
   Those literals are the values of --surface/--border/--blur/--shadow/
   --radius-lg declared at topbar.css:14-46. They are repeated here
   because that token block is keyed to `.wf-bar,.wf-bpop,.wf-fly,
   .wf-toolbar` and topbar.css is another track's file; the one-line
   fix that would delete this duplication is recorded in the track
   report (add `.palette` to that selector list).

   Item colour = the FAMILY TOKENS, never a second set. --pf-pal-family
   is written per item by app.js from PlanFlowBlocks.familyColorVar()
   (planflow-blocks.js:277-279), so it resolves to the very same
   --pf-family-* custom properties the cards use
   (planflow-blocks.css:1337-1352). Everything else on the chip is
   derived from that ONE value with color-mix, using the card system's
   own strengths: 24% = --wf-family-tint and 36% = --wf-family-line
   (planflow-blocks.css:1374-1375). Repoint a family token and the
   palette follows on the next repaint — there is nothing to drift.

   Badge chip = the prototype's own small-scale badge, copied from the
   plan-group section-number chip at workflow-template.html:7485:
     `border-radius:5px; background:#E7DBC0; border:1px solid #D8C69E;
      color:#8F6B33; font-weight:800; font-size:9.5px;
      font-family:ui-monospace,Menlo,monospace`
   i.e. fill = family tint, stroke = family line, letters = the family
   colour itself, radius = 1/3 of the chip height. Same three-part
   recipe as the full 78x81 card badge (SVG_BADGE, template:2452 —
   rect fill tint, rect stroke line, letterform path fill family).
   The letters come from PlanFlowBlocks.badgeFor(): IN / AI / OUT /
   FILE — the same resolver the cards call.
   ===================================================================== */

/* ---- the bar itself ---- */
.aw-newblocks .palette {
  /* chrome vocabulary (see header) */
  --pf-pal-surface: rgba(255, 255, 255, 0.56);
  --pf-pal-edge:    rgba(255, 255, 255, 0.70);
  --pf-pal-blur:    blur(20px) saturate(180%) brightness(1.03);
  --pf-pal-shadow:  inset 0 1px 0 rgba(255, 255, 255, 0.6), 0 10px 30px rgba(55, 72, 64, 0.14);
  --pf-pal-ease:    cubic-bezier(0.32, 0.72, 0, 1);
  --pf-pal-focus:   rgba(60, 120, 92, 0.55);
  /* the card title's own ink, measured off .wf-block__title = rgb(31,45,38) */
  --pf-pal-ink-base: #1f2d26;

  /* gap:6px and padding:6px are NOT repeated here: panels.css:163-164
     already sets both to those values, and re-declaring them would pin
     this bar to today's numbers if that file ever moved. Measured 6px /
     6px on the restyled bar in palette-after-1440-dsf1.json. */
  background: var(--pf-pal-surface);
  -webkit-backdrop-filter: var(--pf-pal-blur);
  backdrop-filter: var(--pf-pal-blur);
  border: 1px solid var(--pf-pal-edge);
  border-radius: 16px;
  box-shadow: var(--pf-pal-shadow);
  /* Four chips never need to wrap, but a bar that overflowed the canvas
     would be worse than one that wrapped, so cap it and allow the wrap
     as the failure mode rather than a horizontal scrollbar. */
  max-width: calc(100% - 24px);
  flex-wrap: wrap;
  justify-content: center;
}

/* ---- one item = one mini card ---- */
.aw-newblocks .palette .btn[data-add-block] {
  /* app.js writes --pf-pal-family per item; this is only the fallback
     for the "no family resolved" case and matches familyOf()'s own
     default (planflow-blocks.js:253 → 'ai_prompt'). */
  --pf-pal-family: var(--pf-family-ai-prompt, #3e8e6e);
  --pf-pal-fill:      color-mix(in srgb, var(--pf-pal-family) 12%, white);
  --pf-pal-fill-hi:   color-mix(in srgb, var(--pf-pal-family) 20%, white);
  --pf-pal-fill-down: color-mix(in srgb, var(--pf-pal-family) 28%, white);
  --pf-pal-line:      color-mix(in srgb, var(--pf-pal-family) 30%, white);
  --pf-pal-line-hi:   color-mix(in srgb, var(--pf-pal-family) 44%, white);
  --pf-pal-line-down: color-mix(in srgb, var(--pf-pal-family) 52%, white);
  /* card badge strengths, verbatim (planflow-blocks.css:1374-1375) */
  --pf-pal-badge-fill: color-mix(in srgb, var(--pf-pal-family) 24%, white);
  --pf-pal-badge-line: color-mix(in srgb, var(--pf-pal-family) 36%, white);
  /* Label ink: the family carried INTO the card's title ink, so the word
     stays family-coloured and still lands dark enough to read on its own
     12% chip. Ratios are measured per family in palette-contrast.md. */
  --pf-pal-ink: color-mix(in srgb, var(--pf-pal-family) 45%, var(--pf-pal-ink-base, #1f2d26));

  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px 5px 5px;
  min-height: 30px;
  /* shorthand on purpose: it clears .btn's five-layer mineral gradient */
  background: var(--pf-pal-fill);
  border: 1px solid var(--pf-pal-line);
  border-radius: 9px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.75),
    0 1px 2px rgba(55, 72, 64, 0.10);
  color: var(--pf-pal-ink);
  text-shadow: none;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.01em;
  transition:
    background-color 0.18s var(--pf-pal-ease),
    border-color 0.18s var(--pf-pal-ease),
    box-shadow 0.18s var(--pf-pal-ease);
}

/* the badge chip — template:7485 recipe at 20px */
.aw-newblocks .palette .pf-pal__badge {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 5px;
  border-radius: 6.5px;          /* 5/15 of the chip height, as :7485 */
  background: var(--pf-pal-badge-fill);
  border: 1px solid var(--pf-pal-badge-line);
  color: var(--pf-pal-family);   /* the letterform fill, as SVG_BADGE */
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 9.5px;
  font-weight: 800;
  line-height: 1;
}
.aw-newblocks .palette .pf-pal__label { white-space: nowrap; }
.aw-newblocks .palette .pf-pal__caret {
  font-size: 9px;
  line-height: 1;
  opacity: 0.62;
  margin-left: -2px;
}

/* ---- states ---- */
.aw-newblocks .palette .btn[data-add-block]:hover {
  background: var(--pf-pal-fill-hi);
  border-color: var(--pf-pal-line-hi);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.85),
    0 4px 12px rgba(55, 72, 64, 0.16);
  /* .btn:hover lifts the whole button 1px; a docked rack should not
     bounce, so the lift and the brightness filter are both cancelled. */
  transform: none;
  filter: none;
}
.aw-newblocks .palette .btn[data-add-block]:active {
  background: var(--pf-pal-fill-down);
  border-color: var(--pf-pal-line-down);
  box-shadow: inset 0 2px 4px rgba(55, 72, 64, 0.18);
  transform: none;
  filter: none;
}
.aw-newblocks .palette .btn[data-add-block]:focus-visible {
  outline: 2px solid var(--pf-pal-focus);
  outline-offset: 2px;
}
.aw-newblocks .palette .btn[data-add-block]:disabled,
.aw-newblocks .palette .btn[data-add-block][disabled] { opacity: 0.45; }

/* ---- the Generate kind menu opens off this bar, so it wears the same
        surface. Every entry is the generate family, so every badge is
        slate; the letters are the real format letters from badgeFor(). */
.aw-newblocks .kind-menu {
  --pf-pal-family: var(--pf-family-generate, #64748b);
  --pf-pal-badge-fill: color-mix(in srgb, var(--pf-pal-family) 24%, white);
  --pf-pal-badge-line: color-mix(in srgb, var(--pf-pal-family) 36%, white);
  --pf-pal-ink: color-mix(in srgb, var(--pf-pal-family) 45%, #1f2d26);
  padding: 5px;
  background: rgba(255, 255, 255, 0.88);
  -webkit-backdrop-filter: blur(20px) saturate(180%) brightness(1.03);
  backdrop-filter: blur(20px) saturate(180%) brightness(1.03);
  border: 1px solid rgba(255, 255, 255, 0.70);
  border-radius: 14px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.6),
    0 14px 36px rgba(55, 72, 64, 0.20);

  /* ---- P2: THE SUBMENU IS CAPPED AND SCROLLS (owner, 2026-08-03:
     "sub menu for gen blocks are a bit too long. Can we implement sort
     of a scroll functionality ... and we would just scroll the types of
     blocks to the one we need?").
     Measured before: the eleven entries stood 623.28px tall unclipped
     at 1440x900 dsf 1 — 69% of the window (palette-p1-ink.json,
     summary.base.dsf1.menuH). At 1280x620 the panel's top measured
     -62.28px, i.e. off the TOP of the screen, and a position:fixed
     panel cannot be scrolled back into view, so the "Recommended"
     header and its first entry were unreachable outright
     (palette-p3-caps.json, base["1280x620@1"], offTopPx 62.281,
     firstEntryReachable false).

     THE IDIOM IS BUILD-113's OWN, not a new one. The folded plan
     group's output list is the prototype's capped scroller —
     workflow-template.html:7548-7550:
       .wf-pgout{...max-height:calc(40px * var(--scale));
                 overflow-y:auto;padding-right:3px;
                 overscroll-behavior:contain}
       .wf-pgout::-webkit-scrollbar{width:4px}
       .wf-pgout::-webkit-scrollbar-thumb{
           background:rgba(120,100,60,.28);border-radius:4px}
     Five properties: a max-height stated as the rows it shows, auto
     overflow, a contained wheel, a 4px bar and a 4px-radius thumb in
     the family colour at 28% alpha. Everything below is those five,
     with the plan group's brass swapped for this panel's own family
     token at the SAME 28%. Nothing else is added: no scrollbar-width,
     no scrollbar-gutter, no track colour, no hover state — Build-113
     has none of those and the owner ratified none.
     The gutter needs no padding-right of its own: the panel's 5px
     padding already sits between the rows and the bar, where the
     prototype puts 3px.

     The cap is written the prototype's way — as the rows it shows,
     not as a round number. Reading the terms below in order: the top
     border, the top padding, the "Recommended" header (28), five whole
     entries (5 x 52) and 33px of the sixth, then the bottom border.
     Measured, six whole rows sit in the port (the header plus five
     entries) and exactly one row is left partial, showing 33 of its
     52px: badge and title in, description cut off mid-row
     (palette-p2b-rows.json, fix.partialRows). That cut row is the
     first affordance — the list is visibly unfinished before the user
     has touched anything — and the thumb is the second.
     328 is a multiple of FOUR on purpose, and so is the scroll extent
     it produces. The panel is bottom-anchored, so the whole rack of
     badges sits at (window - anchor - 328) and the scrollable distance
     is (content - port) = 638 - 326 = 312. Both stay on the 4-grid, so
     the badges share ONE device-pixel phase at dsf 1, 1.25 and 1.5 in
     both states measured — the top of the list and the end of the
     scroll. Cap and cut are in palette-p2-cap.json (borderBoxH 328,
     scrollExtent 312, sixthVisiblePx 33); the one phase is in
     palette-p1-ink.json (dy spread 0.00px at every scale, scrolled and
     unscrolled) and the 51px/50px counter-cases are in
     palette-p9-four.json. */
  max-height: calc(1px + 5px + 28px + 5 * 52px + 33px + 1px); /* = 328px */
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* template:7549-7550 exactly — 4px wide, 4px radius, the family at 28%
   alpha — with the plan group's brass replaced by this panel's family
   token. 28% is also this section's own --pf-pal-fill-down step
   (components.css:624): composited over white the two are the same
   swatch to the byte, rgb(212,216,223) (palette-p6-scroll.json,
   swatches.ours_matches_fillDown_swatch = true).
   MEASURED, in a HEADED browser — headless Chromium paints no
   scrollbar at all, so a headless reading of this proves nothing: the
   bar reserves 4px of the panel's width, the thumb paints
   rgb(211,216,223) over this panel's own 88%-white surface, and it
   travels 0 -> 67 -> 147px down a 300px band as the list is scrolled
   top -> middle -> end (palette-p6-scroll.json, headed.fix).
   It is a FAINT thumb, and knowingly so: 1.43:1 against its track,
   where WCAG 1.4.11 asks 3:1 of a non-text control. That is the
   prototype's own register — Build-113's brass thumb composited over
   the same white measures 1.48:1 — and the cut row above, not the
   thumb, is what makes the scroll discoverable. Raising it would be a
   deviation from Build-113, so it is left for the owner to rule on;
   the exact one-line change is in the track report. */
.aw-newblocks .kind-menu::-webkit-scrollbar { width: 4px; }
.aw-newblocks .kind-menu::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--pf-pal-family) 28%, transparent);
  border-radius: 4px;
}
.aw-newblocks .kind-menu-section-header {
  color: #6e8077;                 /* topbar --muted */
  letter-spacing: 0.06em;
  padding: 9px 10px 5px;
  /* P1, same reason as .kind-menu-desc below: 9 + 14 + 5 = 28, so the
     header advances the column by a multiple of 4 too and the entries
     after it keep the same device-pixel phase as the ones before it. */
  line-height: 14px;
}
.aw-newblocks .kind-menu-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 9px;
  row-gap: 2px;
  align-items: center;
  padding: 7px 9px;
  border-radius: 9px;
  color: var(--pf-pal-ink);
  transition: background-color 0.16s var(--pf-pal-ease, ease);
}
.aw-newblocks .kind-menu-item > .pf-pal__badge {
  grid-column: 1;
  grid-row: 1 / -1;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  height: 20px;
  padding: 0 5px;
  border-radius: 6.5px;
  background: var(--pf-pal-badge-fill);
  border: 1px solid var(--pf-pal-badge-line);
  color: var(--pf-pal-family);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 9.5px;
  font-weight: 800;
  line-height: 1;
}
.aw-newblocks .kind-menu-item > .kind-menu-label,
.aw-newblocks .kind-menu-item > .kind-menu-desc { grid-column: 2; }
/* ---- P1: THE BADGE LETTERS ARE OFF-CENTRE (owner, screenshot 5:
   "the small initials ... are not aligned properly to the centre
   vertically and horizontally compared to the squares where these are
   located").

   MEASURED CAUSE. The eleven badges in this MENU sat at a FRACTIONAL
   y, because the row height carried a fraction: `.kind-menu-desc` had
   `line-height: 1.35`, which at 11px computes to 14.85px, so every
   entry measured 50.844px and each one landed on a different fraction
   — measured badge tops 256.72 / 307.56 / 358.41 / 409.25 / 460.09 /
   510.94 / 587.78 / 638.63 / 689.47 / 740.31 / 791.16 at 1440x900
   dsf 1 (palette-p1-ink.json, summary.base.dsf1.badgeTops). Each row
   therefore rasterised its glyph run at a different sub-pixel phase:
   the SAME "FILE" chip read +0.19px in row 1 and -0.19px in row 11 at
   dsf 8, and across the eleven the residual SPREAD reached 1.00px at
   dsf 1, 1.60px at dsf 1.25, 1.33px at dsf 1.5 and 0.88px at dsf 8.
   It is a spread, not an offset — no two rows agree — which is why it
   reads as "not aligned properly" rather than as one shifted chip.
   The four badges in the palette BAR did not have this problem: their
   tops are whole (measured 853 at 1440x900, all four) and all four
   families read one identical residual at each scale.

   THE FIX is to give the description and the section header an integer
   line box, so the whole column becomes integral: 20 (the chip's row)
   + 2 (row-gap) + 16 = 38, the 20px chip centres in that span at
   (38-20)/2 = 9, the entry is 7 + 38 + 7 = 52px exactly and the header
   is 9 + 14 + 5 = 28px exactly. Nothing here touches the chip's own
   recipe or the letters inside it — the chip was never the problem,
   where the chip landed was. Pinning a letterform by its measured
   geometry rather than trusting a layout default is also what the CARD
   badge does (planflow-blocks.js:551-562 — "centered at x=50.5 y=68
   ... the baseline rises so the visual centre (~58.6 ...) stays
   fixed"), so this matches the card system's treatment.

   52 and 28 are multiples of FOUR, and that is load-bearing, not
   decoration — it was tested, not assumed. Entries of 51px and 50px
   are equally whole and both hold the spread at 0.00px at the TOP of
   the list; but they make the scroll extent 299 and 286, and once the
   list is scrolled to its END the spread reopens to 0.80px at dsf 1.25
   (both) and 0.66px at dsf 1.5 (51px). At 52/28 the extent is 312 and
   the rack, the entry and the scroll distance are all on the 4-grid,
   so the spread stays 0.00px in every state measured
   (palette-p9-four.json).

   MEASURED AFTER: 0 of 11 badge tops fractional (was 11 of 11), and
   the residual spread across the eleven is 0.00px at dsf 1, 1.25, 1.5
   and 8 — at the top of the list and at the end of the scroll alike
   (palette-p1-ink.json, summary.fix.*.perScrollState). The residual
   itself is 0.00 / -0.40 / -0.33 / -0.06px at dsf 1 / 1.25 / 1.5 / 8.
   The untouched bar reads 0.00 / +0.40 / -0.33 / -0.06px, so the two
   badge sites now read the SAME residual at three of the four scales,
   including dsf 8 where the device grid is not rounding anything. At
   dsf 1.25 they differ by 0.80px — exactly one device pixel: the two
   racks sit at different y, and at 1.25 that puts them on opposite
   halves of a device pixel. The bar's y moves with the window, so no
   value in this sheet can pin that; it is not claimed.

   HORIZONTALLY the letters are already centred by layout: the text
   run's own box sits within 0.01px of the chip's centre in BOTH racks
   at every scale (menu_ldx / bar_ldx). What is left is the letterform's
   own side bearings — at dsf 8, <= 0.25px in this menu and <= 0.41px
   in the bar ("AI") — and this patch does not change it. Two
   corrections were measured and neither is adopted:
   letter-spacing:normal on the chip helps AI (-0.41 -> -0.29) but
   hurts IN (0.02 -> 0.21) and moves the chip widths; a per-string
   optical nudge reaches 0.18/0.13 but needs one constant per string,
   which is a property of the local monospace fallback rather than of
   the design (palette-p8-hexp.json). */
.aw-newblocks .kind-menu-label { font-weight: 600; }
.aw-newblocks .kind-menu-desc  { color: #6e8077; line-height: 16px; }
.aw-newblocks .kind-menu-item:hover {
  background: color-mix(in srgb, var(--pf-pal-family) 13%, white);
}
.aw-newblocks .kind-menu-item:focus-visible {
  outline: 2px solid rgba(60, 120, 92, 0.55);
  outline-offset: -2px;
}

/* Tool / type badges row inside block cards. */
.tool-badges { margin-left: 6px; opacity: 0.85; font-size: 12px; letter-spacing: 1px; }
.tool-badge { margin: 0 1px; }

/* File chips (inspector) */
.upload-row { display: flex; flex-direction: column; gap: 4px; }
.files-list { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; }
.file-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fdfdfd;
  font-size: 12px;
}
.file-chip .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-chip .size { color: var(--text-muted); font-size: 11px; }

/* Connection editor rows */
.conn-list { display: flex; flex-direction: column; gap: 6px; }
.conn-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fdfdfd;
  font-size: 12px;
}
.conn-row .src {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.select-sm { padding: 3px 6px; font-size: 11px; width: auto; }
.badge {
  font-size: 10px;
  padding: 2px 7px;
  border-radius: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.badge-data    { background: rgba(46, 142, 93, 0.14); color: #2e8e5d; }
.badge-trigger { background: rgba(214, 138, 28, 0.16); color: #a26a14; }
.tag.tag-input  { background: rgba(45, 121, 158, 0.18); color: #1d4f6c; }

/* Picker list (selected-context blocks) */
.picker-list {
  max-height: 140px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 8px;
  background: #fff;
}

/* Artifact thumbnails / file links */
.artifacts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}
.artifact {
  display: inline-flex;
  flex-direction: column;
  gap: 4px;
  text-decoration: none;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px;
  background: #fdfdfd;
  color: var(--text);
  font-size: 11.5px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  /* Phase 10 Slice 2 — clamp the artifact card to its parent so a
     long filename or wide QA badge cannot force a page-level
     horizontal scrollbar on the inspector Output tab. */
  max-width: 100%;
  min-width: 0;
}
.artifact:hover { border-color: var(--accent-3); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); }
.artifact.image img {
  max-width: 280px;
  max-height: 280px;
  border-radius: 4px;
  display: block;
}
.artifact.file {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
}
.artifact.file .ico { font-size: 16px; }
.artifact.file .lbl {
  flex: 1;
  font-weight: 500;
  /* Truncate long filenames with ellipsis rather than letting them
     blow the inspector panel wider than its container. min-width: 0
     is required so this flex item can actually shrink below its
     intrinsic content width. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.artifact.file .size { color: var(--text-muted); font-size: 11px; }
.artifact .artifact-meta { color: var(--text-muted); font-size: 11px; }
.artifact .artifact-body {
  display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0;
}
.artifact .meta-tag { color: var(--text-muted); font-size: 10.5px; }
.artifact .size-and-badges { display: flex; flex-direction: column; gap: 4px; align-items: flex-end; }
.artifact-badges { display: flex; flex-wrap: wrap; gap: 4px; }
.artifact-badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 500;
  border-radius: 3px;
  padding: 1px 6px;
  white-space: nowrap;
}

/* Meta row under outputs */
.meta-row { font-size: 11px; color: var(--text-muted); margin-top: 6px; }

/* Decision UX §11 — two-level run summary */
.run-headline {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 8px 10px;
  background: #f8fafc;
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  font-size: 12px;
  margin-bottom: 6px;
}
.run-headline strong { font-weight: 600; }
.run-warnings {
  margin-top: 6px;
  padding: 6px 10px;
  background: #fff7ed;
  color: #7c2d12;
  border: 1px solid #fed7aa;
  border-radius: 6px;
  font-size: 11px;
  line-height: 1.45;
}
.run-warnings > div + div { margin-top: 2px; }
.run-technical summary { color: #475569; }
.run-technical[open] summary { color: var(--text); }

/* ----- Tools list (per-block tool toggles) ----- */
.tool-list { display: flex; flex-direction: column; gap: 4px; }
.tool-item {
  display: grid;
  grid-template-columns: 18px 16px 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 6px;
  border: 1px solid transparent;
  font-size: 12.5px;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.tool-item:hover { background: #f6faf8; border-color: var(--border); }
.tool-item input[type="checkbox"] { margin: 0; accent-color: var(--accent-2); }
.tool-item .tool-label { color: var(--text); }
.tool-item .ico-host { color: var(--accent); display: inline-flex; }
.tool-item .hint { font-size: 10.5px; }

/* ----- Execution stage badge on block cards ----- */
.block-stage {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 1px 6px;
  margin-right: 4px;
  font-size: 10px;
  font-weight: 700;
  color: var(--accent);
  background: rgba(67, 145, 109, 0.12);
  border-radius: 4px;
  letter-spacing: 0.4px;
}
.block.type-input  .block-stage { color: #1d4f6c; background: rgba(45, 121, 158, 0.18); }
.block.type-output .block-stage { color: #3b2a72; background: rgba(94, 73, 168, 0.18); }

/* ----- "Open chat" inspector button ----- */
.chat-open-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.chat-open-btn .ico-host { display: inline-flex; }

/* ----- Per-block chat ----- */
.chat-history {
  max-height: 280px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fbfdfc;
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 8px;
}
.chat-hint {
  font-size: 11.5px;
  color: var(--text-muted);
  font-style: italic;
}
.chat-msg {
  display: flex;
  flex-direction: column;
  gap: 2px;
  line-height: 1.45;
  font-size: 12.5px;
}
.chat-msg .chat-role {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--text-muted);
}
.chat-msg .chat-content {
  white-space: pre-wrap;
  word-break: break-word;
  border-radius: 8px;
  padding: 6px 9px;
  background: #fff;
  border: 1px solid var(--border);
}
.chat-msg.chat-user .chat-content {
  background: #eef6f1;
  border-color: #d3e6dc;
}
.chat-msg.chat-assistant .chat-content {
  background: #fff;
  border-color: var(--border);
}
.chat-msg.chat-thinking .chat-content {
  color: var(--text-muted);
  background: #f5f9f7;
  font-style: italic;
}
.chat-msg.chat-thinking .dots {
  display: inline-flex;
  gap: 3px;
  align-items: center;
}
.chat-msg.chat-thinking .dots span {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent-2);
  opacity: 0.4;
  animation: chatDot 1.2s infinite ease-in-out;
}
.chat-msg.chat-thinking .dots span:nth-child(2) { animation-delay: 0.2s; }
.chat-msg.chat-thinking .dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes chatDot {
  0%, 100% { opacity: 0.3; transform: translateY(0); }
  50%      { opacity: 1;   transform: translateY(-2px); }
}

.chat-input-row {
  display: flex;
  gap: 6px;
  align-items: stretch;
  margin-bottom: 8px;
}
.chat-input { flex: 1; min-height: 44px; resize: vertical; }
.chat-input-row .btn { align-self: stretch; }

.chat-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.chat-actions .btn { padding: 4px 9px; font-size: 11.5px; }

/* ----- Floating chat dialog (left of screen) ----- */
.chat-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(20, 30, 25, 0.18);
  z-index: 998;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease;
}
.chat-backdrop.active { opacity: 1; pointer-events: auto; }

.chat-dialog {
  position: fixed;
  left: 0;
  top: 0;
  bottom: 0;
  width: 400px;
  max-width: 90vw;
  background: #fff;
  z-index: 999;
  display: flex;
  flex-direction: column;
  transform: translateX(-100%);
  transition: transform 0.22s cubic-bezier(.2,.8,.2,1);
  box-shadow: 6px 0 28px rgba(0, 0, 0, 0.18);
}
.chat-dialog.open { transform: translateX(0); }

.chat-dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, #fafcfb, #f5f9f7);
}
.chat-dialog-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: var(--accent);
  font-size: 14px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.chat-dialog-title .ico-host { color: var(--accent-2); display: inline-flex; }

.chat-dialog .chat-history {
  flex: 1;
  margin: 0;
  border: none;
  border-radius: 0;
  background: #fbfdfc;
  padding: 14px 14px 8px;
  max-height: none;
}
.chat-dialog .chat-input-row {
  border-top: 1px solid var(--border);
  padding: 10px 14px;
  margin: 0;
  background: #fff;
}
.chat-dialog .chat-input { min-height: 50px; }
.chat-dialog #chat-dialog-send {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.chat-dialog-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 14px 12px;
  border-top: 1px solid var(--border);
  background: #fdfdfd;
}
.chat-dialog-hint { font-size: 11px; color: var(--text-muted); }

/* Per-message action row, hover-revealed for tidiness. */
.chat-msg-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  margin-bottom: 2px;
}
.chat-msg-actions {
  display: inline-flex;
  gap: 4px;
  opacity: 0;
  transition: opacity 0.15s ease;
}
.chat-msg:hover .chat-msg-actions,
.chat-msg:focus-within .chat-msg-actions { opacity: 1; }
.chat-action {
  background: #f1f5f3;
  border: 1px solid transparent;
  color: var(--text-muted);
  font-size: 10.5px;
  padding: 2px 7px;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.12s ease;
  font-family: inherit;
}
.chat-action:hover {
  background: #e7f1ec;
  color: var(--accent);
  border-color: var(--accent-3);
}

.chat-empty {
  text-align: center;
  color: var(--text-muted);
  padding: 24px 8px;
  font-size: 12.5px;
}
.chat-empty p { margin: 4px 0; }

/* Code-ish output box */
.output-box {
  background: #fbfdfc;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 12px;
  font-family: 'EB Garamond', Georgia, serif;
  font-size: 12.5px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 340px;
  overflow-y: auto;
  color: #3a4a42;
}

/* ============================================================
   Repeat compiler: connections, generated blocks, modal.
   ============================================================ */

/* Repeat port: a single bottom handle per block. Both ends of a
   repeat connection anchor here, with a U-shaped curve dipping below
   the canvas and an arrowhead at the target (the segment head). */
.handle.handle-repeat-out {
  width: 14px;
  height: 14px;
  background: #ede9fe;
  border: 2px solid #8b5cf6;
  border-radius: 50%;
  cursor: crosshair;
  transition: opacity 0.12s ease, transform 0.15s ease, background 0.15s ease;
  left: 50%;
  bottom: -7px;
  top: auto;
  transform: translateX(-50%);
}
.handle.handle-repeat-out:hover {
  background: #c4b5fd;
  transform: translateX(-50%) scale(1.25);
}

.connection-path.kind-repeat {
  stroke: #8b5cf6;
  stroke-width: 2.2;
  stroke-dasharray: 8 5;
  fill: none;
  opacity: 0.85;
}
.connection-path.kind-repeat.preview { opacity: 0.6; }
.connection-path.is-generated {
  stroke: #43916d;
  stroke-dasharray: 4 3;
  opacity: 0.7;
}
.connection-path.is-disabled {
  stroke: #b8b8b8;
  stroke-dasharray: 2 4;
  opacity: 0.45;
}

.block.is-repeat-generated {
  border-style: dashed;
  border-color: #8b5cf6;
  background-image:
    linear-gradient(180deg, rgba(139, 92, 246, 0.04) 0%, rgba(255, 255, 255, 0.0) 100%);
}
.block.is-repeat-generated .block-title { color: #5b3da9; }
.block.is-repeat-generated .block-title { min-width: 0; }

.repeat-badges {
  display: inline-flex;
  gap: 4px;
  margin-left: auto;
  flex-shrink: 0;
}
.repeat-badge {
  display: inline-block;
  padding: 1px 6px;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.3px;
  color: #5b3da9;
  background: #ede9fe;
  border: 1px solid #c4b5fd;
  border-radius: 999px;
  text-transform: uppercase;
  white-space: nowrap;
}
.repeat-badge.stale {
  color: #8a4a00;
  background: #fff3d6;
  border-color: #ffcf6b;
}
.repeat-badge.source {
  color: #0d5c47;
  background: #d8efe5;
  border-color: #43916d;
}
/* Original blocks that own a repeat group: subtle purple top accent
   so the user can spot the repeat-source-ness without confusing it
   with a fully generated block (which uses a dashed border). */
.block.is-repeat-source:not(.is-repeat-generated) {
  border-top: 2px solid #8b5cf6;
}
.block.is-stale-repeat {
  /* Subtle amber outline so users notice without overriding the
     dashed purple border. */
  box-shadow: 0 0 0 2px rgba(255, 207, 107, 0.55);
}

.block.type-repeat_result,
.block.type-repeat_summary,
.block.type-repeat_history {
  border-color: #c4b5fd;
}
.block.type-repeat_summary { border-width: 2px; }

/* ----- repeat-group container (collapse / expand) ----- */
/* Visual-only wrapper around generated blocks of a repeat group.
   Expanded state: a low-z bordered box behind the blocks with a header
   strip on top. Collapsed state: a compact card (z-index above paths)
   with a title row + action buttons. */
.repeat-group {
  position: absolute;
  border: 1px dashed #c4b5fd;
  background: rgba(237, 233, 254, 0.18);
  border-radius: 12px;
  z-index: 0;
  pointer-events: none;
  box-sizing: border-box;
  transition: box-shadow 0.18s ease, background 0.18s ease;
}
/* Loop-chrome unit correction (sweep S26).
   `.repeat-group` is a direct child of #canvas-stage, so — unlike a
   card — nothing counter-transformed it and every px literal in the
   rules below painted at BASE_SCALE (0.7): a 32 px header band came out
   22.4 px tall with 8.4 px text, 8.05 px count and a 6.65 px status
   badge, i.e. smaller than the card's own smallest label.
   The fix is the mechanism, not the numbers: the container carries the
   SAME counter-transform the card root does (planflow-blocks.css:95),
   and canvas.js writes its box in CSS px (stage units / --pf-zoom-comp)
   so the painted footprint is unchanged. `transform-origin:0 0` keeps
   the stage-space top-left exactly where left/top put it.
   Scoped under `.aw-newblocks`: with the flag off the selector does not
   match, --pf-zoom-comp is never written on <body>, and canvas.js's
   _pfbCompFactor() returns 1 — so flag-off geometry is untouched. */
body.aw-newblocks .repeat-group {
  transform: scale(var(--pf-zoom-comp, 1));
  transform-origin: 0 0;
}
.repeat-group.rg-expanded {
  background:
    repeating-linear-gradient(
      135deg,
      rgba(139, 92, 246, 0.05) 0,
      rgba(139, 92, 246, 0.05) 10px,
      rgba(139, 92, 246, 0.10) 10px,
      rgba(139, 92, 246, 0.10) 20px
    ),
    rgba(237, 233, 254, 0.55);
}
.repeat-group.rg-collapsed {
  z-index: 2;
  background: #fff;
  border: 1px solid #c4b5fd;
  border-left: 3px solid #8b5cf6;
  pointer-events: auto;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(91, 61, 169, 0.12), var(--shadow-soft);
}
.repeat-group.rg-collapsed:hover {
  box-shadow: 0 6px 18px rgba(91, 61, 169, 0.18), var(--shadow-medium);
}
.repeat-group.rg-stale {
  border-color: #ffcf6b;
  background: rgba(255, 243, 214, 0.35);
}
.repeat-group.rg-stale.rg-collapsed { background: #fff; border-left-color: #d6921a; }

.repeat-group-header {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 32px;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 10px;
  background: linear-gradient(180deg, #f3efff, #ede9fe);
  border-bottom: 1px solid #c4b5fd;
  border-radius: 12px 12px 0 0;
  font-size: 12px;
  pointer-events: auto;
  cursor: grab;
  user-select: none;
}
.repeat-group-header.dragging { cursor: grabbing; }
.repeat-group-header > .rg-toggle,
.repeat-group-header > .rg-actions,
.repeat-group-header > .rg-actions > * { cursor: pointer; }
.repeat-group.rg-collapsed .repeat-group-header { border-radius: 11px 11px 0 0; }
/* Hide redundant mode/count in the collapsed header — they're in the
   summary body. Status badge + actions stay visible. */
.repeat-group.rg-collapsed .rg-mode,
.repeat-group.rg-collapsed .rg-count { display: none; }
.repeat-group .rg-toggle {
  background: transparent;
  border: 0;
  cursor: pointer;
  font-size: 24px;
  color: #5b3da9;
  padding: 0px 1px;
  border-radius: 4px;
  line-height: 1;
}
.repeat-group .rg-toggle:hover { background: rgba(139, 92, 246, 0.15); }
.repeat-group .rg-mode {
  font-weight: 600;
  color: #5b3da9;
  white-space: nowrap;
}
.repeat-group .rg-count {
  color: #6b5fa8;
  font-size: 11.5px;
  white-space: nowrap;
}
.repeat-group .rg-status {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 999px;
  margin-left: 4px;
}
.repeat-group .rg-status.rg-status-ready {
  color: #0d5c47;
  background: #d8efe5;
  border: 1px solid #43916d;
}
.repeat-group .rg-status.rg-status-stale {
  color: #8a4a00;
  background: #fff3d6;
  border: 1px solid #ffcf6b;
}
.repeat-group .rg-status.rg-status-needs_apply {
  color: #1d4f6c;
  background: #e8f2f8;
  border: 1px solid #2d799e;
}
.repeat-group .rg-status.rg-status-preview_unavailable {
  color: #6b6b6b;
  background: #eef0ee;
  border: 1px solid #b8b8b8;
}
/* Runtime statuses on the group container (collapsed card + expanded
   header). Aggregated from the group's generated block_results in
   ``repeatGroupSummary`` so the badge ticks during/after a run. */
.repeat-group .rg-status.rg-status-not_started {
  color: var(--text-muted);
  background: #eef0ee;
  border: 1px solid var(--border);
}
.repeat-group .rg-status.rg-status-running {
  color: var(--st-running);
  background: rgba(224, 164, 55, 0.14);
  border: 1px solid var(--st-running);
}
.repeat-group .rg-status.rg-status-completed {
  color: var(--st-completed);
  background: rgba(46, 142, 93, 0.14);
  border: 1px solid var(--st-completed);
}
.repeat-group .rg-status.rg-status-failed {
  color: var(--st-failed);
  background: rgba(176, 72, 72, 0.14);
  border: 1px solid var(--st-failed);
}
.repeat-group .rg-status.rg-status-disabled {
  color: #5b3da9;
  background: rgba(139, 92, 246, 0.12);
  border: 1px solid rgba(139, 92, 246, 0.40);
}

/* Template-only inspector — replaces "Run this block" / "Pause for
   human review" on the For Each Item source block, which is not
   executed at run time. Notice + a single bulk action that
   enables/disables every generated child of the group. */
.run-options.template-run-options {
  background: rgba(237, 233, 254, 0.55);
  border: 1px dashed #c4b5fd;
  border-radius: 8px;
  padding: 10px 12px;
  display: block;
}
.run-options.template-run-options .template-notice {
  font-size: 12.5px;
  line-height: 1.45;
  color: #3d2370;
  margin-bottom: 10px;
}
.run-options.template-run-options .template-notice strong {
  color: #5b3da9;
}
/* ``.template-group-toggle`` button uses the standard .btn / .btn-danger
   styling — no extra rules needed. */
.repeat-group .rg-actions {
  margin-left: auto;
  display: inline-flex;
  gap: 2px;
}
.repeat-group .rg-act {
  background: transparent;
  border: 1px solid transparent;
  cursor: pointer;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.3px;
  color: #5b3da9;
  padding: 2px 7px;
  border-radius: 4px;
  line-height: 1.4;
  text-transform: uppercase;
}
.repeat-group .rg-act:hover {
  background: rgba(139, 92, 246, 0.18);
  border-color: rgba(139, 92, 246, 0.35);
  color: #3d2370;
}

/* Collapsed-state body. Hidden when expanded. */
.repeat-group .rg-summary {
  position: absolute;
  left: 0; right: 0;
  top: 32px;
  bottom: 0;
  padding: 10px 14px 12px;
  font-size: 14px;
  font-weight: 500;
  color: #3d2370;
  display: flex;
  align-items: center;
  pointer-events: none;
  line-height: 1.3;
}

/* Virtual group-port edges — the rerouted incoming / outgoing line
   between the COLLAPSED repeat-group card and an external block.
   Inherits the normal green ``.connection-path`` styling so it reads
   as part of the main execution chain (NOT a special "generated"
   line). ``pointer-events: none`` keeps it decorative — the user
   interacts with the group container, not the synthetic edge. */
.connection-path.rg-external {
  fill: none;
  pointer-events: none;
  /* stroke / stroke-width / opacity inherit from base .connection-path
     so this looks identical to any other normal data edge. */
}

/* Template-to-frame connector — drawn only in EXPANDED mode, from
   the disabled template block's right port to the frame's left
   port. Purple dashed line that visually ties the authored source
   to its generated repeat group without pretending data flows
   through it at run time. */
.connection-path.rg-template-connector {
  stroke: #8b5cf6;
  stroke-width: 2;
  stroke-dasharray: 6 4;
  opacity: 0.7;
  fill: none;
  pointer-events: none;
}

/* ----- repeat context menu ----- */
.repeat-context-menu {
  position: fixed;
  z-index: 30;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  min-width: 220px;
  padding: 4px;
  display: flex;
  flex-direction: column;
}
.repeat-context-menu button {
  text-align: left;
  background: none;
  border: 0;
  padding: 8px 12px;
  font: inherit;
  color: var(--text);
  cursor: pointer;
  border-radius: 4px;
}
.repeat-context-menu button:hover { background: rgba(67, 145, 109, 0.08); }

/* ----- repeat modal ----- */
.rm-host {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
}
.rm-host.hidden { display: none; }
.rm-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(20, 30, 25, 0.45);
}
.rm-dialog {
  position: relative;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
  width: min(560px, 92vw);
  max-height: 86vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}
.rm-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  border-bottom: 1px solid var(--border);
}
.rm-header h2 {
  margin: 0;
  font-size: 18px;
  font-family: 'EB Garamond', Georgia, serif;
  color: var(--accent);
}
.rm-close {
  background: none;
  border: 0;
  font-size: 22px;
  cursor: pointer;
  color: var(--text-muted);
}
.rm-close:hover { color: var(--text); }

.rm-body { padding: 16px 20px; }

.rm-source-display {
  display: flex;
  gap: 8px;
  align-items: baseline;
  padding: 8px 12px;
  margin-bottom: 14px;
  background: #f3f7f5;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 13px;
}
.rm-source-label {
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  font-size: 10.5px;
  letter-spacing: 0.4px;
}
.rm-source-text { color: var(--text); }

.rm-modes {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-bottom: 14px;
}
.rm-field-stack { flex-direction: column; align-items: flex-start; gap: 6px; }
.rm-field-stack .rm-label { min-width: 0; }
.rm-manual-items {
  width: 100%;
  font-family: 'Menlo', 'Consolas', monospace;
  font-size: 12.5px;
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 6px 8px;
  resize: vertical;
}
.rm-item-config { margin-bottom: 8px; }
.rm-item-config.hidden { display: none; }
.rm-items-preview {
  margin-top: 6px;
  padding: 8px 10px;
  background: #f3f7f5;
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 12.5px;
}
.rm-items-preview.hidden { display: none; }
.rm-items-list { margin: 4px 0 0 18px; padding: 0; }
.rm-mode-card {
  text-align: left;
  padding: 12px;
  border: 1px solid var(--border);
  background: #fafdfb;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.15s ease;
}
.rm-mode-card:hover { border-color: var(--accent-3); background: #f0f7f3; }
.rm-mode-card.selected {
  border-color: var(--accent);
  background: #e8f2ec;
  box-shadow: 0 0 0 2px rgba(67, 145, 109, 0.18);
}
.rm-mode-name { font-weight: 600; color: var(--accent); margin-bottom: 4px; }
.rm-mode-desc { margin: 0; font-size: 12.5px; color: var(--text-muted); line-height: 1.4; }

.rm-config { margin-bottom: 14px; }
.rm-config.hidden { display: none; }
.rm-field {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-bottom: 6px;
}
.rm-label {
  font-size: 13px;
  color: var(--text);
  min-width: 160px;
}
.rm-count {
  width: 90px;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 4px;
  font: inherit;
}
.rm-hint {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--text-muted);
}

.rm-preview {
  padding: 10px 12px;
  background: #f6faf8;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 13px;
}
.rm-preview.hidden { display: none; }
.rm-preview-row { padding: 2px 0; }
.rm-warning {
  color: #8a5d00;
  background: #fff5d6;
  border: 1px solid #ffd76b;
  border-radius: 4px;
  padding: 6px 8px;
  margin-top: 6px;
  font-size: 12.5px;
}
.rm-error {
  color: #842029;
  background: #fde8e8;
  border: 1px solid #f5b5b5;
  border-radius: 4px;
  padding: 6px 8px;
  margin-top: 6px;
  font-size: 12.5px;
}

.rm-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 20px 16px;
  border-top: 1px solid var(--border);
}
