/* app/set-pipeline.css — page-local styles for Stages + Labels.
   Prefix every selector `.e8-set-pipeline-`. Shared grammar lives in app/set-core.css and must not
   be duplicated here; if a page needs a new shared primitive, that is a core change, not a
   local override. Tokens only — no hex, no raw font sizes.

   WHAT IS HERE AND WHY IT IS ONLY THIS

   A stage row is a `.e8-set-row` — core's padding, ink, dividers and narrow behaviour, untouched —
   with three ornaments bolted on the ends: a grip, a status dot and a kebab. Nothing here re-states
   a padding, a font size or a divider, so a stage row is dimensionally a row on Billing and stays
   that way when the core rhythm changes.

   THE GRIP IS THE POINT OF THE PAGE, AND TWO DECLARATIONS MAKE IT WORK
     `touch-action: none`  — without it the browser claims the vertical gesture for scrolling and
                             the drag never starts a single pointermove on a touch device.
     `cursor: grab`        — the reference calls for it, and it is the only affordance saying the
                             row can be moved before you try.

   THE MENU IS `position: fixed` ON PURPOSE. `.e8-set-card` is `overflow: hidden` (it has to be, to
   clip the card's own radius), so an absolutely-positioned menu opening from the last row of a card
   would be sliced off at the card edge. Fixed escapes that — no ancestor here establishes a
   containing block for fixed — at the cost that the menu must be closed by anything that moves the
   world underneath it, which the component does.

   COLOUR IS SLOT-BASED, NEVER LITERAL. Stage dots and label swatches read the SAME 8 categorical
   slots defined in product.css, with a dark-mode override in app.css, from one selector list at the
   foot of this file; Won and Lost keep the success and tertiary tokens the legacy Stages screen
   uses. Everything here inverts with the theme for free.

   ONE THING THIS FILE CANNOT FIX AND DOES NOT PRETEND TO. `.e8-set-cardhead` has no narrow rule in
   core, so at 390px the header of every card on both pages grows to 130-171px with its description
   squeezed into a ~132px column beside the action button — while `.e8-set-row` right underneath it
   wraps correctly at the same width. That is a shared primitive disagreeing with itself, and the
   repair is four declarations in app/set-core.css. Restating the primitive here would fix these two
   pages and leave the other twenty drifting, which is the exact failure the shared layer exists to
   prevent, so it is reported rather than worked around. */

/* ---- ONE LEADING GUTTER FOR THE WHOLE CARD ----------------------------------------------------
   The Stages card holds two kinds of row: reorderable stage rows that begin with a grip and a dot,
   and the two milestone rows under them that begin with nothing. Left alone their labels start
   51px apart inside a single bordered card — a ragged left edge you notice before you can name it.

   So the gutter is declared ONCE, here, and consumed twice: the stage row builds it out of these
   numbers, and the milestone row reproduces the same width as an empty leading flex item. No rule
   anywhere restates 51px, so the two columns cannot drift apart when the grip or the dot is
   resized — change --e8-set-pipeline-grip and both edges move together. */
.e8-set-pipeline-stage,
.e8-set-pipeline-milestone {
  --e8-set-pipeline-grip: 26px;
  /* the grip is pulled back into the card padding so its ICON, not its hit area, sets the edge */
  --e8-set-pipeline-grip-pull: 5px;
  --e8-set-pipeline-dot-size: 8px;
  --e8-set-pipeline-lead-gap: var(--ui-space-2);
  --e8-set-pipeline-lead: calc(
    var(--e8-set-pipeline-grip) - var(--e8-set-pipeline-grip-pull) +
    var(--e8-set-pipeline-lead-gap) + var(--e8-set-pipeline-dot-size));
}

/* ---- stage row ornaments ---------------------------------------------------------------------
   Grip and dot travel together as one leading unit with a tighter gap than the row's own 14px, so
   the pair reads as a single handle rather than as two unrelated marks. */
.e8-set-pipeline-lead {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--e8-set-pipeline-lead-gap);
}

.e8-set-pipeline-grip {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--e8-set-pipeline-grip);
  height: var(--e8-set-pipeline-grip);
  margin-left: calc(var(--e8-set-pipeline-grip-pull) * -1);
  padding: 0;
  border: 0;
  border-radius: var(--ui-radius);
  background: transparent;
  color: var(--ui-text-tertiary);
  cursor: grab;
  touch-action: none;
}
.e8-set-pipeline-grip .material-symbols-outlined { font-size: var(--ui-icon-sm); }
.e8-set-pipeline-grip:hover { background: var(--ui-fill); color: var(--ui-text-secondary); }
.e8-set-pipeline-grip:active { cursor: grabbing; }

/* Won and Lost are the only two dots whose colour is an OUTCOME. Every other stage takes a hue from
   its position in the run, through the shared `.is-cat-N` list at the foot of this file — one
   vocabulary for stage dots and label swatches, and one place that maps a slot to a token. Painting
   all five open stages with the accent, which is what an outcome-keyed dot does, left the column
   saying nothing about the rows that matter; see e8spStageHue in app/set-pipeline.jsx. */
.e8-set-pipeline-dot {
  flex: none;
  width: var(--e8-set-pipeline-dot-size, 8px);
  height: var(--e8-set-pipeline-dot-size, 8px);
  border-radius: 50%;
  background: var(--ui-text-tertiary);
}
.e8-set-pipeline-dot.is-won { background: var(--ui-success-dot); }
.e8-set-pipeline-dot.is-lost { background: var(--ui-text-tertiary); }

/* The row under the pointer. Tinted rather than lifted: a shadow would need a transform to look
   right, and a transformed row inside a card that clips is a second problem. */
.e8-set-pipeline-stage.is-dragging {
  background: var(--set-tint);
  user-select: none;
}
.e8-set-pipeline-stage.is-dragging .e8-set-pipeline-grip {
  cursor: grabbing;
  color: var(--ui-text);
}

/* ---- the milestone rows' matching gutter -------------------------------------------------------
   An empty leading flex item the exact width of the grip+dot pair, so the two ordinary setting rows
   at the foot of the card share one left edge with the stage rows above them.

   `::after`, not `::before`: core draws the card's inset divider with each row's own `::before`
   (`.e8-set-card > * + *::before` in app/set-core.css), and taking that pseudo would delete the
   hairline. `order: -1` puts this box first in the flex line instead, and core's own 14px row gap
   then separates it from the label — which is the point. This file never names that 14px, so the
   gutter tracks the row grammar rather than a copy of it. */
.e8-set-pipeline-milestone::after {
  content: '';
  flex: none;
  order: -1;
  width: var(--e8-set-pipeline-lead);
}

/* ---- kebab + menu ----------------------------------------------------------------------------- */
.e8-set-pipeline-menuwrap { display: inline-flex; }
.e8-set-pipeline-kebab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: var(--ui-radius);
  background: transparent;
  color: var(--ui-text-tertiary);
  cursor: pointer;
}
.e8-set-pipeline-kebab .material-symbols-outlined { font-size: var(--ui-icon-sm); }
.e8-set-pipeline-kebab:hover,
.e8-set-pipeline-kebab[aria-expanded="true"] { background: var(--ui-fill); color: var(--ui-text); }

.e8-set-pipeline-menu {
  position: fixed;
  z-index: 70;
  min-width: 200px;
  padding: var(--ui-space-1);
  border: 1px solid var(--ui-border);
  border-radius: var(--ui-radius-md);
  background: var(--ui-surface);
  box-shadow: var(--ui-shadow-overlay);
}
.e8-set-pipeline-menuitem {
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  width: 100%;
  padding: 6px 9px;
  border: 0;
  border-radius: var(--ui-radius);
  background: transparent;
  color: var(--ui-text);
  font: inherit;
  font-size: var(--ui-text-base);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}
.e8-set-pipeline-menuitem .material-symbols-outlined {
  font-size: var(--ui-icon-xs);
  color: var(--ui-icon-quiet);
}
.e8-set-pipeline-menuitem:hover:not(:disabled) { background: var(--ui-fill); }
.e8-set-pipeline-menuitem:disabled { opacity: 0.42; cursor: not-allowed; }
.e8-set-pipeline-menuitem.is-danger { color: var(--ui-danger); }
.e8-set-pipeline-menuitem.is-danger .material-symbols-outlined { color: var(--ui-danger); }
.e8-set-pipeline-menuitem.is-danger:hover:not(:disabled) {
  background: color-mix(in srgb, var(--ui-danger) 10%, transparent);
}

/* ---- the add / rename composer ----------------------------------------------------------------
   A `.e8-set-row`, so it sits on the card's rhythm and gets its own inset divider from core. Only
   the gap changes: four controls at the row's 14px gap read as four unrelated things. */
.e8-set-pipeline-form {
  flex-wrap: wrap;
  gap: var(--ui-space-2);
}

/* ---- label swatches ----------------------------------------------------------------------------
   `--ui-cat-N-text` rather than `-bg`: the -bg pair is a pale chip fill and disappears at 10px. */
.e8-set-pipeline-labelname {
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-2);
}
.e8-set-pipeline-swatch {
  flex: none;
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 3px;
  background: var(--ui-cat-8-text);
}
.e8-set-pipeline-swatchrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.e8-set-pipeline-swatchbtn {
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: var(--ui-radius);
  background: var(--ui-cat-8-text);
  cursor: pointer;
}
/* The selected ring is a double shadow so it reads on any of the eight fills, in both themes. */
.e8-set-pipeline-swatchbtn.is-on {
  box-shadow: 0 0 0 2px var(--ui-surface), 0 0 0 3px var(--ui-text-secondary);
}

/* One slot list for all three marks on these two pages — the label swatch, the swatch picker, and
   the stage dot. Adding the dot here rather than repeating six declarations up beside it means a
   slot can only ever mean one colour on this surface. Stage dots use 1,2,3,5,6,7; 4 and 8 are
   reserved for Won and Lost and are reachable only from the label picker. */
.e8-set-pipeline-swatch.is-cat-1, .e8-set-pipeline-swatchbtn.is-cat-1, .e8-set-pipeline-dot.is-cat-1 { background: var(--ui-cat-1-text); }
.e8-set-pipeline-swatch.is-cat-2, .e8-set-pipeline-swatchbtn.is-cat-2, .e8-set-pipeline-dot.is-cat-2 { background: var(--ui-cat-2-text); }
.e8-set-pipeline-swatch.is-cat-3, .e8-set-pipeline-swatchbtn.is-cat-3, .e8-set-pipeline-dot.is-cat-3 { background: var(--ui-cat-3-text); }
.e8-set-pipeline-swatch.is-cat-4, .e8-set-pipeline-swatchbtn.is-cat-4, .e8-set-pipeline-dot.is-cat-4 { background: var(--ui-cat-4-text); }
.e8-set-pipeline-swatch.is-cat-5, .e8-set-pipeline-swatchbtn.is-cat-5, .e8-set-pipeline-dot.is-cat-5 { background: var(--ui-cat-5-text); }
.e8-set-pipeline-swatch.is-cat-6, .e8-set-pipeline-swatchbtn.is-cat-6, .e8-set-pipeline-dot.is-cat-6 { background: var(--ui-cat-6-text); }
.e8-set-pipeline-swatch.is-cat-7, .e8-set-pipeline-swatchbtn.is-cat-7, .e8-set-pipeline-dot.is-cat-7 { background: var(--ui-cat-7-text); }
.e8-set-pipeline-swatch.is-cat-8, .e8-set-pipeline-swatchbtn.is-cat-8, .e8-set-pipeline-dot.is-cat-8 { background: var(--ui-cat-8-text); }

/* ---- page footnote ----------------------------------------------------------------------------
   Both pages save silently as you edit. The line says so once, rather than a toast on every arrow
   key — holding ArrowDown would otherwise fire the toast stack five times in a second. */
.e8-set-pipeline-foot {
  margin: var(--ui-space-5) 0 0;
  font-size: var(--ui-text-base);
  line-height: 1.45;
  color: var(--ui-text-tertiary);
}

/* ---- narrow -----------------------------------------------------------------------------------
   AFTER every rule it overrides, per CLAUDE.md: a conditional at-rule adds no specificity, so a
   @media block above its own base rule never applies in any state.

   Core stacks a row's control under its text below 640px, which is right for a wide select and
   wrong for a 28px kebab — stacking it would put the row's menu a full line away from the row it
   belongs to and double the height of every stage. Stage rows AND label rows keep their shape and
   let the name take the squeeze instead; both are name-plus-kebab, not name-plus-control. Double-
   classed to beat core's equal-specificity rule whatever the stylesheet order turns out to be. */
@media (max-width: 640px) {
  .e8-set-pipeline-stage.e8-set-row,
  .e8-set-pipeline-labelrow.e8-set-row {
    flex-wrap: nowrap;
    align-items: center;
  }
  .e8-set-pipeline-stage .e8-set-row-ctl,
  .e8-set-pipeline-labelrow .e8-set-row-ctl { width: auto; }
  .e8-set-pipeline-menu { min-width: 168px; }
  /* The SLA / outcome meta is a duplicate of the coloured dot's meaning at this width; the dot and
     the menu are what a thumb needs. A LABEL row's meta is the only usage signal it has and there
     is no dot restating it, so that one stays. */
  .e8-set-pipeline-stage .e8-set-row-meta { display: none; }
  /* The milestone gutter is dropped here, and this is a trade rather than an oversight. Below 640
     core stacks a milestone row into label-over-select, so the select returns to the card padding
     while the label would still be held 51px in — aligning it to the stage rows above would leave
     it out of line with its OWN control, which is the worse of the two ragged edges. It also costs
     17% of a 348px card. Above 640, where both are single-line siblings, the gutter is what makes
     the card read as one column. */
  .e8-set-pipeline-milestone::after { display: none; }
}
