/* ==========================================================================
   Visual Test Builder
   --------------------------------------------------------------------------
   Owned by the Visual Test Builder workstream. Every value here comes from
   tokens.css — no raw colours, no new spacing scale — so the builder flips
   with [data-theme] like the rest of the product.
   ========================================================================== */

.qb {
  --qb-palette-width: 264px;
  --qb-props-width: 340px;
  --qb-header-height: 52px;
  --qb-rail: 3px;

  display: grid;
  /* The canvas keeps a floor so a step title never wraps one letter per line; below the
     breakpoints in builder.js the side panels become drawers and stop competing for width. */
  grid-template-columns: var(--qb-palette-width) 1px minmax(360px, 1fr) 1px var(--qb-props-width);
  grid-template-rows: var(--qb-header-height) minmax(0, 1fr);
  grid-template-areas:
    'header header header header header'
    'palette rail-l canvas rail-r props';
  height: 100%;
  min-height: 0;
  background: var(--qp-canvas);
  border: 1px solid var(--qp-border-subtle);
  border-radius: var(--qp-radius-lg);
  overflow: hidden;
}

.qb[data-palette='collapsed'] {
  grid-template-columns: 0 1px minmax(0, 1fr) 1px var(--qb-props-width);
}

.qb[data-props='collapsed'] {
  grid-template-columns: var(--qb-palette-width) 1px minmax(0, 1fr) 1px 0;
}

.qb[data-palette='collapsed'][data-props='collapsed'] {
  grid-template-columns: 0 1px minmax(0, 1fr) 1px 0;
}

/* Not enough room for side panels: the canvas takes the whole width and the panels
   open over it as drawers instead. */
.qb[data-layout='compact'] {
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    'header'
    'canvas';
}

.qb[data-layout='compact'] .qb__rail {
  display: none;
}

/* The header has to stay on one line, so the least useful pieces step aside first. */
.qb[data-layout='compact'] .qb__version,
.qb[data-layout='compact'] .qb__divider,
.qb[data-layout='minimal'] .qb__version,
.qb[data-layout='minimal'] .qb__divider,
.qb[data-layout='minimal'] .qb__header-group {
  display: none;
}

.qb[data-layout='compact'] .qb__header,
.qb[data-layout='minimal'] .qb__header {
  gap: var(--qp-space-2);
}

.qb[data-layout='compact'] .qb__identity,
.qb[data-layout='minimal'] .qb__identity {
  flex: 0 1 auto;
  min-width: 0;
}

/* Below the narrowest useful width the test number is the first thing to go — the name
   identifies the test well enough, and the canvas needs the room. */
.qb[data-layout='minimal'] .qb__identity .qb__number {
  display: none;
}

/* Too narrow to author in at all — a calm explanation above a readable storyboard. */
.qb[data-layout='minimal'] {
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    'header'
    'canvas';
}

.qb-toonarrow {
  display: flex;
  align-items: flex-start;
  gap: var(--qp-space-2);
  padding: var(--qp-space-3);
  margin-bottom: var(--qp-space-4);
  border: 1px solid var(--qp-border);
  border-radius: var(--qp-radius-md);
  background: var(--qp-surface-sunken);
  color: var(--qp-text-muted);
  font-size: var(--qp-text-xs);
  line-height: var(--qp-leading-normal);
}

.qb-toonarrow strong {
  display: block;
  color: var(--qp-text-strong);
  font-weight: var(--qp-weight-semibold);
  margin-bottom: 2px;
}

/* The drawer bodies hold a whole panel, which brings its own chrome. */
.qb-drawer-panel {
  margin: calc(var(--qp-space-4) * -1);
  height: calc(100% + var(--qp-space-8));
}

.qb-drawer-panel .qb__panel {
  height: 100%;
}

/* --------------------------------------------------------------- header -- */

.qb__header {
  grid-area: header;
  display: flex;
  align-items: center;
  gap: var(--qp-space-3);
  padding: 0 var(--qp-space-3);
  border-bottom: 1px solid var(--qp-border-subtle);
  background: var(--qp-surface);
  min-width: 0;
}

.qb__identity {
  display: flex;
  align-items: baseline;
  gap: var(--qp-space-2);
  min-width: 0;
}

.qb__number {
  font-family: var(--qp-font-mono);
  font-size: var(--qp-text-xs);
  color: var(--qp-text-subtle);
  letter-spacing: var(--qp-tracking-tight);
}

.qb__name {
  font-size: var(--qp-text-md);
  font-weight: var(--qp-weight-semibold);
  color: var(--qp-text-strong);
  letter-spacing: var(--qp-tracking-tight);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.qb__header-group {
  display: flex;
  align-items: center;
  gap: var(--qp-space-1);
}

.qb__spacer {
  flex: 1 1 auto;
  min-width: var(--qp-space-2);
}

.qb__divider {
  width: 1px;
  height: 20px;
  background: var(--qp-border-subtle);
  margin: 0 var(--qp-space-1);
}

/* ---------------------------------------------------------------- panels -- */

.qb__panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  background: var(--qp-surface);
  overflow: hidden;
}

.qb__panel--palette {
  grid-area: palette;
}

.qb__panel--props {
  grid-area: props;
}

.qb__panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--qp-space-2);
  padding: var(--qp-space-3) var(--qp-space-3) var(--qp-space-2);
}

.qb__panel-title {
  font-size: var(--qp-text-xs);
  font-weight: var(--qp-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--qp-tracking-caps);
  color: var(--qp-text-subtle);
}

.qb__panel-body
{
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 0 var(--qp-space-3) var(--qp-space-4);
}

/* Drag-to-resize rails between the panels. */
.qb__rail {
  position: relative;
  background: var(--qp-border-subtle);
  border: 0;
  padding: 0;
  cursor: col-resize;
  touch-action: none;
  transition: background var(--qp-duration-fast) var(--qp-ease);
}

.qb__rail--left {
  grid-area: rail-l;
}

.qb__rail--right {
  grid-area: rail-r;
}

.qb__rail::after {
  content: '';
  position: absolute;
  inset-block: 0;
  inset-inline: calc(var(--qb-rail) * -1);
}

.qb__rail:hover,
.qb__rail:focus-visible {
  background: var(--qp-accent);
}

.qb__rail:focus-visible {
  outline: 2px solid var(--qp-focus-ring);
  outline-offset: 1px;
}

body.qb-resizing {
  cursor: col-resize;
  user-select: none;
}

/* --------------------------------------------------------------- palette -- */

.qb-palette__search {
  padding: 0 var(--qp-space-3) var(--qp-space-2);
}

.qb-palette__group {
  margin-top: var(--qp-space-3);
}

/* Native disclosure controls keep every group collapsed until opened or searched. */
.qb-palette__group-title
{
  display: flex;
  align-items: center;
  gap: var(--qp-space-2);
  cursor: pointer;
  list-style: none;
  font-size: var(--qp-text-2xs);
  font-weight: var(--qp-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--qp-tracking-caps);
  color: var(--qp-text-faint);
  padding: var(--qp-space-1) var(--qp-space-1) var(--qp-space-2);
}

.qb-palette__group-title::-webkit-details-marker
{
  display: none;
}

.qb-palette__group-title:hover
{
  color: var(--qp-text);
}

.qb-palette__group-title:focus-visible
{
  outline: 2px solid var(--qp-focus-ring);
  outline-offset: 1px;
  border-radius: var(--qp-radius-xs);
}

.qb-palette__group[open] > .qb-palette__group-title > svg
{
  transform: rotate(90deg);
}

.qb-palette__list
{
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.qb-palette__item {
  display: flex;
  align-items: center;
  gap: var(--qp-space-2);
  width: 100%;
  padding: var(--qp-space-2);
  border: 0;
  border-radius: var(--qp-radius-sm);
  background: transparent;
  color: var(--qp-text);
  font: inherit;
  font-size: var(--qp-text-sm);
  text-align: start;
  cursor: grab;
  transition: background var(--qp-duration-fast) var(--qp-ease);
}

.qb-palette__item:hover {
  background: var(--qp-surface-hover);
}

.qb-palette__item:focus-visible {
  outline: 2px solid var(--qp-focus-ring);
  outline-offset: -2px;
}

.qb-palette__item:active {
  cursor: grabbing;
}

.qb-palette__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  border-radius: var(--qp-radius-xs);
  background: var(--qb-tint, var(--qp-surface-sunken));
  color: var(--qb-accent, var(--qp-text-muted));
}

.qb-palette__label {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.qb-palette__hint {
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-faint);
  font-family: var(--qp-font-mono);
}

/* ---------------------------------------------------------- quick add -- */

.qp-dialog.qb-quick-add
{
  display: flex;
  flex-direction: column;
  width: min(640px, 100%);
  height: min(640px, calc(100dvh - 2 * var(--qp-space-6)));
}

.qb-quick-add .qp-dialog__body,
.qb-quick-add .qp-dialog__text
{
  flex: 1 1 auto;
  min-height: 0;
}

.qb-quick-add .qp-dialog__title,
.qb-quick-add .qp-input-wrap,
.qb-quick-add .qp-dialog__footer
{
  flex-shrink: 0;
}

.qb-quick-add__results
{
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin-top: var(--qp-space-3);
}

.qb-quick-add .qb-palette__label
{
  white-space: normal;
  overflow-wrap: anywhere;
}

.qb-quick-add .qb-palette__item
{
  cursor: pointer;
}

/* ---------------------------------------------------------------- canvas -- */

.qb__canvas {
  grid-area: canvas;
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  background: var(--qp-canvas);
}

/* Allow wheel scrolling to reach the page when the editor grows with its content. */
.qb-canvas__scroll
{
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: var(--qp-space-5) var(--qp-space-6) var(--qp-space-12);
}

.qb-canvas__inner {
  max-width: 760px;
  margin-inline: auto;
}

.qb-list {
  display: flex;
  flex-direction: column;
  gap: var(--qp-space-2);
  margin: 0;
  padding: 0;
  list-style: none;
  min-height: var(--qp-space-4);
}

/* A container's own list gets a little breathing room and a guide line. */
.qb-lane {
  position: relative;
  margin-top: var(--qp-space-2);
  padding-left: var(--qp-space-5);
}

.qb-lane::before {
  content: '';
  position: absolute;
  inset-block: 0;
  left: var(--qp-space-3);
  width: 2px;
  border-radius: var(--qp-radius-full);
  background: var(--qb-accent, var(--qp-border));
  opacity: 0.35;
}

.qb-lane--empty .qb-list {
  min-height: 44px;
  border: 1px dashed var(--qp-border);
  border-radius: var(--qp-radius-md);
  display: grid;
  place-items: center;
  color: var(--qp-text-faint);
  font-size: var(--qp-text-xs);
}

/* ------------------------------------------------------------------ card -- */

.qb-card {
  position: relative;
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--qp-space-2);
  padding: var(--qp-space-2) var(--qp-space-2) var(--qp-space-2) 0;
  border: 1px solid var(--qp-border-subtle);
  border-radius: var(--qp-radius-md);
  background: var(--qp-surface);
  cursor: pointer;
  transition:
    border-color var(--qp-duration-fast) var(--qp-ease),
    box-shadow var(--qp-duration-fast) var(--qp-ease),
    background var(--qp-duration-fast) var(--qp-ease);
}

/* The category accent, as a hairline down the leading edge. */
.qb-card::before {
  content: '';
  position: absolute;
  inset-block: -1px;
  inset-inline-start: -1px;
  width: 3px;
  border-start-start-radius: var(--qp-radius-md);
  border-end-start-radius: var(--qp-radius-md);
  background: var(--qb-accent, var(--qp-border));
}

.qb-card:hover {
  border-color: var(--qp-border);
  background: var(--qp-surface-hover);
}

.qb-card[data-selected='true'] {
  border-color: var(--qp-accent-border);
  background: var(--qp-surface-selected);
  box-shadow: 0 0 0 1px var(--qp-accent-border);
}

.qb-card:focus-visible {
  outline: 2px solid var(--qp-focus-ring);
  outline-offset: 2px;
}

.qb-card[data-disabled='true'] {
  opacity: 0.55;
}

.qb-card[data-disabled='true'] .qb-card__title {
  text-decoration: line-through;
  text-decoration-color: var(--qp-text-faint);
}

.qb-card__number {
  grid-row: 1;
  align-self: center;
  min-width: 22px;
  padding-inline-start: var(--qp-space-2);
  font-family: var(--qp-font-mono);
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-faint);
  text-align: end;
  font-variant-numeric: tabular-nums;
}

.qb-card__icon {
  grid-row: 1;
  align-self: center;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: var(--qp-radius-xs);
  background: var(--qb-tint, var(--qp-surface-sunken));
  color: var(--qb-accent, var(--qp-text-muted));
}

.qb-card__main {
  grid-row: 1;
  min-width: 0;
  padding-block: 2px;
}

.qb-card__title {
  font-size: var(--qp-text-sm);
  color: var(--qp-text-strong);
  line-height: var(--qp-leading-snug);
  /* break-word, not anywhere: a long locator still wraps, but ordinary words are never
     broken mid-letter when the column gets tight. */
  overflow-wrap: break-word;
}

.qb-card__title em {
  font-style: normal;
  font-weight: var(--qp-weight-medium);
  color: var(--qp-text-strong);
  background: var(--qp-surface-sunken);
  border-radius: var(--qp-radius-xs);
  padding: 0 4px;
}

.qb-card__title code {
  font-family: var(--qp-font-mono);
  font-size: var(--qp-text-xs);
  color: var(--qp-accent-text);
  background: var(--qp-accent-subtle);
  border-radius: var(--qp-radius-xs);
  padding: 0 4px;
}

.qb-card__note {
  margin-top: var(--qp-space-1);
  font-size: var(--qp-text-xs);
  color: var(--qp-text-muted);
}

.qb-card__actions {
  grid-row: 1;
  align-self: center;
  display: flex;
  align-items: center;
  gap: 2px;
  opacity: 0;
  transition: opacity var(--qp-duration-fast) var(--qp-ease);
}

.qb-card:hover .qb-card__actions,
.qb-card:focus-within .qb-card__actions,
.qb-card[data-selected='true'] .qb-card__actions {
  opacity: 1;
}

.qb-card__handle {
  cursor: grab;
  color: var(--qp-text-faint);
}

.qb-card__handle:active {
  cursor: grabbing;
}

/* ---------------------------------------------------- assertion cards ---- */

/* Assertions are first-class: an eyebrow and a labelled row per part, so a
   stakeholder can read what is being checked without knowing the step model. */
.qb-card--assert {
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  background: var(--qp-pass-bg);
  border-color: var(--qp-pass-border);
}

.qb-card--assert:hover {
  background: var(--qp-pass-bg);
  border-color: var(--qp-pass);
}

.qb-card--assert .qb-card__icon {
  background: var(--qp-surface);
  color: var(--qp-pass);
}

.qb-card__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--qp-text-3xs);
  font-weight: var(--qp-weight-semibold);
  letter-spacing: var(--qp-tracking-caps);
  text-transform: uppercase;
  color: var(--qp-pass);
  margin-bottom: 2px;
}

.qb-assert-rows {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 2px var(--qp-space-2);
  margin-top: var(--qp-space-1);
}

.qb-assert-rows dt {
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-subtle);
  text-transform: uppercase;
  letter-spacing: var(--qp-tracking-caps);
  padding-top: 1px;
}

.qb-assert-rows dd {
  margin: 0;
  font-size: var(--qp-text-sm);
  color: var(--qp-text-strong);
  overflow-wrap: break-word;
}

/* -------------------------------------------------- business-action card -- */

.qb-card__params {
  display: flex;
  flex-wrap: wrap;
  gap: var(--qp-space-1);
  margin-top: var(--qp-space-1);
}

.qb-param {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  padding: 1px 6px;
  border-radius: var(--qp-radius-full);
  background: var(--qp-surface-sunken);
  font-size: var(--qp-text-2xs);
}

.qb-param__key {
  color: var(--qp-text-subtle);
}

.qb-param__value {
  font-family: var(--qp-font-mono);
  color: var(--qp-text);
}

.qb-card__inner {
  margin-top: var(--qp-space-2);
  padding: var(--qp-space-2);
  border-radius: var(--qp-radius-sm);
  background: var(--qp-surface-sunken);
}

.qb-card__inner-title {
  font-size: var(--qp-text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--qp-tracking-caps);
  color: var(--qp-text-faint);
  margin-bottom: var(--qp-space-1);
}

.qb-card__inner ol {
  margin: 0;
  padding-inline-start: var(--qp-space-4);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.qb-card__inner li {
  font-size: var(--qp-text-xs);
  color: var(--qp-text-muted);
}

/* ------------------------------------------------------- inline issues --- */

.qb-card__issue {
  grid-column: 3 / -1;
  display: flex;
  align-items: flex-start;
  gap: var(--qp-space-1);
  margin-top: var(--qp-space-1);
  font-size: var(--qp-text-xs);
  line-height: var(--qp-leading-snug);
}

.qb-card__issue[data-severity='error'] {
  color: var(--qp-fail);
}

.qb-card__issue[data-severity='warning'] {
  color: var(--qp-warn);
}

.qb-card[data-has-error='true'] {
  border-color: var(--qp-fail-border);
}

/* ------------------------------------------------------ drag affordances -- */

.qb-card--ghost {
  opacity: 0.4;
}

.qb-card--ghost::after {
  content: '';
  position: absolute;
  inset: -1px;
  border: 1px dashed var(--qp-accent);
  border-radius: var(--qp-radius-md);
  background: var(--qp-accent-subtle);
}

.qb-card--chosen {
  box-shadow: var(--qp-shadow-2);
}

.qb-card--dragging {
  box-shadow: var(--qp-shadow-3);
  transform: rotate(0.4deg);
}

body.qb-dragging {
  cursor: grabbing;
}

body.qb-dragging .qb-card__actions {
  opacity: 0;
}

/* In the "compact" layout the palette is a QpDrawer, which sits behind a full-viewport `.qp-scrim` — fine
   for a click (the scrim is what closes the drawer), but a palette-to-canvas drag needs its dragover/drop
   to reach the connectors *behind* the scrim, and pointer/drag hit-testing follows stacking order exactly
   like a click would. The scrim also blurs and dims the very canvas the author is aiming at, so for the
   duration of a drag it goes fully transparent as well as click-through — restored the instant qb-dragging
   comes off (drop, or Escape cancelling the browser's own drag). `[data-side='start']` is exclusively the
   builder's own palette drawer (the only place the product opens one on that side, see TestBuilder.razor);
   it fades out of the way so nothing sits between the palette item's starting point and the drop target
   it is headed for — opacity only, deliberately NOT `pointer-events: none` and NOT a translate:
   - a translate moves the drawer's box, which relocates the drag SOURCE living inside it (the palette
     item itself) mid-drag; a synthetic (CDP-driven) drag session tracks that source to keep dispatching
     move events, and moving it hangs Chromium outright — reproduced directly (a `page.mouse.move` after
     `mouse.down()` on the source never resolves once its ancestor's `transform` changed).
   - `pointer-events: none` on this same ancestor is just as fatal and for the same reason: CSS
     pointer-events cascades to descendants, so it silently makes the drag source itself un-hit-testable
     mid-drag — same hang, confirmed by toggling only this one declaration back and forth.
   Opacity alone changes nothing about hit-testing or geometry, only paint — the drawer's box (and the
   item inside it) stays exactly where and *what* it was, so there is nothing to confuse a drag session
   that is still, as far as Chromium is concerned, anchored to it. The scrim (a sibling, not an ancestor
   of the drag source) has no such restriction. The transition lives outside the qb-dragging rule so it
   also plays in reverse. */
.qp-drawer[data-side='start'] {
  transition: opacity var(--qp-duration-base) var(--qp-ease);
}

body.qb-dragging .qp-scrim {
  pointer-events: none;
  background: transparent;
  backdrop-filter: none;
}

body.qb-dragging .qp-drawer[data-side='start'] {
  opacity: 0;
}

/* ------------------------------------------------------------ issues bar -- */

.qb-issues {
  flex: 0 0 auto;
  border-top: 1px solid var(--qp-border-subtle);
  background: var(--qp-surface);
  max-height: 168px;
  overflow-y: auto;
}

.qb-issues__head {
  position: sticky;
  top: 0;
  display: flex;
  align-items: center;
  gap: var(--qp-space-2);
  padding: var(--qp-space-2) var(--qp-space-4);
  background: var(--qp-surface);
  border-bottom: 1px solid var(--qp-border-subtle);
}

.qb-issues__list {
  margin: 0;
  padding: var(--qp-space-1) 0;
  list-style: none;
}

.qb-issue {
  display: flex;
  align-items: flex-start;
  gap: var(--qp-space-2);
  width: 100%;
  padding: var(--qp-space-1) var(--qp-space-4);
  border: 0;
  background: transparent;
  color: var(--qp-text);
  font: inherit;
  font-size: var(--qp-text-xs);
  text-align: start;
  cursor: pointer;
}

.qb-issue:hover {
  background: var(--qp-surface-hover);
}

.qb-issue:focus-visible {
  outline: 2px solid var(--qp-focus-ring);
  outline-offset: -2px;
}

.qb-issue[data-severity='error'] .qb-issue__icon {
  color: var(--qp-fail);
}

.qb-issue[data-severity='warning'] .qb-issue__icon {
  color: var(--qp-warn);
}

/* ------------------------------------------------------------ properties -- */

.qb-props__empty {
  padding: var(--qp-space-8) var(--qp-space-3);
  text-align: center;
  color: var(--qp-text-subtle);
  font-size: var(--qp-text-xs);
}

.qb-props__section {
  padding-top: var(--qp-space-3);
}

.qb-props__section + .qb-props__section {
  margin-top: var(--qp-space-3);
  border-top: 1px solid var(--qp-border-subtle);
}

.qb-props__section-title {
  font-size: var(--qp-text-2xs);
  font-weight: var(--qp-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--qp-tracking-caps);
  color: var(--qp-text-faint);
  margin-bottom: var(--qp-space-2);
}

.qb-props__fields {
  display: flex;
  flex-direction: column;
  gap: var(--qp-space-3);
}

.qb-props__head {
  display: flex;
  align-items: center;
  gap: var(--qp-space-2);
  padding-bottom: var(--qp-space-2);
}

.qb-props__type {
  font-size: var(--qp-text-sm);
  font-weight: var(--qp-weight-semibold);
  color: var(--qp-text-strong);
}

.qb-props__help {
  font-size: var(--qp-text-xs);
  color: var(--qp-text-muted);
  line-height: var(--qp-leading-normal);
}

.qb-row {
  display: flex;
  gap: var(--qp-space-2);
}

.qb-row > * {
  flex: 1 1 0;
  min-width: 0;
}

/* Element picker rows inside the combobox. */
.qb-element-option {
  display: flex;
  align-items: center;
  gap: var(--qp-space-2);
  min-width: 0;
}

.qb-element-option__text {
  min-width: 0;
  flex: 1 1 auto;
}

.qb-element-option__name {
  display: block;
  font-size: var(--qp-text-sm);
  color: var(--qp-text-strong);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.qb-element-option__meta {
  display: block;
  font-family: var(--qp-font-mono);
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.qb-health {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: var(--qp-radius-full);
  background: var(--qp-neutral);
}

.qb-health[data-status='Healthy'] {
  background: var(--qp-pass);
}

.qb-health[data-status='Warning'] {
  background: var(--qp-warn);
}

.qb-health[data-status='Broken'] {
  background: var(--qp-fail);
}

/* ----------------------------------------------- variable autocomplete --- */

.qb-token-field {
  position: relative;
}

.qb-token-menu {
  position: absolute;
  z-index: var(--qp-z-popover);
  inset-inline: 0;
  top: calc(100% + 4px);
  max-height: 232px;
  overflow-y: auto;
  padding: var(--qp-space-1);
  margin: 0;
  list-style: none;
  background: var(--qp-surface-overlay);
  border: 1px solid var(--qp-border);
  border-radius: var(--qp-radius-md);
  box-shadow: var(--qp-shadow-2);
}

.qb-token-menu__item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--qp-space-2);
  width: 100%;
  padding: var(--qp-space-1) var(--qp-space-2);
  border: 0;
  border-radius: var(--qp-radius-xs);
  background: transparent;
  color: var(--qp-text);
  font: inherit;
  font-size: var(--qp-text-xs);
  text-align: start;
  cursor: pointer;
}

.qb-token-menu__item[data-active='true'],
.qb-token-menu__item:hover {
  background: var(--qp-surface-hover);
}

.qb-token-menu__name {
  font-family: var(--qp-font-mono);
  color: var(--qp-accent-text);
}

.qb-token-menu__kind {
  color: var(--qp-text-faint);
  font-size: var(--qp-text-2xs);
  white-space: nowrap;
}

.qb-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: var(--qp-space-1);
}

.qb-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 6px;
  border-radius: var(--qp-radius-full);
  background: var(--qp-accent-subtle);
  color: var(--qp-accent-text);
  font-family: var(--qp-font-mono);
  font-size: var(--qp-text-2xs);
}

/* --------------------------------------------------------- cheat sheet --- */

.qb-shortcuts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--qp-space-4) var(--qp-space-6);
}

.qb-shortcuts__group-title {
  font-size: var(--qp-text-2xs);
  font-weight: var(--qp-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--qp-tracking-caps);
  color: var(--qp-text-faint);
  margin-bottom: var(--qp-space-2);
}

.qb-shortcuts__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--qp-space-3);
  padding: var(--qp-space-1) 0;
  font-size: var(--qp-text-xs);
}

.qb-shortcuts__keys {
  display: flex;
  gap: 3px;
  flex: 0 0 auto;
}

/* --------------------------------------------------------- storyboard ---- */

.qb-story {
  display: flex;
  flex-direction: column;
}

.qb-story__step {
  position: relative;
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  gap: var(--qp-space-3);
  padding-bottom: var(--qp-space-4);
}

/* The connector between consecutive steps. */
.qb-story__step:not(:last-child)::before {
  content: '';
  position: absolute;
  top: 32px;
  bottom: 0;
  left: 15px;
  width: 2px;
  background: var(--qp-border);
}

.qb-story__marker {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: var(--qp-radius-full);
  background: var(--qp-surface);
  border: 1px solid var(--qp-border);
  font-family: var(--qp-font-mono);
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-muted);
  font-variant-numeric: tabular-nums;
}

.qb-story__step[data-assert='true'] .qb-story__marker {
  background: var(--qp-pass-bg);
  border-color: var(--qp-pass-border);
  color: var(--qp-pass);
}

.qb-story__body {
  min-width: 0;
  padding-top: var(--qp-space-1);
}

.qb-story__title {
  font-size: var(--qp-text-md);
  color: var(--qp-text-strong);
  line-height: var(--qp-leading-snug);
  overflow-wrap: anywhere;
}

.qb-story__step[data-assert='true'] .qb-story__title {
  font-weight: var(--qp-weight-medium);
}

.qb-story__eyebrow {
  font-size: var(--qp-text-3xs);
  font-weight: var(--qp-weight-semibold);
  letter-spacing: var(--qp-tracking-caps);
  text-transform: uppercase;
  color: var(--qp-pass);
  margin-bottom: 2px;
}

.qb-story__note {
  margin-top: var(--qp-space-1);
  font-size: var(--qp-text-sm);
  color: var(--qp-text-muted);
}

.qb-story__children {
  margin-top: var(--qp-space-3);
  padding-left: var(--qp-space-4);
  border-left: 2px solid var(--qp-border-subtle);
}

.qb-story__shot {
  margin-top: var(--qp-space-2);
  border-radius: var(--qp-radius-md);
  overflow: hidden;
  border: 1px solid var(--qp-border-subtle);
}

.qb-story__shot img {
  display: block;
  width: 100%;
  height: auto;
}

.qb-story__disabled {
  opacity: 0.5;
}

/* --------------------------------------------------- field editors (v2) -- */

.qb-kv {
  display: flex;
  flex-direction: column;
  gap: var(--qp-space-2);
}

.qb-kv__empty {
  font-size: var(--qp-text-xs);
  color: var(--qp-text-faint);
}

.qb-kv__row {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr) auto;
  gap: var(--qp-space-2);
  align-items: start;
}

.qb-kv__cell {
  min-width: 0;
}

.qb-kv__warning {
  display: flex;
  align-items: flex-start;
  gap: 4px;
  margin: calc(var(--qp-space-1) * -1) 0 0;
  font-size: var(--qp-text-2xs);
  color: var(--qp-warn);
}

.qb-secret-field {
  display: flex;
  flex-direction: column;
  gap: var(--qp-space-1);
}

.qb-secret-field .qb-row {
  align-items: center;
}

.qb-secret-field .qb-row > :last-child {
  flex: 0 0 auto;
}

.qb-secret-field__error {
  display: flex;
  align-items: flex-start;
  gap: 4px;
  margin: 0;
  font-size: var(--qp-text-2xs);
  color: var(--qp-fail);
  line-height: var(--qp-leading-normal);
}

.qb-secret-field__error code {
  font-family: var(--qp-font-mono);
  background: var(--qp-fail-bg);
  border-radius: var(--qp-radius-xs);
  padding: 0 3px;
}

.qb-secret-picker {
  display: flex;
  flex-direction: column;
  min-width: 240px;
  max-width: 320px;
  padding: var(--qp-space-2);
  gap: var(--qp-space-2);
}

.qb-secret-picker__list {
  margin: 0;
  padding: 0;
  list-style: none;
  max-height: 220px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.qb-secret-picker__item {
  display: flex;
  align-items: center;
  gap: var(--qp-space-2);
  width: 100%;
  padding: var(--qp-space-1) var(--qp-space-2);
  border: 0;
  border-radius: var(--qp-radius-xs);
  background: transparent;
  color: var(--qp-text);
  font: inherit;
  font-size: var(--qp-text-xs);
  text-align: start;
  cursor: pointer;
}

.qb-secret-picker__item:hover,
.qb-secret-picker__item:focus-visible {
  background: var(--qp-surface-hover);
  outline: none;
}

.qb-secret-picker__footer {
  display: flex;
  flex-direction: column;
  gap: var(--qp-space-1);
  padding-top: var(--qp-space-2);
  border-top: 1px solid var(--qp-border-subtle);
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-muted);
}

.qb-status-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--qp-space-2);
}

.qb-status-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 4px 2px 8px;
  border-radius: var(--qp-radius-full);
  background: var(--qp-accent-subtle);
  color: var(--qp-accent-text);
  font-family: var(--qp-font-mono);
  font-size: var(--qp-text-xs);
}

.qb-status-chip button {
  display: grid;
  place-items: center;
  width: 16px;
  height: 16px;
  border: 0;
  border-radius: var(--qp-radius-full);
  background: transparent;
  color: inherit;
  cursor: pointer;
}

.qb-status-chip button:hover {
  background: var(--qp-accent-border);
}

.qb-status-list__add {
  width: 84px;
}

.qb-json-editor {
  display: flex;
  flex-direction: column;
  gap: var(--qp-space-1);
}

.qb-json-editor__toolbar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--qp-space-2);
}

.qb-json-editor__textarea {
  min-height: 140px;
  font-size: var(--qp-text-xs);
  resize: vertical;
}

.qb-json-editor__textarea[data-invalid='true'] {
  border-color: var(--qp-fail-border);
}

.qb-json-editor__error {
  display: flex;
  align-items: flex-start;
  gap: 4px;
  margin: 0;
  font-size: var(--qp-text-2xs);
  color: var(--qp-fail);
  font-family: var(--qp-font-mono);
}

.qb-capture-list,
.qb-mailbox,
.qb-auth-config {
  display: flex;
  flex-direction: column;
  gap: var(--qp-space-3);
}

.qb-capture-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 128px minmax(0, 1fr) auto;
  gap: var(--qp-space-2);
  align-items: start;
}

.qb-capture-list__hint {
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-faint);
  font-family: var(--qp-font-mono);
  line-height: var(--qp-leading-normal);
}

.qb-regex-field {
  display: flex;
  flex-direction: column;
  gap: var(--qp-space-2);
}

.qb-regex-tester {
  padding: var(--qp-space-3);
  border: 1px solid var(--qp-border-subtle);
  border-radius: var(--qp-radius-md);
  background: var(--qp-surface-sunken);
  display: flex;
  flex-direction: column;
  gap: var(--qp-space-2);
}

.qb-regex-tester__toggle {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border: 0;
  background: transparent;
  color: var(--qp-accent-text);
  font: inherit;
  font-size: var(--qp-text-xs);
  cursor: pointer;
  padding: 0;
}

.qb-regex-tester__result {
  padding: var(--qp-space-2);
  border-radius: var(--qp-radius-sm);
  background: var(--qp-surface);
  border: 1px solid var(--qp-border-subtle);
  font-family: var(--qp-font-mono);
  font-size: var(--qp-text-xs);
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

.qb-regex-tester__result mark {
  background: var(--qp-accent-subtle);
  color: var(--qp-accent-text);
  border-radius: 2px;
  padding: 0 1px;
}

.qb-regex-tester__result mark.qb-regex-tester__group {
  background: var(--qp-pass-bg);
  color: var(--qp-pass);
  font-weight: var(--qp-weight-semibold);
}

.qb-regex-tester__status {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-muted);
}

.qb-attachment-picker {
  display: flex;
  flex-direction: column;
  gap: var(--qp-space-2);
}

.qb-attachment-picker__current {
  display: flex;
  align-items: center;
  gap: var(--qp-space-2);
  padding: var(--qp-space-2);
  border: 1px solid var(--qp-border-subtle);
  border-radius: var(--qp-radius-sm);
  background: var(--qp-surface-sunken);
  font-size: var(--qp-text-sm);
}

.qb-attachment-picker__meta {
  color: var(--qp-text-faint);
  font-size: var(--qp-text-2xs);
  font-family: var(--qp-font-mono);
}

.qb-attachment-picker__list {
  margin: 0;
  padding: 0;
  list-style: none;
  max-height: 260px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.qb-attachment-picker__item {
  display: flex;
  align-items: center;
  gap: var(--qp-space-2);
  width: 100%;
  padding: var(--qp-space-2);
  border: 0;
  border-radius: var(--qp-radius-xs);
  background: transparent;
  color: var(--qp-text);
  font: inherit;
  text-align: start;
  cursor: pointer;
}

.qb-attachment-picker__item:hover,
.qb-attachment-picker__item:focus-visible {
  background: var(--qp-surface-hover);
  outline: none;
}

/* ------------------------------------------------------------- flow view --
   A real diagram, not the step list redrawn: a dot-grid canvas, a centred
   ~560px spine of Start pill → cards+connectors → End pill, then the
   teardown lane under its own header and terminal. One rule threads through
   every measurement below: nothing here is computed in script. Connector
   height is a fixed token, the loop-back arc stretches through its SVG
   viewBox, and card width is a CSS max-width — so there is nothing for a
   ResizeObserver to measure per card, which is what keeps a 120-step test
   scrolling smoothly (STEP-ENGINE-V2 flow §10). ---------------------------- */

.qb-flow {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
}

/* Floats over the canvas rather than taking its own row, and stays put while the canvas scrolls
   underneath it — "the toolbar" reads as a tool belonging to the whole view, not to whatever has
   scrolled past. */
.qb-flow__toolbar {
  position: absolute;
  z-index: 2;
  top: var(--qp-space-3);
  right: var(--qp-space-3);
  display: flex;
  align-items: center;
  gap: var(--qp-space-1);
  padding: var(--qp-space-2);
  border: 1px solid var(--qp-border-subtle);
  border-radius: var(--qp-radius-md);
  background: var(--qp-surface-overlay);
  box-shadow: var(--qp-shadow-1);
}

.qb-flow__zoom-label {
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-faint);
  text-transform: uppercase;
  letter-spacing: var(--qp-tracking-caps);
  margin-inline-end: var(--qp-space-1);
}

.qb-flow__zoom-value {
  min-width: 44px;
  padding: 0 4px;
  border: 0;
  background: transparent;
  color: var(--qp-text-muted);
  font-family: var(--qp-font-mono);
  font-size: var(--qp-text-xs);
  font-variant-numeric: tabular-nums;
  text-align: center;
  cursor: pointer;
  border-radius: var(--qp-radius-xs);
}

.qb-flow__zoom-value:hover {
  background: var(--qp-surface-hover);
  color: var(--qp-text);
}

.qb-flow__scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
}

/* The dot grid: a low-contrast lattice via color-mix, so it reads in both themes without a second,
   dark-mode-only declaration. It travels with the canvas (not the viewport), so it stays a stable
   backdrop for the diagram rather than a texture sliding underneath it. */
.qb-flow__canvas {
  --qb-flow-dot: color-mix(in oklab, var(--qp-border) 60%, transparent);
  min-height: 100%;
  padding: var(--qp-space-10) var(--qp-space-6) var(--qp-space-16);
  background-image: radial-gradient(var(--qb-flow-dot) 1px, transparent 1px);
  background-size: 22px 22px;
  transition: transform var(--qp-duration-base) var(--qp-ease);
}

/* ── Start / End / teardown terminals — small pill markers on the centre spine ──────────────── */

.qb-flow__terminal {
  display: flex;
  justify-content: center;
  margin-inline: auto;
  max-width: var(--qb-flow-col, 520px);
}

.qb-flow__terminal span {
  display: inline-flex;
  align-items: center;
  padding: 3px var(--qp-space-3);
  border: 1px solid var(--qp-border-strong);
  border-radius: var(--qp-radius-full);
  background: var(--qp-surface-raised);
  color: var(--qp-text-subtle);
  font-size: var(--qp-text-2xs);
  font-weight: var(--qp-weight-semibold);
  letter-spacing: var(--qp-tracking-caps);
  text-transform: uppercase;
  box-shadow: var(--qp-shadow-1);
}

.qb-flow__terminal--start span {
  border-color: var(--qp-accent-border);
  color: var(--qp-accent-text);
}

.qb-flow__terminal--end {
  margin-top: calc(var(--qp-space-6) * -1);
  margin-bottom: var(--qp-space-2);
}

.qb-flow__terminal--end span {
  position: relative;
  z-index: 1;
}

/* A tiny icon terminal rather than a text pill — the teardown lane already names itself in its own
   header right above; the terminal here only has to mark "the spine starts again here". */
.qb-flow__terminal--teardown {
  margin-bottom: var(--qp-space-2);
}

.qb-flow__terminal--teardown span,
.qb-flow__terminal--teardown {
  display: grid;
}

.qb-flow-lane--teardown .qb-flow__terminal--teardown {
  width: 26px;
  height: 26px;
  margin-inline: auto;
  place-items: center;
  border-radius: var(--qp-radius-full);
  background: var(--qp-neutral-bg);
  color: var(--qp-neutral);
  border: 1px solid var(--qp-border-strong);
}

/* ── Lanes — "Setup" / "Steps" (headers drawn inline by FlowList) and "Always runs afterwards" ── */

.qb-flow-lane {
  position: relative;
}

.qb-flow-lane--teardown {
  margin-top: var(--qp-space-8);
  padding-top: var(--qp-space-6);
  border-top: 1px dashed var(--qp-border);
}

.qb-flow-lane--teardown::before {
  /* A calm, distinct tint behind the whole teardown lane, per the visual spec — a wash, not a box,
     so it reads as "a different part of the same canvas" rather than a separate panel. */
  content: '';
  position: absolute;
  inset: calc(var(--qp-space-6) * -1) calc(var(--qp-space-4) * -1) calc(var(--qp-space-6) * -1);
  background: color-mix(in oklab, var(--qp-neutral-bg) 55%, transparent);
  border-radius: var(--qp-radius-lg);
  z-index: -1;
}

.qb-teardown__head {
  display: flex;
  align-items: flex-start;
  gap: var(--qp-space-2);
  max-width: var(--qb-flow-col, 520px);
  margin: 0 auto var(--qp-space-3);
}

.qb-teardown__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  margin-top: 1px;
  border-radius: var(--qp-radius-xs);
  background: var(--qp-neutral-bg);
  color: var(--qp-neutral);
}

.qb-teardown__title-group {
  min-width: 0;
  flex: 1 1 auto;
}

.qb-teardown__title {
  margin: 0;
  font-size: var(--qp-text-sm);
  font-weight: var(--qp-weight-semibold);
  color: var(--qp-text-strong);
}

.qb-teardown__hint {
  margin: 2px 0 0;
  font-size: var(--qp-text-xs);
  color: var(--qp-text-muted);
  line-height: var(--qp-leading-normal);
}

.qb-teardown__count {
  flex: 0 0 auto;
  align-self: center;
  font-size: var(--qp-text-2xs);
  font-family: var(--qp-font-mono);
  color: var(--qp-text-faint);
}

/* "Setup" / "Steps" section headers — plain non-draggable <li>s FlowList interleaves between cards
   (see its doc comment for why that is safe for SortableJS's index counting). */
.qb-flow-lanehead {
  display: flex;
  align-items: baseline;
  gap: var(--qp-space-2);
  max-width: var(--qb-flow-col, 520px);
  margin: var(--qp-space-5) auto var(--qp-space-1);
  padding-inline-start: calc(var(--qb-flow-gutter, 28px) + var(--qp-space-2));
}

.qb-flow-lanehead:first-child {
  margin-top: 0;
}

.qb-flow-lanehead__title {
  font-size: var(--qp-text-2xs);
  font-weight: var(--qp-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--qp-tracking-caps);
  color: var(--qp-text-subtle);
}

.qb-flow-lanehead__hint {
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-faint);
}

/* ── The spine: one flex column of <li> nodes and connectors ─────────────────────────────────── */

.qb-flow-list {
  --qb-flow-col: 520px;
  --qb-flow-gutter: 28px;
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
  min-height: var(--qp-space-4);
}

.qb-flow-list--empty {
  min-height: 0;
}

/* A node and a connector share this exact column template, so the card's own horizontal centre and
   the line/button riding the connector above and below it always land on the same vertical axis,
   regardless of how wide the pane is — .qb-flow-node's number sits in the gutter column, the card in
   the main one; the connector's spine (see FlowConnector) sits in the main column too. */
.qb-flow-node {
  position: relative;
  display: grid;
  grid-template-columns: var(--qb-flow-gutter) minmax(0, var(--qb-flow-col));
  justify-content: center;
  column-gap: var(--qp-space-2);
  list-style: none;
}

.qb-flow-node__number {
  grid-column: 1;
  align-self: start;
  margin-top: var(--qp-space-3);
  text-align: right;
  font-family: var(--qp-font-mono);
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-faint);
  font-variant-numeric: tabular-nums;
}

/* ── The card ──────────────────────────────────────────────────────────────────────────────── */

.qb-flow-card {
  container-type: inline-size;
  grid-column: 2;
  position: relative;
  width: 100%;
  min-width: 320px;
  padding: var(--qp-space-3);
  border: 1px solid var(--qp-border-subtle);
  border-radius: var(--qp-radius-lg);
  background: var(--qp-surface-raised);
  box-shadow: var(--qp-shadow-1);
  cursor: pointer;
  transition:
    border-color var(--qp-duration-fast) var(--qp-ease),
    box-shadow var(--qp-duration-fast) var(--qp-ease),
    background var(--qp-duration-fast) var(--qp-ease),
    transform var(--qp-duration-fast) var(--qp-ease);
}

.qb-flow-card::before {
  content: '';
  position: absolute;
  inset-block: -1px;
  inset-inline-start: -1px;
  width: 3px;
  border-start-start-radius: var(--qp-radius-lg);
  border-end-start-radius: var(--qp-radius-lg);
  background: var(--qb-accent, var(--qp-border));
}

.qb-flow-card:hover {
  border-color: var(--qp-border);
  box-shadow: var(--qp-shadow-2);
}

.qb-flow-node[data-selected='true'] .qb-flow-card {
  border-color: var(--qp-accent-border);
  background: var(--qp-surface-selected);
  box-shadow: 0 0 0 1px var(--qp-accent-border), var(--qp-shadow-2);
  transform: translateY(-1px);
}

.qb-flow-card:focus-visible {
  outline: 2px solid var(--qp-focus-ring);
  outline-offset: 2px;
}

.qb-flow-node[data-disabled='true'] .qb-flow-card {
  opacity: 0.55;
}

.qb-flow-node[data-disabled='true'] .qb-flow-card__title {
  text-decoration: line-through;
  text-decoration-color: var(--qp-text-faint);
}

.qb-flow-node[data-has-error='true'] .qb-flow-card {
  border-color: var(--qp-fail-border);
}

.qb-flow-card__head {
  display: flex;
  align-items: flex-start;
  gap: var(--qp-space-2);
}

.qb-flow-card__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  border-radius: var(--qp-radius-sm);
  background: var(--qb-tint, var(--qp-surface-sunken));
  color: var(--qb-accent, var(--qp-text-muted));
}

.qb-flow-card__title-group {
  flex: 1 1 auto;
  min-width: 0;
}

.qb-flow-card__title {
  font-size: var(--qp-text-sm);
  color: var(--qp-text-strong);
  line-height: var(--qp-leading-snug);
  /* Two lines max, then an ellipsis — the full sentence is always in the title attribute/tooltip. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: break-word;
}

/* Drag handle and kebab menu appear on hover/focus/selection, exactly like the list view's own
   .qb-card__actions — visible chrome only when it is about to be used. */
.qb-flow-card__actions {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: 0 0 auto;
  opacity: 0;
  transition: opacity var(--qp-duration-fast) var(--qp-ease);
}

.qb-flow-card:hover .qb-flow-card__actions,
.qb-flow-card:focus-within .qb-flow-card__actions,
.qb-flow-node[data-selected='true'] .qb-flow-card__actions {
  opacity: 1;
}

.qb-flow-card__badges {
  display: flex;
  align-items: center;
  gap: var(--qp-space-1);
  flex: 0 0 auto;
}

.qb-flow-badge {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 1px 6px;
  border-radius: var(--qp-radius-full);
  font-size: var(--qp-text-3xs);
  font-weight: var(--qp-weight-medium);
  white-space: nowrap;
}

.qb-flow-badge[data-tone='warning'] {
  background: var(--qp-warn-bg);
  color: var(--qp-warn);
}

.qb-flow-badge[data-tone='neutral'] {
  background: var(--qp-neutral-bg);
  color: var(--qp-neutral);
}

.qb-flow-dot {
  width: 7px;
  height: 7px;
  border-radius: var(--qp-radius-full);
  flex: 0 0 auto;
}

.qb-flow-dot[data-severity='error'] {
  background: var(--qp-fail);
}

.qb-flow-dot[data-severity='warning'] {
  background: var(--qp-warn);
}

.qb-flow-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: var(--qp-space-2);
  margin-inline-start: 34px;
}

.qb-flow-chip {
  display: inline-flex;
  align-items: center;
  padding: 1px 7px;
  border-radius: var(--qp-radius-full);
  background: var(--qp-surface-sunken);
  color: var(--qp-text-muted);
  font-size: var(--qp-text-2xs);
  font-family: var(--qp-font-mono);
}

.qb-flow-card__note {
  margin: var(--qp-space-2) 0 0 34px;
  font-size: var(--qp-text-xs);
  color: var(--qp-text-muted);
}

.qb-flow-card__issue {
  display: flex;
  align-items: flex-start;
  gap: var(--qp-space-1);
  margin: var(--qp-space-2) 0 0 34px;
  font-size: var(--qp-text-xs);
  line-height: var(--qp-leading-snug);
}

.qb-flow-card__issue[data-severity='error'] {
  color: var(--qp-fail);
}

.qb-flow-card__issue[data-severity='warning'] {
  color: var(--qp-warn);
}

.qb-flow-toggle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin: var(--qp-space-2) 0 0 34px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--qp-text-subtle);
  font: inherit;
  font-size: var(--qp-text-2xs);
  cursor: pointer;
}

.qb-flow-toggle:hover {
  color: var(--qp-text);
}

/* A structural step's own body — its children render INSIDE this box, not as a sibling lane, so a
   condition/loop/group reads as a container the way it behaves at run time (design system §4d). */
.qb-flow-container {
  position: relative;
  margin: var(--qp-space-3) 0 0;
  padding: var(--qp-space-3) var(--qp-space-3) var(--qp-space-2);
  border: 1px solid var(--qp-border-subtle);
  border-radius: var(--qp-radius-md);
  background: var(--qp-surface-sunken);
}

.qb-flow-container .qb-flow-list {
  --qb-flow-col: 100%;
  --qb-flow-gutter: 22px;
}

.qb-flow-container--readonly {
  font-size: var(--qp-text-xs);
  color: var(--qp-text-muted);
}

.qb-flow-container--readonly ol {
  margin: 0 0 var(--qp-space-2);
  padding-inline-start: var(--qp-space-4);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.qb-flow-empty {
  margin: 0;
  padding: var(--qp-space-2) var(--qp-space-3);
  border: 1px dashed var(--qp-border);
  border-radius: var(--qp-radius-sm);
  color: var(--qp-text-faint);
  font-size: var(--qp-text-2xs);
  text-align: center;
}

/* The 320px floor is for a card standing in the main column. A card inside another card (a branch's
   "Yes" column, a loop body, an expanded action) takes the width its container has left, or it pokes
   out of the right edge of that container at 1024px. */
.qb-flow-card .qb-flow-card {
  min-width: 0;
}

/* Condition: "Yes" is the main column — the only branch the model can actually hold steps in — with a
   slim bypass rail beside it for "No", not a second half-width box competing for the same room. Yes
   gets ~75% (a floor of 260px so its own cards can keep their 320px minimum a little further before
   this branch has to stack), the rail a floor of 140px. @container (declared on .qb-flow-card, the
   nearest ancestor with layout of its own) stacks them once nested width is genuinely too tight — a
   viewport media query would miss a branch nested two levels deep in a wide window. */
.qb-flow-branch {
  display: grid;
  grid-template-columns: minmax(320px, 3fr) minmax(140px, 1fr);
  gap: var(--qp-space-3);
  margin-top: var(--qp-space-2);
  align-items: stretch;
}

@container (max-width: 480px) {
  .qb-flow-branch {
    grid-template-columns: 1fr;
  }

  .qb-flow-branch__bypass {
    flex-direction: row;
    align-items: center;
    gap: var(--qp-space-2);
  }

  .qb-flow-branch__bypass-line {
    width: 28px;
    height: 20px;
    flex: 0 0 auto;
    transform: rotate(-90deg);
  }
}

.qb-flow-branch__main {
  min-width: 0;
  border-radius: var(--qp-radius-md);
  padding: var(--qp-space-2);
  background: color-mix(in oklab, var(--qp-pass-bg) 70%, transparent);
  border: 1px dashed var(--qp-pass-border);
}

.qb-flow-branch__main .qb-flow-list {
  --qb-flow-col: 100%;
  --qb-flow-gutter: 20px;
}

.qb-flow-branch__label {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-bottom: var(--qp-space-2);
  font-size: var(--qp-text-2xs);
  font-weight: var(--qp-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--qp-tracking-caps);
  color: var(--qp-pass);
}

/* The bypass rail: a short curved connector (skip past the branch entirely) plus a one-line caption —
   informational, not a drop target, because the step model has no else-branch to drop a step into. */
.qb-flow-branch__bypass {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--qp-space-1);
  min-width: 140px;
  padding: var(--qp-space-3) var(--qp-space-2);
  border-radius: var(--qp-radius-md);
  background: var(--qp-surface-sunken);
  border: 1px dashed var(--qp-border);
  text-align: center;
}

.qb-flow-branch__bypass-line {
  width: 24px;
  height: 40px;
  stroke: var(--qp-border-strong);
  stroke-width: 1.5;
  stroke-linecap: round;
  fill: none;
}

.qb-flow-branch__bypass-label {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: var(--qp-text-2xs);
  font-weight: var(--qp-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--qp-tracking-caps);
  color: var(--qp-text-subtle);
}

.qb-flow-branch__bypass-caption {
  margin: 0;
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-faint);
  font-style: italic;
  line-height: var(--qp-leading-snug);
}

/* Loop: the body sits on the same centred spine as everything else, with a curved SVG arc riding the
   left edge from the bottom back up to the top — its viewBox stretches to fill the container's actual
   height via CSS alone (height: 100%, preserveAspectRatio="none"), so there is nothing to measure. */
.qb-flow-loop__label {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: var(--qp-radius-full);
  background: var(--qp-neutral-bg);
  color: var(--qp-neutral);
  font-size: var(--qp-text-2xs);
  font-weight: var(--qp-weight-medium);
  margin-bottom: var(--qp-space-1);
}

/* The arc occupies x: 8px–30px (left: var(--qp-space-2) + its own 22px width) — this padding has to
   clear that plus a little breathing room, or the loop-back line runs straight through the first
   child's leading connector "+". */
.qb-flow-container--loop {
  padding-left: var(--qp-space-10);
}

.qb-flow-loop__arc {
  position: absolute;
  left: var(--qp-space-2);
  top: var(--qp-space-2);
  bottom: var(--qp-space-2);
  width: 22px;
  height: calc(100% - var(--qp-space-4));
  fill: none;
  stroke: var(--qb-accent, var(--qp-neutral));
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

.qb-flow-loop__arc polygon {
  fill: var(--qb-accent, var(--qp-neutral));
  stroke: none;
}

/* ── Connectors — the spine's "+" affordances ──────────────────────────────────────────────── */

.qb-flow-connector {
  position: relative;
  display: grid;
  grid-template-columns: var(--qb-flow-gutter) minmax(0, var(--qb-flow-col));
  justify-content: center;
  height: var(--qp-space-8);
}

.qb-flow-connector__spine {
  grid-column: 2;
  position: relative;
  display: flex;
  justify-content: center;
  height: 100%;
}

.qb-flow-connector__line {
  width: 12px;
  height: 100%;
  stroke: var(--qp-border-strong);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: var(--qp-border-strong);
  transition: stroke var(--qp-duration-fast) var(--qp-ease), fill var(--qp-duration-fast) var(--qp-ease);
}

.qb-flow-connector__add {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 20px;
  padding: 0 4px;
  border: 1px solid var(--qp-border-strong);
  border-radius: var(--qp-radius-full);
  background: var(--qp-surface);
  color: var(--qp-text-muted);
  cursor: pointer;
  transition:
    background var(--qp-duration-fast) var(--qp-ease),
    color var(--qp-duration-fast) var(--qp-ease),
    border-color var(--qp-duration-fast) var(--qp-ease),
    width var(--qp-duration-fast) var(--qp-ease);
}

.qb-flow-connector__pill-text {
  max-width: 0;
  overflow: hidden;
  white-space: nowrap;
  font-size: var(--qp-text-2xs);
  font-weight: var(--qp-weight-medium);
  transition: max-width var(--qp-duration-fast) var(--qp-ease);
}

/* At rest the button is a plain 20px dot; hovering, focusing or dragging over it (or anywhere in the
   flow while a drag is in progress, via body.qb-dragging) grows it into an "Insert here" pill, per the
   visual spec's drag affordance. Opacity, never display, hides it at rest — a keyboard user tabbing
   through the flow still lands on every connector in the flow in turn. */
.qb-flow-node:hover .qb-flow-connector__add,
.qb-flow-connector__add:focus-visible,
body.qb-dragging .qb-flow-connector__add {
  width: auto;
  padding-inline: var(--qp-space-2);
}

.qb-flow-node:hover .qb-flow-connector__add .qb-flow-connector__pill-text,
.qb-flow-connector__add:focus-visible .qb-flow-connector__pill-text,
body.qb-dragging .qb-flow-connector__add .qb-flow-connector__pill-text {
  max-width: 80px;
}

.qb-flow-connector__add:hover,
.qb-flow-connector__add:focus-visible,
.qb-flow-connector[data-active='true'] .qb-flow-connector__add {
  background: var(--qp-accent);
  color: var(--qp-text-on-accent);
  border-color: var(--qp-accent);
  width: auto;
  padding-inline: var(--qp-space-2);
}

.qb-flow-connector__add:hover .qb-flow-connector__pill-text,
.qb-flow-connector__add:focus-visible .qb-flow-connector__pill-text,
.qb-flow-connector[data-active='true'] .qb-flow-connector__pill-text {
  max-width: 80px;
}

.qb-flow-connector__add:focus-visible {
  outline: 2px solid var(--qp-focus-ring);
  outline-offset: 2px;
}

/* --qp-border-strong reads fine as a hairline against a surface panel, but the flow canvas is a dot-grid
   in the same dark, near-black family as every surface token (design intentionally keeps the whole
   canvas quiet) — measured against --qp-canvas, --qp-border-strong is only ~1.7:1. --qp-text-muted (the
   same colour the "+" glyph already uses) measures ~10:1, so at rest and while every target is grown
   during a drag, the pill's own outline is what a keyboard or low-vision user can actually see it by. */
[data-theme='dark'] .qb-flow-connector__add {
  border-color: var(--qp-text-muted);
}

.qb-flow-connector[data-active='true'] .qb-flow-connector__line {
  stroke: var(--qp-accent);
  fill: var(--qp-accent);
}

/* ── Empty drop zones (FlowEmptyDrop) ──────────────────────────────────────────────────────── */

.qb-flow-empty-drop {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--qp-space-2);
  min-height: 64px;
  padding: var(--qp-space-3);
  border: 1px dashed var(--qp-border);
  border-radius: var(--qp-radius-md);
  color: var(--qp-text-faint);
  font-size: var(--qp-text-xs);
  list-style: none;
  transition: background var(--qp-duration-fast) var(--qp-ease), border-color var(--qp-duration-fast) var(--qp-ease);
}

.qb-flow-empty-drop[data-active='true'] {
  border-color: var(--qp-accent);
  border-style: solid;
  background: var(--qp-accent-subtle);
  color: var(--qp-accent-text);
}

.qb-flow-empty-drop__add {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px var(--qp-space-3);
  border: 1px solid var(--qp-border-strong);
  border-radius: var(--qp-radius-full);
  background: var(--qp-surface);
  color: var(--qp-text);
  font: inherit;
  font-size: var(--qp-text-xs);
  font-weight: var(--qp-weight-medium);
  cursor: pointer;
  transition: background var(--qp-duration-fast) var(--qp-ease), border-color var(--qp-duration-fast) var(--qp-ease);
}

.qb-flow-empty-drop__add:hover {
  background: var(--qp-surface-hover);
  border-color: var(--qp-accent-border);
}

.qb-flow-empty-drop__add:focus-visible {
  outline: 2px solid var(--qp-focus-ring);
  outline-offset: 2px;
}

.qb-flow-empty-drop__hint {
  font-size: var(--qp-text-2xs);
  color: var(--qp-text-faint);
}

@media (max-width: 1024px) {
  .qb-flow__canvas {
    padding-inline: var(--qp-space-4);
  }

  .qb-flow-list {
    --qb-flow-col: min(520px, 100%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .qb-flow-card,
  .qb-flow-connector__add,
  .qb-flow-connector__pill-text,
  .qb-flow-connector__line,
  .qb-flow-empty-drop,
  .qb-flow__canvas {
    transition: none;
  }
}

/* ----------------------------------------------------- category accents -- */

[data-category='nav'] {
  --qb-accent: var(--qp-info);
  --qb-tint: var(--qp-info-bg);
}

[data-category='mouse'] {
  --qb-accent: var(--qp-accent);
  --qb-tint: var(--qp-accent-subtle);
}

[data-category='input'] {
  --qb-accent: var(--qp-accent);
  --qb-tint: var(--qp-accent-subtle);
}

[data-category='wait'] {
  --qb-accent: var(--qp-warn);
  --qb-tint: var(--qp-warn-bg);
}

[data-category='data'] {
  --qb-accent: var(--qp-info);
  --qb-tint: var(--qp-info-bg);
}

[data-category='assert'] {
  --qb-accent: var(--qp-pass);
  --qb-tint: var(--qp-pass-bg);
}

[data-category='reusable'] {
  --qb-accent: var(--qp-accent);
  --qb-tint: var(--qp-accent-subtle);
}

[data-category='structure'] {
  --qb-accent: var(--qp-neutral);
  --qb-tint: var(--qp-neutral-bg);
}

/* STEP-ENGINE-V2 §1.1 / §1.2 — previously fell back to the "data" accent's colour. */
[data-category='api'] {
  --qb-accent: var(--qp-accent);
  --qb-tint: var(--qp-accent-subtle);
}

[data-category='email'] {
  --qb-accent: var(--qp-warn);
  --qb-tint: var(--qp-warn-bg);
}

/* --------------------------------------------------------------- teardown -- */

.qb-teardown {
  margin-top: var(--qp-space-6);
  padding-top: var(--qp-space-5);
  border-top: 1px dashed var(--qp-border);
}

.qb-teardown__head {
  display: flex;
  align-items: flex-start;
  gap: var(--qp-space-2);
  margin-bottom: var(--qp-space-3);
}

.qb-teardown__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  margin-top: 1px;
  border-radius: var(--qp-radius-xs);
  background: var(--qp-neutral-bg);
  color: var(--qp-neutral);
}

.qb-teardown__title-group {
  min-width: 0;
}

.qb-teardown__title {
  margin: 0;
  font-size: var(--qp-text-sm);
  font-weight: var(--qp-weight-semibold);
  color: var(--qp-text-strong);
}

.qb-teardown__hint {
  margin: 2px 0 0;
  font-size: var(--qp-text-xs);
  color: var(--qp-text-muted);
  line-height: var(--qp-leading-normal);
  max-width: 56ch;
}

.qb-teardown__empty {
  display: flex;
  align-items: center;
  gap: var(--qp-space-3);
  min-height: 52px;
  padding: var(--qp-space-3);
  border: 1px dashed var(--qp-border);
  border-radius: var(--qp-radius-md);
  color: var(--qp-text-faint);
  font-size: var(--qp-text-xs);
}

/* ------------------------------------------------------------ responsive -- */

/* Below ~1100px the properties panel becomes an overlay so the canvas keeps
   a usable width. The palette collapses to icons via [data-palette]. */
@media (max-width: 1180px) {
  .qb {
    --qb-palette-width: 216px;
    --qb-props-width: 300px;
  }

  .qb-canvas__scroll
  {
    padding-inline: var(--qp-space-4);
  }
}

@media (prefers-reduced-motion: reduce) {
  .qb-card,
  .qb-palette__item,
  .qb__rail,
  .qb-card__actions {
    transition: none;
  }

  .qb-card--dragging {
    transform: none;
  }
}
