/* v3-only classes, layered over the shared ../assets/styles.css.
 *
 * Nothing in here may redefine a class that v1 uses. If a v3 surface needs
 * a variant of an existing component, give it a new modifier class rather
 * than overriding the base, so the two versions cannot drift into each
 * other. Colour comes from ../assets/tokens.css unless this file sets a
 * token — no other literal hex in components.
 *
 * Contrast that used to sit behind Projector is the default here. The
 * room is a Teams share, not a washed wall; one look has to survive
 * compression. Type scale stays at sitting-distance size so 1280 still
 * fits.
 */
:root {
  --ink:         #0f1216;
  --ink-2:       #262b33;
  --ink-3:       #3f444c;
  --line:        #b3b6ae;
  --line-soft:   #c9ccc4;
  --line-strong: #8f9389;
  --on-brand-dim:#c6d3c1;

  --accent-text: #2c3d16;
  --ok-text:     #0a3a21;
  --warn-text:   #4e3103;
  --risk-text:   #5e1512;
  --accent-fill: #e2ebd3;
  --ok-fill:     #d6ebe0;
  --warn-fill:   #f8e6c4;
  --risk-fill:   #f7d8d5;

  --cad-ink:     #000000;
  --cad-thin:    #33383e;
  --cad-dim:     #4d5259;
  --cad-grid:    #bfbdb2;

  --pen-hair:    0.9;
  --pen-thin:    1.4;
  --pen-med:     2.1;
  --pen-thick:   3.2;
  --pen-heavy:   4.8;
}

/* ---------- orientation graphic ----------
 * Softer than a drawing on purpose: rounded shapes, the interface
 * typeface, no dimensions. The room should be able to tell an explanation
 * from a document without being told. */
.gfx-orient .o-ln    { stroke: var(--ink-3); stroke-width: 2.4; fill: none; stroke-linecap: round; }
.gfx-orient .o-ln-t  { stroke: var(--ink-3); stroke-width: 1.4; fill: none; opacity: .65; }
.gfx-orient .o-ln-h  { stroke: var(--ink-2); stroke-width: 3; fill: none; stroke-linecap: round; }
.gfx-orient .o-cond  { stroke: var(--ink-2); stroke-width: 2.6; fill: none; stroke-linecap: round; }
.gfx-orient .o-ground{ stroke: var(--ink-2); stroke-width: 3; }
.gfx-orient .o-arrow { fill: var(--ink-2); stroke: none; }
.gfx-orient .o-old   { fill: var(--panel-3); stroke: var(--line-strong); stroke-width: 2; }
.gfx-orient .o-new   { fill: var(--accent-fill); stroke: var(--accent); stroke-width: 2.2; }
.gfx-orient .o-pier  { fill: var(--panel-3); stroke: var(--ink-3); stroke-width: 2; }
.gfx-orient .o-band  { fill: var(--accent-fill); stroke: var(--accent); stroke-width: 1.4;
                       stroke-dasharray: 7 5; opacity: .55; }
.gfx-orient .o-band-tx { fill: var(--accent-text); font-weight: 700;
                         text-transform: uppercase; letter-spacing: var(--track-eyebrow); }
.gfx-orient .o-gap-tx { fill: var(--ink-3); letter-spacing: var(--track-eyebrow);
                        text-transform: uppercase; font-size: 12px; }

/* The new bay arrives as one idea: band, then devices left to right,
 * then the conductor tying the line into T-1. Only the added frame
 * carries `.orient-play`, so walking back to "already there" is still. */
.orient-play .o-band, .orient-play .o-band-tx,
.orient-play .o-equip, .orient-play .o-legend-new {
  animation-duration: var(--dur-3);
  animation-timing-function: var(--ease);
  animation-fill-mode: both;
}
.orient-play .o-band { animation-name: orientBand; }
.orient-play .o-band-tx, .orient-play .o-equip, .orient-play .o-legend-new {
  animation-name: orientIn;
}
.orient-play .o-equip { animation-delay: calc(var(--dur-2) + var(--i) * 90ms); }
.orient-play .o-legend-new { animation-delay: calc(var(--dur-3) * 2); }
.orient-play .o-new-cond {
  stroke-dasharray: 420;
  stroke-dashoffset: 420;
  animation: orientDraw calc(var(--dur-3) * 1.6) var(--ease) both;
  animation-delay: calc(var(--dur-3) + var(--dur-2) * 2);
}
@keyframes orientIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes orientBand {
  from { opacity: 0; }
  to   { opacity: .55; }
}
@keyframes orientDraw { to { stroke-dashoffset: 0; } }

.orient-copy {
  animation: orientIn var(--dur-3) var(--ease) both;
}

@media (prefers-reduced-motion: reduce) {
  .orient-play .o-band, .orient-play .o-band-tx,
  .orient-play .o-equip, .orient-play .o-legend-new,
  .orient-play .o-new-cond, .orient-copy {
    animation: none;
    transform: none;
    stroke-dashoffset: 0;
  }
  .orient-play .o-band-tx, .orient-play .o-equip,
  .orient-play .o-legend-new, .orient-copy { opacity: 1; }
  .orient-play .o-band { opacity: .55; }
}

/* ---------- landing screen ---------- */
.card-landing { border-top: 3px solid var(--accent); }
.card-landing > h2 { font-size: var(--t-2xl); }

.landing-points {
  list-style: none; margin: var(--s5) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: var(--s3) var(--s5);
}
.landing-points li {
  display: flex; flex-direction: column; gap: 2px;
  padding-left: var(--s3); border-left: 2px solid var(--line);
}
.landing-points li b { font-size: var(--t-base); }
.landing-points li span { color: var(--ink-2); font-size: var(--t-sm); line-height: 1.5; }

.landing-go {
  display: flex; align-items: center; gap: var(--s4);
  margin-top: var(--s5); padding-top: var(--s4);
  border-top: 1px solid var(--line);
}
.landing-go .muted { font-size: var(--t-sm); }

/* New in v2: the one call to action on the title card. v1 has only
   .btn-chrome and .btn-ghost, so this adds rather than overrides. */
.btn-primary {
  background: var(--accent); border-color: var(--accent); color: var(--panel);
  font-weight: 600;
}
.btn-primary:hover:not([disabled]) { filter: brightness(1.08); color: var(--panel); }

/* The logo becomes the way home, so it needs to read as pressable without
   turning into a button in the visual hierarchy. */
.brand-home {
  background: none; border: 0; padding: 0; cursor: pointer;
  display: inline-flex; align-items: center;
  border-radius: var(--radius);
}
.brand-home:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ---------- phase rail ---------- */
.ph-rail {
  display: grid; grid-template-columns: repeat(10, 1fr);
  gap: var(--s2); margin-top: var(--s4);
}
.ph {
  border: 1px solid var(--line); border-top: 3px solid var(--line-strong);
  border-radius: var(--radius); padding: var(--s2) var(--s2) var(--s3);
  background: var(--panel); min-width: 0;
}
.ph h5 { margin: 4px 0 2px; font-size: var(--t-sm); line-height: 1.25; }
.ph-top { display: flex; align-items: center; justify-content: space-between; gap: 4px; }
.ph-n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--panel-3); color: var(--ink-2);
  font-size: var(--t-xs); font-weight: 700;
}
.ph-n.sm { width: 18px; height: 18px; }
.ph-state {
  font-size: var(--t-xs); text-transform: uppercase;
  letter-spacing: var(--track-eyebrow); color: var(--ink-3);
}
.ph-clock { margin: 0; font-size: var(--t-xs); color: var(--ink-2); line-height: 1.4; }

.ph-done  { opacity: .72; }
.ph-now   { border-top-color: var(--accent); background: var(--accent-fill); }
.ph-now .ph-n { background: var(--accent); color: var(--panel); }
.ph-now .ph-state { color: var(--accent-text); font-weight: 700; }
.ph-later { opacity: .55; }

/* ---------- RAG ----------
 * Four states. Grey is "no lead-time evidence in the file", which is a
 * real answer and must not be painted green. */
.rag {
  display: inline-block; min-width: 54px; text-align: center;
  font-size: var(--t-xs); font-weight: 700; text-transform: uppercase;
  letter-spacing: var(--track-eyebrow);
  padding: 3px 8px; border-radius: var(--radius); border: 1px solid;
}
.rag-red   { background: var(--risk-fill);  border-color: var(--risk);  color: var(--risk-text); }
.rag-amber { background: var(--warn-fill);  border-color: var(--warn);  color: var(--warn-text); }
.rag-green { background: var(--ok-fill);    border-color: var(--ok);    color: var(--ok-text); }
.rag-grey  { background: var(--panel-3);    border-color: var(--line-strong); color: var(--ink-2); }
.rag-lg { min-width: 76px; font-size: var(--t-sm); padding: 6px 12px; }

/* ---------- bay table ---------- */
.bom-tools {
  display: flex; align-items: center; gap: var(--s3);
  margin: var(--s4) 0 var(--s3); flex-wrap: wrap;
}
.bom-q {
  flex: 1 1 260px; min-width: 200px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel); color: var(--ink);
  padding: var(--s2) var(--s3); font-size: var(--t-sm); font-family: inherit;
}
.bom-q:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.seg { display: inline-flex; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.seg-b {
  border: 0; background: var(--panel); color: var(--ink-2);
  font-size: var(--t-xs); padding: var(--s2) var(--s3); cursor: pointer; font-family: inherit;
}
.seg-on { background: var(--accent); color: var(--panel); font-weight: 700; }

.bom tr.grp td {
  background: var(--panel-2); font-size: var(--t-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: var(--track-eyebrow); color: var(--ink-2);
}
.bom tr.grp .grp-n { margin-left: 8px; opacity: .7; font-weight: 400; }
.bom-r td { vertical-align: top; }
.bom-r.bom-amber td:first-child { box-shadow: inset 3px 0 0 var(--warn); }
.bom-sel td { background: var(--accent-fill); }

/* A red row is the problem, not a tinted status pill. Wash the whole
 * line — cells and the reason under it — so it reads as one finding. */
.bom-r.bom-red td,
.bom-why-red td {
  background: var(--risk-fill);
}
.bom-r.bom-red td:first-child,
.bom-why-red td:first-child {
  box-shadow: inset 4px 0 0 var(--risk);
}

/* The reason sits under its row, so the status is never a colour without
   a stated cause and a document behind it. */
.bom-why td {
  font-size: var(--t-sm); color: var(--ink-2);
  padding-top: 0; border-top: 0; line-height: 1.5;
}
.bom-why-red td { color: var(--risk-text); }
.bom-why-green td, .bom-why-grey td { display: none; }

.btn.sm, .cite-btn.sm { font-size: var(--t-xs); padding: 2px 8px; }

/* Quote overlay has to scroll inside the flex box so the cited lead-time
 * field can be brought into view. */
.ovl-body { flex: 1; min-height: 0; }

/* ---------- scour ---------- */
.scour-head { display: flex; align-items: center; gap: var(--s4); margin: var(--s4) 0; }
.scour-sum { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.scour-sum b { font-size: var(--t-lg); }
.scour-actions { display: flex; align-items: center; gap: var(--s2); flex: none; }

.drivers { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s3); }
.drv {
  border: 1px solid var(--line); border-left-width: 3px;
  border-radius: var(--radius); padding: var(--s3);
  display: flex; align-items: baseline; gap: var(--s3); flex-wrap: wrap;
}
.drv-red   { border-left-color: var(--risk); background: var(--risk-fill); }
.drv-amber { border-left-color: var(--warn); background: var(--warn-fill); }
.drv-k {
  font-size: var(--t-xs); font-weight: 700; text-transform: uppercase;
  letter-spacing: var(--track-eyebrow); color: var(--ink-2); white-space: nowrap;
}
.drv p { margin: 0; flex: 1 1 320px; font-size: var(--t-sm); line-height: 1.5; }

/* ---------- research lanes ----------
 *
 * The page re-renders wholesale on every beat, so the only reliable
 * animation clock is "this node was just mounted". Every animation here
 * starts at mount and finishes inside its own beat. Nothing tries to span
 * a re-render, because nothing can.
 */
.lanes {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: var(--s3); margin: var(--s4) 0;
}
.lane {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--s3); background: var(--panel); min-height: 96px;
}
.lane-top { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.lane-top b { font-size: var(--t-sm); }
.lane-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--line-strong); flex: none;
}
.lane-n {
  margin-left: auto; font-size: var(--t-xs); color: var(--ink-3);
  text-transform: uppercase; letter-spacing: var(--track-eyebrow);
}

.lane-pending { opacity: .45; }
.lane-wait { margin: 0; font-size: var(--t-xs); color: var(--ink-3); }

.lane-live { border-color: var(--accent); background: var(--accent-fill); }
.lane-live .lane-dot { background: var(--accent); }
.lane-doing { margin: 0 0 8px; font-size: var(--t-sm); color: var(--accent-text); }

/* Finite, and exactly as long as the beat. The bar reaching the end and
   the sequence advancing are the same instant, which is what makes an
   indeterminate progress indicator honest rather than decorative. */
.lane-sweep {
  height: 3px; border-radius: 2px; background: var(--accent);
  transform-origin: left center;
  animation-name: laneSweep;
  animation-timing-function: linear;
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}
@keyframes laneSweep { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.lane-resolved .lane-dot { background: var(--ok); }

.finds { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.find {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  font-size: var(--t-sm); line-height: 1.45;
}
.find p { margin: 0; flex: 1 1 200px; }
.find-none { color: var(--ink-3); font-style: italic; }
/* A lane that proves a negative is a finding, not a gap. */
.find-neg p { font-weight: 600; color: var(--risk-text); }

/* Only the newly-mounted lane animates, and its children stagger by index
   within a bounded window that always fits the shortest dwell. */
.lane-live, .lane-resolved .find {
  animation-duration: var(--dur-3);
  animation-timing-function: var(--ease);
  animation-fill-mode: both;
}
.lane-live { animation-name: laneIn; }
.lane-resolved .find { animation-name: laneIn; animation-delay: calc(var(--i) * 80ms); }
@keyframes laneIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

.converge {
  border-top: 3px solid var(--accent); border-radius: var(--radius);
  background: var(--panel-2); padding: var(--s4); margin-top: var(--s4);
  animation: laneIn var(--dur-3) var(--ease) both;
}
.converge h4 { margin-top: 0; }
.converge h3 { font-size: var(--t-lg); margin: 0 0 var(--s3); }
.conv-facts {
  margin: 0 0 var(--s3); padding: 0;
  display: grid; gap: 0;
}
.conv-facts > div {
  display: grid; grid-template-columns: 11em 1fr;
  gap: var(--s3); align-items: baseline;
  padding: var(--s3) 0;
  border-top: 1px solid var(--line);
}
.conv-facts > div:last-child { border-bottom: 1px solid var(--line); }
.conv-facts dt {
  margin: 0; font-size: var(--t-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: var(--track-eyebrow);
  color: var(--ink-3);
}
.conv-facts dd { margin: 0; font-size: var(--t-sm); line-height: 1.5; }

/* The whole screen must still work with motion off. */
@media (prefers-reduced-motion: reduce) {
  .lane-sweep { animation: none; transform: scaleX(1); }
}

/* ---------- outreach and context ---------- */
.outreach-picks {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3);
  margin-top: var(--s4);
}
.outreach-pick {
  text-align: left; display: flex; flex-direction: column; gap: 4px;
  padding: var(--s4); border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel); cursor: pointer; font: inherit; color: inherit;
}
.outreach-pick:hover { border-color: var(--accent); background: var(--accent-fill); }
.outreach-pick .op-k {
  font-size: var(--t-xs); font-weight: 700; text-transform: uppercase;
  letter-spacing: var(--track-eyebrow); color: var(--ink-3);
}
.outreach-pick b { font-size: var(--t-base); line-height: 1.3; }
.outreach-pick .op-n { font-size: var(--t-sm); color: var(--ink-2); line-height: 1.4; }
.outreach-who {
  margin: 0 0 var(--s3); font-size: var(--t-sm); color: var(--ink-2);
}
.email .hdr td:first-child {
  width: 7rem; padding-right: var(--s4); white-space: nowrap; color: var(--ink-3);
  vertical-align: top;
}
.email .hdr td { padding: 6px 0; }
.outreach-row {
  display: flex; align-items: center; gap: var(--s4);
  flex-wrap: wrap; margin-top: var(--s4);
}
/* The draft stamp sits in the same family as the memo's "not an approval". */
.draft-stamp {
  display: inline-block; margin-bottom: var(--s3);
  border: 2px solid var(--warn); color: var(--warn-text); background: var(--warn-fill);
  border-radius: var(--radius); padding: 4px 12px;
  font-size: var(--t-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: var(--track-eyebrow);
}
.sim-strip {
  margin: var(--s4) 0 var(--s3);
  background: var(--warn-fill); border: 1px solid var(--warn); color: var(--warn-text);
  border-radius: var(--radius); padding: var(--s3);
  font-size: var(--t-sm); line-height: 1.5;
}
.sim-strip.sim-off {
  background: var(--panel-2); border-color: var(--line); color: var(--ink-2);
}
.email-sim { border: 1px dashed var(--warn); border-radius: var(--radius); padding: var(--s3); }
.ask-clock {
  border-left: 3px solid var(--risk); background: var(--risk-fill);
  padding: var(--s2) var(--s3); border-radius: var(--radius);
}

.card-kicker {
  display: flex; align-items: center; gap: var(--s2);
  margin-bottom: var(--s2); flex-wrap: wrap;
}
.card-kicker h4 { margin: 0; }
.card-kicker .chip { margin-left: auto; }
.card-ic {
  width: 20px; height: 20px; flex: none; color: var(--ink-3);
}
.card-ic svg {
  width: 100%; height: 100%; display: block;
  fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.chip {
  display: inline-block;
  font-size: var(--t-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: var(--track-eyebrow);
  padding: 2px 8px; border-radius: 99px;
  color: var(--warn-text); background: var(--warn-fill);
  border: 1px solid var(--warn);
  white-space: nowrap;
}

.card-context {
  border-top: 3px solid var(--warn);
  background: var(--panel-2);
}
.card-context .card-ic { color: var(--warn-text); }
.macro-inline {
  list-style: none; margin: var(--s4) 0 0; padding: 0;
  display: grid; gap: var(--s3);
}
.macro-inline li {
  display: grid;
  grid-template-columns: 36px 1fr;
  column-gap: var(--s4);
  row-gap: 4px;
  margin: 0;
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--panel);
  align-items: start;
}
.macro-inline .macro-ic {
  grid-row: 1 / span 3;
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  margin-top: 2px;
  border-radius: var(--radius);
  background: var(--panel-3);
  color: var(--ink-2);
}
.macro-inline .macro-ic svg {
  width: 18px; height: 18px; display: block;
  fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.macro-inline li > b { grid-column: 2; display: block; font-size: var(--t-base); margin: 0; }
.macro-inline p { grid-column: 2; margin: 0; font-size: var(--t-sm); line-height: 1.5; }
.macro-inline .ask { grid-column: 2; font-size: var(--t-xs); color: var(--ink-3); }

.card-outreach { border-top: 3px solid var(--line-strong); }
.card-outreach .card-ic { color: var(--ink-2); }
.outreach-pick { border-left: 3px solid var(--line-strong); }
.outreach-pick-alt { border-left-color: var(--warn); }

.card-sub {
  background: var(--panel-3);
  border-top: 3px solid var(--line);
}
.card-sub .card-ic { color: var(--ink-3); }
.ll { margin: var(--s3) 0; padding-left: 20px; }
.ll li { font-size: var(--t-sm); line-height: 1.6; margin-bottom: 10px; }

@media (max-width: 1200px) {
  .ph-rail { grid-template-columns: repeat(5, 1fr); }
  .lanes { grid-template-columns: 1fr; }
}
@media (max-width: 900px) {
  .landing-points { grid-template-columns: 1fr; }
  .ph-detail { grid-template-columns: 1fr; }
  .shift { grid-template-columns: 1fr; }
  .outreach-picks { grid-template-columns: 1fr; }
  .card-kicker .chip { margin-left: 0; }
}

/* ================= v3: the story ================= */

/* The rail. Eight stops, always visible, so the room knows where it is
   and how much is left. Replaces v2's acts + sub-tabs entirely. */
.rail {
  display: flex; gap: 2px; align-items: stretch;
  padding: 0 var(--s6); background: var(--brand); overflow-x: auto;
}
.stop {
  display: flex; align-items: center; gap: 8px;
  background: none; border: 0; cursor: pointer; font-family: inherit;
  padding: var(--s3) var(--s3); color: var(--panel);
  opacity: .5; white-space: nowrap;
  border-bottom: 3px solid transparent;
}
.stop:hover { opacity: .8; }
.stop-past { opacity: .72; }
.stop-on { opacity: 1; border-bottom-color: var(--panel); }
.stop-n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%;
  border: 1px solid currentColor; font-size: var(--t-xs); font-weight: 700; flex: none;
}
.stop-on .stop-n { background: var(--panel); color: var(--brand); border-color: var(--panel); }
.stop-l { font-size: var(--t-sm); }

/* Forward motion lives under the content, not in the header. */
.storynav {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s4); max-width: 1320px; margin: 0 auto;
  padding: var(--s5) var(--s6) var(--s6);
}
.storynav-mid { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.storynav-mid b { font-size: var(--t-sm); }
.storynav-mid .muted { font-size: var(--t-xs); text-transform: uppercase; letter-spacing: var(--track-eyebrow); }

/* ---- beat 1 · where we are ---- */
.card-open { border-top: 3px solid var(--accent); }
.card-open > h2 { font-size: var(--t-2xl); max-width: 28ch; }
.orient-steps {
  display: flex; gap: 8px; margin: 0 0 var(--s4);
}
.orient-step {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 6px 12px 6px 8px;
  color: var(--ink-2); cursor: pointer; font: inherit; font-size: var(--t-sm);
}
.orient-step:hover { border-color: var(--line-strong); color: var(--ink); }
.orient-step-n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%;
  border: 1px solid currentColor; font-size: var(--t-xs); font-weight: 700; flex: none;
}
.orient-step-on {
  border-color: var(--accent); background: var(--accent-fill); color: var(--accent-text);
  font-weight: 600;
}
.orient-step-on .orient-step-n { background: var(--accent); color: var(--panel); border-color: var(--accent); }
.open-points {
  list-style: none; margin: var(--s5) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s3) var(--s5);
}
.open-points li { display: flex; flex-direction: column; gap: 2px;
                  padding-left: var(--s3); border-left: 2px solid var(--line); }
.open-points li b { font-size: var(--t-base); }
.open-points li span { color: var(--ink-2); font-size: var(--t-sm); line-height: 1.5; }

/* ---- beat 2 · why this happens ---- */
.whys { list-style: none; margin: var(--s5) 0 0; padding: 0; display: grid; gap: var(--s4); }
.why { display: flex; gap: var(--s4); align-items: flex-start; }
.why-n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%; flex: none;
  background: var(--accent-fill); color: var(--accent-text);
  font-weight: 700; font-size: var(--t-base);
}
.why b { font-size: var(--t-lg); }
.why p { margin: 4px 0 0; color: var(--ink-2); font-size: var(--t-base); line-height: 1.6; max-width: 68ch; }

@media (max-width: 1100px) {
  .open-points { grid-template-columns: 1fr; }
}

/* ---- beat 3 · what is watched where ---- */
.watch td { vertical-align: top; }
.watch th:first-child, .wrow-n { width: 34px; padding-right: 0; }
.wrow-now { background: var(--accent-fill); }
.wrow-hero { box-shadow: inset 3px 0 0 var(--warn); }
.ph-n-now { background: var(--accent); color: var(--panel); }
.wrow-live {
  margin-left: 8px; font-size: var(--t-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: var(--track-eyebrow);
  color: var(--accent-text);
}

/* Masthead: the proposition's name leads, the job detail recedes. */
.h1-sub { font-weight: 400; opacity: .72; font-size: .8em; }

/* The bank. Deliberately quiet — it is a question, not a finding, so it
 * carries no status colour and no number. */
.card-ask { border-top: 3px solid var(--ink-3); background: var(--panel-2); }

/* ---- beat 8 · the alternatives ---- */
.cands { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s4); margin: var(--s5) 0 var(--s4); }
.cand {
  display: flex; flex-direction: column; gap: var(--s2);
  border: 1px solid var(--line); border-top: 3px solid var(--line-strong);
  border-radius: var(--radius); padding: var(--s4); background: var(--panel);
}
.cand-in  { border-top-color: var(--ok); background: var(--ok-fill); }
/* Disqualified. Stood down, never coloured by its date — a unit that fails
 * a stated requirement must not read as the fast option. */
.cand-out { border-top-color: var(--ink-3); opacity: .68; }
.cand-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s3); }
.cand-top div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cand-top b { font-size: var(--t-base); line-height: 1.3; }
.cand-top .muted { font-size: var(--t-xs); }
.cand-lead { display: flex; align-items: baseline; gap: var(--s2); margin-top: var(--s2); }
.cand-lead b { font-size: var(--t-3xl); line-height: 1; font-variant-numeric: tabular-nums; }
.cand-lead span { font-size: var(--t-sm); color: var(--ink-2); }
.cand-verdict { margin: 0; font-size: var(--t-sm); line-height: 1.5; }
.cand-fails { margin: 0; padding-left: var(--s4); display: grid; gap: 2px; }
.cand-fails li { font-size: var(--t-xs); color: var(--ink-2); line-height: 1.5; }
.cand-note { margin: 0; font-size: var(--t-xs); color: var(--ink-2); line-height: 1.5; }
.cand .cite-btn { align-self: flex-start; margin-top: auto; }
/* Weaker evidence than a quotation, and it has to look it. */
.pill-weak { background: var(--panel-3); color: var(--ink-2); border-color: var(--line-strong); }

@media (max-width: 1100px) {
  .cands { grid-template-columns: 1fr; }
}

/* ---- spacing corrections, 18 Aug ----
 *
 * Two faults reported from a walk of the story, both the same underlying
 * mistake: vertical rhythm was set on the top of each block and never on
 * the bottom, so anything that followed a list sat straight against it.
 *
 * Fixed here rather than in the shared stylesheet — v1 and v2 read that
 * file too, and neither has these compositions.
 */

/* A closing note after a list is a separate thought and has to read as
 * one. It was landing 0px under the last item. */
.whys + .hint, .whys + p,
.open-points + .hint, .open-points + p,
.cands + .hint, .cands + p,
.statrow + .hint {
  margin-top: var(--s5);
}

/* The eyebrow sits 4px off its heading, which is right when the heading is
 * 27px display type on a hero card and too tight at 20px on an ordinary
 * one — the two lines read as a single wrapped string. */
.card > h4 { margin-bottom: var(--s2); }
.card-hero > h4 { margin-bottom: var(--s1); }

/* A lede directly under a heading needs air, and a lede followed by a list
 * needs more of it than a paragraph does. */
.card > h2 + .lede { margin-top: var(--s3); }

/* The bank reads as a spoken question, so it should break where a person
 * would pause, not at an arbitrary column. */
.card-ask > h2 { max-width: 44ch; }

/* `.why b` was written when the only bold in a why-block was its heading.
 * Emphasis inside the body now exists, and it was inheriting heading size
 * — one word in a paragraph rendering three points larger than the words
 * around it. Scope the heading rule to the heading. */
.why > div > b { font-size: var(--t-lg); }
.why p b { font-size: inherit; font-weight: 700; }

/* ---- beat 6 · the paper behind each lane ----
 *
 * The document renders at its true page width inside a fixed-height
 * window and is scaled down, so the proportions are a real page rather
 * than a shrunken box. It is deliberately unreadable at this size — its
 * job is to show that the thing exists and to carry the highlight, not to
 * be read. The whole tile opens the readable version.
 */
.lane-body { display: grid; grid-template-columns: 1fr 336px; gap: var(--s4); align-items: start; }
.lane-doc {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel); overflow: hidden; cursor: pointer;
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
}
.lane-doc:hover, .lane-doc:focus-visible { border-color: var(--accent); box-shadow: var(--elev-1); }
.lane-doc:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.lane-paper { position: relative; height: 168px; overflow: hidden; background: var(--panel); }
/* Inert. Every click belongs to the tile, and nothing inside a 42% page
 * is a usable target. */
.lane-paper-in {
  width: 760px; transform: scale(.42); transform-origin: top left;
  pointer-events: none; user-select: none;
}
.lane-doc-wide .lane-paper-in { width: 1500px; transform: scale(.213); }
/* The page continues below the window, and saying so is more honest than
 * a hard crop that reads as the end of the document. */
.lane-paper::after {
  content: ''; position: absolute; inset: auto 0 0 0; height: 46px; pointer-events: none;
  background: linear-gradient(to bottom, transparent, var(--panel));
}
.lane-doc-bar {
  display: flex; align-items: center; gap: var(--s2);
  padding: 6px var(--s3); border-top: 1px solid var(--line); background: var(--panel-2);
  font-size: var(--t-xs);
}
.lane-doc-kind {
  text-transform: uppercase; letter-spacing: var(--track-eyebrow);
  color: var(--ink-3); font-weight: 600; white-space: nowrap;
}
.lane-doc-name {
  color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1;
}
.lane-doc-go { color: var(--accent-text); font-weight: 700; white-space: nowrap; }

/* One lane per row now that each carries a page — two columns of scaled
 * paper is a contact sheet, not evidence. */
.lanes { grid-template-columns: 1fr; }

@media (max-width: 1100px) {
  .lane-body { grid-template-columns: 1fr; }
}

/* ---- beat 9 · the blast radius ----
 * Two runs of the same derivation, side by side at one scale. The size
 * difference is the argument, so nothing here may be styled to exaggerate
 * it — same type, same padding, same everything except the numbers.
 */
.blast-grid {
  display: grid; grid-template-columns: 1fr auto 1fr; gap: var(--s4);
  align-items: stretch; margin: var(--s5) 0 var(--s4);
}
.blast {
  display: flex; flex-direction: column; gap: var(--s3);
  border: 1px solid var(--line); border-top: 3px solid var(--line-strong);
  border-radius: var(--radius); padding: var(--s4); background: var(--panel);
}
.blast-then { border-top-color: var(--ok); background: var(--ok-fill); }
.blast-now  { border-top-color: var(--risk); background: var(--risk-fill); }
.blast-top { display: flex; flex-direction: column; gap: 2px; }
.blast-top b { font-size: var(--t-base); }
.blast-top .muted { font-size: var(--t-xs); }
.blast-n { display: flex; align-items: baseline; gap: var(--s3); }
.blast-n b { font-size: var(--t-4xl); line-height: 1; font-variant-numeric: tabular-nums; }
.blast-n span { font-size: var(--t-sm); color: var(--ink-2); max-width: 14ch; line-height: 1.4; }
.blast-discs { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px;
               background: var(--line); border: 1px solid var(--line); border-radius: var(--radius);
               overflow: hidden; }
.blast-discs li {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3);
  padding: 6px var(--s3); background: var(--panel); font-size: var(--t-sm);
}
.blast-discs li span { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--ink-2); }
.blast-arrow { align-self: center; font-size: var(--t-2xl); color: var(--ink-3); }

@media (max-width: 1100px) {
  .blast-grid { grid-template-columns: 1fr; }
  .blast-arrow { transform: rotate(90deg); justify-self: center; }
}

/* ---- 20 Aug: the programme, grouped by stage, in four frames ----
 *
 * The same table across all four frames. Frame 0 is the stage column
 * alone — five rows, the concise picture; frame 1 grows the phase detail
 * in beside it, each stage cell spanning the rows it now covers; frame 2
 * puts the Design→Buy gate in the flow of the table; frame 3 lights the
 * live rows. The rules do the grouping work: light between phases inside
 * a stage, heavy between stages. Motion runs only on the forward step
 * (`.prog-in`, from Store.progPlay), so Back and incidental re-renders
 * are still.
 */
.prog-t { margin-top: var(--s5); }
.prog-t td { vertical-align: top; }

/* The grouping column. A merged cell over its phases, so the stage reads
 * as one thing the eye can rest on rather than a word repeated. */
.prog-t .prog-s {
  width: 170px; padding-top: var(--s3);
  border-right: 1px solid var(--line);
}
.prog-t .prog-s b { font-size: var(--t-base); }
.prog-t thead .prog-s {
  padding-top: var(--s2); border-right-color: transparent;
}
.prog-t .prog-n { width: 34px; padding-right: 0; }
.prog-c {
  margin-left: var(--s3); padding: 1px 8px; border-radius: 999px;
  background: var(--panel-3); color: var(--ink-3);
  font-size: var(--t-xs); font-weight: 700; white-space: nowrap;
  text-transform: uppercase; letter-spacing: var(--track-eyebrow);
}

/* Light between phases inside a stage, heavy where a stage begins — the
 * separation is the grouping, so it has to be visible at a glance. */
.prog-r > td, .watch.prog-t .wrow > td { border-bottom: 1px solid var(--line-soft); }
.prog-gs > td { border-top: 2px solid var(--line-strong); }
.prog-t tbody tr:last-child > td { border-bottom: 0; }

/* Where the job is standing. */
.prog-now > td { background: var(--accent-fill); }
.prog-hero > td:first-child { box-shadow: inset 3px 0 0 var(--warn); }

/* The gate the story turns on, in the flow of the table. */
.prog-gr > td {
  border-top: 2px solid var(--accent); border-bottom: 1px solid var(--accent);
  background: var(--accent-fill); color: var(--ink-2); line-height: 1.5;
}
.prog-gr b { color: var(--accent-text); }
.prog-tick {
  display: inline-flex; align-items: center; justify-content: center;
  width: 17px; height: 17px; border-radius: 50%; vertical-align: -3px;
  background: var(--accent); color: var(--panel);
  font-size: 10px; font-weight: 700;
}

/* ---- motion ---- */
.prog-in { animation: progIn var(--dur-3) var(--ease) both; animation-delay: calc(var(--i, 0) * 55ms); }
@keyframes progIn { from { opacity: 0; transform: translateY(-5px); } }
.prog-lit { animation: progLit calc(var(--dur-3) * 1.8) var(--ease) both; }
@keyframes progLit { from { background: transparent; } }
@media (prefers-reduced-motion: reduce) {
  .prog-in, .prog-lit { animation: none; }
}

/* ---- 19 Aug: the merged programme, the phase strip, the staged bay ---- */

/* Where the room is standing, on every screen that is standing somewhere.
 * Sits under the rail so it reads as chrome rather than as content — it
 * labels the screen, it is not part of the argument on it. */
.phasestrip {
  display: flex; align-items: baseline; gap: var(--s2); flex-wrap: wrap;
  padding: 6px var(--s6);
  background: var(--warn-fill); border-bottom: 1px solid var(--warn);
  font-size: var(--t-sm); color: var(--warn-text);
}
.phasestrip b { font-weight: 700; }
.ps-n {
  text-transform: uppercase; letter-spacing: var(--track-eyebrow);
  font-size: var(--t-xs); font-weight: 700;
  padding: 2px 8px; border-radius: 999px;
  background: var(--warn); color: var(--ink);
}
.ps-sep { opacity: .5; }

/* The why, as a tooltip on the programme screen. Hover or focus — focus
 * matters because a presenter tabbing is more reliable than a presenter
 * finding a small target with a trackpad in front of a room. */
.tip { position: relative; display: inline-block; }
.tip-k {
  color: var(--accent-text); font-weight: 600; cursor: help;
  border-bottom: 1px dashed var(--accent);
}
.tip-body {
  position: absolute; left: 0; top: calc(100% + 8px); z-index: 40;
  width: min(560px, 80vw); padding: var(--s4);
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: var(--elev-2);
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity var(--dur-1) var(--ease), transform var(--dur-1) var(--ease),
              visibility var(--dur-1);
  font-size: var(--t-sm); line-height: 1.6; text-align: left;
}
.tip:hover .tip-body, .tip:focus .tip-body, .tip:focus-within .tip-body {
  opacity: 1; visibility: visible; transform: translateY(0);
}
.tip-h { display: block; margin-bottom: var(--s3); font-size: var(--t-base); font-weight: 700; }
.tip-list { display: grid; gap: var(--s3); }
.tip-i { display: grid; gap: 2px; padding-left: var(--s3); border-left: 2px solid var(--line); }
.tip-i b { font-size: var(--t-sm); }
.tip-i > span { color: var(--ink-2); }

/* The two one-shot reveals. A deliberate click, sized to be findable from
 * across a room. */
.reveal-row {
  display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap;
  margin-top: var(--s5); padding-top: var(--s4); border-top: 1px solid var(--line);
}
.reveal-row .muted { font-size: var(--t-sm); }

/* A row nothing has evaluated yet.
 *
 * This must not read as grey. Grey is a real status here — "no lead-time
 * evidence in the file" — and the demo defends it on screen as not the
 * same as safe. So an unrun row gets no chip fill at all: a dashed outline
 * and an em dash, which reads as absence of a process rather than as the
 * outcome of one. */
.rag-unrun {
  background: transparent; color: var(--ink-3);
  border: 1px dashed var(--line-strong); font-weight: 700;
}

/* The assess button sits in its own column so it is in the same place on
 * every row, scored or not — the list is now something the presenter
 * drives, and a control that moves is a control that gets missed. */
.bom-go { text-align: right; white-space: nowrap; width: 1%; }

/* Letterhead children are a stack, not a sentence.
 *
 * The quotations build their heading from .lh-name / .lh-sub divs, but the
 * catalogue, the cross-reference, the PO register and the performance
 * record build theirs from <b> and <span> — inline elements, so the
 * supplier name, the subtitle and the date ran together as one line. Only
 * visible once these documents started rendering inline in the research
 * lanes and being opened in the room. */
.lh > b { display: block; font-size: var(--t-lg); font-weight: 700; letter-spacing: .02em; }
.lh > span { display: block; font-size: var(--t-xs); color: var(--ink-3); line-height: 1.5; }
.lh > span + span { margin-top: 2px; }

/* "(we are here today)" beside the live phase. Quiet green italics rather
 * than a tracked uppercase chip — it is an aside pointing at a row, not a
 * status badge competing with the phase name it sits next to. */
.wrow-live {
  margin-left: 8px; font-size: var(--t-sm); font-style: italic;
  font-weight: 600; text-transform: none; letter-spacing: 0;
  color: var(--accent-text);
}

/* ---- 20 Aug · presentation-density pass ---- */

/* Beat 2: the phase summary is useful but secondary. Smaller and quieter
 * than `.muted`, so the phase names read as the picture. */
.prog-sum { font-size: var(--t-xs); color: var(--ink-3); line-height: 1.4; }

/* Beat 4: the three questions this job turns on stay at full weight; the
 * rest are present but dimmed, so the room sees the question is asked
 * everywhere without reading all ten. */
.wrow-dim td:not(.prog-s) { color: var(--ink-3); opacity: .62; }
.wrow-dim td b { color: var(--ink-2); font-weight: 500; }
.wrow-dim.wrow-now td { color: inherit; opacity: 1; }
/* The stage cell is never dimmed, and the hero bar sits on the phase
 * number cell, not across the stage cell. */
.watch .wrow-hero { box-shadow: none; }
.watch .wrow-hero .wrow-n { box-shadow: inset 3px 0 0 var(--warn); }
.watch.prog-t .wrow-now .prog-s { background: var(--panel); }
.watch.prog-t .wrow-n { width: 34px; }

/* The rewind. The table re-renders, so the highlight cannot slide; the
 * new hero row lights in from nothing and everything else settles, which
 * reads as the clock moving. The masthead date changes at the same time. */
.watch-rewind .wrow-land { animation: progLit calc(var(--dur-3) * 2.2) var(--ease) both; }
.watch-rewind .wrow-land .wrow-live { animation: frameIn calc(var(--dur-3) * 2.2) var(--ease) both; }
.watch-rewind .wrow-land .ph-n-now { animation: frameIn calc(var(--dur-3) * 1.4) var(--ease) both; }

/* A frame revealed on request arrives, rather than appearing. */
.frame-in { animation: frameIn calc(var(--dur-3) * 1.6) var(--ease) both; }
@keyframes frameIn { from { opacity: 0; transform: translateY(8px); } }
@media (prefers-reduced-motion: reduce) {
  .frame-in, .watch-rewind .wrow-land, .watch-rewind .wrow-land .wrow-live,
  .watch-rewind .wrow-land .ph-n-now { animation: none; }
}

/* Beat 6: candidates grouped by the kind of paper behind them. The group
 * heading carries the sorting rule, so the lede no longer has to. */
.cand-grp { margin-top: var(--s5); }
.cand-grp + .cand-grp { margin-top: var(--s4); }
.cand-grp-h { display: flex; align-items: baseline; gap: var(--s3); flex-wrap: wrap; }
.cand-grp-h b { font-size: var(--t-sm); text-transform: uppercase; letter-spacing: var(--track-eyebrow); }
.cand-grp-h .muted { font-size: var(--t-xs); }
.cand-grp .cands { margin-top: var(--s3); margin-bottom: 0; }
.cand-from { margin: 0; font-size: var(--t-xs); color: var(--ink-2); line-height: 1.5; }
.cand-grp + .hint { margin-top: var(--s5); }

/* Beat 2: one colour and one flat icon per stage. The colour is a bar on
 * the left edge of the stage cell and a tint on the phase numbers inside
 * it, so the five stages read as five things without any of them
 * shouting. Muted hues, all sitting under the brand green. */
:root {
  --stage-0: #4f6b86;   /* Define — slate */
  --stage-1: #526E2D;   /* Design — the brand accent */
  --stage-2: #9a7b2f;   /* Buy — ochre */
  --stage-3: #8f5a43;   /* Build — terracotta */
  --stage-4: #2f6f6a;   /* Prove and close — teal */
}
.prog-t tbody .prog-s {
  box-shadow: inset 4px 0 0 var(--stage-c, var(--accent));
  padding-left: calc(var(--s3) + 6px);
}
.prog-t tbody .prog-s b { display: flex; align-items: center; gap: var(--s2); }
.prog-ic { width: 20px; height: 20px; flex: none; color: var(--stage-c, var(--accent)); }
.prog-ic svg { width: 100%; height: 100%; display: block; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
/* The phase numbers inside a stage take its colour, lightly. The live
 * ones keep the accent fill — state still outranks grouping. */
.prog-r .ph-n:not(.ph-n-now), .watch .wrow .ph-n:not(.ph-n-now) { color: var(--stage-c, var(--ink-2)); border-color: color-mix(in srgb, var(--stage-c, var(--line)) 45%, transparent); background: color-mix(in srgb, var(--stage-c, var(--panel-3)) 8%, var(--panel)); }
.prog-t + .hint { margin-top: var(--s4); }
.watch.prog-t { table-layout: fixed; }
.watch.prog-t .prog-s { width: 150px; }
.watch.prog-t th:nth-child(2), .watch.prog-t td:nth-child(2) { width: 34px; }
.watch.prog-t th:nth-child(3), .watch.prog-t td:nth-child(3) { width: 330px; }
.watch.prog-t .wrow-live { white-space: nowrap; }

/* ---- the all-items sweep ---- */
.bom-reading td { background: var(--accent-fill); }
.rag-reading { background: transparent; color: var(--accent-text); border: 1px solid var(--accent); }
.rag-new { animation: ragIn var(--dur-3) var(--ease) both; }
@keyframes ragIn { from { opacity: 0; transform: scale(.85); } }
.ovl-sweep { background: rgba(20, 24, 31, .22); animation: none; align-items: start; padding-top: 22vh; }
.sweep-box {
  width: min(520px, 100%); padding: var(--s5); gap: var(--s4); animation: none;
}
.sweep-head { display: flex; align-items: center; gap: var(--s3); }
.sweep-head b { font-size: var(--t-base); }
.sweep-head .muted { margin-left: auto; font-variant-numeric: tabular-nums; }
.sweep-cur { display: flex; align-items: baseline; gap: var(--s3); min-height: 1.5em; }
.sweep-tag { font-weight: 700; font-variant-numeric: tabular-nums; }
.sweep-txt { margin: 0; font-size: var(--t-xs); color: var(--ink-3); line-height: 1.5; }
.sweep-spin {
  width: 14px; height: 14px; border-radius: 50%; flex: none;
  border: 2px solid var(--line-strong); border-top-color: var(--accent);
  animation: sweepSpin .7s linear infinite;
}
@keyframes sweepSpin { to { transform: rotate(360deg); } }
.sweep-bar { display: block; height: 6px; border-radius: 3px; background: var(--panel-3); overflow: hidden; }
.sweep-bar span { display: block; height: 100%; background: var(--accent); transition: width .15s linear; }
@media (prefers-reduced-motion: reduce) { .sweep-spin, .rag-new { animation: none; } }

/* ---------- programme impact: the Gantt off Assess ---------- */
.sim-ctl { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 18px 0 12px; }
.btn-lg { font-size: var(--t-base); padding: 11px 20px; }
.rag-xs { font-size: 10px; padding: 1px 6px; margin-right: 8px; min-width: 0; vertical-align: 1px; }
.g-key { margin-left: auto; display: inline-flex; align-items: center; gap: 14px; font-size: var(--t-xs); color: var(--ink-3); }
.g-key i { display: inline-block; width: 22px; height: 10px; border-radius: 2px; margin-right: 6px; vertical-align: -1px; }
.g-key-base { border: 1.5px dashed var(--ink-3); background: transparent; }
.g-key-proj { background: var(--ink-2); }
.g-key-arr { background: var(--risk); }
.g-key-today { width: 2px !important; height: 14px !important; background: var(--ink-3); border-radius: 0 !important; }

.gantt { table-layout: fixed; width: 100%; border-collapse: collapse; }
.gantt thead th:nth-child(1) { width: 84px; }
.gantt thead th { white-space: nowrap; }
.gantt thead th:nth-child(2) { width: 330px; }
.gantt thead th:nth-child(3) { width: 64px; }
.gantt thead th:nth-child(4) { width: 80px; }
.gantt th.g-num, .gantt td.g-num { text-align: right; padding-right: 14px; }
.gantt td.g-num { font-variant-numeric: tabular-nums; font-size: var(--t-sm); color: var(--ink-2); white-space: nowrap; }
.gantt td.g-num small { font-size: 11px; color: var(--ink-3); margin-left: 2px; }
.gantt td.g-num.g-neg { color: var(--risk-text); font-weight: 700; }
.gantt td.g-id { font-family: var(--mono); font-size: 12px; color: var(--ink-3); padding: 7px 12px 7px 14px; white-space: nowrap; box-shadow: inset 4px 0 0 var(--stage-c, transparent); }
/* WBS summary rows, the P6 idiom: a bold name, a dark rolled-up bar with
 * end ticks, activities indented beneath. */
.gantt .g-wbs td { background: var(--panel-2); border-top: 1px solid var(--line-strong); }
.gantt .g-wbs .g-id { color: var(--ink-2); font-weight: 600; }
.gantt .g-wbs .g-name b { display: inline-flex; align-items: center; gap: 8px; font-weight: 700; color: var(--stage-c, var(--ink)); }
.gantt .g-wbs .g-name { padding: 9px 12px; }
.gantt .g-wbs .g-track { height: 30px; }
.g-sum { position: absolute; top: 11px; height: 8px; background: var(--stage-c, var(--ink-2)); z-index: 2; }
.g-sum::before, .g-sum::after { content: ''; position: absolute; top: 0; width: 0; height: 0; border-style: solid; }
.g-sum::before { left: 0; border-width: 8px 5px 0 0; border-color: var(--stage-c, var(--ink-2)) transparent transparent transparent; transform: translateY(8px); }
.g-sum::after { right: 0; border-width: 8px 0 0 5px; border-color: var(--stage-c, var(--ink-2)) transparent transparent transparent; transform: translateY(8px); }
.g-moved .g-sum { background: color-mix(in srgb, var(--stage-c) 82%, var(--risk)); }
.g-wbs-it { --stage-c: var(--risk); }
.g-wbs-it .g-name b { color: var(--risk-text); }
.g-wbs-ms { --stage-c: var(--ink-3); }
.g-wbs-ms .g-name b { color: var(--ink-2); }
.g-item .g-id, .g-ms .g-id { --stage-c: transparent; }
.g-item .g-id { --stage-c: var(--risk); }
.g-ms .g-id { --stage-c: var(--ink-3); }
.gantt .g-row .g-name { padding-left: 22px; }
.g-key-crit { background: color-mix(in srgb, var(--stage-3) 82%, var(--risk)); }
.gantt thead th.g-axis { padding: 0; vertical-align: bottom; }
.gantt thead .g-track { height: 28px; position: relative; }
.g-yr { position: absolute; bottom: 6px; transform: translateX(-50%); font-size: var(--t-xs); font-weight: 600; color: var(--ink-3); letter-spacing: .04em; }
.g-yr-0 { transform: none; margin-left: 6px; }
.g-yr-0::after { left: -6px; }
.g-yr::after { content: ''; position: absolute; left: 50%; top: 100%; width: 1px; height: 6px; background: var(--line-strong); }

.gantt tbody td { vertical-align: middle; }
.gantt td.g-name { padding: 7px 12px; }
.gantt td.g-name > span { display: block; font-weight: 500; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gantt td.g-name .g-dates { font-size: var(--t-xs); font-weight: 400; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.g-dates s { opacity: .6; margin-left: 4px; }
.gantt td.g-lane { padding: 0; }
.g-track { position: relative; height: 40px; }
.g-today { position: absolute; top: 0; bottom: 0; width: 0; border-left: 2px solid var(--ink-3); opacity: .5; z-index: 1; }
.g-base, .g-proj, .g-arr { position: absolute; top: 12px; height: 16px; border-radius: 3px; }
.g-base { border: 1.5px dashed color-mix(in srgb, var(--stage-c) 70%, transparent); background: color-mix(in srgb, var(--stage-c) 8%, transparent); box-sizing: border-box; }
.g-proj { background: var(--stage-c); box-shadow: 0 1px 0 rgba(0,0,0,.08); z-index: 2; }
.g-moved .g-proj { background: color-mix(in srgb, var(--stage-c) 82%, var(--risk)); }
.g-slip { position: absolute; top: 11px; margin-left: 8px; font-size: var(--t-xs); font-weight: 700; color: var(--risk-text); white-space: nowrap; font-variant-numeric: tabular-nums; z-index: 3; }
/* The stretch between where an activity was and where it now starts. */
.g-gap { position: absolute; top: 19px; height: 0; border-top: 2px dotted var(--risk); opacity: .7; z-index: 1; }
.g-gap::after { content: ''; position: absolute; right: -1px; top: -5px; border: 4px solid transparent; border-left: 6px solid var(--risk); }

/* The late items on top: need date as a tick, arrival as a red bar out of
 * today. An amber item shows its band — fast end to slow end — across the
 * need tick, in the bar's lighter part. */
.g-item .g-name > span { font-weight: 600; }
.gantt .g-item td.g-name > span:first-child { white-space: normal; line-height: 1.25; }
.g-need { position: absolute; top: 6px; height: 28px; width: 0; border-left: 2px solid var(--ink); z-index: 2; }
.g-need i { position: absolute; top: -2px; left: 5px; font-style: normal; font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2); }
.g-arr { background: var(--risk); opacity: .9; z-index: 1; overflow: hidden; }
.g-item-amber .g-arr { background: var(--warn); }
.g-band { position: absolute; top: 0; bottom: 0; right: 0; background: repeating-linear-gradient(135deg, rgba(255,255,255,.55) 0 4px, transparent 4px 8px); }
.g-slip-it { color: var(--risk-text); }
.g-item-amber .g-slip-it { color: var(--warn-text); }
/* The line dropped from the late item's arrival through the rows it moves. */
.g-land { position: absolute; top: 0; bottom: 0; width: 0; border-left: 2px dashed var(--risk); opacity: .55; z-index: 1; }
.g-driving .g-name > span:first-child { color: var(--risk-text); }

/* Milestones: an unrotated anchor, the diamond on ::before. */
.g-dia { position: absolute; top: 0; width: 0; height: 100%; z-index: 2; }
.g-dia::before { content: ''; position: absolute; top: 14px; left: 0; width: 12px; height: 12px; transform: translateX(-50%) rotate(45deg); border-radius: 2px; box-sizing: border-box; }
.g-dia-base::before { border: 1.5px dashed var(--ink-3); }
.g-dia-proj::before { background: var(--ink); }
.g-moved .g-dia-proj::before { background: var(--risk); }
.g-ms .g-slip { margin-left: 12px; }

/* The run, in order: arrivals draw out of today (0–.9s); the line drops
 * from the late one (.9s); the dependent bars slide across, staggered
 * down the rows (1.2s on); the gaps and labels settle last. Runs once;
 * the store clears the class afterwards. */
.g-play .g-arr { animation: gGrow .9s var(--ease) both; animation-delay: calc(var(--k, 0) * 120ms); }
.g-play .g-slip-it { animation: gFade .3s var(--ease) both; animation-delay: calc(.85s + var(--k, 0) * 120ms); }
.g-play .g-land { animation: gDrop .5s var(--ease) both; animation-delay: 1s; }
.g-play .g-moved .g-proj { animation: gSlide 1s var(--ease) both; animation-delay: calc(1.2s + var(--k, 0) * 90ms); }
.g-play .g-moved .g-dia-proj { animation: gSlideDia 1s var(--ease) both; animation-delay: calc(1.2s + var(--k, 0) * 90ms); }
.g-play .g-moved .g-sum { animation: gSlide 1s var(--ease) both; animation-delay: calc(1.2s + var(--k, 0) * 90ms); }
.g-play .g-moved .g-num.g-neg { animation: gFade .4s var(--ease) both; animation-delay: calc(2.1s + var(--k, 0) * 90ms); }
.g-play .g-gap { animation: gFade .4s var(--ease) both; animation-delay: calc(2s + var(--k, 0) * 90ms); }
.g-play .g-moved .g-slip { animation: gFade .4s var(--ease) both; animation-delay: calc(2.1s + var(--k, 0) * 90ms); }
.g-play .g-moved .g-dates { animation: gFade .4s var(--ease) both; animation-delay: calc(1.2s + var(--k, 0) * 90ms); }
@keyframes gGrow { from { width: 0; } }
@keyframes gDrop { from { transform: scaleY(0); transform-origin: top; } }
@keyframes gSlide { from { left: var(--l0); width: var(--w0); } }
@keyframes gSlideDia { from { left: var(--l0); } }
@keyframes gFade { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .g-play .g-arr, .g-play .g-slip-it, .g-play .g-land, .g-play .g-moved .g-proj, .g-play .g-moved .g-dia-proj, .g-play .g-gap, .g-play .g-moved .g-slip { animation: none; } }
