/* =====================================================================
   AWE demo — shared styles
   Black background, teal system accent (per COLOR_SYSTEM.md).
   Grows as screens are built; kept readable and grouped by area.
   ===================================================================== */

:root {
  --bg:      #000000;
  --text:    #FFFFFF;
  --muted:   #CCCCCC;
  --teal:    #59BBBB;   /* system / neutral accent */
  --red:     #FC2323;   /* alerts only */
  --yellow:  #FFD60A;   /* COLOR_SYSTEM.md secondary — "Highlights, Attention states" */
  --line:    #333333;

  /* Ported from the proto for the Phase 1 assessment screen (pills + input modal). */
  --teal-deep: #3D8A85;   /* pill rest fill */
  --card-bg:   #ffffff;   /* modal card */
  --card-fg:   #1a1a1a;   /* modal text */

  /* Height of the shared .app-header, which is NOT fixed-position — every full-height screen
     container subtracts it from the viewport. A DECISION, not a measurement (David, 2026-07-16):
     .app-header asserts this same height explicitly, so the two cannot drift. Change one and you
     must change the other; that is the point. The header's natural render is 71.492px (padding
     25+16, plus 30.492px of content that falls out of baseline-aligning a 23.492px logo — 157px
     wide at the SVG's 22/147 aspect — against a 27px .header-right). That number is an artifact
     of an asset ratio and a font baseline; nobody chose it. 72px is chosen. */
  --app-header-h: 72px;
}

* { box-sizing: border-box; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: 'Raleway', -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  margin: 0;
  line-height: 1.5;
}

a { color: var(--teal); }

/* ---- top brand bar (evolve.work) ---- */
.brand { padding: 0; }                      /* logo inset now provided by .app-header (below) */
.logo  { display: block; width: 157px; height: auto; }   /* by-eye size */

/* ---- shared header: flex row (logo left / right side) ---- */
/* height is pinned so --app-header-h describes an asserted fact rather than an emergent render
   (David, 2026-07-16). Natural render is 71.492px; the 0.508px of slack sits below the baseline
   group, so nothing moves. ACCEPTED TRADE: a pinned header cannot grow, so a taller element added
   here would clip — which fails visibly, unlike the ~7px page overflow this replaces. */
.app-header   { display: flex; justify-content: space-between; align-items: baseline; padding: 25px 43px 16px; height: 72px; }
.header-right { position: relative; display: flex; align-items: baseline; }

/* Facilitator-only dev menu (proto style; vars remapped to the demo's). Shell holds Reset now. */
#dev-bar      { position: absolute; bottom: calc(100% + 1px); right: 0; font-size: 13px; line-height: 1; z-index: 5; }
#menu-trigger { background: transparent; color: var(--muted); border: 1px solid rgba(255,255,255,0.35);
                border-radius: 999px; padding: 2px 9px; font-family: inherit;
                font-size: 9px; font-weight: 500; letter-spacing: 0.14em; line-height: 1; cursor: pointer;
                transition: color .15s ease, border-color .15s ease; }
#menu-trigger:hover { color: var(--teal); border-color: var(--teal); }
#menu-trigger:focus-visible { outline: 1px solid var(--teal); outline-offset: 4px; }
#menu-panel   { position: absolute; top: calc(100% + 10px); right: 0; min-width: 220px;
                background: rgba(20,20,20,0.95); border: 1px solid rgba(255,255,255,0.15); border-radius: 8px;
                padding: 16px 18px; display: flex; flex-direction: column; gap: 16px;
                box-shadow: 0 8px 24px rgba(0,0,0,0.4); backdrop-filter: blur(8px); z-index: 1000; font-size: 13px; font-weight: 500; }
#menu-panel[hidden] { display: none; }
.menu-header  { display: none; }
#reset-btn    { background: transparent; color: var(--text); border: 1px solid rgba(255,255,255,0.35);
                border-radius: 999px; padding: 3px 12px; font-family: inherit; font-size: 13px;
                font-weight: 500; cursor: pointer; align-self: flex-end; text-decoration: none;
                transition: color .15s ease, border-color .15s ease; }
#reset-btn:hover { color: var(--teal); border-color: var(--teal); }
.menu-row     { display: flex; align-items: center; gap: 8px; margin: 0; }
.menu-label   { font-size: 13px; font-weight: 500; color: var(--text); letter-spacing: 0.14em; }
#phase-jump   { background: transparent; color: var(--text); border: 1px solid rgba(255,255,255,0.35);
                border-radius: 6px; padding: 3px 6px; font-family: inherit; font-size: 13px; font-weight: 500;
                cursor: pointer; transition: color .15s ease, border-color .15s ease; }
#phase-jump:hover { color: var(--teal); border-color: var(--teal); }
#phase-jump:focus-visible { outline: 1px solid var(--teal); outline-offset: 2px; }

.phase-label  { font-size: 18px; font-weight: 400; color: var(--text); letter-spacing: 0;
                transform: translateY(-1px); }   /* nudge up to the logo's visual baseline */

/* ---- centered stage (login / holding screens) ---- */
.stage {
  min-height: calc(100vh - var(--app-header-h));
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 24px;
}
.eyebrow {
  color: var(--teal);
  font-weight: 700;
  font-size: 26px;
  letter-spacing: 1px;
  margin-bottom: -8px;
}
.headline {
  font-size: 64px;
  font-weight: 300;
  margin: 0 0 44px;
}

/* company box on the login screen — wide banner (matches Login.png) */
.company-box {
  border: 2px solid var(--teal);
  border-radius: 16px;
  width: min(720px, 82%);
  padding: 36px 44px;
  font-size: 34px;
  font-weight: 700;
  margin-bottom: 44px;
}
.confirm-line {
  font-size: 30px;
  font-weight: 300;
  line-height: 1.45;
  margin-bottom: 44px;
}
.confirm-line b { font-weight: 700; }
/* Login-only: widen the Next button. Scoped to .stage so the global .btn (every
   other button in the demo) is unaffected. */
.stage .btn { padding-left: 48px; padding-right: 48px; }
/* Login-only: lift the whole centered group up 10px as a unit. Scoped via :has to
   the login stage (the only .stage with a .company-box) so the other centered
   screens (waiting, thank-you, complete) are unaffected. Exact shift (transform,
   no layout reflow) — a margin nudge would only move it ~half under flex centering. */
.stage:has(.company-box) { transform: translateY(-30px); }

/* ---- buttons ---- */
.btn {
  background: var(--teal);
  color: #fff;
  border: 0;
  border-radius: 22px;
  padding: 11px 30px;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
}
.btn:disabled { opacity: 0.4; cursor: default; }
.btn-ghost {
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--line);
}

/* ---- interim status view (Increment 2) ---- */
.status-wrap { max-width: 720px; margin: 40px auto; padding: 0 28px; }
.muted { color: var(--muted); }
.small { font-size: 14px; }

/* ---- Enter Cards: participant form ---- */
/* Enter Cards — participant. Restyled to proto twin P2_S1_INPUT_PART (design pass). */
.cards-wrap { width: 100%; max-width: none; margin: 30px 0; padding: 0; }
.cards-name   { color: var(--text); font-size: 18px; font-weight: 700; letter-spacing: 0.05em; margin: 0 0 8px; }
.cards-prompt { color: var(--text); font-size: 18px; font-weight: 500; margin: 0 0 4px; }
/* Live product rule (TB-10 all-or-nothing) — kept, styled as small secondary text. */
.cards-rule { margin: 0 0 28px; padding-left: 43px; }   /* logo-aligned; .cards-rule is a sibling of .cards-head, so it needs the gutter too */
/* Submit row — proto .p2-input-submit-row values (centered Submit, not the lower-right convention).
   NOTE: .cards-wrap stays TOP-ANCHORED (no justify-content:center) — deliberate divergence from the
   proto's .p2-input-view centering so the header block never moves when card content changes. */
.cards-submit { display: flex; justify-content: center; margin-top: 22px; }
.card-grid {
  /* Proto .p2-input-grid: 6-col grid, 3 wide cards top / 2 centered bottom. */
  /* DIVERGENCE from proto: proto .p2-input-grid sets max-width:none and comments that cards
     should fill screen width (not narrow and centered). David deliberately reverses that — the
     cards get too wide on large viewports — so the grid is capped and centered here. Intentional. */
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 28px;
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 40px;
  box-sizing: border-box;
}
.card-grid .entry-card:nth-child(1) { grid-column: 1 / span 2; }
.card-grid .entry-card:nth-child(2) { grid-column: 3 / span 2; }
.card-grid .entry-card:nth-child(3) { grid-column: 5 / span 2; }
.card-grid .entry-card:nth-child(4) { grid-column: 2 / span 2; }
.card-grid .entry-card:nth-child(5) { grid-column: 4 / span 2; }
.entry-card {
  /* Proto .p2-card: white body, dark text, 8px participant-colour top stripe
     (identity band). --seat comes from the seat-<color_id> class on .card-grid. */
  background: #fff;
  color: #1a1a1a;
  border: 2px solid var(--seat, var(--teal));
  border-top-width: 8px;
  border-radius: 8px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  height: 200px;
}
.card-title {
  /* Proto .p2-card-title-input: 2-line fixed zone, dark, centered, no divider. */
  border: 0;
  outline: none;
  background: transparent;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.35;
  color: #1a1a1a;
  text-align: center;
  padding: 14px 16px 8px;
  flex: 0 0 auto;
  height: calc(2 * 16px * 1.35 + 14px + 8px);
  resize: none;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(0,0,0,0.30) transparent;
}
.card-title::-webkit-scrollbar { width: 4px; }
.card-title::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.30); border-radius: 999px; }
.card-detail {
  /* Proto .p2-card-input--desc: fills remaining space, dark secondary text. */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  border: 0;
  outline: none;
  resize: none;
  padding: 0 16px 16px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
  color: #1a1a1a;
  background: transparent;
  scrollbar-width: thin;
  scrollbar-color: rgba(0,0,0,0.30) transparent;
}
.card-detail::-webkit-scrollbar { width: 5px; }
.card-detail::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.30); border-radius: 999px; }
.card-title::placeholder  { color: rgba(0,0,0,0.4); font-weight: 600; }
.card-detail::placeholder { color: rgba(0,0,0,0.4); font-style: italic; }
.card-title:focus, .card-detail:focus { outline: none; }

/* ---- Enter Cards: facilitator view ----
   The question uses the shared .prompt-view / .prompt-text standard (below). The Cards rules
   (.cards-fac / .cards-question) were byte-identical duplicates of it and were folded in. The
   timer below is Cards-only — Legal has no equivalent — and stays here. */
/* Cards-only; spacing below the question comes from .prompt-view gap:32px.
   SIZE — 52px (was 29px, which the register flagged as too small): 52px is the display step already
   established ON THIS SCREEN by .prompt-text, so the timer stays on the type scale rather than
   inventing a size. NOT 64px — that is the messaging-headline step and would make the timer outrank
   the question, inverting the register's "the question is the hero".
   WEIGHT — 500, the weight this element already carried at 29px. The 1.8x size jump delivers the
   prominence on its own; 700 was tried and shouted next to the question's 400 (David, 2026-07-16).
   500 against 400 is one step: enough to mark a glanceable value against body copy, not a headline.
   FAMILY — Avenir Next, NOT Raleway. Raleway's numerals are display figures and it ships NO tabular
   figure set: measured at 52px its digits span 25.675px ("1") to 31.928px ("0"), and BOTH
   font-variant-numeric:tabular-nums AND font-feature-settings:"tnum" change nothing — there is no
   feature to switch on. A centred Raleway countdown lurches ~19px as it counts ("1:11" 89.9px vs
   "0:00" 108.7px) and jumps 3.5px the instant it starts. Avenir Next is tabular BY DEFAULT (0px
   spread), is on every macOS, costs nothing, and as a geometric humanist sits under Raleway as a
   relative rather than a stranger. tabular-nums is kept as belt-and-braces, not load-bearing.
   COLOUR is set inline by the timer IIFE (a computed OKLCH ramp); the var(--teal) here is the
   at-rest value before the first paint. The 1s linear transition is what makes the ramp read as a
   continuous boil rather than per-tick micro-steps. */
.cards-timer {
  font-family: "Avenir Next", -apple-system, sans-serif;
  font-size: 52px;
  font-weight: 500;
  color: var(--teal);
  cursor: pointer;
  user-select: none;
  font-variant-numeric: tabular-nums;
  transition: color 1s linear;
}

/* Begin presence dots (index.php) */
.dot { width: 11px; height: 11px; border-radius: 50%; display: inline-block; }
.dot-empty  { border: 1px solid #555; }

/* ---- Completion tracker (proto P2_S1_INPUT_FAC) — bare anonymous dots, lower-left.
   Shared by the Cards facilitator (#p2-input-tracker) and the Workflow Votes facilitator
   (#p2-wfvote-tracker); they differ only in fill source, not in markup or styling.
   Distinct from the .dot classes above, which render the Begin presence dots and which
   this does NOT touch. ---- */
.completion-tracker {
  display: flex;
  flex-wrap: wrap;
  /* 8px matches Begin's .presence-dots — Begin is the reference screen for the dot row
     (David, 2026-07-16). Was 9px; the two rows are one component and now share one gap. */
  gap: 8px;
  align-items: center;
}
/* Shared placement for both trackers (Cards facilitator + Workflow Votes facilitator),
   identical to Begin's .presence-dots — one dot row, one position, three screens.
   left 43px aligns to the logo; bottom 35px centres the dots on the NEXT triangle.
   See the .presence-dots derivation below. Was 28px/26px (David, 2026-07-16). */
#p1-assessment-tracker,
#p2-input-tracker,
#p2-wfvote-tracker,
#p2-catrank-tracker {
  position: fixed;
  left: 43px;
  bottom: 35px;
  z-index: 30;
  flex: 0 0 auto;
  justify-content: flex-start;
  margin: 0;
}
.completion-dot {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  display: inline-block;
  flex: 0 0 auto;
  background: transparent;
  border: 1.5px solid var(--track, #888);
  transition: background 0.2s ease, border-color 0.2s ease;
}
/* DIVERGENCE from proto: proto leaves .is-done empty and fills inline with the participant's roster
   colour, and its unfilled dot borders use #6a6f78. David's locked standard is ONE anonymous GRAY,
   no colours — so done dots fill #888 (matching Begin's presence dots, .dot-joined) and the unfilled
   border falls back to #888 too, not the proto's #6a6f78. Gray, not roster colour; one gray everywhere. */
.completion-dot.is-done { background: #888; border-color: #888; }

@media (max-width: 640px) { .card-grid { grid-template-columns: 1fr; } .card-grid .entry-card { grid-column: auto; } }

/* ---- Messaging standard: the room is waiting, or is being told something ----
   Six callers: Session complete, Cards thank-you, Cards operator, Legal in-progress,
   Votes thank-you, Votes operator. Named for what the screen IS in session language, not
   for Legal, which merely happened to be built first (was .legal-center/-topic/-subline).

   This is Family B, and it is the standard. It is NOT the proto's messaging treatment:
   Family B is 64/600 headline + 30/300 subline; the proto's .passive-* is 60/500 + 40/500.
   That divergence is deliberate and ratified (David, 2026-07-16), not an oversight. The
   login screen keeps its own treatment (Family A) — two families, this one is the standard. */
.status-view {
  min-height: calc(100vh - var(--app-header-h));
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center; padding: 24px;
}
.status-title { color: var(--teal); font-size: 64px; font-weight: 600; line-height: 1.1; margin: 0; }
.status-line { color: var(--text); font-size: 30px; font-weight: 300; margin: 10px 0 0; }

/* Hero (workflow_hero stop) — the closing reveal. The workflow NAME is the reveal, so on this
   screen the .status-line is sized to the prototype's .passive-subtext treatment (30pt / weight 500 /
   white, from root styles.css:1063) — substantially larger and heavier than the standard 30px/300
   subtext, and nearly as large as the teal headline, exactly as the proto S10 transition reads. Scoped
   to .status-view--hero so every other .status-view screen keeps Family B untouched. */
.status-view--hero .status-line {
  color: var(--text);
  font-size: 35pt;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1.3;
}

/* ---- Question standard: a question is on screen — the question is the hero ----
   Two callers: Legal facilitator, Cards facilitator (proto .centered-prompt / .prompt-text).
   Was .legal-centered-prompt / .legal-prompt-text, with .cards-fac / .cards-question a
   byte-identical duplicate (plus a position:relative); folded into one rule.

   NO position:relative — .cards-fac carried one; it was dead and is gone (David, 2026-07-16).
   It would only matter for an absolutely-positioned descendant, and neither caller has one:
   the whole subtree is .prompt-text and .cards-timer (static) plus #p2-input-tracker and
   .begin-footer (fixed). Fixed children ignore a relative ancestor — they are trapped only by
   a transform/filter/perspective/will-change/contain on the container, and this rule has none.
   Do not re-add it "for the tracker": the tracker is fixed and was never held by it. */
.prompt-view {
  min-height: calc(100vh - var(--app-header-h));
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center; padding: 24px; gap: 32px;
}
.prompt-text {
  font-size: 52px; font-weight: 400; line-height: 1.3;
  max-width: 780px; margin: 0; letter-spacing: 0.005em;
}

/* Phase 3 Department / Task header (proto .p3-task-header block). Ported wholesale from
   the prototype styles.css. ONE substitution: .p3-task-name uses var(--text) — the live
   sheet's white token — where the proto used var(--fg) (which the live sheet does not
   define; both are #ffffff). Structure and class names are byte-identical. */
.p3-task-header {
  /* A 2-row stacked block (Department row on top, Task row below). The internal
     .p3-task-header-row carries the baseline-aligned flex layout. */
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: 8px;
  font-size: 18px;
  line-height: 1.4;
}
.p3-task-header-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.p3-task-label {
  color: var(--teal);
  font-weight: 600;
}
.p3-task-name {
  color: var(--text);
  font-weight: 400;
}

/* Phase 3 screen shell. The nine P3 screens share one frame: the Department/Task header
   (.p3-task-header) pinned to the top, the screen body filling the height beneath it.
   Self-sizes to the viewport minus the (non-fixed) app-header, the same way every other
   live full-height view does. Additive: this shell exists BECAUSE .prompt-view alone
   can't do this — its full-height centering ignores a header placed above it — so no
   existing rule (including .prompt-view) is touched. The four P3 topic question stops
   (Triggers/Inputs/Outputs/Success) all wrap in .p3-screen; the header alone lands on
   all nine P3 screens. */
.p3-screen {
  min-height: calc(100vh - var(--app-header-h));
  display: flex;
  flex-direction: column;
  padding: 0 43px;   /* 43px aligns to the logo (.app-header left padding = 43px) */
}
/* Editor variant only: the draft/final/readonly screens carry .p3-item-editor (the scroller); the
   question stop carries .p3-screen-body (centered) instead. Bounding the wrapper with a DEFINITE
   height — mirroring .legal-review-view — is what activates .p3-item-editor's flex chain so the row
   list fills the space left under the task-header/eyebrow/heading. It is scoped with :has() so the
   centered question stop keeps min-height (grow + page-scroll), per the centered-view rule. The 72px
   bottom padding clears the fixed .begin-footer, the same value the working scroller wrappers use.

   TWO SCROLLER VARIANTS NOW SHARE THIS BLOCK, and they SHARE it rather than each carrying a copy:
   .p3-item-editor (the draft/final/readonly item editor) and .p3-output-view (the Phase 3 atomic
   tasks listing stop). Both need the identical thing — a DEFINITE height so their inner
   `flex: 1 1 auto; min-height: 0` scroller has something real to fill, and 72px of clearance under
   the fixed footer. Duplicating the block would put a SECOND 72px and a second viewport calc in the
   sheet, free to drift from this one; that is precisely the duplicated-constant trap TB-56's 420px
   pair records and this rule exists to avoid. A third variant joins the selector list, it does not
   get its own copy. */
.p3-screen:has(.p3-item-editor),
.p3-screen:has(.p3-output-view) {
  height: calc(100vh - var(--app-header-h));
  box-sizing: border-box;
  padding-bottom: 72px;
}
/* The question region: fills the height left under the .p3-task-header and centers the
   prompt within THAT (flex:1), so the centering accounts for the header above rather
   than re-centering against the whole viewport. */
.p3-screen-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}

/* =====================================================================
   PHASE 3 — ITEM EDITOR (the .p3-item-editor shell + rows)
   The three-field draft/final editor: a #N badge, a contenteditable
   header, a contenteditable description, an × delete per row, and a
   trailing "+ Add Topic" control. Ported from the prototype's P3 review
   rules (root styles.css), re-scoped from [data-screen="P3_Q*_REVIEW_FAC"]
   to .p3-item-editor. Additive only — NO .p2-final-* rule is touched.

   RULING A (P3 rows own their classes): the prototype built these rows on
   the shared .p2-final-* base plus a screen-scoped override. Here the rows
   carry P3's OWN classes (.p3-row / .p3-row-body / .p3-row-head /
   .p3-row-badge / .p3-row-title / .p3-row-desc) so a future P2 retune can
   never silently retypeset these editable fields, and nothing P3 writes
   references a .p2-final-* selector.

   Declarations are ported byte-identical from the prototype's corresponding
   rules — same padding, gap, border, font sizes, weights, radii, transitions
   — with only these established, sheet-wide token remaps (identical to the
   live .p2-final-* block and the .p3-task-header block above): proto --fg →
   --text, --fg-dim → --muted, --border → --line; --teal / --alert shared.

   SELF-CONTAINED TYPOGRAPHY (the one place a mechanical rename drops style):
   the editable spans carry .p3-row-title / .p3-row-desc alongside .p3-editable.
   In the prototype the typography came from the P2 title/desc classes; here it
   is defined on .p3-row-title / .p3-row-desc below, so the editable element
   still gets its color/size/weight/line-height from a P3-owned rule. .p3-editable
   itself stays affordance-only (as in the prototype).
   ===================================================================== */

/* Editor shell (proto .p2-final-view) — a flex column that fills its P3 frame. */
.p3-item-editor {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-height: 0;
}

/* Row list (proto .p2-final-list). No height ceiling: the bounded
   .p3-screen:has(.p3-item-editor) wrapper + .p3-item-editor's flex column give
   this list a real remaining height, so it fills the space left under the
   task-header/eyebrow/heading and stops above the fixed footer — the same flex
   chain the working scroller views use. The former max-height
   (calc(100vh - var(--app-header-h))) did not subtract that stacked chrome or the
   footer, so a long list ran under the nav; removing it hands sizing to the chain. */
.p3-item-list {
  margin-top: 8px;
  border-top: 1px solid var(--line);
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  padding-right: 20px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.55) rgba(255,255,255,0.10);
}
.p3-item-list::-webkit-scrollbar { width: 8px; }
.p3-item-list::-webkit-scrollbar-track {
  background: rgba(255,255,255,0.10);
  border-radius: 999px;
  margin: 4px 0;
}
.p3-item-list::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,0.55);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: padding-box;
}
.p3-item-list::-webkit-scrollbar-thumb:hover {
  background: rgba(255,255,255,0.75);
  background-clip: padding-box;
}
.p3-item-list::-webkit-scrollbar-corner { background: transparent; }

/* Row (proto .p2-final-row base + the P3 review override, folded together:
   the override set gap:0 and cursor:grab on every row — every P3 row is
   draggable, so grab is the resting cursor). */
.p3-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  align-items: start;
  padding: 18px 4px;
  border-bottom: 1px solid var(--line);
  transition: background 120ms ease, opacity 120ms ease;
  cursor: grab;
}
.p3-row:active { cursor: grabbing; }
.p3-row.dragging { opacity: 0.5; }
.p3-row.drag-over { background: rgba(93, 189, 181, 0.08); }

/* Read-only twin (.p3-readonly, the facilitator view-back list): the rows are static — no
   draggable, no editor JS — so reset the row's resting cursor: grab to default. A false drag
   affordance reads worst in front of a room. Additive and scoped to .p3-readonly, so no editable
   .p3-row (the .p3-item-editor without .p3-readonly) is affected. */
.p3-readonly .p3-row { cursor: default; }

.p3-row-body { min-width: 0; }

.p3-row-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 6px;
}

/* #N badge (proto .p2-final-priority). */
.p3-row-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  padding: 2px 8px;
  border-radius: 12px;
  background: var(--teal);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
}

/* Title / description typography (proto .p2-final-row-title / .p2-final-row-desc).
   P3-owned so the editable spans keep their type independent of P2 — see the
   SELF-CONTAINED TYPOGRAPHY note above. */
.p3-row-title {
  color: var(--text);
  font-size: 20px;
  font-weight: 500;
  letter-spacing: 0.02em;
  flex: 1;
}
.p3-row-desc {
  color: var(--muted);
  font-size: 18px;
  font-weight: 300;
  line-height: 1.5;
}

/* Editable affordance (proto .p3-editable) — affordance only: invisible until
   focus, subtle underline on focus, no outline. Typography comes from the
   .p3-row-title / .p3-row-desc the element also carries. */
.p3-editable {
  outline: none;
  cursor: text;                 /* overrides the row's cursor: grab */
  border-radius: 2px;
  border-bottom: 1px solid transparent;
  padding: 0 2px;
  margin: 0 -2px;
  transition: border-color 120ms ease;
  -webkit-user-select: text;
  user-select: text;
  word-break: break-word;
  overflow-wrap: anywhere;
  min-height: 1em;
}
.p3-editable:hover { border-bottom-color: rgba(255, 255, 255, 0.15); }
.p3-editable:focus { border-bottom-color: var(--teal); }

/* Empty-editable placeholder (proto [data-screen] .p3-editable:empty::before),
   re-scoped to .p3-item-editor. contenteditable ignores the native placeholder
   attribute; the hint is pulled from data-placeholder and vanishes on first char. */
.p3-item-editor .p3-editable:empty::before {
  content: attr(data-placeholder);
  color: rgba(255, 255, 255, 0.30);
  font-style: italic;
  font-weight: inherit;
  pointer-events: none;
}

/* Per-row × delete (proto .p3-q-topic-del) — hidden at rest, fades in on row
   hover or keyboard focus-within. Floor of 1: the sole remaining row's button
   renders disabled (dimmed, non-clickable). */
.p3-q-topic-del {
  flex: 0 0 auto;
  align-self: center;
  width: 22px;
  height: 22px;
  padding: 0;
  background: transparent;
  border: none;
  color: rgba(255, 255, 255, 0.30);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  border-radius: 3px;
  opacity: 0;
  transition: opacity 120ms ease, color 100ms, background 100ms;
}
/* The prototype's reveal rules keyed off the shared .p2-final-row selector; per
   ruling A they are re-scoped to .p3-item-editor .p3-row so nothing P3 writes
   references a .p2-final-* selector. */
.p3-item-editor .p3-row:hover .p3-q-topic-del,
.p3-item-editor .p3-row:focus-within .p3-q-topic-del {
  opacity: 1;
}
.p3-q-topic-del:hover {
  color: var(--alert, #FC2323);
  background: rgba(252, 35, 35, 0.10);
}
.p3-q-topic-del:disabled {
  opacity: 0.18 !important;
  cursor: default;
}
.p3-q-topic-del:disabled:hover {
  color: rgba(255, 255, 255, 0.30);
  background: transparent;
}

/* + Add Topic (proto .p3-q-topic-add) — compact dashed ghost pill, appended
   after the last row inside the scroll list. */
.p3-q-topic-add {
  display: inline-block;
  background: transparent;
  border: 1px dashed rgba(255, 255, 255, 0.22);
  border-radius: 4px;
  color: rgba(255, 255, 255, 0.55);
  font-family: inherit;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.04em;
  padding: 5px 10px;
  margin-top: 10px;
  cursor: pointer;
  transition: color 120ms, border-color 120ms, background 120ms;
}
.p3-q-topic-add:hover {
  color: var(--teal);
  border-color: var(--teal);
  background: rgba(93, 189, 181, 0.06);
}
.p3-q-topic-add:focus {
  outline: none;
  border-color: var(--teal);
  color: var(--teal);
}

/* Evidence Responses roster (evidence_q facilitator view) — matches the proto P1_S1_RAW_FAC layout:
   left-aligned block near the top-left (title's left edge aligned to the logo gutter, 43px), a
   compact name column + wide answer column grid, thin dividers. Submitters only, in submission order
   (server-side); no placeholder rows. Dedicated classes — the shared .review-/.legal- classes are
   left untouched. */
.responses-roster-view {
  /* Mirror of .legal-review-view (the Legal scroll WRAPPER): fills the viewport below the static
     header and lays out as a flex column (title on top, scroll region taking the rest). The 72px
     bottom padding is what lifts the scroll region — and its scrollbar — clear of the fixed footer
     (the wrapper shrinks the scroll child; the clearance is NOT bottom padding inside the scroller). */
  height: calc(100vh - var(--app-header-h));
  display: flex; flex-direction: column;
  padding: 24px 43px 72px;   /* 43px left/right gutter; 72px bottom clears the fixed BACK|NEXT / Start Listening */
  box-sizing: border-box;
}
.responses-roster-title {
  text-align: left; font-size: 36px; font-weight: 300; margin: 0 0 12px; letter-spacing: 0;
  flex: 0 0 auto;   /* stays pinned above the scroll region */
}
.responses-roster {
  /* Complete mirror of the Legal scroll container (.legal-review-view .review-synthesis) — flex
     column scroller, thin subtle scrollbar, 20px right gutter, and the top/bottom content-fade mask.
     Footer clearance is provided by the WRAPPER's 72px bottom padding (above), NOT a bottom padding
     here, so the scrollbar itself ends above the nav. Only list-style is kept (this is an <ol>). */
  list-style: none; margin: 0;
  flex: 1 1 auto;
  min-height: 0;
  display: flex; flex-direction: column;
  justify-content: flex-start;
  max-width: none;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 30px 20px 0 0;   /* top spacing + right scrollbar gutter (mirrors legal; no bottom pad) */
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.55) rgba(255,255,255,0.10);
  /* Fade the first/last 16px into the background so partial rows never clip mid-glyph. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
}
.responses-roster::-webkit-scrollbar { width: 8px; }
.responses-roster::-webkit-scrollbar-track { background: rgba(255,255,255,0.08); border-radius: 999px; }
.responses-roster::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.45); border-radius: 999px; }
.responses-roster-row {
  display: grid; grid-template-columns: 130px 1fr; gap: 24px;
  padding: 16px 0; border-bottom: 1px solid rgba(255,255,255,0.14);
  font-size: 22px; line-height: 1.45; align-items: start;
}
.responses-roster-name { font-weight: 600; color: var(--text); }
.responses-roster-answer { font-weight: 400; color: var(--text); }

/* TEST-ONLY assessment fill button (DEMO_TEST_FILL) — reuses the GSD&M draft button look
   (.legal-dev-fill) but parked lower-left like .legal-listen, so it doesn't reuse that button's
   absolute top-right pinning. Placement only; the button's own dashed look is unchanged. */
.assessment-fill { position: fixed; left: 43px; bottom: 28px; z-index: 30; }
.assessment-fill .legal-dev-fill { position: static; }

/* "Start Listening" — animated teal pill parked lower-left (proto listening button, Legal-scoped;
   NOT reusing awe's .btn-ghost, which is shared by Votes/Cards and styled differently). */
.legal-listen { position: fixed; left: 43px; bottom: 28px; }
.legal-listen-btn {
  font-family: inherit; font-size: 14px; font-weight: 500;
  border: none; border-radius: 24px; cursor: pointer;
  letter-spacing: 0.04em; transition: all 0.2s ease;
  background: var(--teal); color: #fff; opacity: 0.95;
  width: 156px; text-align: left; padding: 10px 12px 10px 22px;
}
.legal-listen-btn:hover { background: #3D8A85; }   /* proto --teal-deep, inlined so no base token is added/changed */
/* Listening state: center the label and reserve a fixed 3-dot zone so "Listening" never shifts. */
.legal-listen-btn[data-listening="true"] { text-align: center; padding-left: 22px; padding-right: 22px; }
.legal-lb-dots { display: inline-block; width: 0.9em; text-align: left; }
.legal-lb-d { visibility: hidden; }   /* all three always rendered; frame reveals the first N */
.legal-listen-btn[data-frame="1"] .legal-lb-d:nth-child(-n+1),
.legal-listen-btn[data-frame="2"] .legal-lb-d:nth-child(-n+2),
.legal-listen-btn[data-frame="3"] .legal-lb-d:nth-child(-n+3) { visibility: visible; }

/* ---- Legal: facilitator processing (proto .processing-view / .circle-loader / .processing-caption) ---- */
.legal-processing-view {
  position: relative;
  min-height: calc(100vh - var(--app-header-h));
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  padding: 24px 43px;
}
/* Teal "Legal" section title pinned top-left of the processing view (proto .section-title.left). */
.legal-section-title { color: var(--teal); font-size: 36px; font-weight: 300; text-align: left; margin: 0; }
.legal-processing-view .legal-section-title { position: absolute; top: 24px; left: 43px; }
.legal-circle-loader { width: 240px; height: 240px; animation: legal-spin 2.5s linear infinite; }
.legal-circle-loader svg { width: 100%; height: 100%; }
@keyframes legal-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.legal-processing-caption { margin-top: 32px; color: var(--muted); font-size: 16px; letter-spacing: 0.05em; }
/* Animated 3-dot ellipsis cycling inside the caption; fixed-width so "Processing" never shifts. */
.legal-processing-caption .legal-dot-anim {
  display: inline-block; width: 1.5em; text-align: left; vertical-align: baseline;
}
.legal-processing-caption .legal-dot-anim::after { content: '...'; animation: legal-processingDots 2s infinite; }
@keyframes legal-processingDots {
  0% { content: ''; } 25% { content: '.'; } 50% { content: '..'; } 75% { content: '...'; }
}

/* ---- Legal: operator "begin transcript capture" (proto .oper-cue-view; title pinned top-left) ---- */
.legal-op-view { max-width: 1100px; margin: 48px 0 0; padding: 0 43px; }
.legal-op-title { color: var(--teal); font-size: 36px; font-weight: 300; text-align: left; margin: 0; }
.legal-op-body { margin-top: 64px; max-width: 720px; }
.legal-op-headline { font-size: 34px; font-weight: 600; color: var(--text); margin: 0 0 16px; }
.legal-op-sub { font-size: 18px; line-height: 1.5; color: var(--muted); margin: 0; }

/* ---- Legal: contenteditable bullet editor (operator draft + facilitator final) ---- */
/* Bounded flex column (proto .review-view): title fixed at top, .review-synthesis scroll fills the
   middle, NEXT fixed at bottom. Replaces the old page-scroll model — the list scrolls inside itself. */
.legal-review-view {
  height: calc(100vh - var(--app-header-h));   /* viewport minus the (non-fixed) app-header */
  display: flex; flex-direction: column;
  padding: 24px 43px 72px;      /* 43px left/right gutter; 72px bottom clears the fixed NEXT */
  box-sizing: border-box;
}
/* position:relative so the pinned GSD&M dev-fill button anchors to this row's top-right (content edge). */
.legal-edit-head { position: relative; display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; }

/* GSD&M Content — proto .btn.dev-fill port, Legal-scoped. Pinned top-right of the editor
   header so it never floats with content/width. Does NOT reuse .btn/.btn-ghost. */
.legal-dev-fill {
  position: absolute; top: 0; right: 0;
  padding: 4px 10px;
  font-family: inherit; font-size: 11px; letter-spacing: 0.08em;
  border: 1px dashed var(--muted);
  background: transparent;
  color: var(--muted);
  opacity: 0.6;
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
  transition: opacity .15s ease, color .15s ease;
}
.legal-dev-fill:hover { opacity: 1; color: var(--text); }
.legal-eyebrow { color: var(--teal); font-size: 12px; font-weight: 700; letter-spacing: 0.5px; }
.legal-title { font-size: 26px; font-weight: 400; margin: 4px 0 0; letter-spacing: 1px; }
.gsdm-btn { white-space: nowrap; }

/* Scroll+fade container (proto .review-synthesis, root styles.css ~1398-1437), Legal-scoped.
   The list scrolls inside this container — not the browser window. */
.legal-review-view .review-synthesis {
  flex: 1 1 auto;
  min-height: 0;
  display: flex; flex-direction: column;
  justify-content: flex-start;
  max-width: none;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 30px 20px 0 0;   /* top spacing + right scrollbar gutter */
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.55) rgba(255,255,255,0.10);
  /* Fade the first/last 16px into the background so partial rows never clip mid-glyph. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
}
.legal-review-view .review-synthesis::-webkit-scrollbar { width: 8px; }
.legal-review-view .review-synthesis::-webkit-scrollbar-track { background: rgba(255,255,255,0.08); border-radius: 999px; }
.legal-review-view .review-synthesis::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.45); border-radius: 999px; }

/* Numbered list (proto .review-list block, ~1457-1550). */
.legal-review-view .review-list { list-style: none; counter-reset: review; margin: 0; padding: 0; max-width: none; width: 100%; }
.legal-review-view .review-list li {
  counter-increment: review;
  position: relative;
  padding-left: 56px;    /* "1." number gutter */
  margin: 0 0 24px;
  font-size: 24px;
  font-weight: 400;
  line-height: 1.45;
  color: var(--text);
}
.legal-review-view .review-list li::before {
  content: counter(review) ".";
  position: absolute; left: 0; top: 0;
  width: 40px; text-align: right;
  font-size: 24px; font-weight: 400; color: var(--text);
}
.legal-review-view .review-list li:last-child { margin-bottom: 0; }

/* Inline-editable bullet text (proto .review-bullet-text): cursor:text, teal-tint focus, placeholder. */
.legal-review-view .review-bullet-text {
  display: block;
  cursor: text;
  outline: none;
  border-radius: 3px;
  padding: 2px 6px;
  margin: -2px -6px;   /* preserve visual position despite the focus padding */
  transition: background 0.12s ease;
  word-break: normal;
  overflow-wrap: break-word;
}
.legal-review-view .review-bullet-text:hover { background: rgba(255,255,255,0.04); }
.legal-review-view .review-bullet-text:focus { background: rgba(93,189,181,0.10); }
.legal-review-view .review-bullet-text:empty::before {
  content: attr(data-placeholder);
  color: var(--muted);
  opacity: 0.55;
  pointer-events: none;
}

/* Forward "NEXT ▶" — proto .nav-next look, Legal-scoped (NOT the base .begin-btn). Positioned
   lower-right via the reused .begin-footer wrapper. Stays type="submit" → saves + advances.
   Disabled-when-empty dims to 0.4 (and does not go teal on hover). */
.legal-next-btn {
  background: transparent; border: 0; color: var(--text);
  font-family: inherit; font-size: 14px; font-weight: 500; letter-spacing: 0.06em;
  cursor: pointer; display: inline-flex; align-items: center; gap: 9px;
  transition: color .15s ease;
}
.legal-next-btn:not(:disabled):hover { color: var(--teal); }
.legal-next-btn:disabled { opacity: 0.4; cursor: default; }
.legal-next-arrow { font-size: 11px; }

/* ---- Legal facilitator FINAL — title only. The editor (list/rows/text) now uses the
   shared proto .review-list styling above, identical to the operator draft. The 820px cap
   and 17px bullet overrides from the prior round were removed (superseded by full-width 24px). ---- */
/* Title matches the Legal screen's effective override (36px/300 white, no border) — NOT the
   base .review-section-header (22px teal bordered), which the proto overrides on this screen. */
.legal-final-title { color: var(--text); font-size: 36px; font-weight: 300; letter-spacing: 0; margin: 0 0 12px; }

/* ---- Tools: two-category content (approved / unapproved) ----
   Ported from the root proto, merging its TWO separate blocks: the display rules at
   styles.css:1690-1734 and the editable-row rules at styles.css:6474-6530. The proto declared
   .tools-review-list twice (once in each block); it is declared ONCE here.

   Everything else on the Tools screens reuses the Legal chrome (.legal-review-view,
   .legal-edit-head, .legal-processing-view, .legal-op-view, .legal-next-btn), the same way
   Evidence, Usage and Friction do. Only this two-category content is new.

   ONE RULE FOR EVERY STATE, matching the proto. The proto's .tools-review-list is UNSCOPED
   (root styles.css:1712), so its read state and both editable states share identical metrics:
   3 columns, 30px/600 names, a 24px bullet gutter, break-inside:avoid. An earlier version of
   this block split those into --display and --edit variants with a smaller single-column
   editing surface; that split was a deviation, not something the proto does, and it has been
   collapsed. screen_tools.php still emits the --display / --edit modifier classes, but they no
   longer carry differing metrics and nothing styles them. The only thing that still differs
   between read and edit is the .tool-edit-* affordance layer below (flex row, hover-revealed
   remove, add button, bullet suppression), which the proto also has. */
.tools-review { width: 100%; max-width: 1100px; }
/* The cap above is DEAD on its own: this div carries both .tools-review and .review-synthesis,
   and .legal-review-view .review-synthesis (0,2,0) out-specifies .tools-review (0,1,0), so
   max-width:none was winning and the container ran full width (measured 1194px at a 1280px
   viewport). This rule matches that 0,2,0 specificity and sits later in the file, so source
   order settles it and the cap actually applies. 1100px on ALL THREE Tools screens: the proto
   caps its facilitator review at 1100px but its operator distill at 820px, and that 820px is a
   container-reuse artifact (.review-synthesis), not a design choice. At 30px type it yields
   ~225px columns that wrap "Microsoft Copilot" onto two lines, so it is deliberately not copied. */
.legal-review-view .tools-review { max-width: 1100px; }
.tools-review-heading {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.14em;
  color: var(--muted);
  text-transform: uppercase;
  margin: 0 0 18px;
}
.tools-review-divider {
  border: none;
  border-top: 1px solid rgba(255,255,255,0.25);
  margin: 36px 0;
}
/* The shared list, unscoped exactly as the proto has it (root styles.css:1712-1718).
   Declared once here; the proto re-declared it at its line 6515 with no columns, which is
   the duplicate this port drops. */
.tools-review-list {
  list-style: none;
  margin: 0 0 8px;
  padding: 0;
  columns: 3;
  column-gap: 64px;
}
/* Shared item metrics for read AND edit (proto styles.css:1719-1728). The "+ Add tool" row is
   the last <li> in the list, so it flows into the column layout and lands at the foot of the
   final column, which is what the proto does too. */
.tools-review-list li {
  position: relative;
  padding-left: 24px;    /* bullet gutter; retained on editable rows as alignment whitespace */
  margin: 0 0 16px;
  font-size: 30px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--text);
  break-inside: avoid;   /* never split a row across a column boundary */
}
.tools-review-list li::before {
  content: "\2022";
  position: absolute;
  left: 0;
  top: 0;
}

/* Editable row: tool name + a remove control revealed on hover, then one "+ Add tool" per section.
   These affordances are the ONLY thing that now differs between the read and edit states; the
   list metrics above are shared by both, as in the proto. */
.tool-edit-row { display: flex; align-items: center; gap: 10px; }
/* Drop the bullet glyph on editable rows and on the add row (proto styles.css:6513-6514). Newly
   required: while the bullet was scoped to --display it never reached these rows, but the shared
   .tools-review-list li::before above now does. The 24px gutter deliberately stays, so editable
   rows keep the same left edge as the bulleted read state. */
.tool-edit-row::before,
.tool-edit-addrow::before { content: none !important; }
.tool-edit-text {
  flex: 1;
  /* A flex item defaults to min-width:auto, i.e. it refuses to shrink below its longest
     unbreakable word. In a 3-column layout at narrow viewports that pushed long tool names
     straight out of the column (measured: a 20-character word needed 278px in a 195px column,
     overflowing by 102px). min-width:0 lets the item shrink; overflow-wrap:anywhere lets the
     word itself break, and unlike break-word it also lowers the min-content contribution, which
     is what actually removes the overflow rather than just hiding it. */
  min-width: 0;
  overflow-wrap: anywhere;
  cursor: text;
  outline: none;
  border-radius: 3px;
  /* Proto parity (root styles.css:6484 uses padding: 2px 0). The build previously carried
     padding:2px 6px with a compensating margin:-2px -6px, ported from Legal's bullet editor;
     that made every field 12px wider than the proto's for no gain here. Both are gone. */
  padding: 2px 0;
  transition: background 0.12s ease;
}
.tool-edit-text:hover { background: rgba(255,255,255,0.04); }
.tool-edit-text:focus { background: rgba(93,189,181,0.10); }
.tool-edit-text:empty::before {
  content: attr(data-placeholder);
  color: var(--muted);
  opacity: 0.55;
  pointer-events: none;
}
.tool-edit-remove {
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
  opacity: 0;
  transition: opacity 0.15s ease, color 0.15s ease;
}
.tool-edit-row:hover .tool-edit-remove,
.tool-edit-remove:focus { opacity: 0.6; }
.tool-edit-remove:hover { opacity: 1; color: var(--red); }
.tool-edit-addrow { margin-top: 6px; }
.tool-edit-add {
  background: transparent;
  border: 1px dashed var(--muted);
  color: var(--teal);
  border-radius: 8px;
  padding: 5px 12px;
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.tool-edit-add:hover { border-color: var(--teal); background: rgba(93,189,181,0.08); }

/* ---- Error banner (rejected save: no title / no bullets) ---- */
.err-banner {
  max-width: 900px;
  margin: 0 auto 18px;
  border: 1px solid var(--red);
  border-radius: 8px;
  background: rgba(252,35,35,0.08);
  color: var(--red);
  padding: 10px 14px;
  font-size: 14px;
}

/* ---- Enter Cards: header row (name/prompt + test-fill button) ---- */
/* 43px left gutter aligns the header text to the logo (.app-header left padding = 43px).
   padding-left (not margin) so the space-between fill button stays anchored at the right edge. */
.cards-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; padding-left: 43px; padding-right: 43px; }
/* A card with a description but no title is flagged until a title is added. */
.entry-card.card-invalid { box-shadow: 0 0 0 1px var(--red) inset; border-radius: 8px; }

/* ---- Workflow Votes: PARTICIPANT (ported from the proto P2_S8_WORKFLOW_VOTE_PART) ----
   Header block (role / category / instruction / counter) is left-aligned at the 43px logo
   gutter; only the card grid centres. Committed submit (.votes-submit + .btn) is retained —
   the proto's .p2-vote-submit-row is deliberately NOT ported (it conflicts with what's
   committed, and the submit path stays untouched). ---- */
.p2-vote-view {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-height: 0;
  /* Left 43px aligns the header block to the logo; right 43px keeps the box symmetric so the
     auto-centred grid stays on the viewport centreline. Matches the committed .p2-wfvote-view. */
  padding: 24px 43px 0;
  /* The proto's --participant-color, sourced from this build's committed per-seat --seat var
     (.seat-participant_* below), set via the seat class on this container. Teal fallback. */
  --participant-color: var(--seat, var(--teal));
}
/* Token mapping: proto --fg → --text, --fg-dim → --muted (neither exists in this build). */
.p2-vote-role { color: var(--text); font-size: 18px; font-weight: 500; letter-spacing: 0.05em; margin: 0; }
.p2-vote-instruction { color: var(--muted); font-size: 14px; margin: 0 0 8px; }
.p2-wfvote-header--part { font-size: 16px; margin-top: -4px; }
.p2-wfvote-counter {
  margin: 0 0 14px;
  font-size: 12px;
  font-weight: 500;
  color: var(--teal);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.p2-vote-row {
  flex: 1 1 auto;
  min-height: 0;
  /* Hard height ceiling so the grid scrolls INTERNALLY rather than the page. */
  max-height: calc(100vh - 320px);
  /* Centred rows of up to 3; the container caps at 3 cards + gaps so wrap forces 3 per row
     and a short last row centres beneath. Card count is variable per category. */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  max-width: calc(3 * 300px + 2 * 16px + 24px);
  margin-left: auto;
  margin-right: auto;
  gap: 16px;
  align-content: start;
  align-items: start;
  /* Vertical scroll only — never horizontal. 20px right padding gutters the scrollbar. */
  overflow-x: hidden;
  overflow-y: auto;
  padding: 4px 20px 16px 2px;
  /* Grid-scoped scrollbar; does NOT touch the global scrollbar rules. */
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.55) rgba(255,255,255,0.10);
}
.p2-vote-row::-webkit-scrollbar {
  width: 8px;
}
.p2-vote-row::-webkit-scrollbar-track {
  background: rgba(255,255,255,0.10);
  border-radius: 999px;
  margin: 4px 0;
}
.p2-vote-row::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,0.55);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: padding-box;
}
.p2-vote-row::-webkit-scrollbar-thumb:hover {
  background: rgba(255,255,255,0.75);
  background-clip: padding-box;
}
.p2-vote-row::-webkit-scrollbar-corner {
  background: transparent;
}

/* Teal borders in ALL states, including .is-ranked — only the rank badge carries seat colour,
   because it is information (this participant's own private picks), not styling. The proto's
   per-owner --card-color is dead plumbing (never read) and is NOT ported. */
.p2-vote-row-card {
  flex: 0 0 300px;
  width: 300px;
  /* Height fixed so every card is identical regardless of text length; the description
     scrolls internally rather than growing the card. */
  height: 130px;
  background: #000;
  color: #ffffff;
  border: 2px solid var(--teal);
  border-radius: 8px;
  padding: 14px 16px;
  position: relative;
  transition: all 0.15s ease;
  min-width: 0;
  box-sizing: border-box;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  text-align: center;
  /* The proto's hover rule is scoped to [data-cat-id] (category cards), so its workflow cards
     get no pointer despite being clickable — a proto gap, not intent. Pointer retained here
     (committed demo behaviour); the [data-cat-id] hover is not ported. */
  cursor: pointer;
}
.p2-vote-row-card .vote-check { position: absolute; opacity: 0; pointer-events: none; }
.p2-vote-row-card.is-ranked {
  /* Ranked: 2px teal border (consistent thickness) + teal tint inside the dark card so the
     pick reads as confirmed. The rank badge is the primary "confirmed" signal. */
  border: 2px solid var(--teal);
  background: color-mix(in srgb, var(--teal) 12%, #000);
}
.p2-vote-row-card-title {
  color: #ffffff;
  font-size: 15px;
  font-weight: 700;
  margin-bottom: 6px;
  letter-spacing: 0.02em;
  /* DIVERGENCE from the proto (David, 2026-07-16): the proto reserves padding-right: 32px only,
     which with centred text pushes the title left-of-centre and wraps it early. Symmetric 32px
     centres it truly and still clears the badge. Accepted cost: long titles wrap a line sooner. */
  padding: 0 32px;
}
.p2-vote-row-card-desc {
  color: rgba(255,255,255,0.70);
  font-size: 13px;
  font-weight: 400;
  line-height: 1.45;
  /* Escape hatch for runaway descriptions: the desc takes the remaining card height and SCROLLS
     inside it, so nothing is lost and the card stays a fixed 130px (~4 lines). The scrollbar
     appears only when the description actually overflows. */
  flex: 1 1 auto;
  width: 100%;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(89,187,187,0.6) transparent;
}
.p2-vote-row-card-desc::-webkit-scrollbar { width: 4px; }
.p2-vote-row-card-desc::-webkit-scrollbar-thumb {
  background: rgba(89,187,187,0.6);
  border-radius: 999px;
}
/* Pick badge: the VIEWING participant's own seat colour, never teal. Sits INSIDE the card so
   it is never clipped; dark glyph for contrast across the full seat palette. Shown via the
   checkbox state (the proto renders it conditionally in JS — same result, and it keeps the
   committed native-form submit semantics intact). */
.p2-vote-row-card-rank {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--participant-color);
  color: #000;
  font-size: 12px;
  font-weight: 600;
  display: none;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 6px rgba(0,0,0,0.4);
}
.p2-vote-row-card.is-ranked .p2-vote-row-card-rank { display: flex; }

.votes-submit { text-align: center; margin-top: 26px; }

/* ---- Workflow Votes: FACILITATOR monitor (ported from the proto P2_S8_WORKFLOW_VOTE_FAC).
   Facilitator-only; the participant .p2-vote-row/.p2-vote-row-card above are untouched. ---- */

/* Container view. */
.p2-wfvote-view {
  display: flex;
  flex-direction: column;
  gap: 0;
  flex: 1 1 auto;
  min-height: 0;
  /* Left 43px aligns the header to the logo (.app-header left padding = 43px). Right also
     43px — deliberate: it keeps the box symmetric so the centered grid stays centered on the
     viewport, and matches the committed 43px gutter (.cards-head, .legal-processing-view).
     Top 24px and bottom 0 are the proto's, kept as-is; the tracker and NEXT are position:fixed,
     so no bottom padding is needed. */
  padding: 24px 43px 0;
  overflow: hidden;
}

/* "Workflow Category: NAME" — plain text, NO pill or chip wrapper. The category name is
   plain foreground, NOT teal. Token mapping: the proto's --fg (#ffffff) is this build's
   --text; the proto's --fg-dim (rgba(255,255,255,0.65)) maps to this build's committed dim
   token --muted (#CCCCCC), as used by .status-line / .p2-vote-instruction. --fg/--fg-dim
   are not defined here. */
.p2-wfvote-header {
  margin: 0 0 8px;
  font-family: 'Raleway', sans-serif;
  font-size: 18px;
  font-weight: 400;
  color: var(--text);
  letter-spacing: 0;
}
.p2-wfvote-cat-label {
  color: var(--muted);
  margin-right: 8px;
  font-weight: 400;
}

/* Section subhead (proto .p2-wfvote-subhead). Restored 2026-07-16; the earlier "subhead
   removed" divergence is withdrawn. Every value is verbatim from the proto except colour:
   KNOWN TOKEN-LEVEL DIVERGENCE — the proto's --fg-dim (rgba(255,255,255,0.65)) is undefined
   in this build and would render white, so this uses --muted (#CCCCCC, ~80% white), matching
   .p2-wfvote-cat-label. Slightly brighter than the proto by design; consistency with the
   build's committed dim token beats inventing a new one. */
.p2-wfvote-subhead {
  margin: 0 0 18px;
  font-size: 14px;
  font-weight: 400;
  color: var(--muted);
  line-height: 1.45;
  max-width: 880px;
}

.p2-vote-monitor-grid {
  /* Hard height ceiling so the grid scrolls INTERNALLY rather than letting the page
     scroll. Subtracts header + title + footer + vertical padding from the viewport. */
  flex: 1 1 auto;
  min-height: 0;
  max-height: calc(100vh - 240px);
  /* Centered rows of up to 3, wrapping; card count is variable. */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  max-width: calc(3 * 300px + 2 * 16px + 24px);
  margin-left: auto;
  margin-right: auto;
  gap: 16px;
  align-content: start;
  align-items: stretch;
  /* Vertical scroll only — never horizontal. */
  overflow-x: hidden;
  overflow-y: auto;
  /* 20px right padding creates a gutter between the cards and the scrollbar. */
  padding: 4px 20px 16px 2px;
  /* Grid-scoped scrollbar; does NOT touch the global scrollbar rules. */
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.55) rgba(255,255,255,0.10);
}
.p2-vote-monitor-grid::-webkit-scrollbar {
  width: 8px;
}
.p2-vote-monitor-grid::-webkit-scrollbar-track {
  background: rgba(255,255,255,0.10);
  border-radius: 999px;
  margin: 4px 0;
}
.p2-vote-monitor-grid::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,0.55);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: padding-box;
}
.p2-vote-monitor-grid::-webkit-scrollbar-thumb:hover {
  background: rgba(255,255,255,0.75);
  background-clip: padding-box;
}
.p2-vote-monitor-grid::-webkit-scrollbar-corner {
  background: transparent;
}

/* Uniformly teal: the convergence/evaluation framing carries no participant identity.
   (The proto's per-owner --card-color is dead plumbing — nothing reads it. Not ported.) */
.p2-vote-monitor-card {
  flex: 0 0 300px;
  width: 300px;
  height: 130px;
  background: #000;
  color: #ffffff;
  border: 2px solid var(--teal);
  border-radius: 8px;
  padding: 14px 16px;
  position: relative;
  min-width: 0;
  box-sizing: border-box;
  overflow: hidden;
  cursor: default;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.p2-vote-monitor-card-title {
  color: #ffffff;
  font-size: 15px;
  letter-spacing: 0.02em;
}

/* Breathing room between the top content and the grid (David, 2026-07-16). 14px on top of
   the subhead's own 18px bottom margin and the grid's 4px padding-top = 36px total. Scoped
   here so the ported .p2-vote-monitor-grid / .p2-wfvote-subhead rules stay verbatim. Fits
   the max-height budget's ~20px breathing allowance, so no max-height change is needed. */
#p2-wfvote-fac-grid {
  margin-top: 14px;
}

/* Title-only shorthand: no description, so the lone title is vertically centered and bold. */
#p2-wfvote-fac-grid .p2-vote-monitor-card {
  justify-content: center;
}
#p2-wfvote-fac-grid .p2-vote-monitor-card-title {
  font-weight: 700;
  margin-bottom: 0;
}

/* ============================================================
   Category Ranking (P2 `category_rank` stop) — the category-only rules absent from the
   live build. The .p2-vote-view / .p2-vote-row / .p2-vote-row-card / .p2-vote-monitor-*
   families above are REUSED; only the token row, the drop-target state, the category card
   variant, its member-workflow list, and this screen's taller-bucket sizing are new.
   Token mapping vs. the proto: --fg → --text, --fg-dim → --muted (neither exists here).
   ============================================================ */

/* Participant token row (proto .p2-vote-tokens / .p2-vote-token). One draggable token per rank; the
   token colour comes from --p-color, set inline by category_rank.js from the seat's --seat var. */
.p2-vote-tokens {
  display: flex;
  gap: 10px;
  align-items: center;
}
.p2-vote-token {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  /* Neutral fallback only — no teal — so the token is fully tied to participant identity via --p-color. */
  --p-color: rgba(255, 255, 255, 0.55);
  border: 2px solid var(--p-color);
  background: transparent;
  color: var(--p-color);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: grab;
  transition: all 0.15s ease;
}
.p2-vote-token:hover:not(:disabled) {
  background: var(--p-color);
  color: #000;
}
.p2-vote-token.is-selected {
  background: var(--p-color);
  color: #000;
  box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.15);
}
.p2-vote-token.is-used {
  /* Reduced opacity but keeps colour identity (dashed outline still shows participant colour). */
  opacity: 0.3;
  cursor: not-allowed;
  border-style: dashed;
  background: transparent;
  color: var(--p-color);
}
.p2-vote-token.dragging {
  opacity: 0.5;
}

/* Drop target while a token/badge is dragged over a category card (proto .p2-vote-row-card.is-drop-target). */
.p2-vote-row-card.is-drop-target {
  border: 2px solid var(--teal);
  background: color-mix(in srgb, var(--teal) 22%, #000);
}

/* Category card variant (proto .p2-vote-monitor-card--category): stronger headline weight so
   categories scan quickly on the facilitator board. Border treatment is the standard teal. */
.p2-vote-monitor-card--category {
  border-color: var(--teal);
}
.p2-vote-monitor-card--category .p2-vote-monitor-card-title {
  font-weight: 700;
  font-size: 17px;
  letter-spacing: 0.01em;
}
/* The monitor card's description slot (proto .p2-vote-monitor-card-desc) — absent from the live
   build, which only ever rendered title-only monitor cards. It holds the member-workflow list and
   SCROLLS inside the fixed-height card if the list overflows, so nothing is lost. Only the category
   board renders a desc, so this does not touch the title-only #p2-wfvote-fac-grid cards. */
.p2-vote-monitor-card-desc {
  color: rgba(255,255,255,0.70);
  font-size: 13px;
  font-weight: 400;
  line-height: 1.45;
  flex: 1 1 auto;
  width: 100%;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(89,187,187,0.6) transparent;
}
.p2-vote-monitor-card-desc::-webkit-scrollbar { width: 4px; }
.p2-vote-monitor-card-desc::-webkit-scrollbar-thumb {
  background: rgba(89,187,187,0.6);
  border-radius: 999px;
}

/* Member-workflow list inside a category card (proto .p2-vote-workflow-list). Tight bullets; the
   parent desc scrolls on overflow. Shared by the facilitator board and the participant grid cards. */
.p2-vote-workflow-list {
  margin: 0;
  padding-left: 16px;
  list-style: disc;
}
.p2-vote-workflow-list li {
  margin: 0 0 3px 0;
  line-height: 1.35;
}

/* Sizing — this screen's buckets are ~60% taller than the reused 130px card (→ 208px), SCOPED to
   this screen's grid ids so the workflow-vote grids are untouched. */
#p2-catrank-part-grid .p2-vote-row-card { height: 208px; }
#p2-catrank-fac-grid .p2-vote-monitor-card { height: 208px; }

/* Grid layout — BOTH role grids, so facilitator + participant stay consistent.
   Wider max-width: enough for THREE 300px columns + the larger gap below + the grid's 22px
   horizontal padding + a full scrollbar's width of slack, so a transient vertical scrollbar can
   never steal the 3rd column. With the old tight cap (2px slack) any scrollbar dropped the grid to
   2 columns → more rows → permanent scroll; the roomier cap lets 3 columns reflow in as soon as the
   width allows and the scroll fall away the moment it is not needed. Gap between cards enlarged. */
#p2-catrank-fac-grid,
#p2-catrank-part-grid {
  gap: 24px;
  max-width: calc(3 * 300px + 2 * 24px + 46px);
}
/* Header → grid breathing room, tuned per role to land on the same visible gap: the facilitator grid
   sits directly under the title (container gap 0), the participant grid sits under the token row in a
   gap:16px flex column, so its own margin is smaller. The max-height budgets are re-tuned to keep the
   taller cards scrolling INSIDE the grid rather than pushing the page / fixed nav. */
#p2-catrank-fac-grid  { margin-top: 36px; max-height: calc(100vh - 286px); }
#p2-catrank-part-grid { margin-top: 20px; max-height: calc(100vh - 336px); }

/* Card interiors — BOTH roles. Title stays centred (the card's text-align); more space beneath it;
   the member-workflow list left-aligns with its bullet dots and reads at a larger size. */
#p2-catrank-fac-grid  .p2-vote-monitor-card-title,
#p2-catrank-part-grid .p2-vote-row-card-title { margin-bottom: 12px; }
/* Card title font +1px each role (facilitator 17→18, participant 15→16). */
#p2-catrank-fac-grid  .p2-vote-monitor-card-title { font-size: 18px; }
#p2-catrank-fac-grid  .p2-vote-monitor-card-desc,
#p2-catrank-part-grid .p2-vote-row-card-desc { text-align: left; }
/* Workflow-list item font +1px (15→16), both roles. */
#p2-catrank-fac-grid  .p2-vote-workflow-list,
#p2-catrank-part-grid .p2-vote-workflow-list { font-size: 16px; }
/* Bullet dots: the default `disc` marker is tiny, and on the participant card it was not rendering
   at all. Replace it with an explicit custom dot (list-style:none + a sized ::before) so a
   noticeably larger bullet renders identically on BOTH roles, independent of any marker clipping in
   the scrolling desc. currentColor keeps the dot the list's own text colour. */
#p2-catrank-fac-grid  .p2-vote-workflow-list,
#p2-catrank-part-grid .p2-vote-workflow-list { list-style: none; padding-left: 0; }
#p2-catrank-fac-grid  .p2-vote-workflow-list li,
#p2-catrank-part-grid .p2-vote-workflow-list li { position: relative; padding-left: 16px; }
#p2-catrank-fac-grid  .p2-vote-workflow-list li::before,
#p2-catrank-part-grid .p2-vote-workflow-list li::before {
  content: ""; position: absolute; left: 2px; top: 0.5em;
  width: 7px; height: 7px; border-radius: 50%; background: currentColor;
}

/* Participant rank badge — noticeably larger; the title's horizontal padding grows to match so the
   (still centred) title clears the bigger badge. */
#p2-catrank-part-grid .p2-vote-row-card-rank { width: 36px; height: 36px; font-size: 16px; }
#p2-catrank-part-grid .p2-vote-row-card-title { padding: 0 48px; font-size: 16px; }

/* Editor ↔ thank-you flip toggle (category_rank.js). The `hidden` attribute is INERT on these two
   containers because both set `display` in authored CSS, which beats the UA `[hidden]{display:none}`.
   So the flip toggles this class instead: the compound selectors are (0,2,0), beating the (0,1,0)
   .p2-vote-view / .status-view base rules regardless of source order. */
.p2-vote-view.p2-catrank-hidden,
.status-view.p2-catrank-hidden { display: none; }

/* ---- Workflow Votes: facilitator overlays ---- */
.overlay {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.72);
  display: flex; align-items: center; justify-content: center;
  z-index: 50;
}
.overlay[hidden] { display: none; }
.overlay-card {
  background: #0d0d0d;
  border: 1px solid var(--line);
  border-radius: 14px;
  width: 420px; max-width: calc(100vw - 40px);
  padding: 20px 22px;
}
.overlay-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; }
.overlay-head h2 { color: var(--teal); font-size: 17px; font-weight: 600; margin: 0; }
.overlay-x { background: none; border: 0; color: var(--muted); font-size: 22px; line-height: 1; cursor: pointer; }
.overlay-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }

/* Missing ("Still waiting on") modal — ported from the prototype's missing-modal CSS (styles.css
   6419-6464). GLOBAL, not scoped to one screen: both the Category Ranking and Workflow Votes missing
   modals want this identical light-card appearance (David's ruling), so these rules are shared exactly
   as the sibling loops share their chrome. Tokens use the PROTOTYPE's ACTUAL values, NOT this build's
   set: the prototype's --border is rgba(255,255,255,0.15) and --fg-dim is rgba(255,255,255,0.65) — both
   translucent white, so on the #ffffff card the sub copy and the row borders render INVISIBLE, exactly
   as the prototype does. (An earlier slice established that translating these to --line/--muted, which
   are opaque, makes them visible and breaks the appearance.) --card-fg / --teal exist as-is. Card width
   is written .modal-card.missing-card, not the prototype's bare .missing-card: this block sits ABOVE
   .modal-card here, so the extra class buys the specificity the prototype got from source order. */
.modal-card.missing-card { max-width: 460px; }
.missing-title { color: var(--teal); }
.missing-sub {
  margin: 0 0 16px;
  font-size: 14px;
  color: rgba(255, 255, 255, 0.65);   /* prototype --fg-dim: invisible on the white card */
  text-align: center;
  line-height: 1.4;
}
.missing-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.missing-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border: 1px solid rgba(255, 255, 255, 0.15);   /* prototype --border: invisible on the white card */
  border-radius: 10px;
  font-size: 15px;
  color: var(--card-fg);
}
.missing-row.is-proxy {
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.missing-row.is-proxy:hover {
  border-color: var(--teal);
  background: rgba(93, 189, 181, 0.08);
}
.missing-row-name { flex: 1; color: var(--card-fg); font-weight: 500; }
.missing-row-cue {
  font-size: 12px;
  color: var(--teal);
  letter-spacing: 0.02em;
}
.missing-foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
}
/* Per-row roster dot: the prototype fills .completion-dot inline with the participant's colour; this
   build has no CSS colour to inline (the missing endpoints return a color_id), so the dot carries a
   seat-<id> class and its fill flows from the committed --seat var — scoped to the missing card so the
   global .completion-dot (the anonymous GRAY tracker dot, David's locked standard) stays untouched. The
   border keeps the base gray, exactly as the prototype leaves it. */
.missing-card .completion-dot { background: var(--seat, var(--teal)); }
/* Keep-waiting (non-primary footer button): the live .btn base fills teal, but the prototype's plain
   .btn is light grey. Scope a grey fill to the missing modal's non-primary footer button so global .btn
   (and the Proceed .btn.primary) are untouched — the same treatment used on the proxy modal. */
.missing-card .modal-foot .btn:not(.primary) {
  background: #e8e8e8;
  color: #1a1a1a;
}

.proxy-list { max-height: 46vh; overflow-y: auto; }
.proxy-option {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; margin-bottom: 8px;
  border: 1px solid var(--line); border-radius: 9px; cursor: pointer;
}
.proxy-option .proxy-check { width: 16px; color: var(--teal); opacity: 0; }
.proxy-option.is-picked { border-color: var(--teal); background: rgba(89,187,187,0.12); }
.proxy-option.is-picked .proxy-check { opacity: 1; }
.proxy-option-label { font-size: 14px; }

/* Proxy ranking modal (Category Ranking) — ported from the prototype's proxy modal CSS
   (styles.css 6535-6644). SCOPED under .proxy-card so the live Workflow-Votes proxy (which uses
   .overlay-card and shares the .proxy-option* class names) is left untouched.
   Tokens use the PROTOTYPE's ACTUAL values, NOT this build's set: the prototype's --border is
   rgba(255,255,255,0.15) and --fg-dim is rgba(255,255,255,0.65) — both translucent white, so on the
   #ffffff card the sub copy, the divider (text + dashed lines), the empty rank circles, and the
   unranked/unpicked row borders render INVISIBLE, exactly as the prototype does. (An earlier revision
   translated these to --line/--muted, which are opaque and made all of that visible.) The sub copy and
   divider stay in the DOM and are set in JS unconditionally — the prototype hides them by colour, not
   by a condition, so this matches it without a JS change. --card-fg / --teal exist as-is.
   (The card-width rule is written .modal-card.proxy-card, not the prototype's bare .proxy-card: this
   block sits ABOVE .modal-card here, so the extra class buys the specificity the prototype got from
   source order — otherwise .modal-card's max-width:700px would win and the card wouldn't narrow.) */
.modal-card.proxy-card { max-width: 480px; }
.proxy-card .proxy-title { color: var(--teal); }
.proxy-card .proxy-sub {
  margin: 0 0 16px;
  font-size: 14px;
  color: rgba(255, 255, 255, 0.65);   /* prototype --fg-dim: invisible on the white card */
  text-align: center;
  line-height: 1.4;
}
.proxy-card .proxy-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 50vh;
  overflow-y: auto;
}
.proxy-card .proxy-option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  border: 1px solid rgba(255, 255, 255, 0.15);   /* prototype --border: invisible on the white card */
  border-radius: 10px;
  font-size: 15px;
  color: var(--card-fg);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.proxy-card .proxy-option:hover { border-color: var(--teal); }
.proxy-card .proxy-option.is-picked {
  border-color: var(--teal);
  background: rgba(93, 189, 181, 0.10);
}
.proxy-card .proxy-option-label { flex: 1; }
.proxy-card .proxy-rank {
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, 0.15);   /* prototype --border: invisible on the white card */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 600;
  color: var(--card-fg);
}
.proxy-card .proxy-option.is-picked .proxy-rank {
  border-color: var(--teal);
  background: var(--teal);
  color: #fff;
}
.proxy-card .proxy-check {
  width: 20px;
  flex: 0 0 auto;
  text-align: center;
  color: var(--teal);
  font-weight: 700;
}
.proxy-card .proxy-foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
}
.proxy-card .proxy-drag { cursor: grab; }
.proxy-card .proxy-drag.is-dragging { opacity: 0.4; }
.proxy-card .proxy-option.is-unranked {
  opacity: 0.55;
  border-style: dashed;
}
.proxy-card .proxy-option.is-unranked .proxy-rank {
  border-color: rgba(255, 255, 255, 0.15);   /* prototype --border: invisible on the white card */
  background: transparent;
}
.proxy-card .proxy-drag-handle {
  flex: 0 0 auto;
  color: rgba(255, 255, 255, 0.65);   /* prototype --fg-dim: invisible on the white card */
  font-size: 13px;
  letter-spacing: -2px;
  cursor: grab;
}
.proxy-card .proxy-cutoff {
  display: flex;
  align-items: center;
  text-align: center;
  margin: 4px 0;
  color: rgba(255, 255, 255, 0.65);   /* prototype --fg-dim: invisible on the white card */
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.proxy-card .proxy-cutoff::before,
.proxy-card .proxy-cutoff::after {
  content: "";
  flex: 1;
  border-top: 1px dashed rgba(255, 255, 255, 0.15);   /* prototype --border: invisible on the white card */
}
.proxy-card .proxy-cutoff span { padding: 0 10px; }
.proxy-card .proxy-option.is-disabled {
  opacity: 0.35;
  cursor: default;
  pointer-events: none;
}
/* Cancel (non-primary footer button): the live .btn base fills teal, but the prototype's plain .btn is
   a light-grey button. Scope a grey fill to the modal's non-primary footer button so global .btn (and
   the Record vote .btn.primary) are untouched. */
.proxy-card .modal-foot .btn:not(.primary) {
  background: #e8e8e8;
  color: #1a1a1a;
}

/* ---- bad-link / error ---- */
.error-title { color: var(--red); }

/* ---- Presence dots (facilitator Begin screen): anonymous gray dots, no label/number ---- */
/* Lower-left dot row. Placement is MEASURED, not by eye (David, 2026-07-16), and is shared
   verbatim with the Cards/Votes trackers (#p2-input-tracker, #p2-wfvote-tracker above).
     left:   43px — aligns to the logo (.app-header left padding).
     bottom: 35px — centres the dots on the NEXT/BEGIN triangle's INK centre, which is the
             ruled anchor. Derivation: the ▶ glyph (U+25B6, .begin-arrow, 11px) renders its
             ink centre 40.65px above the viewport bottom on every screen carrying the
             control; the dot box is 11px, so half is 5.5px; 40.65 - 5.5 = 35.15 ≈ 35px.
   SUPERSEDES the old 32px "+4px over BEGIN's 28px to center the row on BEGIN's text": the
   triangle's ink centre and the text's ink centre are 0.83px apart, and 32px centred on
   NEITHER (it sat 3.15px below the triangle, 2.32px below the text). The control does not
   move — .begin-footer stays at bottom:28px; it is the anchor. */
.presence-dots { display: flex; gap: 8px; justify-content: flex-start; flex-wrap: wrap;
                 position: fixed; left: 43px; bottom: 35px; }
.dot-joined { background: #888; }   /* neutral gray fill — deliberately not a success or participant colour */

/* ---- Begin / waiting screen (P1_START twins) ---- */
.begin-view  { display: flex; flex-direction: column; align-items: center; text-align: center; }
.begin-title { color: var(--teal); font-size: 64px; font-weight: 600; line-height: 1.1; margin: 0; }
.begin-sub   { color: var(--text); font-size: 38px; font-weight: 500; margin: 4px 0 0; }

/* BEGIN — bottom-right, arrow style (not a pill). action=advance wiring unchanged.
   .begin-footer is the lower-right nav CLUSTER anchor: a right-aligned flex row so the
   facilitator ◀ BACK | NEXT ▶ pair (ported from the proto's .footer-actions) sits as one
   unit. NEXT is the rightmost child, so its ink centre stays at the ruled anchor whether
   or not BACK is present — the presence-dot measurement above is unaffected. With a lone
   control (Begin, legal_q, participant/operator screens) the row has a single child and
   renders exactly as before. */
.begin-footer { position: fixed; right: 43px; bottom: 28px; margin: 0; display: flex; align-items: center; }
.begin-footer form { margin: 0; display: inline-flex; }
.begin-btn    { background: transparent; border: 0; color: var(--text); font-family: inherit;
                font-size: 15px; font-weight: 600; letter-spacing: 0.06em; cursor: pointer;
                display: inline-flex; align-items: center; gap: 9px; text-decoration: none; transition: color .15s ease; }
.begin-btn:hover { color: var(--teal); }
.begin-arrow  { font-size: 11px; }

/* Facilitator ◀ BACK — the left half of the nav cluster (proto .btn.nav-back). Matched to
   .begin-btn (the build's forward control it pairs with) so the two read as one cluster;
   the proto's own nav-back is 14px/500, but this ports INTO the build's 15px/600 NEXT. */
.nav-back      { background: transparent; border: 0; color: var(--text); font-family: inherit;
                 font-size: 15px; font-weight: 600; letter-spacing: 0.06em; cursor: pointer;
                 display: inline-flex; align-items: center; gap: 9px; text-decoration: none; transition: color .15s ease; }
.nav-back:hover { color: var(--teal); }
.nav-back-arrow { font-size: 11px; }
/* Thin separator between BACK and NEXT — proto .nav-divider verbatim (1px × 18px, half-opacity,
   6px each side). Only emitted when both controls are present; Back-alone (complete) omits it. */
.nav-divider   { display: inline-block; width: 1px; height: 18px; background: var(--text);
                 opacity: 0.5; margin: 0 6px; }

/* ---- Seat colours: per-seat CSS vars (--seat), reusable in the design pass ---- */
.seat-participant_blue   { --seat: #2979FF; }
.seat-participant_green  { --seat: #00E676; }
.seat-participant_orange { --seat: #FF6D00; }
.seat-participant_pink   { --seat: #FF4081; }
.seat-participant_yellow { --seat: #FFD60A; }
.seat-participant_purple { --seat: #7C4DFF; }

/* =====================================================================
   PHASE 1 ASSESSMENT (p1_assessment stop) — participant view
   Ported from the proto (root styles.css) for the P1_S1_PROMPT_PART
   markup: name eyebrow + question + interactive slider + three pills +
   Submit, plus the shared input modal. var(--fg) remapped to this
   build's var(--text). The container/footer are adapted to this build's
   full-page render (no .app/.screen wrapper); the rest is a faithful
   byte port. Behaviour lives in assets/app.js (guarded by
   #participant-slider). See screen_assessment.php for the four
   ratified divergences from the proto.
   ===================================================================== */

/* Full-height stage for the assessment (this build renders a whole page, so there is
   no .app/.screen flex parent — this supplies it). Submit now lives in the natural flow
   inside .participant-input, so no bottom footer band is reserved. */
.assessment-view {
  min-height: calc(100vh - var(--app-header-h));
  display: flex;
  flex-direction: column;
  padding: 0 48px 48px;
}

/* ---- name eyebrow (proto .role-tag) ---- */
.role-tag {
  color: var(--teal);
  font-size: 22px;
  font-weight: 500;
  letter-spacing: 0.05em;
  margin: 0 0 24px;
}

/* ---- participant input block (proto .participant-input) ---- */
.participant-input {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding-top: 20px;
  min-height: 0;
}
.participant-input .role-tag { align-self: flex-start; }
.participant-input .prompt-text {
  /* proto participant question — size it here so it does not inherit this
     build's 52px facilitator .prompt-text. */
  font-size: 28px;
  max-width: 720px;
  margin: 16px 0 0;
}

/* ---- slider (proto .scale / .scale-track / .scale-marker / .scale-labels) ---- */
.scale {
  position: relative;
  width: 90%;
  max-width: 900px;
  margin: 48px auto 32px;
  height: 100px;
}
.scale-track {
  position: absolute;
  top: 52px;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--text);
}
.scale-marker {
  position: absolute;
  top: 44px;
  width: 1px;
  height: 16px;
  background: var(--text);
}
.scale-labels span {
  position: absolute;
  top: 68px;
  transform: translateX(-50%);
  font-size: 14px;
  color: var(--text);
  font-weight: 400;
  white-space: nowrap;
}
.scale.interactive { cursor: pointer; user-select: none; touch-action: none; }
.participant-pointer {
  position: absolute;
  top: 20px;
  font-size: 18px;
  color: var(--text);
  transform: translateX(-50%);
  pointer-events: none;
  left: 50%;
  transition: none;
}
/* DIVERGENCE #4 (build-only; not in the proto): an untouched pointer reads as
   provisional — ghosted — and snaps to full opacity on the first touch. */
.participant-pointer.ghost { opacity: 0.3; }

/* ---- pills (proto .pill-row / .pill) ---- */
.pill-row {
  display: flex;
  justify-content: center;
  gap: 64px;
  margin-top: 24px;
}
.pill {
  background: var(--teal-deep);
  color: var(--text);
  border: none;
  font-family: inherit;
  font-size: 14px;
  padding: 12px 36px;
  border-radius: 24px;
  cursor: pointer;
  letter-spacing: 0.04em;
  opacity: 0.85;
  transition: all 0.2s ease;
}
.pill:hover { opacity: 1; background: var(--teal); }
.pill.completed {
  background: var(--teal);
  opacity: 1;
}
.pill.completed::after {
  content: ' \2713';
  font-weight: 600;
}

/* ---- Submit (natural flow, centered, just below the pills) ---- */
/* Sits in the participant's normal vertical stack (slider → pills → Submit), not
   anchored to the viewport bottom. margin-top gives clean spacing under the pills. */
.assessment-submit-row {
  display: flex;
  justify-content: center;
  margin-top: 40px;
}
.btn.primary {
  background: var(--teal);
  color: #fff;
}
.btn.primary:hover { background: var(--teal-deep); }
/* Fixed width, a bit wider than the Evidence/Usage/Friction pills, so the centered
   Submit reads as the primary commit action (not full-width). */
#assessment-submit { width: 200px; text-align: center; }

/* ============================================================
   INPUT MODAL (proto .modal-* ) — one shared card, title/question/
   placeholder swapped per pill. The three modal-card--<type>
   modifiers share one enlarged treatment (proto).
   ============================================================ */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 500;
  padding: 24px;
}
.modal-overlay[hidden] { display: none; }
.modal-card {
  width: 100%;
  max-width: 700px;
  background: var(--card-bg);
  color: var(--card-fg);
  border-radius: 14px;
  border: 2px solid var(--teal);
  padding: 28px 32px;
  font-family: inherit;
  position: relative;
}
.modal-head {
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  margin-bottom: 18px;
}
.modal-title {
  margin: 0;
  color: var(--teal);
  font-size: 22px;
  font-weight: 500;
  letter-spacing: 0.05em;
}
.modal-close {
  position: absolute;
  right: 0;
  top: 0;
  background: white;
  border: 1px solid #333;
  font-family: inherit;
  font-size: 12px;
  width: 28px;
  height: 28px;
  border-radius: 4px;
  cursor: pointer;
}
.modal-rating {
  margin: 0 0 8px;
  font-size: 15px;
}
.modal-question {
  margin: 0 0 16px;
  font-size: 17px;
  font-weight: 400;
  color: #444;
}
.modal-input {
  width: 100%;
  min-height: 100px;
  border: 1px solid #ccc;
  border-radius: 8px;
  padding: 14px;
  font-family: inherit;
  font-size: 14px;
  resize: vertical;
}
.modal-input:focus {
  outline: none;
  border-color: var(--teal);
}
.modal-foot {
  display: flex;
  justify-content: flex-end;
  margin-top: 16px;
}

/* Enlarged modal treatment shared by all three input variants (proto). */
.modal-card.modal-card--evidence,
.modal-card.modal-card--usage,
.modal-card.modal-card--friction {
  width: clamp(720px, 74vw, 1100px);
  /* min-height, NOT a fixed height: at narrow widths the question wraps to more lines and
     the content grows taller than a fixed card, which pushed the footer (and Enter button)
     down past the bottom border. With min-height the card grows to fit, so the footer always
     sits inside the card's bottom padding. */
  min-height: clamp(480px, 65vh, 760px);
  max-width: 92vw;
  max-height: 88vh;
  border-radius: 24px;
  border-width: 5px;
  /* Bottom padding matches the horizontal padding so the Enter button is inset by the same
     gutter on the right and bottom edges. */
  padding: 28px 36px 36px;
  display: flex;
  flex-direction: column;
}
.modal-card--evidence .modal-head,
.modal-card--usage .modal-head,
.modal-card--friction .modal-head {
  margin-bottom: 22px;
}
.modal-card--evidence .modal-title,
.modal-card--usage .modal-title,
.modal-card--friction .modal-title {
  font-size: 36px;
  font-weight: 600;
  letter-spacing: 0.08em;
}
.modal-card--evidence .modal-close,
.modal-card--usage .modal-close,
.modal-card--friction .modal-close {
  width: 38px;
  height: 38px;
  font-size: 18px;
  font-weight: 500;
  border-radius: 4px;
  border: 1.5px solid #444;
}
.modal-card--evidence .modal-rating,
.modal-card--usage .modal-rating,
.modal-card--friction .modal-rating {
  font-size: 22px;
  font-weight: 700;
  color: #1f2937;
  margin: 0 0 18px;
}
.modal-card--evidence .modal-question,
.modal-card--usage .modal-question,
.modal-card--friction .modal-question {
  font-size: 24px;
  font-weight: 400;
  color: #4b5563;
  margin: 0 0 28px;
  line-height: 1.3;
}
.modal-card--evidence .modal-body,
.modal-card--usage .modal-body,
.modal-card--friction .modal-body {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
}
.modal-card--evidence .modal-input,
.modal-card--usage .modal-input,
.modal-card--friction .modal-input {
  flex: 0 0 auto;
  height: 160px;
  min-height: 160px;
  border-radius: 14px;
  border: 1px solid #6b7280;
  padding: 22px 28px;
  font-size: 17px;
  font-weight: 400;
  color: #1f2937;
  resize: none;
  white-space: pre-wrap;
}
.modal-card--evidence .modal-input::placeholder,
.modal-card--usage .modal-input::placeholder,
.modal-card--friction .modal-input::placeholder {
  /* Dimmed so the prompt reads as placeholder, not typed content — but still
     comfortably readable. Typed text keeps the full-intensity value color
     (#1f2937) set on .modal-input above; this rule is placeholder-only. */
  color: #9099a3;
  font-weight: 400;
  font-size: 17px;
  opacity: 1;               /* controlled dim — override Firefox's own placeholder fade */
  line-height: 1.5;
  white-space: pre-wrap;
}
.modal-card--evidence .modal-foot,
.modal-card--usage .modal-foot,
.modal-card--friction .modal-foot {
  margin-top: auto;
  padding-top: 24px;
  display: flex;
  justify-content: flex-end;
}
.modal-card--evidence .modal-foot .btn.primary,
.modal-card--usage .modal-foot .btn.primary,
.modal-card--friction .modal-foot .btn.primary {
  min-width: 160px;
  /* Keep the Enter button inside the card at narrow widths: cap it to the foot's
     content box so the fixed 160px min-width can't push it past the card's left
     padding, and let it shrink if the window is narrower than the button. The
     right gutter is the modal's own padding (justify-content:flex-end inside the
     36px-padded card), so it stays consistent with the left padding at every width. */
  max-width: 100%;
  min-width: min(160px, 100%);
  padding: 14px 40px;
  font-size: 18px;
  font-weight: 500;
  border-radius: 32px;
}

/* =====================================================================
   GROUP CONSENSUS (consensus stop) — facilitator view
   Ported from the proto (root styles.css 618-645, 648-667, 720-737,
   909-925, 1088-1092) for the P1_S1_CONSENSUS_FAC markup: the four-point
   scale with every participant's assessment slider plotted as a coloured
   dot, plus the facilitator's draggable consensus pointer and the name
   legend. var(--fg) remapped to this build's var(--text).

   The scale itself (.scale / .scale-track / .scale-marker /
   .scale-labels / .scale.interactive) is NOT repeated here: it is
   already committed above (1058-1090) for the participant slider and is
   shared verbatim. Only the consensus-specific rules live in this block.

   The legend selectors are namespaced .consensus-legend* rather than the
   proto's generic .legend*, which is an easy name for a later screen to
   reach for and collide with.

   Dot and swatch colour come from the committed per-seat --seat vars
   (.seat-participant_* above), set by a seat class on the element, so
   this build keeps ONE colour mapping. Teal fallback if color_id is
   somehow absent, matching screen_cards / screen_votes.
   ===================================================================== */

/* Full-height stage (this build renders a whole page, so there is no
   .app/.screen flex parent — this supplies it, like .assessment-view).
   The proto's .consensus-view also carried min-height:0 as a flex-child
   overflow guard inside .app/.screen; that parent does not exist here,
   so it is deliberately dropped rather than overriding the calc.

   Content is centred on BOTH axes: align-items centres the column
   horizontally, justify-content centres it vertically in the stage.
   Vertical padding is symmetric (48px top and bottom) so it does not
   bias the centring; the earlier 24px top was there to top-park the
   content and would pull it upward now. Horizontal padding is
   unchanged at 48px. The nav cluster is position:fixed (.begin-footer)
   so it sits outside this flow and does not fight the centring. */
.consensus-view {
  min-height: calc(100vh - var(--app-header-h));
  display: flex;
  flex-direction: column;
  position: relative;
  align-items: center;
  justify-content: center;
  padding: 48px;
}
/* MEASURED, consensus-only. The proto's 820px holds this question on 2 lines at the
   proto's 36px, but this build renders the shared facilitator hero at 52px
   (styles.css:357, also used by Cards / Legal / Assessment and deliberately not touched),
   and at 52px the same 820px forces a 3-line wrap with a short orphan.
   Swept live at a 1280px viewport: the 2-line break lands at 970px, and the break holds
   at "…the company’s" / "overall approach to AI right now?" (963px / 794px, an even
   82% balance) all the way to 1140px. At 1150px and above it re-breaks to 1140px / 619px,
   a worse orphan, so wider is NOT better here.
   1000px is chosen: just above the 970px break with ~37px of slack over the 963px longest
   line (so a font-metric shift cannot silently drop it back to 3 lines), comfortably inside
   the 1184px usable stage (1280 minus .consensus-view's 2x48px padding), and equal to
   .consensus-view .scale's own max-width, so the heading and the scale share one measure. */
.consensus-view .prompt-text {
  text-align: center;
  max-width: 1000px;
}
.consensus-view .scale {
  width: 86%;
  max-width: 1000px;
}

/* ---- reference spread: participant dots, centred ON the line ---- */
.consensus-dots-layer {
  position: absolute;
  top: 52px;
  left: 0;
  right: 0;
  height: 0;
  pointer-events: none;
}
/* PROTO BASELINE, verbatim: 16px, matching the proto's .dot-marker exactly. Measured
   live in both, at a matched 1280px viewport, the proto and this build render the dot
   at the same 16px with no transform scale, so there is no port drift to correct here.
   A 20px variant was tried, to balance this build's 52px/400 consensus heading against
   the proto's 36px/300 (the facilitator "question is the hero" standard, styles.css:357,
   shared by Cards / Legal / Assessment and so deliberately left alone), and reverted:
   matching the proto is the baseline, and sizing up to compensate for a heading
   difference is a design change rather than a port fix. */
.dot-marker {
  position: absolute;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--seat, var(--teal));
  transform: translate(-50%, 0);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.4);
}
.consensus-dots-layer .dot-marker {
  transform: translate(-50%, -50%);
}

/* ---- the facilitator's consensus pointer (proto .consensus-pointer) ---- */
.consensus-pointer {
  position: absolute;
  top: 20px;
  font-size: 18px;
  color: var(--text);
  transform: translateX(-50%);
  pointer-events: none;
  left: 50%;
  transition: none;
}

/* ---- FROZEN state (write-once): the committed screen is not re-enterable.
   Same treatment as the proto's participant-mode lock (styles.css:1088-1092).
   Belt-and-suspenders only: screen_consensus.php does not emit the drag JS
   at all when locked, so there is no handler for this to disarm. ---- */
.scale.interactive.is-locked {
  pointer-events: none;
  cursor: default;
}

/* ---- legend below the scale (proto .legend / .legend-item / .legend-swatch) ---- */
.consensus-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  /* PROTO BASELINE, verbatim: gap 40px, margin-top 60px, font-size 15px, matching the
     proto's .legend exactly. A tighter 40px margin-top was tried, to pull the legend
     closer under the scale, and reverted with the dot and swatch sizes above and below.
     font-size sits on the CONTAINER and reaches the items by inheritance, exactly as the
     proto does it: .consensus-legend-item deliberately declares no font-size of its own. */
  gap: 40px;
  margin-top: 60px;
  font-size: 15px;
}
.consensus-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 500;
}
.consensus-legend-swatch {
  display: inline-block;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--seat, var(--teal));
}

/* ---- P2 cluster: plain preliminary-sort display (slice 2a; the canvas replaces this later).
   New selectors only — no P1 rule is touched. Reuses .btn/.btn-ghost, .begin-footer/.begin-btn,
   and the --teal/--text/--muted tokens already defined above. ---- */
.p2-prelim-view { padding: 24px 43px 96px; }
.p2-prelim-heading { color: var(--teal); font-size: 36px; font-weight: 300; margin: 0 0 12px; }
.p2-prelim-scaffold { margin: 0 0 4px; }
/* Destructive build scaffold — tinted with the alert token so "this deletes cards" is visible. */
.btn.p2-prelim-scaffold-btn { border-color: var(--red); color: var(--red); }
.p2-prelim-scaffold-note { margin: 0 0 20px; }
.p2-prelim-cats { display: flex; flex-wrap: wrap; gap: 20px; align-items: flex-start; }
.p2-prelim-cat { flex: 0 0 220px; }
.p2-prelim-cat-title {
  color: var(--text); font-weight: 500; letter-spacing: 0.04em;
  padding: 4px 0 8px; margin-bottom: 8px; border-bottom: 1px solid rgba(255,255,255,0.30);
}
.p2-prelim-cards { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.p2-prelim-card {
  background: #fff; color: #1a1a1a; border-radius: 6px; padding: 10px 12px;
  font-size: 13px; box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.p2-prelim-card--unresolved {
  background: transparent; color: var(--muted); border: 1px dashed var(--muted); box-shadow: none;
}

/* =====================================================================
   P2 cluster canvas (slice 2b) — ported from the prototype's cluster
   component (root styles.css :2091-2573, :6648-6666; the legend block
   :679-716 is NOT ported this slice). New selectors only; NO P1 rule
   touched. Token mapping per the build's committed divergence: proto
   --fg → --text, --fg-dim → --muted, --pink-dot → --red. Card colour uses
   the live --seat mechanism (seat-<color_id> class) instead of the proto's
   inline hex. Merge/selection/shake/merge-bar, the card-detail overlay, and
   the expand (⤢) affordance are NOT ported (next slice).
   ===================================================================== */
.p2-cluster-screen {
  /* ADAPTED: stands in for the proto's flex-column .screen parent (absent in the live build).
     Full height below the header so the board is flex:1 and the in-flow footer sits beneath it —
     the nav no longer overlaps the board the way the fixed .begin-footer did. */
  height: calc(100vh - var(--app-header-h));
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 8px 43px 12px;
}
.p2-cluster-view {                    /* proto flex:1, now under the flex-column wrapper above */
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.p2-cluster-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 16px; }
.p2-cluster-scaffold form { margin: 0; }
.p2-cluster-title { font-size: 36px; font-weight: 300; margin: 0; }
.p2-cluster-canvas-wrap {
  flex: 1;
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: 16px;
  scrollbar-width: thin;                                   /* Firefox */
  scrollbar-color: rgba(255,255,255,0.55) rgba(255,255,255,0.10);
}
.p2-cluster-canvas-wrap::-webkit-scrollbar { height: 8px; }
.p2-cluster-canvas-wrap::-webkit-scrollbar-track { background: rgba(255,255,255,0.10); border-radius: 999px; margin: 0 4px; }
.p2-cluster-canvas-wrap::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.55); border-radius: 999px; border: 1px solid transparent; background-clip: padding-box; }
.p2-cluster-canvas-wrap::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.75); background-clip: padding-box; }
.p2-cluster-canvas-wrap::-webkit-scrollbar-corner { background: transparent; }
.p2-cluster-canvas {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  height: 100%;
  transform: scale(var(--p2-zoom, 1));                     /* --p2-zoom set from cluster.js */
  transform-origin: top left;
  transition: transform 0.15s ease;
  min-width: max-content;
  padding-left: 16px;
  padding-right: 24px;
}
.p2-cluster-col {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  border-left: 1px solid rgba(255, 255, 255, 0.30);
  padding-left: 12px;
  align-self: stretch;
  min-height: 0;
}
.p2-cluster-col:first-child { border-left: none; padding-left: 0; }
.p2-cluster-stacks { display: flex; flex-direction: row; gap: 12px; flex: 1 1 auto; min-height: 0; }
.p2-cluster-label {
  background: transparent;
  color: var(--text);                                      /* proto --fg */
  border: none;
  outline: none;
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.04em;
  padding: 4px 0;
  width: 100%;
}
.p2-cluster-label:focus { border-bottom: 1px solid var(--teal); }
.p2-cluster-cards {
  display: flex;
  flex-direction: column;
  gap: 0;
  min-height: 60px;
  padding: 4px 2px;
  border-radius: 4px;
  transition: background 0.15s ease;
  flex: 0 0 200px;
  width: 200px;
  overflow-y: auto;
  overflow-x: hidden;
}
.p2-cluster-cards.drag-over { background: rgba(93, 189, 181, 0.15); }
.p2-cc-card {
  background: #ffffff;
  color: #1a1a1a;
  border-radius: 6px;
  /* ADAPTED: colour from the live --seat var (seat-<color_id> class), teal
     fallback for neutral (new) cards — replaces the proto's inline hex. */
  border: 2px solid var(--seat, var(--teal));
  border-top-width: 8px;                                   /* identity stripe */
  cursor: grab;
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 0;
  height: 72px;
  flex: 0 0 auto;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0,0,0,0.4);
  position: relative;
}
.p2-cc-card-header { padding: 14px 12px 10px; background: transparent; flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center; }
/* Subtle divider between stacked cards — adjacent-sibling rule; depends on the
   card nesting the render preserves. */
.p2-cluster-cards .p2-cc-card + .p2-cc-card { margin-top: 6px; position: relative; }
.p2-cluster-cards .p2-cc-card + .p2-cc-card::before {
  content: ''; position: absolute; top: -3px; left: 8px; right: 8px; height: 1px; background: rgba(255, 255, 255, 0.18);
}
.p2-cc-card:active { cursor: grabbing; }
.p2-cc-card.dragging { opacity: 0.4; }
.p2-cc-delete {
  position: absolute;
  top: 4px;
  right: 2px;
  width: 13px;
  height: 13px;
  line-height: 11px;
  text-align: center;
  padding: 0;
  border: 1px solid rgba(0,0,0,0.28);
  background: rgba(255,255,255,0.85);
  color: rgba(0,0,0,0.42);
  font-size: 10px;
  cursor: pointer;
  border-radius: 2px;
  opacity: 0;
  transition: opacity 120ms ease, color 120ms ease, background 120ms ease, border-color 120ms ease;
  z-index: 2;
}
.p2-cc-card:hover .p2-cc-delete { opacity: 1; }
.p2-cc-delete:hover { color: var(--red); border-color: var(--red); background: rgba(233,75,75,0.10); }  /* proto --pink-dot */
.p2-cc-title {
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.2;
  color: #000;
  box-sizing: border-box;
  width: 100%;
  max-height: 100%;
  align-self: center;
  text-align: center;
  margin: 0;
  padding: 0 4px;
  overflow-y: auto;
  overflow-x: hidden;
  overflow-wrap: break-word;
  word-break: break-word;
  scrollbar-width: thin;
  scrollbar-color: rgba(0,0,0,0.30) transparent;
}
.p2-cc-title::-webkit-scrollbar { width: 4px; }
.p2-cc-title::-webkit-scrollbar-track { background: transparent; }
.p2-cc-title::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.30); border-radius: 999px; }
.p2-cluster-addcard {
  display: block;
  width: 100%;
  margin-top: 8px;
  background: transparent;
  color: var(--muted);                                     /* proto --fg-dim */
  border: 1px dashed rgba(255,255,255,0.25);
  border-radius: 6px;
  font-family: inherit;
  font-size: 12px;
  letter-spacing: 0.02em;
  padding: 7px 10px;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.p2-cluster-addcard:hover { color: var(--teal); border-color: var(--teal); background: rgba(93, 189, 181, 0.06); }
.p2-cluster-add {
  flex: 0 0 200px;
  align-self: stretch;
  background: transparent;
  color: var(--muted);                                     /* proto --fg-dim */
  border: 1px dashed rgba(255,255,255,0.30);
  border-radius: 6px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.02em;
  cursor: pointer;
  padding: 12px 14px;
  text-align: center;
  margin-left: 4px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
}
.p2-cluster-add:hover { color: var(--teal); border-color: var(--teal); background: rgba(93, 189, 181, 0.06); }
/* Footer row (proto :2530-2546): zoom left, legend centre, BACK | NEXT right. The two margin-left:
   auto splits (legend + the first nav element) push the nav group to the right edge. ADAPTED for
   the live server-nav: the first nav flex child is .nav-back-form (a form), not the proto's bare
   .nav-back button, and the nav forms are made inline-flex so their buttons sit in one row. */
.p2-cluster-footer { display: flex; align-items: center; padding: 12px 0 0; }
.p2-cluster-footer .p2-zoom-controls { margin-left: 0; }
.p2-cluster-footer .cluster-legend { margin-left: auto; }
.p2-cluster-footer .nav-back-form { margin-left: auto; }
.p2-cluster-footer form { display: inline-flex; margin: 0; }
.p2-zoom-controls { display: flex; gap: 8px; }
.p2-zoom-btn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--teal);
  color: #fff;
  border: none;
  font-family: inherit;
  font-size: 18px;
  font-weight: 500;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.p2-zoom-btn:hover { background: var(--teal-deep); }
/* Participant legend (proto :679-717). Ported; the swatch colour comes from the live --seat var
   (seat-<color_id> class) instead of the proto's inline hex. cluster.js shows only participants
   with >=1 card currently on the board. */
.cluster-legend { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 18px; font-size: 12px; font-weight: 500; min-width: 0; }
.cluster-legend-item { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.cluster-legend-swatch { display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--seat, var(--teal)); }

/* =====================================================================
   P2 cluster canvas — merge + card-detail modal (slice 2c). Ported from the
   proto (styles.css :2206-2492 selection/shake/merge-bar/overlay, :1184-1204
   unmerge, :2333-2355 expand). New selectors only; no P1 rule touched. Token
   mapping: proto --fg-dim → --muted, --border → its proto literal (undefined
   in the live build). Modal/merged colour uses the live --seat mechanism.
   The shared .modal-* chrome + .btn.primary already exist in the live build.
   ===================================================================== */
.p2-cluster-screen { position: relative; }   /* merge-bar anchor (proto put this on .screen) */

/* Expand (⤢) affordance — top-left, hover-reveal (proto :2333-2355). */
.p2-cc-expand {
  position: absolute; top: 4px; left: 4px; width: 20px; height: 20px; line-height: 1;
  padding: 0; border: none; background: transparent; color: rgba(0,0,0,0.38); font-size: 18px;
  cursor: pointer; border-radius: 3px; opacity: 0;
  transition: opacity 120ms ease, color 120ms ease, background 120ms ease; z-index: 2;
}
.p2-cc-card:hover .p2-cc-expand { opacity: 1; }
.p2-cc-expand:hover { color: rgba(0,0,0,0.65); background: rgba(0,0,0,0.06); }

/* Merge selection ring (proto :2271-2288). */
.p2-cc-card--selected { box-shadow: 0 0 0 3px var(--yellow, #FFD60A), 0 1px 3px rgba(0,0,0,0.4); }
@keyframes p2CardReject {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-4px); }
  40%      { transform: translateX(4px); }
  60%      { transform: translateX(-3px); }
  80%      { transform: translateX(2px); }
}
.p2-cc-card--shake { animation: p2CardReject 0.3s ease; }

/* Contextual merge action bar (proto :2296-2328), anchored to .p2-cluster-screen. */
.p2-merge-bar {
  position: absolute; left: 50%; bottom: 84px; transform: translateX(-50%); z-index: 20;
  display: flex; align-items: center; gap: 14px; padding: 8px 14px;
  border: 1px solid var(--teal); border-radius: 8px; background: rgba(0, 0, 0, 0.82);
  backdrop-filter: blur(2px); box-shadow: 0 4px 18px rgba(0,0,0,0.55);
}
.p2-merge-bar[hidden] { display: none; }
.p2-merge-count { color: var(--teal); font-weight: 600; font-size: 0.92rem; letter-spacing: 0.01em; }
.p2-merge-bar .p2-merge-clear {
  background: transparent; border: 1px solid rgba(255,255,255,0.3); color: var(--muted);  /* proto --fg-dim */
}
.p2-merge-bar .p2-merge-clear:hover { border-color: #fff; color: #fff; }

/* Card-detail overlay content (proto :2422-2492). Chrome (.modal-*) is the live shared modal.
   Border / author dot / Update button colour read the inherited --seat set by the seat-<color_id>
   class cluster.js puts on .p2-card-detail (participant → author colour; merged/new → neutral teal). */
.p2-card-overlay .p2-card-detail { max-width: 560px; border-width: 6px; border-color: var(--seat, var(--teal)); }
.p2-card-detail .btn.primary { background: var(--seat, var(--teal)); }
.p2-card-detail-title-input {
  flex: 1; border: none; outline: none; background: transparent; color: #1a1a1a;
  font-family: inherit; font-size: 22px; font-weight: 700; letter-spacing: 0.05em;
  text-align: center; line-height: 1.25; padding: 0 28px; resize: none; overflow: hidden; min-height: 1.25em;
}
.p2-card-detail-title-input::placeholder { color: rgba(93,189,181,0.5); }
.p2-card-detail-author {
  display: flex; align-items: center; gap: 8px; margin: 14px 0 0;
  font-size: 13px; font-weight: 600; letter-spacing: 0.02em; color: rgba(0,0,0,0.6);
}
.p2-card-detail-author[hidden] { display: none; }
.p2-card-detail-dot { width: 12px; height: 12px; border-radius: 50%; flex: 0 0 auto; background: var(--seat, var(--teal)); }
.p2-card-detail-desc {
  display: block; width: 100%; min-height: 120px; max-height: 320px; overflow-y: auto; resize: vertical;
  border: 1px solid rgba(255,255,255,0.15);   /* proto --border (undefined live); teal on focus below */
  border-radius: 8px; padding: 12px 14px; font-family: inherit; font-size: 15px; line-height: 1.55;
  color: var(--card-fg); background: #fff; outline: none;
  scrollbar-width: thin; scrollbar-color: rgba(0,0,0,0.30) transparent;
}
.p2-card-detail-desc:focus { border-color: var(--teal); }
.p2-card-detail-desc::placeholder { color: rgba(0,0,0,0.4); font-style: italic; }

/* Un-merge control (proto :1184-1204) — understated text action, sits left of Update. */
.p2-card-detail .modal-foot { justify-content: flex-end; }
.p2-card-detail .modal-foot .p2-card-detail-unmerge { margin-right: auto; }
.p2-card-detail .modal-foot .p2-card-detail-unmerge[hidden] { display: none; }
.p2-card-detail-unmerge {
  background: transparent; border: none; padding: 10px 8px; font-size: 12px; font-weight: 500; color: rgba(0,0,0,0.5);
}
.p2-card-detail-unmerge:hover { color: #1a1a1a; text-decoration: underline; }

/* =====================================================================
   P2 — FINAL CATEGORY SELECTION (`category_select` stop, facilitator)
   Ported from the prototype's .p2-final-* block (root styles.css). The
   selection list: a flat category list with a left radio gutter, a #N
   priority badge on selected rows, the point total on the right, and a
   right-arrow on the #1 row (the sole advance). Token mapping — the
   proto's --fg (#ffffff) is this build's --text, its --fg-dim
   (rgba(255,255,255,0.65)) is --muted, and its --border is --line; --teal
   is shared. The proto's per-row description line is NOT ported (this
   build has no category description), so .p2-final-row-desc is omitted.
   ===================================================================== */
.p2-final-view {
  flex: 1;
  /* Bound the view exactly as the working scroller wrappers do (.legal-review-view /
     .responses-roster-view): a definite height below the (non-fixed) app-header turns the
     already-present flex column into a real bounded chain, so .p2-final-list fills whatever is
     left under the title stack instead of relying on a hand-measured ceiling. */
  height: calc(100vh - var(--app-header-h));
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-height: 0;
  padding: 24px 43px 72px;   /* 72px bottom clears the fixed .begin-footer (same value as the working views) */
}

.p2-final-list {
  margin-top: 8px;
  border-top: 1px solid var(--line);
  /* Internal vertical scroll (matching the sibling P2 screens): the flex chain from the bounded
     .p2-final-view gives the height, so the list fills the remaining space — no hand-measured
     ceiling — with a 20px right gutter between the rows and the scrollbar. */
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  padding-right: 20px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.55) rgba(255,255,255,0.10);
}
.p2-final-list::-webkit-scrollbar { width: 8px; }
.p2-final-list::-webkit-scrollbar-track {
  background: rgba(255,255,255,0.10);
  border-radius: 999px;
  margin: 4px 0;
}
.p2-final-list::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,0.55);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: padding-box;
}
.p2-final-list::-webkit-scrollbar-thumb:hover {
  background: rgba(255,255,255,0.75);
  background-clip: padding-box;
}
.p2-final-list::-webkit-scrollbar-corner { background: transparent; }

.p2-final-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  align-items: start;
  padding: 18px 4px;
  border-bottom: 1px solid var(--line);
  transition: background 120ms ease, opacity 120ms ease;
}
.p2-final-row.is-selected { cursor: grab; }
.p2-final-row.is-selected:active { cursor: grabbing; }
.p2-final-row.dragging { opacity: 0.5; }
.p2-final-row.drag-over { background: rgba(93, 189, 181, 0.08); }

/* Multi-pick variant — adds the left radio gutter for the selection list. */
.p2-final-row.is-multi-pick {
  display: grid;
  grid-template-columns: 40px 1fr;
  align-items: start;
  column-gap: 16px;
}
.p2-final-row.is-multi-pick.is-selected { cursor: grab; }
.p2-final-row.is-multi-pick.is-selected:active { cursor: grabbing; }

.p2-final-radio {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1.5px solid var(--muted);
  background: transparent;
  color: var(--muted);
  /* Hide the glyph rendered in JS — the inner dot is drawn via ::before so its size is independent
     of the system font. */
  font-size: 0;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  margin-top: 2px;
  padding: 0;
  position: relative;
  transition: border-color 120ms, color 120ms;
}
.p2-final-radio::before {
  content: "";
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: transparent;
  transition: background 120ms;
}
.p2-final-radio:hover { border-color: var(--text); color: var(--text); }
.p2-final-radio.is-on { border-color: var(--text); color: var(--text); }
.p2-final-radio.is-on::before { background: var(--text); }

.p2-final-row-body { min-width: 0; }

.p2-final-row-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 6px;
}

.p2-final-priority {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  padding: 2px 8px;
  border-radius: 12px;
  background: var(--teal);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
}
/* "Selected" variant — used on the Workflow Selection screen for the single chosen
   workflow. Same teal pill geometry as the #N badge, widened to fit the word and
   uppercased to read as a status label rather than a rank number. Ported from the
   prototype (root styles.css .p2-final-priority--selected). */
.p2-final-priority--selected {
  padding: 2px 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 11px;
}

.p2-final-row-title {
  color: var(--text);
  font-size: 17px;
  font-weight: 500;
  letter-spacing: 0.02em;
  flex: 1;
}

.p2-final-row-score {
  color: var(--teal);
  font-size: 15px;
  font-weight: 500;
  white-space: nowrap;
}

/* Per-row workflow description — the Workflow Selection list shows the workflow's
   body under its title (the category list had no description, so this is absent from
   that screen). Ported from the prototype .p2-final-row-desc; its --fg-dim maps to
   this build's --muted. */
.p2-final-row-desc {
  color: var(--muted);
  font-size: 13px;
  font-weight: 300;
  line-height: 1.5;
}

/* Right-arrow on the #1 row — the sole advance action (interactive button). */
.p2-final-arrow {
  appearance: none;
  background: transparent;
  border: none;
  padding: 0 0 0 18px;
  margin: 0;
  font: inherit;
  font-size: 14px;
  line-height: 1;
  color: var(--teal);
  cursor: pointer;
  white-space: nowrap;
  letter-spacing: 0;
}
.p2-final-arrow:hover  { opacity: 0.75; }
.p2-final-arrow:active { opacity: 0.55; }
.p2-final-arrow:focus-visible {
  outline: 1px solid var(--teal);
  outline-offset: 3px;
  border-radius: 2px;
}

/* =====================================================================
   PHASE 3 DECOMPOSITION — WORKFLOW SEGMENTATION (port, slice 1 of 2)

   The .p3-seg-* block ported from the prototype (root styles.css:3885-4607),
   for awe/screen_segmentation.php. ADDITIVE ONLY — no .p2-cluster-* and no
   .p3-row-* rule is touched. Declarations are BYTE-IDENTICAL to the proto
   apart from the established sheet-wide remaps and one selector rewrite;
   the full list of changes against the source is FIVE lines:

     - var(--fg)     -> var(--text)    (.p3-seg-title)
     - var(--fg-dim) -> var(--muted)   (.p3-seg-subtitle, .p3-seg-add)
     - [data-screen="P3_WORKFLOW_SEGMENTATION_FAC"] -> .p3-seg-screen, on the
       two rules that must not leak off this screen (the canvas-wrap's
       min-height/overflow-y, and this screen's tighter .p3-task-header
       margin). The live build has no data-screen attribute; the screen
       carries .p3-seg-screen alongside .p2-cluster-screen, the same
       both-classes treatment the canvas gets. See screen_segmentation.php.

   --teal and --alert are left as the proto writes them. NOTE that --alert is
   NOT defined in this sheet, so `var(--alert, #FC2323)` resolves to its
   fallback — which is the same value as this sheet's --red. Identical render,
   no token added; left alone deliberately rather than "corrected" to --red.

   DUPLICATE SELECTORS ARE INTENTIONAL and carried in SOURCE ORDER, because
   the later declaration is the one that wins and the proto depends on that:
   .p3-seg-card--empty appears twice (proto 4358, 4574) and
   .p3-seg-card .p3-seg-name:empty::before appears twice (proto 4550, 4558).
   Do not dedupe them.

   ORPHANED-BY-DESIGN rules are carried too, so a later slice can re-light
   them without re-porting: the whole .p3-seg-card--empty variant (the
   renderer deliberately never applies the modifier — see the proto's own
   sprint-c note inside the block), the .p3-seg-meta* family that sprint-c
   replaced with sectioned bullet lists, and .p3-seg-task.
   ===================================================================== */
/* =========================================================
   PHASE 3 — WORKFLOW SEGMENTATION (additive only)
   Screen: P3_WORKFLOW_SEGMENTATION_FAC.
   Layout shell — outer view container, horizontal scroll
   wrap, footer chrome, and zoom controls — is reused from
   P2_S2_CLUSTER_ACTIVE_FAC via the .p2-cluster-canvas-wrap
   / .p2-cluster-footer / .p2-zoom-controls / .p2-zoom-btn
   class hooks (those rules are not screen-scoped, so they
   apply unchanged). Stage card visuals and sizing are
   Phase 3-specific (.p3-seg-* class namespace).
   ========================================================= */

/* Layout-stability chain for the segmentation screen. The global
   .app rule constrains the page to 100vh; for that ceiling to
   propagate down to the canvas (so internal scrolling kicks in
   instead of pushing the footer below the fold), every flex
   parent in the chain must allow itself to shrink. The default
   min-height:auto on flex children prevents this. min-height:0
   on .p3-seg-view + .p2-cluster-canvas-wrap (scoped to phase 3)
   makes the constraint enforceable without affecting Phase 2's
   cluster screen, which doesn't need the same shrinkage and
   currently fits the viewport on its own. */
.p3-seg-view {
  min-height: 0;
}
.p3-seg-screen .p2-cluster-canvas-wrap {
  min-height: 0;
  /* Vertical scroll on overflow — mirrors the behavior on
     P3_WORKFLOW_MAP_FAC (.p3-map-canvas-wrap). Scrollbar only
     renders when content exceeds the viewport. The base Phase 2
     rule supplies overflow-x: auto for horizontal scroll and the
     scrollbar visual styling, both of which remain unchanged. */
  overflow-y: auto;
}

/* Disabled state for a footer NEXT. NOT PORTED — a live-build
   addition, unlike the two .p3-seg-screen rules above, which stand
   in for the proto's [data-screen] selectors.

   The segmentation NEXT ships disabled and app.js enables it once
   at least one stage carries a name (save_segmentation.php refuses
   an unnamed board, and that bounce is a page load that would wipe
   the unsaved canvas). But .begin-btn — the build's shared forward
   control — has no disabled treatment: it sets only background,
   border and color, so a disabled NEXT would look identical to a
   live one and would still light teal on hover. .legal-next-btn
   (above) is the only other place the build styles this, and these
   two declarations are its values verbatim.

   PROMOTED FROM .p3-seg-screen TO GLOBAL. These two shipped scoped
   to the segmentation screen, with the note that if a second screen
   ever disabled a .begin-btn they should be PROMOTED rather than
   copied. The atomic-tasks stop is that second screen: its NEXT also
   ships disabled, enabled once one task anywhere carries text, and
   for the same reason (save_atomic_tasks.php refuses an empty board,
   and the bounce is a page load that would wipe the typed tasks).
   So the scope comes off rather than a .p3-map- copy going in — two
   identical rules drifting apart is the failure this avoids.

   Dropping the scope does NOT widen the behaviour: :disabled only
   matches a button that carries the attribute, and the only two
   places in the build that set it are these two screens. Every other
   .begin-btn is always enabled and cannot match. .begin-btn:hover is
   left alone for the same reason the scoped version left it alone —
   the :disabled:hover rule below already holds the resting colour,
   so :hover needs no :not(:disabled) rewrite. */
.begin-btn:disabled {
  opacity: 0.4;
  cursor: default;
}
/* Hold the resting color: .begin-btn:hover would otherwise still
   fire teal on a button that cannot be clicked. */
.begin-btn:disabled:hover {
  color: var(--text);
}

/* Title + subtitle block above the horizontal canvas. The Task
   indicator was removed here (it already appears in the top
   p3-task-header), so this block is just title + subtitle. Margin
   kept tight so the canvas — and therefore the stretched stage
   cards — claim as much vertical height as possible. */
.p3-seg-header {
  margin-bottom: 12px;
}
/* Updated layout: title leads the screen, sitting above the
   Department/Task header. p3-seg-title-top supplies the top margin
   the header block would otherwise have provided. */
.p3-seg-title-top {
  margin: 0 0 6px;
}
.p3-seg-screen .p3-task-header {
  margin-bottom: 14px;
}
.p3-seg-title {
  color: var(--text);
  font-size: 28px;
  font-weight: 500;
  letter-spacing: 0.04em;
  margin: 0 0 8px;
}
/* Modifier on .p3-task-header — tighten the vertical spacing so
   the task line nests inside the segmentation header block
   rather than sitting at screen-top like on the Q1-Q4 screens. */
.p3-seg-task {
  margin-top: 0;
  margin-bottom: 10px;
}
.p3-seg-subtitle {
  color: var(--muted);
  font-size: 14px;
  font-weight: 300;
  line-height: 1.5;
  margin: 0;
  white-space: nowrap;
}

/* The canvas itself reuses .p2-cluster-canvas for flex layout +
   horizontal scroll behavior + zoom transform. Cards are NO LONGER
   stretched to canvas height — they take a fixed height (see
   .p3-seg-card) and top-align, so content scrolls inside each card
   and the canvas shows empty space below, matching the approved
   mock. */
.p3-seg-canvas {
  align-items: flex-start;
  /* Bottom padding so the cards don't crowd the bottom edge
     of the scroll wrap; canvas-wrap supplies horizontal scroll. */
  padding-bottom: 8px;
}

/* Stage card. White card body on the dark canvas (matches the
   reference image and is consistent with the .p2-cc-card visual
   treatment). Light-gray header band sits on top, body sits
   below. Card is the draggable unit; its inner editables carry
   draggable="false" so text-selection inside doesn't drag.
   No min-height: the canvas's align-items:stretch makes every
   card the same height (filling the canvas vertical space), so
   cards are uniform regardless of how much content they hold.
   min-height:0 lets the card respect its allotted vertical space
   inside the stretched canvas instead of insisting on fitting
   its intrinsic content height. */
.p3-seg-card {
  flex: 0 0 240px;
  display: flex;
  flex-direction: column;
  background: #fff;
  color: #1a1a1a;
  border-radius: 6px;
  overflow: hidden;
  cursor: grab;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  transition: opacity 120ms ease, box-shadow 120ms ease;
  /* Fixed card height (not stretched to the canvas). The header band
     sits on top; the body (flex:1 + overflow-y:auto) fills the rest
     and scrolls internally when content overflows. This produces the
     uniform, shorter cards in the approved mock with empty canvas
     space below them. Tune this value to make cards taller/shorter. */
  height: 420px;
  max-height: 100%;
}
.p3-seg-card:active { cursor: grabbing; }
.p3-seg-card.dragging { opacity: 0.4; }
.p3-seg-card.drag-over {
  box-shadow: 0 0 0 2px var(--teal), 0 1px 3px rgba(0, 0, 0, 0.4);
}

.p3-seg-card-header {
  /* flex:0 0 auto keeps the colored name band a fixed slice of the
     card; the scrollable body below expands to fill the rest.
     Header is teal across all segmentation cards (Acme ON, manually
     added, empty, dynamically created) per the spec — visually
     anchors each stage and matches the broader teal accent system.
     Fixed min-height + flex centering: every header bar lands at the
     same height across the row regardless of whether the title is
     one line or two. Single-line names visually center; two-line
     names also center, with both lines fitting comfortably within
     the band. Padding is horizontal only — the min-height owns the
     vertical sizing so headers stay aligned card-to-card.
     sprint-c: justify-content removed and replaced by a 3-child
     layout (spacer | name | controls) so the controls cluster
     (drag-grip + × delete) lives in the top-right without breaking
     the name's visual centering. The left spacer is the same fixed
     width as the controls so the name centers across the full band. */
  flex: 0 0 auto;
  background: var(--teal);
  padding: 0 8px;
  min-height: 56px;
  display: flex;
  align-items: center;
  gap: 6px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.10);
}
/* sprint-c: balance child for the right-side controls cluster.
   Same fixed width as .p3-seg-card-controls below so the centered
   name lands in the visual middle of the header. aria-hidden in
   markup so AT skips it.
   sprint-c v2: width reduced from 38px → 24px after the drag-grip
   glyph was removed from the cluster — the facilitator will know
   to drag from the card. Cluster now holds only the × delete-stage
   button. */
.p3-seg-card-header-spacer {
  flex: 0 0 24px;
}
/* sprint-c: top-right control cluster — just the × delete-stage
   button as of v2 (drag-grip glyph removed per UX feedback).
   Subtle at rest; slightly louder on card hover so the affordance
   is discoverable without being noisy. */
.p3-seg-card-controls {
  flex: 0 0 24px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
.p3-seg-card-del {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  background: transparent;
  border: none;
  color: rgba(255, 255, 255, 0.45);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  border-radius: 3px;
  transition: color 100ms, background 100ms;
}
.p3-seg-card:hover .p3-seg-card-del {
  color: rgba(255, 255, 255, 0.85);
}
.p3-seg-card-del:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.18);
}
/* Floor of 1 — the last remaining stage's × is rendered disabled
   so the canvas can never drop below one stage. Mirrors the
   Q1-Q4 review floor pattern. */
.p3-seg-card-del:disabled {
  opacity: 0.20;
  cursor: default;
}
.p3-seg-card-del:disabled:hover {
  color: rgba(255, 255, 255, 0.45);
  background: transparent;
}

.p3-seg-card-body {
  /* flex:1 + min-height:0 + overflow-y:auto = body fills the
     remaining card height and scrolls internally when its
     content overflows. min-height:0 is required because the
     default min-height:auto on flex children would prevent the
     body from shrinking below its intrinsic content height,
     which would silently disable the scroll. */
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 12px;
  /* Polished thin scroll indicator inside the card body
     (Firefox + WebKit) — matches the rest of the system. */
  scrollbar-width: thin;
  scrollbar-color: rgba(0, 0, 0, 0.30) rgba(0, 0, 0, 0.06);
}
.p3-seg-card-body::-webkit-scrollbar {
  width: 6px;
}
.p3-seg-card-body::-webkit-scrollbar-track {
  background: rgba(0, 0, 0, 0.06);
  border-radius: 999px;
  margin: 2px 0;
}
.p3-seg-card-body::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.30);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: padding-box;
}
.p3-seg-card-body::-webkit-scrollbar-thumb:hover {
  background: rgba(0, 0, 0, 0.45);
  background-clip: padding-box;
}
.p3-seg-card-body::-webkit-scrollbar-corner {
  background: transparent;
}

/* Editable name (header) — bold white text on the teal band.
   Color/weight apply across all card states (Acme ON, manually
   added, empty, dynamically created).
   sprint-c: flex:1 so the name fills the middle of the 3-child
   header (spacer | name | controls). min-width:0 lets it shrink
   instead of forcing the controls off-card on long names. */
.p3-seg-name {
  flex: 1;
  min-width: 0;
  display: block;
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-align: center;
  text-transform: uppercase;
  /* Editable affordance — handled by .p3-editable globally for
     the underline; this block only sets typography. */
}

/* Editable description (body) — softer secondary text. */
.p3-seg-desc {
  color: #555;
  font-size: 13px;
  font-weight: 400;
  line-height: 1.5;
  /* sprint-c: room below the description before the section
     headers start, since the body now has stacked Inputs /
     Outputs / Departments sections instead of a single meta
     block of label:value rows. */
  margin-bottom: 10px;
}

/* =========================================================
   sprint-c — PHASE 3 SEGMENTATION: SECTIONED BULLET LISTS
   Replaces the previous one-row "Label: value" meta pattern
   (.p3-seg-meta / .p3-seg-meta-row / .p3-seg-meta-label /
   .p3-seg-meta-value) with proper section headers + per-bullet
   editable lists for Inputs, Outputs, and Departments. The
   old meta classes are left in styles below for now (orphaned,
   no markup references them after the renderer update).

   Per-section structure:
     .p3-seg-section
       .p3-seg-section-label       uppercase header
       <ul.p3-seg-bullet-list>
         <li.p3-seg-bullet>
           .p3-seg-bullet-text     editable span (per-line)
           .p3-seg-bullet-del      × per row, disabled at floor of 1
       .p3-seg-bullet-add          + Add (small)

   Data shape unchanged — state.p3SegStages[i].{inputs,outputs,
   functions} are still \n-joined strings. The renderer splits
   on \n; the input listener splices a single line back in by
   index. Downstream consumer (p3MapSplitList in the workflow
   map renderer) is unaffected.
   ========================================================= */

.p3-seg-section {
  margin-bottom: 10px;
}
.p3-seg-section:last-child {
  margin-bottom: 0;
}
/* sprint-c v2: subtle section divider. Inputs sits directly under
   the description (no top divider — the description's own bottom
   margin reads as the break). Outputs and Departments each carry
   a top divider so the eye groups the three sections distinctly.
   Hairline rule + a touch of extra top padding gives the "section
   break" without adding a heavy frame. */
.p3-seg-section + .p3-seg-section {
  border-top: 1px solid rgba(0, 0, 0, 0.08);
  padding-top: 8px;
  margin-top: 8px;
}
.p3-seg-section-label {
  display: block;
  color: #222;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  /* sprint-c final: margin-bottom removed — spacing between the
     section head and the bullet list is now owned by the .p3-seg-
     bullet-list rule (margin-top added below) so it can stay tight
     to the head row regardless of whether the head wraps. */
}

/* sprint-c final: section head row — label on the left, + Add
   button on the right. Moves the + Add out from below the
   bullet list (which read as a primary list-end affordance) and
   pairs it with its own section header instead, so each section
   visually owns its own add button. */
.p3-seg-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}
.p3-seg-bullet-list {
  list-style: none;
  padding: 0;
  margin: 0 0 4px 0;
}
.p3-seg-bullet {
  /* flex row: bullet glyph (via ::before) + editable text +
     trailing × button. align-items:flex-start so the × stays
     anchored to the first line when the text wraps. */
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 4px;
  padding: 1px 0 1px 12px;
  margin: 0;
}
.p3-seg-bullet::before {
  /* Manual bullet glyph — default list-style markers don't
     render reliably on flex list items across browsers.
     Position absolute against the flex parent so the glyph
     sits in the gutter and the text starts at left:12px. */
  content: "•";
  position: absolute;
  left: 2px;
  top: 1px;
  color: #777;
  font-size: 13px;
  line-height: 1.5;
  pointer-events: none;
}
.p3-seg-bullet-text {
  /* Inherits .p3-editable behavior (focus underline, hover
     hint, contenteditable cursor). The line-height matches
     the bullet glyph so multi-line wraps line up cleanly with
     the dot in the gutter. */
  flex: 1;
  min-width: 0;
  color: #1a1a1a;
  font-size: 13px;
  font-weight: 400;
  line-height: 1.5;
  word-break: break-word;
}
.p3-seg-bullet-del {
  /* Per-bullet remove. Subtle dark-alpha on the white card body
     (mirrors the .p3-q-topic-del treatment on the Q1-Q4 reviews,
     inverted from white-alpha → dark-alpha for the card ground).
     Disabled at the section's floor of 1.
     sprint-c v2: hidden at rest — opacity 0 — and fades in only
     when the facilitator's mouse is on this bullet OR keyboard
     focus is inside it (:focus-within on .p3-seg-bullet). Always-
     visible × per bullet read as too busy with 9-15 bullets per
     card; reserving the layout space at rest avoids text-reflow
     on hover. The button is still in the DOM and tab-reachable,
     and the disabled-floor styling still wins when only one
     bullet remains. */
  flex: 0 0 auto;
  align-self: flex-start;
  width: 16px;
  height: 16px;
  padding: 0;
  background: transparent;
  border: none;
  color: rgba(0, 0, 0, 0.30);
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
  border-radius: 3px;
  margin-top: 2px;
  opacity: 0;
  transition: opacity 120ms ease, color 100ms, background 100ms;
}
.p3-seg-bullet:hover .p3-seg-bullet-del,
.p3-seg-bullet:focus-within .p3-seg-bullet-del {
  opacity: 1;
}
.p3-seg-bullet-del:hover {
  color: var(--alert, #FC2323);
  background: rgba(252, 35, 35, 0.08);
}
.p3-seg-bullet-del:disabled {
  /* Floor-of-1 takes precedence over the hover-reveal — the only
     remaining bullet's × stays muted even on hover so the facilitator
     can't accidentally aim for it. */
  opacity: 0.25 !important;
  cursor: default;
}
.p3-seg-bullet-del:disabled:hover {
  color: rgba(0, 0, 0, 0.30);
  background: transparent;
}
.p3-seg-bullet-add {
  /* sprint-c final: now lives inline-right of its section label
     (not below the bullet list). Smaller and quieter than the
     section label — reads as a tertiary inline affordance rather
     than competing for attention. Dashed border in dark-alpha
     against the white card ground. */
  display: inline-block;
  background: transparent;
  border: 1px dashed rgba(0, 0, 0, 0.20);
  border-radius: 4px;
  color: rgba(0, 0, 0, 0.50);
  font-family: inherit;
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.04em;
  padding: 2px 6px;
  cursor: pointer;
  transition: color 120ms, border-color 120ms, background 120ms;
}
.p3-seg-bullet-add:hover {
  color: var(--teal);
  border-color: var(--teal);
  background: rgba(93, 189, 181, 0.06);
}

/* =========================================================
   PHASE 3 — WORKFLOW SEGMENTATION: empty card treatment
   sprint-c: DEPRECATED. The .p3-seg-card--empty modifier is
   no longer applied by renderP3Segmentation — newly-added
   stages and the non-Acme seed now render with the same
   white-card treatment as filled cards (section headers
   visible, empty bullets showing placeholder text via the
   inline-placeholder pattern below). Selectors below are
   orphaned and kept in case the variant is ever re-introduced;
   nothing matches them while the renderer continues to omit
   the modifier class.
   ========================================================= */
.p3-seg-card--empty {
  background: #000;
  /* Soft 1px outline so the card still has a visible
     boundary on the black canvas — without this the card
     would disappear into the screen background. */
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.18),
              0 1px 3px rgba(0, 0, 0, 0.4);
}
.p3-seg-card--empty .p3-seg-card-body {
  /* Match the dark scrollbar aesthetic used elsewhere in the
     dark UI when the body sits on black. */
  scrollbar-color: rgba(255, 255, 255, 0.30) rgba(255, 255, 255, 0.06);
}
.p3-seg-card--empty .p3-seg-card-body::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.06);
}
.p3-seg-card--empty .p3-seg-card-body::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.30);
}
.p3-seg-card--empty .p3-seg-card-body::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.45);
}
.p3-seg-card--empty .p3-seg-desc {
  color: #ccc;
}
.p3-seg-card--empty .p3-seg-meta-label {
  color: #fff;
}
.p3-seg-card--empty .p3-seg-meta-value {
  color: #ccc;
}
/* Section dividers on the dark body — the default low-alpha-black
   border-tops are invisible against #000, so we re-stroke them
   with a low-alpha white that matches the dark UI system. */
.p3-seg-card--empty .p3-seg-meta {
  border-top-color: rgba(255, 255, 255, 0.12);
}
.p3-seg-card--empty .p3-seg-meta-row + .p3-seg-meta-row {
  border-top-color: rgba(255, 255, 255, 0.12);
}
/* Placeholder ::before text (defined later in this file
   from data-placeholder) inherits color in the empty state
   from the editable's own color rule below — make sure the
   placeholder is visible against black. */
.p3-seg-card--empty .p3-editable:empty::before {
  color: rgba(255, 255, 255, 0.45);
}
/* Hover/focus underline contrast on the dark body. */
.p3-seg-card--empty .p3-editable:hover {
  border-bottom-color: rgba(255, 255, 255, 0.30);
}

/* The .p3-editable focus underline rule (defined earlier in this
   file) uses var(--teal). On the white card body it reads correctly
   because teal has enough contrast against #fff. The underline
   color override below makes the unfocused hover state visible
   against the white background — the global rule uses a low-alpha
   white that disappears here. */
.p3-seg-card .p3-editable:hover {
  border-bottom-color: rgba(0, 0, 0, 0.15);
}
.p3-seg-card .p3-editable:focus {
  border-bottom-color: var(--teal);
}

/* + Add Stage. Ghost slot at the end of the canvas, sized to
   match a stage card's width so it reads as the next slot in the
   sequence rather than a floating CTA. Visually parallel to the
   .p2-cluster-add "+ New Category" treatment. align-self:stretch
   + the canvas's align-items:stretch make this slot exactly the
   same height as the cards beside it. */
/* LIVE DIVERGENCE FROM THE PROTO — a deliberate fix to a proto defect,
   NOT a port. The two sentences ending the comment above describe the
   proto's RETIRED stretch model and no longer hold: .p3-seg-canvas moved
   to align-items:flex-start and .p3-seg-card took a fixed height:420px
   + max-height:100%, but .p3-seg-add was never updated and still sized
   itself by align-self:stretch. That left the two boxes on DIFFERENT
   sizing mechanisms — card = min(420px, canvas height), add = canvas
   height exactly — which coincide ONLY while the canvas is under 420px
   tall. Above that the card pins at 420 and the add box keeps growing.
   Measured on the unmodified prototype: at a short viewport both are
   290px (match); at a 1000px viewport the card is 420px and the add box
   657px (+237px). So the proto has this defect too; it is simply
   invisible at short viewports.
   The fix puts the add box on the CARD's mechanism verbatim — same
   height, same max-height, no align-self — so the two track each other
   at any canvas height. If .p3-seg-card's 420px is ever retuned, this
   value must be retuned with it; they are a pair. */
.p3-seg-add {
  flex: 0 0 240px;
  height: 420px;
  max-height: 100%;
  background: transparent;
  color: var(--muted);
  border: 1px dashed rgba(255, 255, 255, 0.30);
  border-radius: 6px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.02em;
  cursor: pointer;
  padding: 12px 14px;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-left: 4px;
  transition: color 120ms, border-color 120ms, background 120ms;
}
.p3-seg-add:hover {
  color: var(--teal);
  border-color: var(--teal);
  background: rgba(93, 189, 181, 0.06);
}

/* =========================================================
   PHASE 3 — WORKFLOW SEGMENTATION: stage card metadata
   Five-field stage card structure. The description is now a
   short paragraph at the top of the body; below it sits a
   compact metadata block with three label/value rows
   (Inputs, Outputs, Functions). The visual model is
   "structured text" — small bold labels with inline values,
   no input boxes, no separators — not a data entry form.
   ========================================================= */

/* Description sits directly above the metadata block; the divider
   between them lives on the .p3-seg-meta block itself (border-top
   below). Keep a consistent gap between the description text and
   that divider, matching the gap used between meta rows. */
.p3-seg-card .p3-seg-desc {
  margin-bottom: 10px;
}

/* Metadata block — stacked label/value rows. Subtle 1px dividers
   between sections (Description / Inputs / Outputs / Departments)
   improve scanability without adding visual weight. The first
   divider lives on the meta block (separating it from the
   description); the remaining dividers live on each row except
   the first (separating consecutive meta rows). The `padding-top`
   on each divider gives the rule visible breathing room without
   shifting alignment from the previous tight rhythm. */
.p3-seg-meta {
  display: flex;
  flex-direction: column;
  border-top: 1px solid rgba(0, 0, 0, 0.10);
  padding-top: 10px;
}
.p3-seg-meta-row + .p3-seg-meta-row {
  border-top: 1px solid rgba(0, 0, 0, 0.10);
  margin-top: 10px;
  padding-top: 10px;
}
/* Each row is a flex line: the bold label hugs the left, the value
   takes the remaining width and wraps / breaks lines internally.
   align-items:baseline so the first line of the value lines up with
   the label's text baseline; subsequent lines flow under the value
   only (the label stays anchored at the top of the row). This is
   the fix for newline-separated values like Departments where
   pre-wrap content would otherwise drag the label visually downward
   under inline-block + vertical-align:baseline. */
.p3-seg-meta-row {
  display: flex;
  align-items: baseline;
  gap: 4px;
  font-size: 12px;
  line-height: 1.5;
  color: #555;
}

/* Bold inline label — first column of the flex row, fixed-shrink so
   it stays one line. */
.p3-seg-meta-label {
  flex: 0 0 auto;
  font-weight: 600;
  color: #1a1a1a;
}

/* Editable value — fills the remaining row width. min-width:0 so the
   flex item is allowed to shrink and wrap rather than push the label.
   white-space:pre-wrap preserves the newline-per-item convention used
   for Departments (and Inputs/Outputs in the Acme seed). */
.p3-seg-meta-value {
  flex: 1 1 auto;
  min-width: 0;
  color: #555;
  word-break: break-word;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

/* =========================================================
   PHASE 3 — Inline placeholders for empty editables
   contenteditable does not support the native placeholder
   attribute. We use the :empty pseudo-class with a CSS
   ::before that pulls the hint text from data-placeholder.
   The placeholder disappears the moment the user types
   (because the element is no longer :empty). pointer-events
   on the pseudo-element are off so a click lands on the
   editable, not the placeholder.
   ========================================================= */
.p3-seg-card .p3-editable:empty::before {
  content: attr(data-placeholder);
  color: rgba(0, 0, 0, 0.30);
  font-weight: 400;          /* override bold name styling for the hint */
  font-style: italic;
  pointer-events: none;
}
/* The name editable is uppercase + bold; reset the placeholder
   to a softer, non-uppercase hint so "Stage 1" reads as
   guidance rather than a real label. */
.p3-seg-card .p3-seg-name:empty::before {
  text-transform: none;
  letter-spacing: normal;
  font-style: italic;
}
/* Header sits on the teal band — its empty placeholder ("Stage N")
   would be invisible at the dark-on-dark default. Bump to a translucent
   white so it reads as soft guidance against the teal. */
.p3-seg-card .p3-seg-name:empty::before {
  color: rgba(255, 255, 255, 0.65);
}

/* =========================================================
   PHASE 3 — Empty-card black variant
   The Acme-OFF seed is a single empty black card; +Add Stage
   also produces a fresh empty card. The .p3-seg-card--empty
   modifier flips the white card background to black and
   recolors the body editables / labels for dark-on-light
   inversion. As soon as the user types into any field, the
   next render strips the modifier (renderP3Segmentation
   re-evaluates on every render) and the card returns to the
   normal white treatment. The teal header is untouched here
   — it stays teal across all card states per spec.
   ========================================================= */
.p3-seg-card--empty {
  background: #000;
  color: #fff;
  /* The empty card sits on a black canvas, so without a border its
     edges would dissolve into the background. A subtle low-alpha
     white outline restores the card boundary while staying quiet
     visually — the teal header is the loud element here, the body
     should read as "ready to type into" not as a strong container. */
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.18), 0 1px 3px rgba(0, 0, 0, 0.4);
}
.p3-seg-card--empty .p3-seg-desc {
  color: #ccc;
}
.p3-seg-card--empty .p3-seg-meta-row,
.p3-seg-card--empty .p3-seg-meta-value {
  color: #ccc;
}
.p3-seg-card--empty .p3-seg-meta-label {
  color: #fff;
}
/* Body editables on a black card need a light placeholder, otherwise
   the dark-on-dark default is unreadable. Mirrors the white-on-teal
   header treatment above. The :focus and :hover underline rules above
   already use a teal/white that read on either ground, so no
   additional overrides needed there. */
.p3-seg-card--empty .p3-editable:empty::before {
  color: rgba(255, 255, 255, 0.45);
}
/* Hover/focus underlines on dark cards: the existing rules use
   dark-alpha for hover (invisible on black) — switch to a soft
   white so the affordance is visible. Focus stays teal. */
.p3-seg-card--empty .p3-editable:hover {
  border-bottom-color: rgba(255, 255, 255, 0.20);
}

/* Dev-fill button placement (LIVE ADDITION, not a port — the prototype has no
   dev-fill on this screen; it seeds the canvas from its own scenario toggles).
   .legal-dev-fill is `position: absolute; top:0; right:0` because the P1/P3
   editors pin it inside their position:relative .legal-edit-head. Segmentation
   has no such head row, so the button gets a positioned wrapper and hands
   `position: static` back — exactly the .assessment-fill precedent above.
   Parked top-right rather than assessment's lower-left: the lower-left of this
   screen is the footer's zoom cluster. 43px matches the shell's own side
   padding, so the button lines up with the screen's right edge.
   Comes out with the rest of the DEMO_TEST_FILL scaffolding. */
.p3-seg-dev-fill {
  position: fixed;
  right: 43px;
  top: calc(var(--app-header-h) + 8px);
  z-index: 30;
}
.p3-seg-dev-fill .legal-dev-fill { position: static; }

/* =====================================================================
   PHASE 3 DECOMPOSITION — ATOMIC TASKS (port, slice 1 of 2)

   The .p3-map-* block ported from the prototype (root styles.css:4609-5382),
   for awe/screen_atomic_tasks.php. ADDITIVE ONLY — no .p2-cluster-*,
   .p3-seg-* or .p3-row-* rule is touched, and .p3-task-header is overridden
   only inside a wrapper that exists on this screen alone. Declarations are
   BYTE-IDENTICAL to the proto apart from the established sheet-wide remap
   and TWO divergences:

     - var(--fg) -> var(--text)   (.p3-map-header color, .p3-map-title
                                   color and border-bottom)

     - THE HEAD ROW (tweak slice, David 2026-07-26). The proto's
       .p3-map-header carried margin-top:-58px to pull the title up over
       the task header. That offset is GONE, replaced by .p3-map-head-row —
       a grid overlay putting both elements in one cell so the alignment is
       a layout fact rather than a hand-measured constant. .p3-map-header
       keeps every other proto declaration; it loses margin-top and flex,
       and gains a parent. Full reasoning, and the accepted ~1.8px / 6px
       delta, at the .p3-map-head-row rule below.

     - THE PILL BULLET LIST LEFT-ALIGNS (tweak slice, David 2026-07-26).
       .p3-map-pill-list gains text-align:left, which the proto never set,
       so it stopped inheriting .p3-map-pill's centering. It was the only
       bulleted list on the board that centered, and its bullet marker is
       absolutely positioned, so the text drifted away from it per line.
       The pill's LABEL and SINGLE-VALUE cases still center. Reasoning at
       the .p3-map-pill-list rule below.

   --alert is left as the proto writes it. NOTE that --alert is NOT defined
   in this sheet, so `var(--alert, #FC2323)` resolves to its fallback —
   which is the same value as this sheet's --red. Identical render, no token
   added; left alone deliberately rather than "corrected" to --red, the same
   call the .p3-seg-* block above makes.

   THIS SCREEN HAS ITS OWN CANVAS RULE AND ITS OWN ZOOM VARIABLE. Unlike
   segmentation — which rode .p2-cluster-canvas and therefore --p2-zoom —
   .p3-map-canvas is ported whole and consumes --p3-map-zoom, set from the
   atomic-tasks IIFE in app.js. The two boards zoom independently. Only the
   OUTER shell (.p2-cluster-screen / .p2-cluster-footer / .p2-zoom-controls
   / .p2-zoom-btn) is shared, for the footer-in-flow layout; the inner chain
   .p3-map-view -> .p3-map-canvas-wrap -> .p3-map-canvas is this screen's.

   NO SCOPE HOOK IS NEEDED, unlike .p3-seg-screen. The proto's map block
   contains no [data-screen="P3_WORKFLOW_MAP_FAC"] selectors, so there is
   nothing to rewrite and nothing that could leak onto a sibling screen.

   FOUR PROTO RULES ARE DELIBERATELY NOT PORTED, all four dead because their
   markup is gone (David's ruling):
     - .p3-map-meta / -row / -label / -value — the inline meta block was
       dropped from the header when Department/Task moved to the shared
       .p3-task-header, which is what this screen uses.
     - .p3-map-logo — the header's logo SVG was removed to avoid duplicating
       the brand mark the global app-header already carries.
     - .app-header.app-header--hidden — the proto's own comment records that
       the suppression was DROPPED (it made the menu unreachable). Also a
       GLOBAL .app-header rule, exactly the kind of leak the segmentation
       port scoped away; nothing in this build ever sets the class.
     - .p3-map-atomic-collapse — no element carries the class; the renderer
       emits .p3-map-atomic-toggle for Top 5 and .p3-map-card-toggle for the
       stage triangle.

   TWO ORPHANED-BY-DESIGN rules ARE carried, on the .p3-seg-card--empty
   precedent, so a later slice can re-light them without re-porting:
   .p3-map-atomic-card--collapsed (the renderer pins its class to '' — the
   atomic bucket is always open on this screen) and, though it is NOT
   orphaned, the whole --top5 scope, which the renderer does set.
   ===================================================================== */
/* =========================================================
   PHASE 3 — WORKFLOW MAP / ATOMIC TASKS (additive only)
   Screen: P3_WORKFLOW_MAP_FAC.
   The flex chain (.p2-cluster-screen → .p3-map-view →
   .p3-map-canvas-wrap) is the standard bounded chain so the
   canvas scrolls in both axes without pushing the footer
   below the fold.
   ========================================================= */

/* Head row (LIVE ADDITION, no proto counterpart). The Department/Task
   header and the ATOMIC TASKS title are ONE ROW, overlapping in a
   SINGLE GRID CELL: the task header sits left at its natural size, the
   title spans the full row width and centers on it. The row is as tall
   as the taller of the two, and align-items:center does the vertical
   alignment.

   THIS REPLACES A HAND-MEASURED CONSTANT. The proto stacked the two as
   siblings and pulled the title strip back up with margin-top:-58px —
   an asserted number standing in for the task header's own rendered
   height (60.4px of flow: two rows at font-size 18px x line-height 1.4,
   plus a 2px gap and an 8px margin-bottom). It was NOT derivable: the
   quantity is a SIBLING'S height and CSS has no expression that reads
   one, so no calc() could honestly replace it — only re-encode the same
   literals. And it left the task header OVERHANGING by 6px into the
   view region below, invisible only because .p3-map-canvas carries 48px
   of top padding. Every value here is auto, center or 0; no constant
   replaces the one removed.

   GRID OVERLAY, NOT A FLEX ROW, and this is the part that looks wrong
   until you try it: the title must center on the SCREEN, not in the
   space left beside the task header. As a flex sibling it would center
   in the residual space. A 1fr-spacer arrangement centers correctly
   only while the task header stays narrower than its flank, and breaks
   at narrow widths — which the proto's overlay never did. Sharing one
   cell keeps .p3-map-header full-width, so its own justify-content
   centers on the screen exactly as the offset version did.

   ACCEPTED DELTA (David, browser-confirmed): title ~1.8px lower, canvas
   start ~6px lower than the offset version. The 6px IS the overhang
   being paid back. Nothing constant-free lands on the old position
   exactly, because that position was defined by the constant.

   THE margin-bottom:0 IS SCOPED TO THIS WRAPPER, which exists only on
   this screen, so .p3-task-header is untouched on the twelve P3 topic
   stops and on segmentation — all of which share it. Same scoped-
   override pattern segmentation already uses for this very property
   (.p3-seg-screen .p3-task-header). Do NOT promote it to the base rule. */
.p3-map-head-row {
  flex: 0 0 auto;
  display: grid;
  align-items: center;
}
.p3-map-head-row > .p3-task-header,
.p3-map-head-row > .p3-map-header {
  grid-area: 1 / 1;
}
.p3-map-head-row .p3-task-header {
  margin-bottom: 0;
}

/* Title strip — centered across the full row width. pointer-events:none
   lets clicks pass through the empty space either side to anything
   beneath (the title itself has no interactions), which matters more
   here than in the proto: this element now overlays the task header in
   the same grid cell rather than merely being pulled over it. */
.p3-map-header {
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  color: var(--text);
  padding: 0 20px;
  pointer-events: none;
}
.p3-map-title {
  /* Bigger + underlined per the approved map. The underline is a
     bottom border sized to the text (inline-block) rather than a
     full-width rule, matching the mock. */
  display: inline-block;
  font-size: 24px;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--text);
  margin: 0;
  text-align: center;
  padding-bottom: 6px;
  border-bottom: 2px solid var(--text);
}

/* Main content region between the header and the footer.
   Transparent so the workflow map sits directly on the black
   background — consistent with the rest of the AWE system.
   flex:1 + min-height:0 lets the canvas wrap inside actually
   constrain so its overflow:auto can engage. */
.p3-map-view {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* The canvas wrap is the actual scrollable region. Both axes
   scroll inside this container; the page itself never scrolls.
   Scrollbar styling is light-on-dark (white-alpha thumb on a
   transparent track). Transparent track is the key to satisfying
   "no inactive scrollbars at full size": with overflow:auto the
   scrollbar only renders when content overflows; with a transparent
   track, even on systems configured to "always show scrollbars",
   the track is invisible — only the thumb appears, and only when
   scrolling is actually possible. */
.p3-map-canvas-wrap {
  flex: 1;
  min-height: 0;
  overflow: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.55) transparent;
}
.p3-map-canvas-wrap::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
.p3-map-canvas-wrap::-webkit-scrollbar-track {
  background: transparent;
}
.p3-map-canvas-wrap::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.55);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: padding-box;
}
.p3-map-canvas-wrap::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.75);
  background-clip: padding-box;
}
.p3-map-canvas-wrap::-webkit-scrollbar-corner {
  background: transparent;
}

/* The canvas itself is a horizontal flex row containing the
   alternating sequence of pill lane / arrow / stage lane /
   arrow / pill lane / arrow / next stage lane / etc. min-width
   max-content lets the row overflow horizontally; the wrap's
   overflow:auto handles the scroll. align-items:flex-start
   anchors lanes to the top so the stage cards line up across
   the row and atomic-task cards hang beneath them at the same
   y-coordinate. */
.p3-map-canvas {
  /* Single source of truth for stage card height; arrow
     vertical-center math derives from this. */
  --p3-map-card-h: 280px;
  --p3-map-atomic-h: 260px;

  /* Positioned so child offsetTop/offsetParent math in the
     bridge-arrow alignment resolves to this canvas reliably. */
  position: relative;
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 14px;
  /* Breathing room below the title row before the cards start. The
     title overlaps the task-header row (negative margin on
     .p3-map-header); this top padding sets the gap between that row
     and the top of the cards. */
  padding: 48px 48px 40px;
  min-width: max-content;
  /* Zoom — this screen's OWN variable, set from the atomic-tasks IIFE
     in app.js. NOT --p2-zoom: the segmentation board rode the cluster
     canvas and its variable, this one does not.
     transform-origin:top-left keeps the math simple; the zoom handlers
     apply a scroll-correction so the visible centerpoint stays anchored
     across zoom changes. */
  transform: scale(var(--p3-map-zoom, 1));
  transform-origin: top left;
  transition: transform 0.15s ease;
}

/* A "stage lane" stacks the stage card (top) and the atomic
   tasks card (bottom) into one vertical column. The lane is
   the unit that participates in horizontal layout; lanes sit
   between connector pills and arrows. */
.p3-map-stage-lane {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* A "pill lane" wraps a connector pill so it lives in the
   same flex layout as stage lanes. The pill sits at the top
   of the lane (vertically aligned with the stage cards' top
   edge); its width matches the pill's natural width. */
.p3-map-pill-lane {
  flex: 0 0 auto;
  display: flex;
  /* Center the pill vertically against the stage card area
     (top half of the lane height). */
  align-items: center;
  height: var(--p3-map-card-h);
}
/* The between-stage bridge anchors to the TOP of its lane (not
   center) so it and its diagonal trace arrows share the same top
   reference. This keeps the Output/Input rows and the arrows
   pinned in place when a stage card elsewhere in the row expands. */
.p3-map-bridge-lane {
  align-items: flex-start;
  padding-top: 8px;
}

/* Connector arrow between adjacent canvas elements. Drawn as a
   short gradient line with a CSS arrowhead (matches the report's
   decomposition connectors). Base = the leading Input endcap; the
   --to-out and --from-in variants offset vertically to trace the
   diagonal stage -> Output(top) -> Input(bottom) -> next stage flow.

   NOTE — margin-top:130px IS A HAND-DERIVED CONSTANT, keyed to
   --p3-map-card-h above: the pill lane is that height with the pill
   centered in it, so this lands the base arrow on the pill's center
   (280/2, less a few px for the arrow's own 2px height). It applies
   to exactly ONE arrow, the leading Input endcap, and it is the only
   arrow margin app.js does NOT overwrite — alignBridgeArrows selects
   only the two diagonal variants below.

   DELIBERATELY NOT CONVERTED to a calc() off --p3-map-card-h: the
   exact expression that reproduces today's render is not
   calc(var(--p3-map-card-h) / 2), which would shift the arrow 9px
   down. The 130px is the approved position; a "cleaner" derivation
   would change the picture.

   THE COUPLING IS THEREFORE NOT EXPRESSIBLE IN CSS HERE, the same
   trap the duplicated 420px carries in the .p3-seg-* block: IF
   --p3-map-card-h IS EVER RETUNED, THIS MARGIN MUST MOVE WITH IT.
   Nothing enforces that but this note. */
.p3-map-arrow {
  flex: 0 0 auto;
  position: relative;
  width: 30px;
  height: 2px;
  /* Top-anchored (not center): the arrows offset from the TOP of
     the lane, which is a fixed reference. Center-anchoring made the
     arrows jump when a stage card expanded and grew the row's
     centerline. Base arrow (lead Input) sits at the pill vertical
     center via its top offset. */
  align-self: flex-start;
  margin-top: 130px;
  background: linear-gradient(90deg, rgba(89,187,187,0.25), var(--teal));
  user-select: none;
}
.p3-map-arrow::after {
  content: '';
  position: absolute;
  right: -1px;
  top: 50%;
  transform: translateY(-50%);
  width: 0;
  height: 0;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  border-left: 8px solid var(--teal);
}
/* Diagonal trace arrows around the between-stage bridge. Anchored to
   the TOP of the lane (not center) so they stay pinned to the
   bridge's Output (top) and Input (bottom) rows even when a stage
   card elsewhere in the row expands — a center-anchored arrow would
   jump because expanding a card changes the row's centerline.

   THESE TWO MARGINS ARE TRANSIENT, unlike the base arrow's 130px
   above. app.js's alignBridgeArrows resets each arrow to 0px,
   measures its bridge group's real center with getBoundingClientRect,
   and writes an inline margin-top over these values on EVERY render —
   so they are only the pre-measurement paint, and they self-correct
   for any item count, card expand/collapse or Top-5 toggle. The
   proto's "eyeball in Chrome and nudge if a row sits slightly off"
   note predates that measurement pass and is NOT carried: nudging
   these by hand would change nothing after the first frame. */
.p3-map-arrow--to-out,
.p3-map-arrow--from-in {
  align-self: flex-start;
}
.p3-map-arrow--to-out    { margin-top: 54px; }
.p3-map-arrow--from-in   { margin-top: 226px; }

/* Input / Output connector pill. Soft-teal rounded slab,
   "Label:" + value. Display-only. Used for the leading Input
   endcap (feeds Stage 1). Between-stage handoffs use the
   two-part .p3-map-bridge below. */
.p3-map-pill {
  background: rgba(89, 187, 187, 0.16);
  border: 1.5px solid rgba(89, 187, 187, 0.55);
  border-radius: 6px;
  padding: 10px 14px;
  font-size: 12px;
  line-height: 1.4;
  color: #eaf4f4;
  /* Cap pill width so a long input/output value wraps inside
     the pill rather than stretching it across the canvas. */
  max-width: 180px;
  text-align: center;
}
.p3-map-pill-label {
  display: block;
  font-weight: 600;
  color: var(--teal);
  margin-bottom: 2px;
  /* The colon was dropped from the markup (it used to read
     "Output: value"). With multi-line lists below, the
     colon-then-list pattern read awkwardly; the label now reads
     as a sectioning header for the list/value below. */
}
.p3-map-pill-value {
  display: block;
  color: rgba(234, 244, 244, 0.78);
  word-break: break-word;
  overflow-wrap: anywhere;
}
/* Pill mini-list. Used when the pill is carrying a multi-item
   inputs/outputs list — small bulleted lines that match what the
   facilitator typed in segmentation, sitting inside the existing
   pill capsule. */
.p3-map-pill-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
  /* LEFT-ALIGNED, diverging from the proto (tweak slice, David 2026-07-26).
     .p3-map-pill sets text-align:center for its label and single-value case,
     and this list inherited it — so the lead Input pill was the only bulleted
     list on the board that centered, against the bridge boxes and the stage
     card sections which all read left.

     THE DISCRIMINATOR IS THE MARKER, not list-versus-value. The li::before
     bullet is position:absolute at left:2px with padding-left:10px holding
     its gutter, so the marker is PINNED while centered text drifts away from
     it by a different amount on every line — the longer the line, the smaller
     the gap. The single value has no marker and stays centered (see the
     .p3-map-pill-value note): that case is a short one-liner in a 180px
     capsule where centering reads as deliberate. */
  text-align: left;
}
.p3-map-pill-list li {
  position: relative;
  padding-left: 10px;
  color: rgba(234, 244, 244, 0.78);
  font-size: 11px;
  line-height: 1.35;
  word-break: break-word;
  overflow-wrap: anywhere;
}
.p3-map-pill-list li::before {
  content: '';
  position: absolute;
  left: 2px;
  top: 0.55em;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: rgba(89, 187, 187, 0.65);
}

/* Two-part stage-handoff bridge. Soft-teal capsule, quieter than
   the stage headers so it reads as connective tissue. Output
   group (top) over Input group (bottom), divided by a dashed
   rule. Output = the prior stage produces; Input = what the next
   stage consumes. Display-only, live-derived from stage data. */
.p3-map-bridge {
  background: rgba(89, 187, 187, 0.16);
  border: 1.5px solid rgba(89, 187, 187, 0.55);
  border-radius: 6px;
  max-width: 188px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.p3-map-bridge-group {
  padding: 9px 14px;
}
.p3-map-bridge-group--in {
  border-top: 1px dashed rgba(89, 187, 187, 0.45);
}
.p3-map-bridge-label {
  display: block;
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 700;
  margin-bottom: 7px;
}
.p3-map-bridge-group--out .p3-map-bridge-label { color: var(--teal); }
.p3-map-bridge-group--in  .p3-map-bridge-label { color: rgba(234, 244, 244, 0.55); }
.p3-map-bridge-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.p3-map-bridge-list li {
  position: relative;
  padding-left: 11px;
  color: rgba(234, 244, 244, 0.80);
  font-size: 11.5px;
  line-height: 1.35;
  word-break: break-word;
  overflow-wrap: anywhere;
}
.p3-map-bridge-list li::before {
  content: '';
  position: absolute;
  left: 2px;
  top: 0.5em;
  width: 3.5px;
  height: 3.5px;
  border-radius: 50%;
}
.p3-map-bridge-group--out .p3-map-bridge-list li::before { background: var(--teal); }
.p3-map-bridge-group--in  .p3-map-bridge-list li::before { background: rgba(234, 244, 244, 0.34); }

/* Stage card. Teal header band over a white body, dark text —
   same visual language as the segmentation card so the two
   screens read as the same system. Fixed height (driven by the
   canvas-level CSS variable) so every card is uniform and
   content scrolls inside instead of pushing the card. */
.p3-map-card {
  flex: 0 0 auto;
  width: 240px;
  height: var(--p3-map-card-h);
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid #D0D0D0;
  border-radius: 6px;
  overflow: hidden;
}
/* Collapsed top card: only the teal title bar shows (the body is
   omitted from markup). height:auto shrinks the card to the header,
   mirroring the atomic-card collapsed treatment. This is the state
   when the atomic bucket is open (mutually exclusive). */
.p3-map-card--collapsed {
  height: auto;
}
.p3-map-card-header {
  flex: 0 0 auto;
  background: var(--teal);
  padding: 8px 8px 8px 12px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.10);
  /* Flex row: stage name (left, flexes) + toggle triangle (right).
     The triangle drives the expand of the stage card body. */
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
.p3-map-card-name {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
  text-align: center;
  flex: 1;
}
/* Toggle triangle on the top card — semi-transparent chip on the
   teal band, matching the atomic-toggle affordance language. */
.p3-map-card-toggle {
  flex: 0 0 auto;
  background: rgba(255, 255, 255, 0.18);
  border: none;
  color: #fff;
  font-family: inherit;
  font-size: 12px;
  line-height: 1;
  padding: 3px 6px;
  border-radius: 3px;
  cursor: pointer;
  transition: background 120ms ease;
}
.p3-map-card-toggle:hover {
  background: rgba(255, 255, 255, 0.32);
}
.p3-map-card-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 12px;
  /* Polished thin inner scrollbar — same convention as the
     segmentation cards (light-on-light scrollbar for the
     white card body). */
  scrollbar-width: thin;
  scrollbar-color: rgba(0, 0, 0, 0.30) rgba(0, 0, 0, 0.06);
}
.p3-map-card-body::-webkit-scrollbar { width: 6px; }
.p3-map-card-body::-webkit-scrollbar-track {
  background: rgba(0, 0, 0, 0.06);
  border-radius: 999px;
  margin: 2px 0;
}
.p3-map-card-body::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.30);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: padding-box;
}
.p3-map-card-desc {
  margin: 0 0 10px;
  color: #555;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.5;
}

/* Card section — generic block reused for Inputs, Outputs,
   and Departments inside a stage card body. Bold "Label:" line
   followed by a bulleted list. Compact spacing keeps multiple
   sections readable in a fixed-height card. */
.p3-map-card-section {
  font-size: 12px;
  line-height: 1.5;
  color: #555;
  margin-bottom: 10px;
}
.p3-map-card-section:last-child {
  margin-bottom: 0;
}
.p3-map-card-section-label {
  display: block;
  font-weight: 600;
  color: #1a1a1a;
  margin-bottom: 2px;
}
.p3-map-card-section-list {
  margin: 0;
  padding-left: 18px;
  list-style: disc;
}
.p3-map-card-section-list li {
  margin: 2px 0;
}

/* Atomic Tasks card — sits beneath each stage card inside the
   stage lane. Same width as the stage card; teal header band
   (matches the AWE accent color) to differentiate it from the
   stage card visually. Fixed height with internal scroll so
   long lists don't push the lane taller than its peers. When
   collapsed (.p3-map-atomic-card--collapsed), the body is
   omitted from the markup entirely and the card shrinks to the
   header's intrinsic height. */
.p3-map-atomic-card {
  flex: 0 0 auto;
  width: 240px;
  height: var(--p3-map-atomic-h);
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid #D0D0D0;
  border-radius: 6px;
  overflow: hidden;
}
/* ORPHANED BY DESIGN — carried, not live. The renderer pins the
   collapsed class to '' because the atomic bucket is ALWAYS open on
   this screen; the stage card's triangle collapses the card above it,
   not this one. Kept so a later slice can re-light the variant
   without re-porting (the .p3-seg-card--empty precedent). */
.p3-map-atomic-card--collapsed {
  height: auto;
}
/* Top-5 mode is a focused viewing mode: card shrinks to fit only
   the visible 5 rows (height:auto removes the fixed
   --p3-map-atomic-h height; the body's overflow becomes a no-op
   because content no longer overflows). The delete column is
   hidden inside this scope so the focused view is read-only;
   +Add Task is omitted from the markup in app.js for the same
   reason. */
.p3-map-atomic-card--top5 {
  height: auto;
}
.p3-map-atomic-card--top5 .p3-map-task-del {
  display: none;
}

/* Header is a flex row: title on the left, control cluster on
   the right. */
.p3-map-atomic-header {
  flex: 0 0 auto;
  background: var(--teal);
  padding: 6px 8px 6px 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
.p3-map-atomic-name {
  display: block;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #fff;
}
.p3-map-atomic-controls {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

/* Header-control button (Top 5). Compact, semi-transparent so the
   teal header reads as primary chrome and the button reads as an
   affordance within it. */
.p3-map-atomic-toggle {
  background: rgba(255, 255, 255, 0.18);
  border: none;
  color: #fff;
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 3px 8px;
  border-radius: 3px;
  cursor: pointer;
  line-height: 1;
  transition: background 120ms ease;
}
.p3-map-atomic-toggle:hover {
  background: rgba(255, 255, 255, 0.32);
}
/* Disabled Top-5: grayed and non-interactive until there are 6+
   tasks (nothing to limit below that). This is the state every
   bucket opens in while nothing seeds the task lists. */
.p3-map-atomic-toggle--disabled,
.p3-map-atomic-toggle:disabled {
  background: rgba(255, 255, 255, 0.10);
  color: rgba(255, 255, 255, 0.40);
  cursor: not-allowed;
}
.p3-map-atomic-toggle--disabled:hover,
.p3-map-atomic-toggle:disabled:hover {
  background: rgba(255, 255, 255, 0.10);
}

/* Pinned footer holding the +Add Task button. Sits below the
   scrolling .p3-map-atomic-body (flex:0 0 auto) so the button is
   always visible regardless of how long the task list is or whether
   Top-5 is active. A hairline top border separates it from the list. */
.p3-map-atomic-foot {
  flex: 0 0 auto;
  padding: 8px 10px;
  border-top: 1px solid #E2E2E2;
  background: #fff;
}

/* Body: scrollable area for the task list. White-on-light
   scrollbar (track transparent, dark thumb only) for clean
   appearance against the white card body. */
.p3-map-atomic-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 10px 10px 12px;
  scrollbar-width: thin;
  scrollbar-color: rgba(0, 0, 0, 0.30) transparent;
}
.p3-map-atomic-body::-webkit-scrollbar { width: 6px; }
.p3-map-atomic-body::-webkit-scrollbar-track {
  background: transparent;
}
.p3-map-atomic-body::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.30);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: padding-box;
}
.p3-map-atomic-body::-webkit-scrollbar-thumb:hover {
  background: rgba(0, 0, 0, 0.45);
  background-clip: padding-box;
}

.p3-map-atomic-list {
  list-style: none;
  margin: 0 0 8px;
  padding: 0;
  font-size: 12px;
  line-height: 1.5;
  color: #444;
}

/* Each task row: number (drag handle), editable text, delete.
   Grid layout keeps numbering and controls aligned across rows.
   The "1fr" column for the editable text grows so long task text
   wraps inside the row instead of pushing the delete button off
   the right edge. */
.p3-map-task-row {
  display: grid;
  /* Number / text / delete. The delete column is hidden in Top-5
     (display) mode via the .p3-map-atomic-card--top5 scope. */
  grid-template-columns: auto 1fr auto;
  align-items: start;
  gap: 4px;
  padding: 3px 0;
  /* Subtle visual reset for drag interaction states. The number
     element supplies the cursor:grab affordance; the row as a
     whole shows a low-contrast drop indicator on dragover. */
  border-radius: 3px;
  transition: background 100ms;
}
.p3-map-task-row.dragging {
  opacity: 0.4;
}
.p3-map-task-row.drag-over {
  /* Subtle teal drop indicator — matches the .p3-seg-card
     drag-over treatment for visual continuity inside Phase 3. */
  background: rgba(93, 189, 181, 0.10);
  box-shadow: inset 0 -2px 0 0 var(--teal);
}
.p3-map-task-num {
  color: #888;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.5;
  text-align: right;
  padding-top: 1px;
  /* Drag affordance — number doubles as the row's drag handle.
     cursor:grab signals the interaction; user-select:none avoids
     accidental text-selection of the number while dragging. */
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  /* A few pixels of horizontal padding gives the handle a slightly
     larger hit target without changing visible width perceptibly. */
  padding-left: 2px;
  padding-right: 4px;
}
.p3-map-task-num:active {
  cursor: grabbing;
}
.p3-map-task-text {
  color: #1a1a1a;
  font-size: 12px;
  line-height: 1.5;
  /* Editable affordance comes from .p3-editable; this rule
     only sets typography. */
}
/* Delete button — small, low-contrast, hover-emphasized. */
.p3-map-task-del {
  width: 16px;
  height: 16px;
  padding: 0;
  background: transparent;
  border: none;
  color: rgba(0, 0, 0, 0.30);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  border-radius: 3px;
  margin-top: 1px;
  transition: color 100ms, background 100ms;
}
.p3-map-task-del:hover {
  color: var(--alert, #FC2323);
  background: rgba(252, 35, 35, 0.08);
}

/* +Add Task button — sits in the pinned footer below the list.
   Lightweight ghost style to avoid competing with the teal
   header. */
.p3-map-task-add {
  display: block;
  width: 100%;
  background: transparent;
  border: 1px dashed rgba(0, 0, 0, 0.20);
  border-radius: 4px;
  color: #555;
  font-family: inherit;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
  padding: 6px 8px;
  cursor: pointer;
  transition: color 120ms, border-color 120ms, background 120ms;
}
.p3-map-task-add:hover {
  color: var(--teal);
  border-color: var(--teal);
  background: rgba(93, 189, 181, 0.06);
}

/* Editable affordance overrides for the white atomic card —
   the global .p3-editable:hover uses a white-alpha underline
   that disappears on white. Override with a dark-alpha
   underline so hover is visible inside the atomic card. */
.p3-map-atomic-card .p3-editable:hover {
  border-bottom-color: rgba(0, 0, 0, 0.15);
}
.p3-map-atomic-card .p3-editable:focus {
  border-bottom-color: var(--teal);
}

/* Placeholder for empty editable task (e.g. just-added blank).
   Same :empty::before trick used by the segmentation card. */
.p3-map-atomic-card .p3-editable:empty::before {
  content: attr(data-placeholder);
  color: rgba(0, 0, 0, 0.30);
  font-style: italic;
  pointer-events: none;
}

/* Dev-fill button placement (LIVE ADDITION, not a port — the prototype has no
   dev-fill on this screen; it seeds the canvas from its own scenario toggles).
   The .p3-seg-dev-fill treatment verbatim: .legal-dev-fill is
   `position: absolute; top:0; right:0` because the P1/P3 editors pin it inside
   their position:relative .legal-edit-head, and this screen has no such head
   row, so the button gets a positioned wrapper and hands `position: static`
   back. 43px matches the shell's own side padding, so the button lines up with
   the screen's right edge.
   Comes out with the rest of the DEMO_TEST_FILL scaffolding. */
.p3-map-dev-fill {
  position: fixed;
  right: 43px;
  top: calc(var(--app-header-h) + 8px);
  z-index: 30;
}
.p3-map-dev-fill .legal-dev-fill { position: static; }

/* =====================================================================
   PORT RECORD — PHASE 3 OUTPUT (the atomic tasks LISTING stop)
   Source: root styles.css:5480-5597, the P3_OUTPUT_FAC block. Fifteen
   rules, ported byte-identical APART FROM THREE LINES, all token
   remaps on the established sheet-wide mapping (plus ONE added rule,
   .p3-output-placeholder, recorded below): proto var(--fg) ->
   var(--text) on .p3-output-title and .p3-output-task-list, and proto
   var(--fg-dim) -> var(--muted) on .p3-output-empty. --teal is shared.
   That is the same three-line count the atomic tasks port hit (TB-58).

   NO SCOPE HOOK IS NEEDED, and unlike the segmentation port there is
   nothing to invent one for: the proto's output block contains NO
   [data-screen] selectors, so there is nothing to rewrite and nothing
   that can leak onto a sibling screen. The .p3-output-* namespace is
   also unused elsewhere in this sheet and in assets/app.js, so the
   block lands clean.

   NO RULES DROPPED. The atomic tasks port dropped four dead rules
   whose markup was gone; every rule here has live markup. One is a
   NO-OP and is carried anyway rather than "tidied": .p3-output-segment
   sets display:block on a <section>, which is already block. It is the
   proto's byte, it costs nothing, and removing it would make the port
   record a judgement call instead of a copy.

   ONE RULE IS ADDED, .p3-output-placeholder, and it has NO PROTO
   COUNTERPART — it is the only thing in this block that is not a copy.
   It carries a ruling (David): every committed stage renders in
   sequence so the numbering stays dense and agrees with the locked
   board, and a stage with no tasks shows "Not yet determined" in place
   of its list. The prototype instead DROPS such a stage, which skips a
   number; it could afford that because every bucket there was seeded
   and zero tasks was effectively unreachable, while in this build empty
   is an ordinary outcome (TB-58 dropped both seed branches, TB-60
   writes a row for every committed stage). Full reasoning is at the
   call site in screen_atomic_tasks_list.php.

   IT REPLACES THE <ol>, IT IS NOT AN <li> INSIDE IT, which is why it
   needs its own rule rather than a modifier on .p3-output-task:
   .p3-output-task-list is list-style:decimal, so an item there would
   render "1." and assert that a first-ranked task exists — the false
   claim TB-60's at_clean_tasks() drops blank lines to prevent. An
   absence must not occupy a rank. Its font-size, line-height and margin
   are .p3-output-task's exactly, so a stage's vertical rhythm does not
   change when it has no tasks; padding-left is that rule's 4px plus the
   list's own 24px, so the text starts where task text would. Muted +
   italic is the sheet's existing "nothing here yet" idiom (compare the
   atomic card's empty-task placeholder), which distinguishes it from a
   task without introducing a new visual language.

   ONE PROTO COMMENT IS STALE AT SOURCE and is carried intact with this
   note, on the same footing as the superseded align-self sentences in
   the segmentation port: .p3-output-view's comment describes the
   rhythm as "header -> col-headers strip -> scroll region". THERE IS
   NO COL-HEADERS STRIP in the markup — the proto's own P3_OUTPUT_FAC
   has header then scroll region and nothing between them, and neither
   does this build. The sentence describes an earlier shape of the
   screen. The two elements it does name are accurate.

   THE FLEX CHAIN IS WHAT MAKES THIS WORK, and it is the one thing the
   proto got for free and this build does not. .p3-output-view is
   `flex: 1; min-height: 0` and needs a parent with a DEFINITE height;
   in the prototype that parent is a bare .screen with an IN-FLOW
   footer. The live .begin-footer is position:fixed, so the height comes
   from .p3-screen:has(.p3-output-view) further up this sheet — which
   SHARES its declaration block with the item-editor variant rather than
   copying it, so the 72px footer clearance exists once. See the note
   there. No constant is introduced on this side.
   ===================================================================== */
/* =========================================================
   PHASE 3 — OUTPUT
   Read-only final screen (P3_OUTPUT_FAC). For each stage, the
   stage name then its top-5 atomic tasks. Editorial / executive
   feel — sparse, structured text, no heavy cards, no chrome.
   ========================================================= */

.p3-output-view {
  /* Non-scrolling layout container. Owns the screen padding and
     the overall vertical rhythm (header → col-headers strip →
     scroll region). The scroll region inside owns the actual
     overflow handling so the title, metadata, and column headers
     stay pinned while the task lists move underneath. */
  flex: 1;
  min-height: 0;
  overflow: hidden;
  padding: 24px 48px 24px;
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.p3-output-header {
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: 0 0 auto;
}

.p3-output-title {
  margin: 0;
  font-size: 22px;
  font-weight: 400;
  letter-spacing: 0.10em;
  color: var(--text);
  text-transform: uppercase;
}
/* Small subtitle beneath the title noting the top-5 convention.
   Subtle (muted color, small size, mild letter-spacing) so it
   reads as a note rather than a competing headline. */
.p3-output-subtitle {
  margin: 6px 0 0 0;
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.50);
  text-transform: uppercase;
}

/* ====================================================
   PHASE 3 OUTPUT (final screen) — segment name + top-5
   atomic tasks.
   ==================================================== */
.p3-output-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.30) rgba(255, 255, 255, 0.06);
}
.p3-output-scroll::-webkit-scrollbar { width: 6px; }
.p3-output-scroll::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.06);
  border-radius: 999px;
  margin: 2px 0;
}
.p3-output-scroll::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.30);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: padding-box;
}
.p3-output-scroll::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.45);
  background-clip: padding-box;
}
/* Single readable column, centered, with comfortable spacing
   between segments. */
.p3-output-list {
  max-width: 720px;
  margin: 0 auto;
  padding: 8px 0 24px;
  display: flex;
  flex-direction: column;
  gap: 28px;
}
.p3-output-segment {
  display: block;
}
.p3-output-segment-name {
  margin: 0 0 10px;
  color: var(--teal);
  font-size: 16px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding-bottom: 6px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.15);
}
.p3-output-task-list {
  margin: 0;
  padding-left: 24px;
  list-style: decimal;
  color: var(--text);
}
.p3-output-task {
  font-size: 15px;
  line-height: 1.6;
  margin: 4px 0;
  padding-left: 4px;
}
/* LIVE ADDITION, no proto counterpart — the empty-stage placeholder
   ("Not yet determined"), rendered INSTEAD OF .p3-output-task-list so
   it takes no rank. See the port record above the block. Typography is
   .p3-output-task's, so the rhythm is unchanged; padding-left is that
   rule's 4px plus the list's own 24px, so it starts where task text
   would. Muted + italic marks it as an absence, not a task. */
.p3-output-placeholder {
  font-size: 15px;
  line-height: 1.6;
  margin: 4px 0;
  padding-left: 28px;
  color: var(--muted);
  font-style: italic;
}
.p3-output-empty {
  color: var(--muted);
  font-size: 14px;
  text-align: center;
  margin-top: 40px;
}

/* ============================================================
   PHASE 4 — FINDING VALUE (Phase 4a)
   Identify Breakdowns screen: stage cards + tagging overlay.
   Built into the existing system — black bg, teal system chrome,
   Raleway, the shared .modal-overlay/.modal-card patterns. The
   "new card" is a deliberate in-system variation (flatter, issue-
   tag focused), distinct from the P3 map card but NOT a new look.
   Tag colors are the COLOR_SYSTEM roster-free issue palette — no
   new colors introduced (Manual=bronze/gold, Time sink=burnt amber,
   Error-prone=rose/crimson, Bottleneck=slate blue-grey).

   Ported from the prototype's root styles.css:5770-6001.
   TOKEN MAPPING, the same one every prior port in this sheet
   records (see :477-478, :1088, :1258-1260): proto --fg -> --text,
   proto --fg-dim -> --muted. Neither proto token exists here.
   --teal / --teal-deep / --card-fg are spelled the same in both.
   The shared .modal-overlay / .modal-card / .modal-head /
   .modal-title / .modal-close / .modal-body chrome the overlay
   sits inside ALREADY EXISTS in this sheet (:1976-2020) and is
   NOT re-ported — only the .p4-tag-* additions below are new.
   ============================================================ */

/* --- breakdown tag color tokens (alias existing system values) --- */
:root {
  --p4-manual:     #C6A15B;  /* bronze/gold — roster-free (was roster orange) */
  --p4-time:       #E08A3C;  /* burnt amber — roster-free (was roster yellow) */
  --p4-error:      #D4506A;  /* rose/crimson — roster-free (not logo red) */
  --p4-bottleneck: #5B8C9E;  /* slate blue-grey — roster-free (was roster purple) */
}

/* --- screen layout. The shell itself is .p2-cluster-screen (reused, see
   screen_p4_breakdowns.php); .p4-breakdowns-screen is this screen's own scope
   hook and carries no declarations yet — it exists so a later rule can scope
   to this screen without leaking onto the P2 board or the P3 canvases. --- */
.p4-breakdowns-view {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;            /* allow the canvas to scroll inside flex */
  padding: 0 48px;
}
.p4-breakdowns-title {
  flex: 0 0 auto;
  font-family: 'Raleway', sans-serif;
  font-size: 26px;
  font-weight: 600;
  color: var(--teal);
  margin: 8px 0 20px;
  text-align: center;
}

/* --- card grid: wraps and scrolls; never breaks past 6 --- */
.p4-breakdowns-canvas {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  align-content: start;
  padding: 4px 4px 8px;
}

/* --- the breakdown card (new in-system design) --- */
.p4-seg-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 132px;
  padding: 16px 18px;
  background: #0c0c0c;
  border: 1px solid rgba(89, 187, 187, 0.35);   /* teal, dimmed — system chrome */
  border-radius: 10px;
  cursor: pointer;
  transition: border-color 140ms ease, background 140ms ease, transform 140ms ease;
}
.p4-seg-card:hover {
  border-color: var(--teal);
  background: #111;
  transform: translateY(-1px);
}
.p4-seg-card:focus-visible {
  outline: 1px solid var(--teal);
  outline-offset: 3px;
}
/* A card that has at least one issue tagged reads as "looked at". */
.p4-seg-card.is-tagged {
  border-color: var(--teal);
}
.p4-seg-card-name {
  font-family: 'Raleway', sans-serif;
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.3;
  text-align: center;
}
.p4-seg-card-hint {
  font-family: 'Raleway', sans-serif;
  font-size: 12px;
  color: var(--muted);
  margin-top: auto;       /* pin to the bottom when no chips yet */
}
/* chips row — the tags identified for this stage */
.p4-seg-card-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: auto;
}
.p4-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: 'Raleway', sans-serif;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text);
  padding: 3px 9px 3px 7px;
  border-radius: 999px;
  border: 1px solid currentColor;  /* the dot/border carry the tag color */
  background: transparent;
}
.p4-chip .p4-chip-dot {
  width: 8px; height: 8px;
  border-radius: 2px;          /* SQUARE marker — issues are squares,
                                  people/tally dots are round. Holds the
                                  distinction even if color is hard to read. */
  background: currentColor;
}
.p4-chip .p4-chip-text { color: var(--text); }
/* tag color carriers — set `color` so dot + border inherit it */
.p4-tag--manual     { color: var(--p4-manual); }
.p4-tag--time       { color: var(--p4-time); }
.p4-tag--error      { color: var(--p4-error); }
.p4-tag--bottleneck { color: var(--p4-bottleneck); }

/* empty state — no committed Phase 3 stages to tag */
.p4-breakdowns-empty {
  grid-column: 1 / -1;
  text-align: center;
  color: var(--muted);
  font-family: 'Raleway', sans-serif;
  font-size: 14px;
  padding: 48px 0;
}

/* --- legend: lives in the footer row, aligned with BACK/NEXT.
   Matches the Phase 2 .cluster-legend treatment — a compact
   reference strip sitting between the left edge and the nav
   buttons. margin-right:auto pushes BACK/NEXT to the right edge
   while the legend rests at the left, both on the footer baseline.

   PORTED AHEAD OF ITS ONLY CALLER. The Identify Breakdowns screen
   deliberately emits NO legend — its issues are full labeled chips
   on the cards, so a key would be redundant (see the proto comment
   at index.html:1790-1793, carried into screen_p4_breakdowns.php).
   The legend belongs to the Stage Vote screens, where issues are
   bare colored dots, and those are a later slice. These four rules
   are unused until then; that is deliberate, not dead code left
   behind. --- */
.p4-breakdowns-legend {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 18px;
  margin-right: auto;        /* push nav buttons to the right edge */
  min-width: 0;
}
.p4-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: 'Raleway', sans-serif;
  font-size: 12px;
  font-weight: 500;
  color: var(--muted);
  white-space: nowrap;
}
.p4-legend-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.p4-legend-dot.p4-tag--manual     { background: var(--p4-manual); }
.p4-legend-dot.p4-tag--time       { background: var(--p4-time); }
.p4-legend-dot.p4-tag--error      { background: var(--p4-error); }
.p4-legend-dot.p4-tag--bottleneck { background: var(--p4-bottleneck); }

/* --- tagging overlay (reuses .modal-overlay / .modal-card) --- */
.p4-tag-card {
  width: min(460px, 90vw);
}
.p4-tag-title {
  color: var(--teal);
  font-family: 'Raleway', sans-serif;
  font-size: 20px;
  font-weight: 600;
}
.p4-tag-prompt {
  font-family: 'Raleway', sans-serif;
  font-size: 14px;
  color: var(--card-fg);          /* dark text — the card is white */
  opacity: 0.7;
  margin: 0 0 16px;
}
.p4-tag-options {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* a toggle row — multi-select; whole row is clickable */
.p4-tag-option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid rgba(26, 26, 26, 0.18);   /* dark border on white card */
  border-radius: 8px;
  background: transparent;
  cursor: pointer;
  font-family: 'Raleway', sans-serif;
  font-size: 15px;
  color: var(--card-fg);          /* dark text — the card is white */
  transition: border-color 120ms ease, background 120ms ease;
  text-align: left;
}
.p4-tag-option:hover {
  border-color: rgba(26, 26, 26, 0.4);
  background: rgba(26, 26, 26, 0.03);
}
.p4-tag-option .p4-tag-swatch {
  width: 14px; height: 14px;
  border-radius: 50%;
  flex: 0 0 auto;
}
.p4-tag-option .p4-tag-check {
  margin-left: auto;
  font-size: 15px;
  color: var(--teal-deep);        /* readable check on white */
  opacity: 0;
  transition: opacity 120ms ease;
}
/* selected state — multi-select; row stays lit while chosen */
.p4-tag-option.is-selected {
  border-color: var(--teal-deep);
  background: rgba(89, 187, 187, 0.12);
}
.p4-tag-option.is-selected .p4-tag-check { opacity: 1; }
.p4-tag-option .p4-tag-swatch.p4-tag--manual     { background: var(--p4-manual); }
.p4-tag-option .p4-tag-swatch.p4-tag--time       { background: var(--p4-time); }
.p4-tag-option .p4-tag-swatch.p4-tag--error      { background: var(--p4-error); }
.p4-tag-option .p4-tag-swatch.p4-tag--bottleneck { background: var(--p4-bottleneck); }

/* ============================================================
   PHASE 4 — STAGE VOTE (screen_p4_stage_vote.php)
   Ported from the root prototype stylesheet, styles.css:6003-6135
   (the "PHASE 4 — STAGE VOTE / RESULTS / FINAL SELECTION" block,
   from its header comment through .p4-vote-check), plus two rules
   that sit further down that sheet and are pulled up here because
   this screen is their first caller:
     :6678       .p4-chip-row  — the wrapper p4IssueChipsHtml emits.
                 The live sheet already carries .p4-chip and
                 .p4-seg-card-chips from slice 1 but NOT this, so the
                 vote cards' chips would have had no row box.
     :6717-6719  .p4-vote-submit-row and the greyed Submit.
   The ported range STOPS at .p4-vote-check: everything after it in
   the proto block (.p4-result-card onward) belongs to the vote
   RESULTS screen, a later slice.

   TOKEN MAPPING, as everywhere in this sheet: proto --fg -> --text,
   proto --fg-dim -> --muted. Neither proto token exists here.

   THREE RULES OF THE RANGE ARE PORTED BUT UNCALLED THIS SLICE, and
   that is deliberate rather than dead code — the same call slice 1
   made porting the legend "ahead of its only caller":
     .p4-vote-issue-dots        the RESULTS cards' bare dots.
     .p4-part-legend-footer     a participant legend the proto's own
                                stage-vote markup does not use
                                (index.html:1849-1862 has no legend;
                                its facilitator sibling says why —
                                the cards carry LABELED chips, so
                                there is nothing to cross-reference).
     .p4-vote-card--withchips .p4-seg-card-chips
                                the breakdowns-style chip wrapper.
                                These cards use .p4-chip-row instead;
                                the rule is kept so the two sheets
                                stay line-comparable.
   ============================================================ */

/* subhead under the vote/results title */
.p4-vote-subhead {
  flex: 0 0 auto;
  text-align: center;
  font-family: 'Raleway', sans-serif;
  font-size: 14px;
  color: var(--muted);
  margin: -8px 0 18px;
}

/* participant vote screen wrapper */
.p4-vote-part-view {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 0 48px;
  /* SUBSTITUTION (this slice): the proto colours the ✓ token with an inline
     style read from the roster (root app.js:7867). This build has a committed
     per-seat variable chain instead — screen_p4_stage_vote.php puts the
     seat-<color_id> class on this element, which sets --seat, and this maps it
     onto --participant-color exactly as .p2-vote-view does (:1084-1086). Teal
     fallback if color_id is absent. The module never touches colour. */
  --participant-color: var(--seat, var(--teal));
}
.p4-vote-instruction {
  flex: 0 0 auto;
  font-family: 'Raleway', sans-serif;
  font-size: 15px;
  color: var(--muted);
  margin: 8px 0 6px;
}

/* HEADING BLOCK CENTERED (David, 2026-07-30) — the participant board's name
   line, instruction and counter, to match the centered .p4-breakdowns-title /
   .p4-vote-subhead pair the facilitator monitor, the results screen and the
   Identify Breakdowns screen all already use. These three inherited `start`
   from the view and were the one heading block in Phase 4 reading left.

   SCOPED TO .p4-vote-part-view RATHER THAN FIXED ON THE SHARED CLASS, and that
   is forced rather than preferred. .p2-vote-role is the P2 workflow-vote and
   category-rank heading too (:1089) — committed, browser-verified screens whose
   left-aligned heading is their intended treatment — so centering the class
   itself would silently restyle them. The P4 view is the narrowest scope that
   moves only what was asked for.

   THE CANVAS IS DELIBERATELY NOT INCLUDED. text-align inherits, so putting this
   on .p4-vote-part-view itself would also centre every vote card's name inside
   .p4-vote-canvas — a change to the CARD treatment, not the heading. The three
   heading elements are named individually to keep the cards exactly as they are. */
.p4-vote-part-view > .p2-vote-role,
.p4-vote-part-view > .p4-vote-instruction,
.p4-vote-part-view > .p4-vote-counter {
  text-align: center;
}
.p4-vote-counter {
  flex: 0 0 auto;
  font-family: 'Raleway', sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--teal);
  margin: 0 0 18px;
}

/* shared vote/results/final card grid — wraps and scrolls */
.p4-vote-canvas {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  align-content: start;
  padding: 4px 4px 8px;
}

/* base vote card (facilitator monitor + participant) */
.p4-vote-card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 96px;
  padding: 18px;
  background: #0c0c0c;
  border: 1px solid rgba(89, 187, 187, 0.35);
  border-radius: 10px;
}
.p4-vote-card-name {
  font-family: 'Raleway', sans-serif;
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.3;
  /* CENTERED (David, 2026-07-30) to match .p4-seg-card-name (:4881), the
     Identify Breakdowns card name — every other declaration in the two rules
     is already identical, so this is the last line that made the boards read
     differently. The CHIPS STAY LEFT on both screens, as they do on the
     breakdowns card: .p4-chip-row is a flex row at its default flex-start. */
  text-align: center;
}

/* vote card carrying issue chips (facilitator vote screen) —
   top-aligned with room for the chip row, matching the breakdowns
   card proportions rather than the centered bare-card layout. */
.p4-vote-card--withchips {
  justify-content: flex-start;
  gap: 14px;
  min-height: 132px;
  padding: 16px 18px;
}
.p4-vote-card--withchips .p4-vote-card-name {
  /* leave room for the ✓ token (top-right) so a long stage name
     never runs under it on the participant pick card.
     SYMMETRIC since the name centered (David, 2026-07-30): padding-right
     alone would clear the token but push the centered text 15px off the
     card's true centre. Equal padding clears it and still centres. */
  padding: 0 30px;
}
.p4-vote-card--withchips .p4-seg-card-chips {
  margin-top: 0;
}
/* bare colored issue dots on the vote cards (no labels, no legend) */
.p4-vote-issue-dots {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
/* participant vote legend footer — participants have no .footer-actions
   (hidden in participant-mode), so the legend gets its own bottom-anchored
   footer mirroring the facilitator footer's left edge + baseline. */
.p4-part-legend-footer {
  position: absolute;
  left: 48px;
  bottom: 10px;
  display: flex;
  align-items: center;
}

/* pickable variant (participant vote + facilitator final-mark) */
.p4-vote-card--pickable { cursor: pointer; transition: border-color 140ms ease, background 140ms ease, transform 140ms ease; }
.p4-vote-card--pickable:hover {
  border-color: var(--teal);
  background: #111;
  transform: translateY(-1px);
}
/* picked (participant) — ring in the participant's identity color */
.p4-vote-card.is-picked {
  border-color: var(--participant-color, var(--teal));
  box-shadow: 0 0 0 1px var(--participant-color, var(--teal)) inset;
}
/* the ✓ token, top-right */
.p4-vote-check {
  position: absolute;
  top: 12px; right: 12px;
  width: 26px; height: 26px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 700;
  color: #000;
  /* SUBSTITUTION (this slice): the proto sets this background inline, per card,
     from the roster colour. Here it comes off the seat chain declared on
     .p4-vote-part-view above, so the markup carries no colour at all. */
  background: var(--participant-color, var(--teal));
}

/* Shared issue-chip row (breakdowns / vote / results cards). Wraps the
   labeled chips so they sit neatly under the stage name.
   Pulled up from the proto sheet at :6678 — first called here. */
.p4-chip-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }

/* P4 stage-vote Submit (explicit submit model, 2026-07-05) — same
   grayed-until-ready treatment as the P2 workflow vote.
   Pulled up from the proto sheet at :6717-6719.
   SUBSTITUTION: the proto greys a .is-disabled CLASS and blocks the click
   with pointer-events, because it has no real form to guard. This button
   submits one, so the live control is the native [disabled] attribute — which
   also blocks Enter-key submission, which pointer-events cannot. Same
   attribute the committed P2 Submit uses (screen_votes.php:122). */
.p4-vote-submit-row { text-align: center; margin-top: 18px; }
#p4-stagevote-submit[disabled] { opacity: 0.35; pointer-events: none; }

/* ============================================================
   PHASE 4 — VOTE RESULTS (screen_p4_vote_results.php)
   Ported from the root prototype stylesheet, styles.css:6137-6211
   — the ".p4-result-card onward" tail of that sheet's "PHASE 4 —
   STAGE VOTE / RESULTS / FINAL SELECTION" block, which the stage-
   vote port above deliberately stopped short of.

   TOKEN MAPPING, as everywhere in this sheet: proto --fg -> --text,
   proto --fg-dim -> --muted. Neither proto token exists here.

   NOT PORTED — .p4-result-issue-dot AND ITS FOUR COLOUR VARIANTS
   (proto :6166-6174). They are dead in the proto itself: they style
   an older BARE-DOT treatment of the breakdown issues, and the
   renderer calls p4IssueChipsHtml(), which emits .p4-chip-row /
   .p4-chip — LABELED chips with a SQUARE marker. The proto's own
   markup comment (index.html:1891-1893) states the chips are the
   ruled form and are why this screen carries no legend; its stale
   function comment and its `issueDots` variable name are leftovers
   from the same replaced treatment. Porting the rules would have
   carried dead CSS in as if it were live.

   REUSED, NOT REDECLARED: .p4-vote-card--pickable (cursor, hover)
   and .p4-vote-check (the ✓ token box) are already in this sheet
   from the stage-vote port and the results cards carry them too, so
   only .p4-final-check — the teal fill that overrides the vote
   card's per-seat colour — is new. Source order matters: it must
   stay AFTER .p4-vote-check, which is what this block being
   appended gives it. .p4-chip-row, .p4-vote-canvas, .p4-vote-subhead
   and .p4-breakdowns-empty are likewise already here.

   PARKED, AND THE DECISION TRAVELS WITH THESE RULES — THE GRAY-DOT
   TALLY TREATMENT (AWE_P4_FINAL_Handoff.md:117). The dot row below
   is KEPT AS-IS FOR NOW, deliberately: it was to be re-evaluated
   only AFTER the issue-marker colour/shape change landed, because
   the new square-chip separation may resolve the old collision on
   its own and make a tally change unnecessary. The separation has
   now landed here, so the re-evaluation is live. A NUMBER and a
   SEGMENTED/CONTINUOUS BAR both remain on the table. Rationale on
   the park, unchanged: do not move the tally side of the results
   card in the same pass that changes the issue side.

   THE DOT ROW IS ANONYMOUS AND POSITIONAL (TB-68's vocabulary):
   one dot per ROSTER SEAT, the first N filled by count, so a dot's
   POSITION IS NOT A SEAT. An unfilled dot means "a vote this stage
   did not get", never "this person did not vote for it".
   ============================================================ */

/* results card — two systems separated by a divider: labeled issue
   chips above, the round vote tally below. */
.p4-result-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 132px;
  padding: 16px 18px;
  background: #0c0c0c;
  border: 1px solid rgba(89, 187, 187, 0.35);
  border-radius: 10px;
}
.p4-result-card-name {
  font-family: 'Raleway', sans-serif;
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.3;
  /* Leave room for the ✓ token on the right when marked final. SYMMETRIC
     rather than the proto's padding-right alone, because the name is centered
     below: one-sided padding would clear the token but push the text 15px off
     the card's true centre. */
  padding: 0 30px;
  /* CENTERED (David, 2026-07-30) to match .p4-seg-card-name (:4881), the
     Identify Breakdowns card name, so the results board reads like the
     breakdowns board. Chips and the "No issues tagged" line stay LEFT, as they
     do there — both sit inside flex rows at their default flex-start. */
  text-align: center;
}

/* issue-chip row (top). The proto names this "issue dots row"; the
   row holds .p4-chip-row now, per the not-ported note above. */
.p4-result-issue-row {
  display: flex;
  align-items: center;
  gap: 7px;
  min-height: 12px;
  flex-wrap: wrap;
}
.p4-result-noissue {
  font-family: 'Raleway', sans-serif;
  font-size: 11px;
  color: var(--muted);
  opacity: 0.6;
}

/* divider — the visual separation between the two marker systems */
.p4-result-divider {
  height: 1px;
  background: rgba(255, 255, 255, 0.14);
  margin: 2px 0;
}

/* vote-tally dots row — one per roster participant, filled by count */
.p4-result-vote-row {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: auto;
  flex-wrap: wrap;
}
.p4-result-vote-dot {
  width: 11px; height: 11px;
  border-radius: 50%;
  flex: 0 0 auto;
  background: rgba(255, 255, 255, 0.16);   /* faint — a vote this stage did not get */
}
.p4-result-vote-dot.is-cast {
  background: rgba(255, 255, 255, 0.78);   /* strong — a vote this stage did get */
}

/* final-marked results card — teal ring + check. Teal rather than the
   vote card's per-seat colour: this mark is THE ROOM'S decision, made
   by the facilitator, not one participant's pick. */
.p4-result-card.is-final {
  border-color: var(--teal);
  box-shadow: 0 0 0 1px var(--teal) inset;
}
.p4-final-check {
  background: var(--teal);
}

/* ============================================================
   PHASE 4 — FINAL STAGES, THE DEEP-DIVE HUB
   (screen_p4_final_stages.php)
   Ported from the root prototype stylesheet, styles.css:6213-6266
   (its "final stages screen" block) plus :6349-6362, the two rules
   for the completion state that sit further down that sheet.

   TOKEN MAPPING, as everywhere in this sheet: proto --fg -> --text,
   proto --fg-dim -> --muted. Neither proto token exists here.

   NOT PORTED — THE PROTO'S FIRST .p4-final-check (:6209-6211). That
   sheet declares the selector TWICE: once there, as a bare teal
   background riding on .p4-vote-check's box, and again at :6350 as a
   full standalone box that overrides it. The hub's cards carry the
   class ALONE, with no .p4-vote-check beside it, so the second
   declaration is the live one and the first is dead weight in the
   proto. Only the second is ported.

   NOT PORTED — .btn.nav-next.is-disabled (proto :6364-6368). The
   proto greys a CLASS and blocks the click with pointer-events,
   because it has no real control to guard. This screen's NEXT is a
   real submit carrying the native [disabled] attribute, which blocks
   the click AND the Enter key, and .begin-btn:disabled (:2956) is
   already global in this sheet from the segmentation/atomic-tasks
   promotion. The house treatment exists; a class copy would be a
   second one free to drift from it.

   SCOPED, NOT GLOBAL — .p4-final-check. The proto's :6350 rule is a
   FULL BOX (position, 28px, teal fill, centred glyph) declared on the
   bare class. This sheet ALREADY carries a .p4-final-check (:5388)
   from the vote-results port, where it is deliberately just a teal
   background overriding .p4-vote-check's per-seat fill on a box that
   class supplies. Porting the proto's version unscoped would silently
   restyle the shipped results board's ✓ — moving it from 12/12 at
   26px to 16/16 at 28px on a committed, browser-verified screen. So
   the box is scoped to .p4-final-card, which is the only place it is
   worn alone. The results screen is untouched, and the hub gets the
   proto's larger token, which its larger card was drawn for.

   THE HOVER AFFORDANCE IS ON A MODIFIER THE MARKUP DOES NOT YET
   CARRY — .p4-final-card--openable, the shape .p4-vote-card--pickable
   (:5220) already established in this sheet. The proto puts cursor,
   transition and :hover on .p4-final-card itself, because in the
   prototype every card is always clickable. HERE THE CARDS ARE INERT
   THIS SLICE (ruling, David 2026-07-30): the deep-dive screens land
   in slice 5, and a card that lifts and shows a pointer while nothing
   can open it is a broken control rather than a static one. The rules
   ship now so slice 5 turns the affordance on by adding one class to
   the markup, not by finding CSS that was left out.
   ============================================================ */

/* the hub grid — two cards, wider and taller than the vote/results
   boards' three-up because there are only ever two of them */
.p4-final-grid {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 22px;
  align-content: start;
  padding: 8px 4px;
  max-width: 900px;
  margin: 0 auto;
  width: 100%;
}

/* the stage card. No cursor and no transition — see the block header:
   those live on --openable, which slice 5 adds to the markup.

   NUMBER AND NAME SIT SIDE BY SIDE (David, 2026-07-30), where the
   proto stacks them. GRID RATHER THAN A WRAPPER DIV: the card holds
   three children in a fixed order, so two columns and two rows place
   them without the module emitting any markup for the layout —
   number and name share row 1, the hint spans row 2. The ✓ token is
   position:absolute and so is out of flow entirely; it is not a grid
   item and needs no track of its own.

   THE 12px GAP IS THE PROTO'S, unchanged, now serving as both the
   column gap (number to name) and the row gap (name to hint), so the
   card's spacing reads the same as it did stacked. */
.p4-final-card {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;   /* the 30px token, then the name */
  grid-template-rows: auto 1fr;      /* row 2 takes the slack so the hint can sit low */
  gap: 12px;
  min-height: 150px;
  padding: 22px 24px;
  background: #0c0c0c;
  border: 1.5px solid var(--teal);
  border-radius: 12px;
}

/* The open-the-deep-dive affordance, parked on a modifier until the
   cards do something. Slice 5's markup adds the class. */
.p4-final-card--openable {
  cursor: pointer;
  transition: background 140ms ease, transform 140ms ease, box-shadow 140ms ease;
}
.p4-final-card--openable:hover {
  background: #111;
  transform: translateY(-2px);
  box-shadow: 0 0 0 1px var(--teal) inset;
}

/* the 1 / 2 token — POSITION ON THE BOARD, NEVER RANK. The two final
   stages are equal; the number says which card this is. */
.p4-final-card-index {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--teal);
  color: #000;
  font-family: 'Raleway', sans-serif;
  font-size: 15px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.p4-final-card-name {
  font-family: 'Raleway', sans-serif;
  font-size: 19px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.3;
  /* CENTRED AGAINST THE TOKEN rather than sitting at the top of the
     row: the number is a 30px circle and the name one 24.7px line, so
     the default stretch would leave the text riding high beside it. */
  align-self: center;
  /* KEEP THE NAME CLEAR OF THE ✓, which the stacked layout never had
     to do — the token sat on its own line above the name. The check is
     28px wide at right:16px off the padding box, and the content box
     starts 24px in, so it reaches 20px into the text column; 28px
     leaves 8px of air. RESERVED IN BOTH STATES, not only when the card
     is complete, so the name wraps at the same width answered or not
     and the two cards on the board never disagree about where the text
     ends. The results card reserves its token space the same way. */
  padding-right: 28px;
}
.p4-final-card-hint {
  font-family: 'Raleway', sans-serif;
  font-size: 13px;
  color: var(--teal);
  /* SPANS BOTH COLUMNS — it belongs to the card, not to the name, so
     it starts at the card's left edge under the number rather than
     indenting to align with the text beside it. */
  grid-column: 1 / -1;
  /* Still bottom-aligned. In the grid this pushes the hint to the foot
     of row 2 (the 1fr track) exactly as it pushed it to the foot of the
     flex column before — auto margins absorb the free space either
     way. */
  margin-top: auto;
}

/* completed deep-dive: the ✓ token and the inset ring. SCOPED to the
   hub card — see the block header on why this box cannot go on the
   bare class. */
.p4-final-card .p4-final-check {
  position: absolute;
  top: 16px; right: 16px;
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--teal);
  color: #000;
  font-size: 15px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.p4-final-card.is-complete {
  box-shadow: 0 0 0 1px var(--teal) inset;
}

/* ============================================================
   PHASE 4 — THE STAGE DEEP-DIVE (screen_p4_deepdive.php)
   Ported from the root prototype stylesheet, styles.css:6268-6347
   — its "PHASE 4 — STAGE DEEP-DIVE" block in full.

   TOKEN MAPPING, as everywhere in this sheet: proto --fg -> --text,
   proto --fg-dim -> --muted. Neither proto token exists here.

   SIZING RULING (David, 2026-07-31) — A DELIBERATE DEPARTURE FROM
   PROTO FIDELITY, and the only one in this block. EVERY TEXT ELEMENT
   BELOW THE STAGE-NAME HEADLINE IS +4px on the prototype's value:

       .p4-stageq-item          30px -> 34px
       .p4-stage-distill-label  16px -> 20px
       .p4-stage-distill-q      13px -> 17px
       .p4-stage-distill-text   15px -> 19px   (typed AND read-only)

   These screens are read across a room, and the proto's numbers were
   set on a laptop. The measured port matched the prototype exactly on
   all four before this change — this is a design call on top of a
   faithful port, not a correction of one, which is why each rule below
   carries the proto's original value beside the live one.

   TWO THINGS DO NOT MOVE. The STAGE-NAME HEADLINE stays at
   .legal-section-title's 36px — it is the ceiling the ruling is
   measured from, and it is a shared component eight Phase 3 screens
   also render. The OPERATOR'S DRAFT EYEBROW stays at 13px: it sits
   ABOVE the headline, so it is outside what the ruling names.

   NOT PORTED — .section-title / .section-title.p4-teal-heading
   (proto :780-785, :6372-6374). The proto composes a 36px/300
   heading with a teal override; this sheet has neither class, and
   what the composition produces is what .legal-section-title
   (:779) ALREADY IS — teal, 36px, weight 300. The screens use that
   component, which is also what the P3 processing screen titles
   itself with, so the two Phase 4 headings and the eight Phase 3
   ones stay one treatment. Only the centring override below is new.

   THE DRAFT EYEBROW IS THE OPERATOR'S ALONE (ruling, David
   2026-07-31): only the operator's draft screen renders
   .p4-dive-eyebrow. The facilitator's review carries no banner and
   the committed view carries the closed line instead.

   NOT PORTED — the .p4-stageq-item colour restatement at proto
   :6376. It re-declares the same var(--fg) the main rule already
   sets seventy lines earlier, under a comment about a headline
   colour that is not in play. Folded into the one rule below.

   NO PROCESSING-SCREEN CSS AT ALL. The deep-dive's spinner is the
   shared .legal-processing-view / .legal-circle-loader /
   .legal-processing-caption component (:770-789), rendered
   unchanged — the same reuse screen_cluster.php documents.
   ============================================================ */

/* the three questions on one screen, under the stage name */
.p4-stageq-list {
  display: flex;
  flex-direction: column;
  gap: 18px;
  margin-top: 24px;
  align-items: center;
}
.p4-stageq-item {
  font-family: 'Raleway', sans-serif;
  /* 34px — the sizing ruling; proto :6282 is 30px. */
  font-size: 34px;
  font-weight: 300;
  color: var(--text);
  line-height: 1.3;
  text-align: center;
  margin: 0;
}

/* CENTRE THE STAGE NAME on the question screen only. .legal-section-title
   sets text-align:left for its Phase 1 and Phase 3 callers, and a class on
   the element beats .prompt-view's inherited centring, so the hero screen
   needs this one override. Scoped to .prompt-view so the processing
   screen's pinned top-left title is untouched.

   .prompt-view IS THE LIVE NAME for the proto's .centered-prompt (:362-378,
   where the Legal and Cards duplicates were folded into one rule). The
   proto class name appears in this sheet only inside that comment — it
   matches no selector, which is exactly what a class that looks present
   and is not costs a screen that reaches for it. */
.prompt-view .legal-section-title { text-align: center; }

/* The two distill screens' shell — a bounded flex column so the bucket
   list scrolls inside it rather than under the footer. .p2-final-view
   (:2670) supplies the bounded height; this adds the padding and the
   gutter the proto's screens carried on their own section. */
.p4-dive-view {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 24px 43px 12px;
}

/* editable consolidated distill review — three labeled blocks */
.p4-stage-distill-list {
  display: flex;
  flex-direction: column;
  gap: 22px;
  width: 100%;
  max-width: 1100px;
  /* Left-aligned (not centered) and held to the page's left edge so it
     lines up with the headings above it. */
  margin: 0;
  /* Scroll inside the content area, above the footer — matches the
     .p2-final-list ceiling so the nav never overlaps and the list
     scrolls internally rather than running under BACK/NEXT. */
  flex: 1 1 auto;
  min-height: 0;
  max-height: calc(100vh - 260px);
  overflow-x: hidden;
  overflow-y: auto;
  padding-right: 20px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.55) rgba(255,255,255,0.10);
}
.p4-stage-distill-block {
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  padding-bottom: 18px;
}
.p4-stage-distill-block:last-child { border-bottom: none; }
.p4-stage-distill-label {
  font-family: 'Raleway', sans-serif;
  /* 20px — the sizing ruling; proto :6319 is 16px. */
  font-size: 20px;
  font-weight: 700;
  color: var(--teal);
  margin-bottom: 4px;
}
.p4-stage-distill-q {
  font-family: 'Raleway', sans-serif;
  /* 17px — the sizing ruling; proto :6326 is 13px. */
  font-size: 17px;
  color: var(--muted);
  margin-bottom: 10px;
}
.p4-stage-distill-text {
  font-family: 'Raleway', sans-serif;
  /* 19px — the sizing ruling; proto :6332 is 15px. Applies to the
     typed field AND the read-only variant: one rule, both states. */
  font-size: 19px;
  color: var(--text);
  line-height: 1.5;
  padding: 10px 12px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 8px;
  min-height: 48px;
  outline: none;
  transition: border-color 120ms ease;
}
.p4-stage-distill-text:focus { border-color: var(--teal); }
/* The placeholder shows only while the field is genuinely empty, so it is
   correct on a field that has never been typed into — which in part 1 is
   every field, since nothing is saved yet. A field typed into and then
   cleared can retain a <br> and stop matching :empty; that is the same
   limitation every contenteditable placeholder in this sheet carries. */
.p4-stage-distill-text:empty::before {
  content: attr(data-placeholder);
  color: var(--muted);
  opacity: 0.6;
}
/* READ-ONLY VARIANT (the facilitator's review in part 1): no contenteditable
   attribute, so no caret and no placeholder. The border stays — the field is
   still a field, and part 2 makes it editable by flipping one argument. */
.p4-stage-distill-text:not([contenteditable]) { cursor: default; }

/* The deep-dive DRAFT eyebrow — the proto's .oper-distill-status (root
   styles.css:5707-5714) ported at its own numbers, which .legal-eyebrow
   (:829) does not match: that rule is 12px/700 at 0.5px tracking with no
   text-transform, the proto's is 13px/600 at 0.08em and uppercase. Measured
   against the proto rather than assumed, and it was the ONLY size mismatch
   on either dive screen — the stage name, the three question items and the
   distill label/question/text all already compute to the proto's exact
   values.

   ITS OWN CLASS, NOT AN OVERRIDE OF .legal-eyebrow, which the six P1 loops
   and the four P3 topics all render: retuning that class to Phase 4's
   numbers would silently restyle ten committed screens. The proto keeps the
   two treatments separate too.

   text-transform IS SET even though both strings are already uppercase in
   the markup. The live build writes its eyebrows in caps and the proto
   writes them in sentence case and uppercases in CSS; carrying the rule
   means the rendered result matches whichever way a later string is
   written. */
.p4-dive-eyebrow {
  font-family: 'Raleway', sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: 12px;
}

/* The committed deep-dive's quiet line — sits where the DRAFT eyebrow was
   on the live screen, so a closed dive reads as a record rather than as an
   instruction the room cannot obey. The same call the frozen results board
   made with its locked subhead. */
.p4-dive-closed-line {
  font-family: 'Raleway', sans-serif;
  font-size: 14px;
  color: var(--muted);
  margin: 0 0 4px;
}
