/*
 * label-editor-v2.css — the v2 label editor, both hosts.
 *
 * Tier 3, working register. Everything is prefixed `lv2-` so it cannot
 * collide with the legacy partial's `.lm` vocabulary — the two live side
 * by side on projects/dashboard.html for the whole soak, and the legacy
 * file is not to be touched.
 *
 * Canonical components are used, not reinvented: .btn (+ --primary,
 * --ghost, --subtle, --danger, --sm), .chip, .card come from
 * /css/system/components/. This file adds only what the label editor
 * itself is: the areas region, the sets index, the row grid, the colour
 * picker, the import report and the settings page's three-pane layout.
 *
 * Colour, type, spacing and radius come from tokens in
 * colors_and_type.css. No hex codes, no hardcoded radii — the two
 * exceptions are declared where they sit and both are non-brand
 * mechanics rather than colour choices.
 */

/* ---------------------------------------------------------------- root */
.lv2 {
  --lv2-gap: 12px;
  --lv2-row-h: 30px;
  font-family: var(--font-body);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.25;
}
.lv2 *, .lv2 *::before, .lv2 *::after { box-sizing: border-box; }
.lv2 h2, .lv2 h3 { font-family: var(--font-ex); margin: 0; letter-spacing: -0.01em; }
.lv2 h2 { font-size: 15px; font-weight: 700; }
.lv2 h3 { font-size: 13px; font-weight: 700; }
/*
 * BORDERED INPUTS (§17.29). Every text control carries the portal
 * `.input` device and every dropdown `.select`, both from
 * /css/system/components/form.css — so this file styles NONE of them by
 * element and there is nothing native-styled left. What is set here is
 * only the density the editor needs: a table of four hundred rows
 * cannot carry form.css's default control height.
 */
/*
 * ═══ EVERY BUTTON IN THIS SCOPE LOSES THE OS BOX (§17.29, §17.48) ═══
 *
 * A <button> with no `appearance`, `border` or `background` of its own
 * keeps the operating system's button chrome, whatever class it
 * carries. Round three fixed `.lv2-crumb__back` one rule at a time and
 * round four's audit — once it learned to ask the same question of a
 * button that it already asked of a select — found five more:
 * .lv2-tabs__btn, .lv2-tpl__var, .lv2-tpl__famtoggle, .lv2-seg__btn and
 * .lv2-strip__x. Each set a colour, a padding and sometimes a border,
 * and each sat inside an OS box nobody wanted.
 *
 * So it is one reset rather than a sixth patch, and the whole class of
 * defect goes with it.
 *
 * ⚠️ `:where()` IS LOAD-BEARING. It contributes ZERO specificity, so
 * this whole selector weighs nothing and every class — `.btn` from
 * components/buttons.css included — still wins. Written as
 * `.lv2 button` it would score higher than `.btn` and silently strip
 * the portal's own primary button back to plain text.
 */
:where(.lv2) :where(button) {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  text-align: inherit;
  cursor: pointer;
}

.lv2 .input, .lv2 .select {
  width: 100%;
  padding: 6px 8px;
  font-size: 13px;
  min-height: 0;
  height: auto;
}
.lv2-modal .input, .lv2-modal .select { padding: 9px 12px; font-size: 14px; }
.lv2 .lv2-quiet { color: var(--ink-3); font-size: 12px; }
.lv2 .lv2-warn { color: var(--amber); }
.lv2 .lv2-err { color: var(--red-status); }
.lv2 .lv2-sp { flex: 1 1 auto; }
.lv2-mono { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------- notices */
.lv2-note {
  padding: 9px 12px;
  border: 1px solid var(--rule-2);
  border-left: 3px solid var(--accent);
  border-radius: var(--r-soft);
  background: var(--paper-2);
  font-size: 12px;
  color: var(--ink-2);
  margin-bottom: 14px;
}
.lv2-note--err { border-left-color: var(--red-status); }
.lv2-note--ok { border-left-color: var(--green); }
.lv2-note p { margin: 0 0 4px; }
.lv2-note p:last-child { margin-bottom: 0; }
.lv2-note ul { margin: 4px 0 0; padding-left: 18px; }
.lv2-note li { margin-bottom: 2px; }

.lv2-toast {
  position: fixed;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  z-index: 60;
  max-width: 70vw;
  padding: 10px 16px;
  border-radius: var(--r-soft);
  background: var(--ink);
  color: var(--paper);
  font-size: 13px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
}
.lv2-toast--err { background: var(--red-status); }

.lv2-skeleton {
  height: 12px;
  border-radius: var(--r-soft);
  background: var(--rule);
  margin-bottom: 8px;
}

/* --------------------------------------------------------------- areas */
.lv2-abar {
  display: flex;
  align-items: center;
  gap: var(--lv2-gap);
  width: 100%;
  text-align: left;
  padding: 10px 14px;
  border: 1px solid var(--rule);
  border-radius: var(--r-soft);
  background: var(--surface, var(--paper-2));
  margin-bottom: 18px;
  cursor: pointer;
}
.lv2-abar:hover { background: var(--warm, var(--paper-2)); }
.lv2-abar.is-open {
  margin-bottom: 0;
  border-bottom-color: transparent;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
.lv2-abar__cnt { font-size: 12px; color: var(--ink-3); }
.lv2-abar__strip { display: flex; gap: 4px; }
.lv2-abar__strip svg { height: 18px; display: block; border-radius: 2px; }
.lv2-abar__tw { font-size: 12px; color: var(--ink-3); }

.lv2-areas {
  border: 1px solid var(--rule);
  border-radius: var(--r-soft);
  background: var(--surface, var(--paper-2));
  padding: 12px 16px 14px;
  margin-bottom: 18px;
}
.lv2-areas.is-attached { border-top-left-radius: 0; border-top-right-radius: 0; }
.lv2-areas__hd { display: flex; align-items: baseline; gap: var(--lv2-gap); margin-bottom: 8px; }
.lv2-areas__acts {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--rule);
  font-size: 12px;
  color: var(--ink-3);
  flex-wrap: wrap;
}
.lv2-arow {
  display: grid;
  grid-template-columns: 20px 74px minmax(120px, 1fr) 130px 82px auto;
  gap: var(--lv2-gap);
  align-items: center;
  padding: 6px 2px;
  border-top: 1px solid var(--rule);
}
.lv2-arow:first-of-type { border-top: 0; }
.lv2-arow svg { height: 24px; display: block; border-radius: 2px; }
.lv2-arow__drag { color: var(--ink-4); cursor: grab; user-select: none; text-align: center; }
.lv2-arow__name { display: flex; align-items: center; gap: 6px; min-width: 0; }
.lv2-arow__name input { max-width: 260px; }
.lv2-arow__cnt, .lv2-arow__cols { font-size: 12px; color: var(--ink-3); }
.lv2-arow__btns { display: flex; gap: 4px; justify-content: flex-end; }
.lv2-arow.is-dragging { opacity: 0.4; }
.lv2-arow.is-dropzone { border-top: 2px solid var(--accent); }
.lv2-arow.is-retired .lv2-arow__name { color: var(--ink-4); text-decoration: line-through; }

/* ---------------------------------------------------------- sets index */
/*
 * CARDS, in the legacy pattern (authority §17.29). The table this
 * replaced came from ui-mock.html, which was a layout study rather than
 * a style guide; the legacy tab's card grid is what people have been
 * using and it reads better. Geometry copied from
 * label-editor.css:170-195 deliberately: square corners, a 1px rule
 * that goes ink on hover, and the 1px lift.
 */
.lv2-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
}
.lv2-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 144px;
  padding: 20px 22px;
  border: 1px solid var(--rule-2);
  border-radius: 0;
  background: var(--paper);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  position: relative;
  transition: border-color 0.1s, transform 0.1s;
}
.lv2-card:hover { border-color: var(--ink); transform: translateY(-1px); }
.lv2-card__top { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.lv2-card__t {
  font-family: var(--font-ex);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.lv2-card__m { font-size: 12px; color: var(--ink-3); display: flex; gap: 10px; flex-wrap: wrap; }
.lv2-card__mini { display: flex; gap: 3px; margin-top: auto; }
.lv2-card__mini svg { height: 16px; width: 26px; display: block; border-radius: 1px; }
.lv2-card__acts {
  display: flex;
  gap: 4px;
  margin-top: 8px;
  padding-top: 10px;
  border-top: 1px solid var(--rule);
}
/* Hover-revealed delete, exactly as legacy (label-editor.css:202-232). */
.lv2-card__del {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 24px;
  height: 24px;
  padding: 0;
  display: grid;
  place-items: center;
  border: 1px solid var(--rule-2);
  border-radius: 0;
  background: var(--paper);
  color: var(--ink-3);
  font-size: 14px;
  line-height: 1;
  opacity: 0;
  transition: opacity 0.1s, border-color 0.1s, color 0.1s, background 0.1s;
}
.lv2-card:hover .lv2-card__del { opacity: 1; }
.lv2-card__del:hover { border-color: var(--red-status); color: var(--red-status); background: var(--red-soft); }
.lv2-card__del.is-confirm {
  opacity: 1;
  background: var(--red-status);
  border-color: var(--red-status);
  color: var(--paper);
}

/* the set-scoped field, once in the set header */
.lv2-setfield {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  margin: 0 0 12px;
  flex-wrap: wrap;
}
.lv2-setfield label { display: block; max-width: 320px; flex: 1 1 220px; }

.lv2-sets { width: 100%; border-collapse: collapse; }
.lv2-sets th {
  text-align: left;
  font-family: var(--font-cd);
  font-weight: 400;
  color: var(--ink-3);
  font-size: 12px;
  padding: 6px 8px;
  border-bottom: 1px solid var(--rule-structural, var(--rule-3));
  white-space: nowrap;
}
.lv2-sets td { padding: 9px 8px; border-bottom: 1px solid var(--rule); vertical-align: middle; }
.lv2-sets tr:hover td { background: var(--warm, var(--paper-2)); }
.lv2-sets__t { font-weight: 500; }
.lv2-sets__m { font-size: 12px; color: var(--ink-3); }
.lv2-sets__acts { display: flex; gap: 4px; justify-content: flex-end; }
.lv2-sets__mini { display: flex; gap: 3px; }
.lv2-sets__mini svg { height: 14px; display: block; border-radius: 1px; }
.lv2-legacy-note {
  margin: 0 0 12px;
  font-size: 12px;
  color: var(--ink-3);
}
.lv2-legacy-note a { color: var(--link); }

.lv2-fam {
  display: inline-block;
  font-family: var(--font-cd);
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: var(--r-soft);
  border: 1px solid var(--rule-3);
  color: var(--ink-2);
  background: var(--paper);
  white-space: nowrap;
}

.lv2-crumb { font-size: 12px; color: var(--ink-3); margin-bottom: 10px; }
/*
 * A QUIET CRUMB LINK, mirroring legacy's `.back` (label-editor.css:
 * 416-431) rather than resembling it.
 *
 * It was a class that set only `color` and `font-size` — and a <button>
 * with no `appearance`, `border` or `background` of its own keeps the
 * operating system's button chrome, so it rendered as a small bordered
 * grey box. Steve called it a bordered button because it was one.
 *
 * Worth recording twice over: the round-three control audit called this
 * "component class" and moved on, because its OS-widget check covered
 * select, checkbox and radio and never asked the same question of a
 * <button>. The audit now checks buttons too.
 */
.lv2-crumb__back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  padding: 0;
  margin-bottom: 2px;
  font-family: var(--font-cd);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--accent);
  text-decoration: none;
  cursor: pointer;
}
.lv2-crumb__back:hover { text-decoration: underline; }
.lv2-crumb__back:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------------------------------------------------------- the editor */
.lv2-head { display: flex; align-items: center; gap: var(--lv2-gap); margin-bottom: 12px; flex-wrap: wrap; }
.lv2-head h2 { font-size: 20px; letter-spacing: -0.02em; }
.lv2-head input.lv2-title { max-width: 340px; font-family: var(--font-ex); font-size: 16px; }
.lv2-bar { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; flex-wrap: wrap; }
.lv2-bar__sep { width: 1px; align-self: stretch; background: var(--rule-2); margin: 0 2px; }

.lv2-tblwrap { overflow-x: auto; border: 1px solid var(--rule); border-radius: var(--r-soft); }
.lv2-tbl { width: 100%; border-collapse: collapse; min-width: 720px; }
.lv2-tbl th {
  position: sticky;
  top: 0;
  z-index: 2;
  text-align: left;
  font-family: var(--font-cd);
  font-weight: 400;
  font-size: 11px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-3);
  background: var(--paper);
  padding: 7px 8px;
  border-bottom: 1px solid var(--rule-structural, var(--rule-3));
  white-space: nowrap;
}
.lv2-tbl td { padding: 3px 6px; border-bottom: 1px solid var(--rule); vertical-align: top; }
.lv2-tbl tr:last-child td { border-bottom: 0; }
.lv2-tbl tr.is-selected td { background: var(--paper-2); }
.lv2-tbl__n { width: 34px; color: var(--ink-4); font-size: 12px; text-align: right; padding-top: 10px; }
.lv2-tbl__cb { width: 28px; padding-top: 9px; }
.lv2-tbl__q { width: 62px; }
.lv2-tbl__q input { text-align: right; }
.lv2-tbl__acts { width: 62px; white-space: nowrap; padding-top: 6px; }
.lv2-tbl__empty { padding: 26px 10px; text-align: center; color: var(--ink-3); }

/* the background cell */
.lv2-bgcell {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 190px;
  padding: 3px 4px;
  border: 1px solid transparent;
  border-radius: var(--r-1);
  background: none;
  text-align: left;
  width: 100%;
  cursor: pointer;
}
.lv2-bgcell:hover { border-color: var(--rule-2); background: var(--paper); }
.lv2-bgcell[disabled] { cursor: default; }
.lv2-bgcell[disabled]:hover { border-color: transparent; background: none; }
.lv2-bgcell svg { height: 22px; width: 38px; flex: 0 0 auto; display: block; border-radius: 2px; }
.lv2-bgcell__names { font-size: 12px; color: var(--ink-2); min-width: 0; }
.lv2-bgcell__from { font-size: 12px; color: var(--ink-3); }
.lv2-bgcell__b { color: var(--ink-3); }
.lv2-bgcell.is-missing .lv2-bgcell__names { color: var(--red-status); }

/* the area combo — laid out where its parts are styled, below */
.lv2-combo select.is-free { font-style: italic; color: var(--ink-2); }
.lv2-combo input.is-free { font-style: italic; }

/* the ports list */
/*
 * THE PORTS LIST, AND WHY THE AREA COLUMN IS A FIXED TRACK.
 *
 * Every port row is its OWN grid, so an `auto` track is measured per
 * row — each port's area control came out the width of whichever area
 * name happened to be selected, and nothing lined up down the list.
 * `auto` cannot align across separate grids; only an identical track
 * can.
 *
 * The width comes from the DATA, because "wide enough for the longest
 * area name" is not something a stylesheet can know: PortsEditor sets
 * `--lv2-port-area-ch` to the longest label it is about to offer
 * (including "custom…"), once for the whole list. `clamp` is the safety
 * net at both ends — a floor so a project with only short names still
 * has room for the placeholder and the chevron, and a ceiling so one
 * 35-character name (a real show's sheet has several) cannot run the
 * row off the table. Past the ceiling the label ellipsises, which
 * `.lv2-dd__val` already does.
 *
 * The 38px of headroom is measured, not guessed: 16 padding + 2 border
 * + 6 gap + 12 chevron on `.lv2-dd__btn`, plus 2 slack.
 */
.lv2-ports {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 300px;
  padding: 2px 0 5px;
  --lv2-port-area-w: clamp(150px, calc(var(--lv2-port-area-ch, 16) * 1ch + 38px), 300px);
}
.lv2-port {
  display: grid;
  grid-template-columns: 34px minmax(90px, 1fr) var(--lv2-port-area-w) auto;
  gap: 6px;
  align-items: center;
}
.lv2-port__n { font-size: 12px; color: var(--ink-3); text-align: right; font-variant-numeric: tabular-nums; }
.lv2-port .lv2-bgcell { min-width: 130px; }
.lv2-ports__add { align-self: flex-start; }

/* ---------------------------------------------------------- the picker */
/*
 * LEGACY'S MODAL PATTERN (authority §17.29), from
 * label-editor.css:782-800: centred rather than top-anchored, a 35%
 * scrim, and a 1px INK border instead of a soft radius and a drop
 * shadow. The heading is font-ex black at 26px, lowercase, which is the
 * thing that makes a legacy dialog look like this estate's rather than
 * like a generic one.
 */
.lv2-scrim {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: rgba(0, 0, 0, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  overflow: auto;
}
.lv2-modal {
  width: 100%;
  max-width: 520px;
  background: var(--paper);
  border: 1px solid var(--ink);
  border-radius: 0;
  max-height: 88vh;
  overflow-y: auto;
}
.lv2-modal__hd h2 {
  font-family: var(--font-ex);
  font-size: 26px;
  font-weight: 900;
  letter-spacing: -0.02em;
  text-transform: lowercase;
}
.lv2-modal--wide { max-width: 780px; }
.lv2-modal__hd {
  display: flex;
  align-items: baseline;
  gap: var(--lv2-gap);
  padding: 26px 30px 12px;
}
.lv2-modal__bd { padding: 0 30px 4px; }
/*
 * LEGACY'S ARRANGEMENT (label-editor.css:853-860), not an
 * approximation of it: a rule above the actions, and the buttons
 * right-aligned with cancel to the left of the primary. §17.29 —
 * Steve has said twice that the legacy modal reads better, so this
 * matches it rather than resembling it. The one addition is
 * `.lv2-modal__ft--split`, for the two footers that carry a
 * secondary action (download template, history) on the far left.
 */
.lv2-modal__ft {
  display: flex;
  gap: 10px;
  align-items: center;
  justify-content: flex-end;
  margin: 22px 30px 0;
  padding: 18px 0 24px;
  border-top: 1px solid var(--rule);
  flex-wrap: wrap;
}
.lv2-modal__ft--split { justify-content: space-between; }
.lv2-modal__ft--split > .lv2-modal__ft-right {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
}

.lv2-seg { display: inline-flex; border: 1px solid var(--rule-3); border-radius: var(--r-1); overflow: hidden; }
/*
 * Styled by CLASS, not by descendant selector. A `.lv2-seg button` rule
 * works until somebody puts a different button inside the segment, and
 * it is invisible to the control audit — which cannot tell a button
 * styled by its parent from one that is simply native.
 */
.lv2-seg__btn { padding: 5px 12px; font-size: 12px; background: var(--paper); color: var(--ink-2); }
.lv2-seg__btn + .lv2-seg__btn { border-left: 1px solid var(--rule-3); }
.lv2-seg__btn.is-on { background: var(--ink); color: var(--paper); }

.lv2-swatches { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 4px; }
.lv2-sw {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 8px 3px 4px;
  border: 1px solid var(--rule-3);
  border-radius: var(--r-soft);
  background: var(--paper);
  font-size: 12px;
}
.lv2-sw:hover { background: var(--warm, var(--paper-2)); }
.lv2-sw[disabled] { opacity: 0.4; }
.lv2-sw__dot {
  width: 16px;
  height: 16px;
  border-radius: 2px;
  border: 1px solid var(--rule-3);
  flex: 0 0 auto;
  display: block;
}
.lv2-sw__dot svg { width: 100%; height: 100%; display: block; }

.lv2-strip { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; min-height: 30px; }
.lv2-strip__item {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 6px 3px 4px;
  border: 1px solid var(--rule-3);
  border-radius: var(--r-soft);
  background: var(--paper-2);
  font-size: 12px;
  cursor: grab;
}
.lv2-strip__item.is-dragging { opacity: 0.4; }
.lv2-strip__item.is-dropzone { border-color: var(--accent); }
.lv2-strip__x { color: var(--ink-3); padding: 0 2px; }
.lv2-strip__x:hover { color: var(--red-status); }
.lv2-strip__empty { font-size: 12px; color: var(--ink-4); align-self: center; }

.lv2-pickprev { margin: 10px 0 2px; }
.lv2-pickprev svg { width: 100%; max-height: 130px; display: block; border-radius: 2px; border: 1px solid var(--rule); }
.lv2-pickprev__cap { font-size: 11px; color: var(--ink-3); margin-top: 4px; }

/* ------------------------------------------------------- import report */
.lv2-report { font-size: 13px; }
.lv2-report__tiles { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.lv2-report__tile {
  flex: 1 1 110px;
  padding: 9px 11px;
  border: 1px solid var(--rule-2);
  border-radius: var(--r-soft);
  background: var(--paper-2);
}
.lv2-report__num { font-family: var(--font-ex); font-size: 22px; font-weight: 700; line-height: 1; }
.lv2-report__lab {
  font-family: var(--font-cd);
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-top: 4px;
}
.lv2-report__tile.is-warn { border-color: var(--amber); }
.lv2-report h3 { margin: 12px 0 6px; }
.lv2-report ul { margin: 0; padding-left: 18px; }
.lv2-report li { margin-bottom: 3px; }
.lv2-report__list { max-height: 180px; overflow-y: auto; }

/* -------------------------------------------------------------- settings */
.lv2-tabs { display: flex; gap: 20px; border-bottom: 1px solid var(--rule-structural, var(--rule-3)); margin-bottom: 18px; }
.lv2-tabs__btn {
  padding: 0 0 9px;
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  font-size: 13px;
  color: var(--ink-3);
}
.lv2-tabs__btn:hover { color: var(--ink-2); }
.lv2-tabs__btn.is-on { color: var(--ink); border-bottom-color: var(--accent); }

.lv2-cfgtbl { width: 100%; border-collapse: collapse; }
.lv2-cfgtbl th {
  text-align: left;
  font-family: var(--font-cd);
  font-weight: 400;
  font-size: 11px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 6px 8px;
  border-bottom: 1px solid var(--rule-structural, var(--rule-3));
  white-space: nowrap;
}
.lv2-cfgtbl td { padding: 5px 8px; border-bottom: 1px solid var(--rule); vertical-align: middle; }
.lv2-cfgtbl input[type="text"] { min-width: 90px; }
.lv2-cfgtbl__hex { width: 120px; font-variant-numeric: tabular-nums; text-transform: uppercase; }
.lv2-cfgtbl__sw { width: 56px; }
.lv2-cfgtbl__sw svg, .lv2-cfgtbl__sw span {
  display: block;
  height: 24px;
  width: 44px;
  border-radius: 2px;
  border: 1px solid var(--rule-3);
}
.lv2-cfgtbl__drag { width: 22px; color: var(--ink-4); cursor: grab; text-align: center; user-select: none; }
.lv2-cfgtbl tr.is-retired td { opacity: 0.55; }
.lv2-cfgtbl tr.is-dragging td { opacity: 0.4; }
.lv2-cfgtbl tr.is-dropzone td { border-top: 2px solid var(--accent); }
.lv2-cfgtbl__used { font-size: 12px; color: var(--ink-3); white-space: nowrap; }

.lv2-tpl { display: grid; grid-template-columns: 218px minmax(320px, 1fr) 340px; gap: 18px; align-items: start; }
.lv2-tpl__tree { border-right: 1px solid var(--rule); padding-right: 14px; }
.lv2-tpl__fam { margin-bottom: 10px; }
.lv2-tpl__famtoggle { font-family: var(--font-ex); font-size: 12px; font-weight: 700; }
.lv2-tpl__famtoggle:hover { color: var(--accent); }
.lv2-tpl__var {
  display: block;
  width: 100%;
  text-align: left;
  padding: 5px 8px;
  border-radius: var(--r-1);
  font-size: 13px;
  color: var(--ink-2);
}
.lv2-tpl__var:hover { background: var(--warm, var(--paper-2)); }
.lv2-tpl__var.is-on { background: var(--ink); color: var(--paper); }
.lv2-tpl__var .lv2-tpl__v { font-size: 11px; color: var(--ink-4); margin-left: 5px; }
.lv2-tpl__var.is-on .lv2-tpl__v { color: var(--paper-2); }
/*
 * §17.50: THE NAMES ARE EDITABLE WHERE THEY ARE READ. The disclosure
 * arrow became its own button (an <input> cannot sit inside a
 * <button>), so the row is a flex line: arrow, then the name.
 *
 * The input is deliberately quiet — no border until you touch it — so
 * the tree still reads as a tree rather than as a column of form
 * fields. `.input` from form.css supplies the focus ring and the
 * typography; only the resting state is overridden.
 */
.lv2-tpl__famrow { display: flex; align-items: center; gap: 4px; }
.lv2-tpl__varrow { display: flex; align-items: center; gap: 4px; }
.lv2-tpl__varrow .lv2-tpl__var { width: auto; flex: none; padding: 5px 6px; }
.lv2-tpl__rename {
  flex: 1 1 auto;
  min-width: 0;
  height: 26px;
  padding: 2px 4px;
  background: transparent;
  border-color: transparent;
  font-size: 13px;
}
.lv2-tpl__rename:hover { border-color: var(--rule); }
.lv2-tpl__rename:focus { background: var(--paper); border-color: var(--ink); }
.lv2-tpl__famrow .lv2-tpl__rename { font-family: var(--font-ex); font-size: 12px; font-weight: 700; }
.lv2-tpl__rename--var.is-on { font-weight: 700; color: var(--ink); }
.lv2-tpl__rename--head {
  flex: 0 1 auto;
  width: auto;
  min-width: 90px;
  font-family: var(--font-ex);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.lv2-tpl__mid { min-width: 0; }
.lv2-tpl__side { position: sticky; top: 12px; }
/*
 * One field per row, full width, at legacy's label scale
 * (label-editor.css:814-823). The grid came from the mock, which was a
 * layout study; two half-width fields side by side is not what the
 * modal people have been using looks like.
 */
.lv2-form { display: block; margin-bottom: 14px; }
.lv2-form label { display: block; margin-bottom: 14px; }
.lv2-form label:last-child { margin-bottom: 0; }
.lv2-form .input, .lv2-form .select, .lv2-form .textarea { width: 100%; }
.lv2-form__lab {
  display: block;
  font-family: var(--font-cd);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 6px;
}
/* a wide modal may pair two fields; opt in, never by default */
.lv2-form--pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 10px;
}
.lv2-form__group {
  grid-column: 1 / -1;
  padding-top: 8px;
  border-top: 1px solid var(--rule);
  font-family: var(--font-ex);
  font-size: 12px;
  font-weight: 700;
}
.lv2-json {
  width: 100%;
  min-height: 300px;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12px;
  line-height: 1.45;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}
.lv2-bind { display: grid; grid-template-columns: 130px 1fr; gap: 8px; align-items: center; margin-bottom: 6px; }
.lv2-bind__t { font-size: 12px; color: var(--ink-3); }
.lv2-bind.is-unbound { padding: 4px; border-radius: var(--r-1); background: var(--paper-2); }
.lv2-bind.is-unbound .lv2-bind__t { color: var(--amber); }
.lv2-prev { border: 1px solid var(--rule-2); border-radius: var(--r-soft); overflow: hidden; background: var(--paper-2); }
.lv2-prev iframe { width: 100%; height: 330px; border: 0; display: block; background: var(--paper); }
.lv2-prev__empty { padding: 40px 14px; text-align: center; color: var(--ink-3); font-size: 12px; }
.lv2-hist { margin-top: 12px; font-size: 12px; }
.lv2-hist__row { display: flex; align-items: center; gap: 8px; padding: 4px 0; border-top: 1px solid var(--rule); }

/* ----------------------------------------------------------- narrow */
@media (max-width: 900px) {
  .lv2-tpl { grid-template-columns: 1fr; }
  .lv2-tpl__tree { border-right: 0; border-bottom: 1px solid var(--rule); padding: 0 0 12px; }
  .lv2-tpl__side { position: static; }
  .lv2-arow { grid-template-columns: 20px 60px 1fr; grid-row-gap: 4px; }
  .lv2-arow__cols, .lv2-arow__cnt { grid-column: 2 / -1; }
  .lv2-arow__btns { grid-column: 1 / -1; justify-content: flex-start; }
}

/* =========================================================
   Round three (§17.32 to §17.39)
   ========================================================= */

/*
 * The new-set card, in legacy's pattern (label-editor.css:322-345).
 * §17.36: a card button and a modal, not a dropdown and not an inline
 * row of controls in the corner of the index.
 */
.lv2-card--new {
  background: transparent;
  border: 1px dashed var(--rule-3);
  color: var(--ink-3);
  display: grid;
  place-items: center;
  gap: 0;
  font-family: var(--font-cd);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  min-height: 144px;
}
.lv2-card--new:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, transparent);
  transform: none;
}
.lv2-card--new .lv2-card__plus {
  font-family: var(--font-ex);
  font-size: 36px;
  font-weight: 900;
  line-height: 1;
  margin-bottom: 8px;
}

/*
 * A file input is a portal button that opens a hidden input.
 *
 * The audit found the bare `<input type="file">` in the import dialog
 * NATIVE, which it was: no rule in any stylesheet the page links
 * reaches it, so it rendered as the OS "Choose File" widget beside a
 * filename. It cannot be styled into the portal's language — no
 * browser lets you — so the real input is taken out of the layout and
 * a `.btn` opens it. The settings page's InDesign import has always
 * worked this way (settings-page.js:1570); this is that pattern, named.
 */
.lv2-file { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.lv2-file input[type="file"] { display: none; }
.lv2-file__name {
  font-family: var(--font-cd);
  font-size: 12px;
  color: var(--ink-3);
  letter-spacing: 0.03em;
}

/*
 * THE SWATCH IS THE CONTROL (§17.34). A colour wants to be clicked,
 * not to sit beside a button labelled "recolour", so the swatch is a
 * button in its own right wherever an area's colour can be changed.
 */
.lv2-sw-btn {
  padding: 0;
  border: 1px solid var(--rule-2);
  border-radius: 0;
  background: var(--paper);
  line-height: 0;
  cursor: pointer;
  display: inline-block;
  transition: border-color 0.1s, box-shadow 0.1s;
}
.lv2-sw-btn:hover { border-color: var(--ink); box-shadow: 0 0 0 2px var(--paper-2); }
.lv2-sw-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.lv2-sw-btn svg { height: 22px; width: 34px; display: block; }
.lv2-sw-btn[disabled] { cursor: default; border-color: var(--rule); }

/*
 * The delete-disposition dialog. Each choice is a labelled block, not
 * a radio in a sentence, because the two do different things to rows
 * that have already printed.
 */
.lv2-disp { display: block; margin: 4px 0 6px; }
.lv2-disp__opt {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: 10px;
  border: 1px solid var(--rule-2);
  padding: 12px 14px;
  margin-bottom: 8px;
  cursor: pointer;
}
.lv2-disp__opt .radio { margin-top: 2px; }
.lv2-disp__opt:hover { border-color: var(--ink); }
.lv2-disp__opt.is-chosen { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.lv2-disp__t {
  font-family: var(--font-ex);
  font-size: 13px;
  font-weight: 700;
  display: block;
  margin-bottom: 3px;
}
.lv2-disp__d { font-size: 12px; color: var(--ink-3); display: block; }

/* the port's own area selector (§17.35) */
.lv2-port__area { min-width: 0; }
/*
 * The settings page's inline "add one" row (a name field and a create
 * button under a table). It was `.lv2-newset` and shared its name with
 * the sets index's new-set control, which §17.36 turned into a card and
 * a modal — leaving the class named after the one place that no longer
 * uses it. Renamed rather than restored: a class named for something it
 * is not is a trap for whoever reads it next.
 */
.lv2-addrow { display: flex; gap: 8px; align-items: center; margin-top: 14px; flex-wrap: wrap; }
.lv2-addrow .input, .lv2-addrow .select { width: auto; min-width: 170px; }
.lv2-addrow .lv2-dd { min-width: 170px; }

/* =========================================================
   Round four — the portal's own dropdown (§17.48)
   =========================================================
   A <select> is portal-styled when CLOSED and OS-drawn when OPEN: the
   option list is not an element, so no CSS reaches it and no DOM audit
   can see it. That is the whole answer to "why did the audit pass a
   native Size select" — it measured the element, and the native half of
   a select is the half that is not one.

   These two carry the closed .select's exact shape — the portal border,
   the portal chevron, the T3 density — and then own the open state too.
*/
.lv2-dd { position: relative; }
.lv2-dd__btn {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  appearance: none;
  -webkit-appearance: none;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--rule-2);
  border-radius: var(--r-1);
  padding: 6px 8px;
  font-family: var(--font-std);
  font-size: 13px;
  line-height: 1.3;
  text-align: left;
  cursor: pointer;
}
.lv2-dd__btn:hover { border-color: var(--rule-3); }
.lv2-dd__btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}
.lv2-dd.is-disabled .lv2-dd__btn,
.lv2-dd__btn[disabled] {
  background: var(--paper-2);
  color: var(--ink-3);
  cursor: not-allowed;
}
.lv2-dd__val { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lv2-dd__val.is-placeholder { color: var(--ink-3); }
/* the same chevron .select draws, so the two cannot drift apart */
.lv2-dd__chev {
  flex: none;
  width: 12px;
  height: 8px;
  background-repeat: no-repeat;
  background-position: center;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Cpath d='m1 1 5 5 5-5'/%3E%3C/svg%3E");
}
.lv2-dd.is-open .lv2-dd__chev { transform: rotate(180deg); }

/*
 * THE MENU WRAPPER (§17.51). The open panel is portalled to
 * document.body — see the note in /js/system/labels/controls.js — so
 * the FIXED positioning lives on the wrapper and the panel is an
 * ordinary block inside it. `min-width: 100%` therefore still means
 * "at least as wide as the trigger", because the wrapper carries the
 * trigger's measured width inline.
 *
 * The wrapper also carries `.lv2`, which is what keeps the panel's
 * box-sizing, font, colour and the §17.48 button reset once it is no
 * longer inside the editor. It is out of flow, so it adds no layout.
 */
.lv2-menu {
  position: fixed;
  z-index: 80;
}
.lv2-dd__panel,
.lv2-combo__panel {
  position: static;
  min-width: 100%;
  max-width: 320px;
  max-height: 260px;
  overflow-y: auto;
  background: var(--paper);
  border: 1px solid var(--ink);
  border-radius: 0;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
  display: flex;
  flex-direction: column;
  padding: 3px;
}
.lv2-dd__opt,
.lv2-combo__opt {
  display: flex;
  align-items: center;
  gap: 8px;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  border-radius: var(--r-1);
  padding: 6px 8px;
  font-family: var(--font-std);
  font-size: 13px;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
}
.lv2-dd__opt.is-active,
.lv2-combo__opt.is-active { background: var(--paper-2); }
.lv2-dd__opt.is-on,
.lv2-combo__opt.is-on { font-weight: 700; }
.lv2-dd__opt.is-on::after,
.lv2-combo__opt.is-on::after { content: '\2713'; margin-left: auto; color: var(--accent); }
.lv2-dd__sub { color: var(--ink-3); font-size: 12px; margin-left: auto; }
.lv2-dd__empty {
  padding: 8px;
  font-size: 12px;
  color: var(--ink-3);
  font-family: var(--font-cd);
  letter-spacing: 0.04em;
}

/*
 * ⚠️ ONE RULE, AND IT USED TO BE TWO — which is why the linked tick sat
 * UNDER the input instead of beside it, and why a linked row was taller
 * than its neighbours.
 *
 * There was a second `.lv2-combo` five hundred lines above this one,
 * left over from when the cell was a select stacked over a free-text
 * box: `display: flex; flex-direction: column; gap: 2px; min-width:
 * 150px`. Both selectors score 0-1-0, so the later rule won only the
 * properties it RE-DECLARED — `display` and `gap` — and
 * `flex-direction: column` was declared in one place and overridden in
 * none. The `align-items: center` here is the tell: it was written by
 * someone who believed this was a row, and on a column it does nothing
 * but centre the input horizontally.
 *
 * Merged rather than patched with `flex-direction: row`, because a
 * second rule for the same class is the defect and adding a third is
 * not a fix. `min-width` is kept: the cell needs a floor or a short
 * position name collapses the column.
 */
.lv2-combo {
  position: relative;
  display: flex;
  /* LONGHANDS, NOT `flex-flow`. The shorthand is correct in a browser,
     but jsdom's cssstyle does not expand it — so a suite asserting
     `flex-direction: row` was reading the CSS DEFAULT rather than
     anything this rule said, and would have stayed green if the
     declaration were deleted altogether. Declared explicitly so the
     assertion is about the rule. */
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: center;
  gap: 4px;
  min-width: 150px;
}
.lv2-combo__in { flex: 1 1 auto; min-width: 0; }
/*
 * `flex: none` keeps the tick off the input's width, and the fixed
 * line-height/width keep every cell the same height whether the tick is
 * there or not — the row must not change shape when a position links.
 */
.lv2-combo__linked {
  flex: none;
  width: 12px;
  text-align: center;
  line-height: var(--lv2-row-h);
  color: var(--accent);
  font-size: 12px;
}

/* =========================================================
   The sets index, mirrored from legacy (§17.46)
   =========================================================
   Steve twice: legacy's "your label sets" reads better and the team
   will compare. So these are legacy's own figures from
   components/label-editor.css, not an approximation of them — head
   (:55-97), filter pills (:100-121), bulk ribbon (:124-), card grid and
   card (:33-54). The card itself already matched from round three.

   What v2 ADDS, and only this: family colour-coding on the tag, the
   same in the index and in the open set's header, and the mini
   swatches of the backgrounds a set actually uses.
*/
.lv2-sets-idx { display: block; }
.lv2-sets__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 4px;
  flex-wrap: wrap;
}
.lv2-sets__title {
  font-family: var(--font-ex);
  font-weight: 900;
  font-size: 24px;
  letter-spacing: -0.02em;
  text-transform: lowercase;
  margin: 0;
}
.lv2-sets__sub {
  font-family: var(--font-cd);
  font-size: 12px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
}
.lv2-sets__actions { display: flex; align-items: center; gap: 8px; }
.lv2-sets__actions button {
  appearance: none;
  -webkit-appearance: none;
  background: var(--paper);
  border: 1px solid var(--rule-3);
  border-radius: 0;
  padding: 7px 13px;
  font-family: var(--font-cd);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink);
  text-transform: lowercase;
  cursor: pointer;
}
.lv2-sets__actions button:hover { border-color: var(--ink); }
.lv2-sets__actions button.is-on {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}

.lv2-sets__filter { display: flex; gap: 6px; flex-wrap: wrap; margin: 10px 0 14px; }
.lv2-sets__filter button {
  appearance: none;
  -webkit-appearance: none;
  background: var(--paper);
  border: 1px solid var(--rule-3);
  border-radius: 0;
  padding: 6px 12px;
  font-family: var(--font-cd);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--ink-2);
  text-transform: uppercase;
  cursor: pointer;
}
.lv2-sets__filter button:hover { border-color: var(--ink); color: var(--ink); }
.lv2-sets__filter button.is-on {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}

.lv2-sets__bulk {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--ink);
  color: var(--paper);
  padding: 10px 14px;
  margin: 0 0 14px;
  flex-wrap: wrap;
}
.lv2-sets__bulk .lv2-sp { flex: 1 1 auto; }
.lv2-sets__bulk-count { font-family: var(--font-cd); font-size: 12px; letter-spacing: 0.04em; }
.lv2-sets__bulk button {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: 0;
  color: var(--paper);
  padding: 6px 12px;
  font-family: var(--font-cd);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: lowercase;
  cursor: pointer;
}
.lv2-sets__bulk button:hover { border-color: var(--paper); }
.lv2-sets__bulk button.is-danger { background: var(--red-status); border-color: var(--red-status); }

/* the pick control, revealed in picking mode (legacy's .set-card__pick) */
.lv2-cards.is-picking .lv2-card { cursor: default; }
.lv2-card.is-picked { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.lv2-card__pick {
  position: absolute;
  top: 10px;
  left: 10px;
  width: 22px;
  height: 22px;
  padding: 0;
  display: grid;
  place-items: center;
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid var(--rule-2);
  border-radius: 0;
  background: var(--paper);
  cursor: pointer;
}
.lv2-card__pick svg { width: 12px; height: 12px; fill: none; stroke: var(--accent); stroke-width: 2; display: none; }
.lv2-card.is-picked .lv2-card__pick { border-color: var(--accent); }
.lv2-card.is-picked .lv2-card__pick svg { display: block; }

/*
 * FAMILY COLOUR-CODING, the one thing v2 adds to the tag — and the same
 * three colours legacy already uses for its own types
 * (label-editor.css:282-292 and :475-485), so the index, the card and
 * the open set's header agree and nothing has to be learned twice.
 */
.lv2-fam { border: 1px solid var(--accent); color: var(--accent); }
.lv2-fam.t-pal { color: #2c5a8f; border-color: #2c5a8f; }
.lv2-fam.t-soca { color: #1f7a4a; border-color: #1f7a4a; }
.lv2-fam.t-rack { color: #7a4a1f; border-color: #7a4a1f; }

/* the import mapping step (§17.43): one row per column nothing matched */
.lv2-map { display: block; margin: 6px 0 4px; }
.lv2-map__row {
  display: grid;
  grid-template-columns: minmax(90px, 1fr) minmax(150px, 1.2fr) auto;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-top: 1px solid var(--rule);
}
.lv2-map__row:last-child { border-bottom: 1px solid var(--rule); }
.lv2-map__col {
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lv2-map__pick { min-width: 0; }
.lv2-map__rem { font-size: 12px; color: var(--ink-3); }
