/* ==========================================================================
   korscope.com — the sections below the hero.
   Loaded after styles.css; same tokens, same vocabulary. Nothing here
   overrides an existing rule — new classes only.

   The whole point of this file: the page stops describing the product and
   starts showing it. The demo panel is real markup at real fidelity, not a
   screenshot, so it reads on a phone and can't go stale as a picture would.
   ========================================================================== */

:root {
  /* Discipline hues, lifted from app/src/styles/theme.css (dark variants).
     Deliberately no red/amber/yellow/green — those are reserved for risk, so a
     discipline tag can never be misread as a status. */
  --d-mech: 251;
  --d-elec: 273;
  --d-fire: 317;
  --d-ph: 185;
  --d-bms: 295;

  /* Two more risk roles the hero didn't need. Green stays scarce. */
  --ok: oklch(0.80 0.13 150);
  --err: oklch(0.72 0.16 25);
}

/* Anything marked [data-in] fades up once, when it first arrives. Base state is
   visible — .js-demo is added by demo.js, so no-JS keeps everything readable. */
.js-demo [data-in] {
  opacity: 0;
  transform: translateY(0.75rem);
}
.js-demo [data-in].is-in {
  opacity: 1;
  transform: none;
  transition:
    opacity 620ms var(--ease-out-quart),
    transform 720ms var(--ease-out-expo);
}

/* ==========================================================================
   Shared section furniture
   ========================================================================== */

.band {
  padding: var(--stack) var(--gutter);
  border-top: 1px solid var(--bl);
}
/* Alternating bands, so the page reads as sections rather than one long scroll. */
.band.alt { background: var(--bg-deep); }
.band-inner { max-width: 68rem; margin: 0 auto; }

.eyebrow {
  margin: 0 0 0.75rem;
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--light);
}

.band h2 {
  margin: 0 0 0.6rem;
  font-size: clamp(1.375rem, 2.6vw, 1.875rem);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.02em;
  max-width: 32ch;
}

.band > .band-inner > .intro {
  margin: 0 0 clamp(1.75rem, 3vw, 2.75rem);
  color: var(--muted);
  max-width: 52ch;
}

/* ==========================================================================
   The five-minute test — questions on the left, one live panel on the right
   ========================================================================== */

.test-grid {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
  align-items: start;
}

/* Each question is a button, not a tab role: it scrolls nothing and swaps one
   panel, which is what a radio group is. Styled as a ruled list, not chips. */
.qs {
  display: grid;
  border-top: 1px solid var(--bl);
}

.q {
  appearance: none;
  display: block;
  width: 100%;
  padding: 0.9rem 0.25rem 0.95rem;
  border: 0;
  border-bottom: 1px solid var(--bl);
  background: none;
  color: var(--muted);
  font: inherit;
  text-align: left;
  cursor: pointer;
  position: relative;
  transition: color 180ms var(--ease-out-quart);
}
.q::before {
  content: "";
  position: absolute;
  left: -0.75rem;
  top: 1.15rem;
  width: 2px;
  height: 1.1rem;
  background: var(--accent);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 220ms var(--ease-out-quart);
}
.q .q-t {
  display: block;
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--text);
}
.q .q-s {
  display: block;
  font-size: 0.8125rem;
  line-height: 1.45;
}
.q[aria-selected="true"] { color: var(--text); }
.q[aria-selected="true"]::before { transform: scaleY(1); }
@media (hover: hover) and (pointer: fine) {
  .q:hover { color: var(--text); }
}

/* --- the panel ----------------------------------------------------------- */

.panel {
  position: sticky;
  top: 2rem;
  border: 1px solid var(--border);
  border-radius: var(--r12);
  background: var(--bg);
  overflow: clip;
  /* Vellum dot-grid, same device as the app's sheet background. */
  background-image: radial-gradient(circle at 1px 1px, oklch(0.225 0 0) 1px, transparent 0);
  background-size: 1.25rem 1.25rem;
}

.panel-bar {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  flex-wrap: wrap;
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--bl);
  background: var(--surface);
  font-size: 0.75rem;
  color: var(--light);
}
.panel-bar strong {
  color: var(--text);
  font-weight: 500;
}
.panel-bar .sep { color: var(--bl); }
.panel-bar .push { margin-left: auto; }

.view { display: none; padding: 0.9rem; }
.view[data-active] { display: block; }

/* --- register ------------------------------------------------------------ */

.reg {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8125rem;
}
.reg caption { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.reg th {
  padding: 0 0.5rem 0.45rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--light);
  text-align: left;
  white-space: nowrap;
}
/* Hour figures never wrap — "24 h" split over two lines stops being a number. */
.reg th.n, .reg td.n { text-align: right; white-space: nowrap; }
.reg td {
  padding: 0.55rem 0.5rem;
  border-bottom: 1px solid var(--bl);
  vertical-align: middle;
}
.reg tbody tr:last-child td { border-bottom: 0; }
.reg .name { color: var(--text); }
.reg .n { color: var(--muted); }
.reg .n.over { color: var(--warn); }

/* Discipline tag: tinted well + coloured ink, hue driven by --h on the row. */
.disc {
  display: inline-block;
  padding: 0.1rem 0.4rem;
  border-radius: var(--r4);
  background: oklch(0.28 0.045 var(--h));
  color: oklch(0.85 0.065 var(--h));
  font-size: 0.625rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

.who {
  display: inline-grid;
  place-items: center;
  width: 1.55rem; height: 1.55rem;
  border-radius: 9999px;
  border: 1px solid var(--border);
  /* Was 9px. Nothing on this page that a visitor is meant to read goes below
     11px — the drafting annotations below are the only exception, and they are
     annotations. */
  font-size: 0.6875rem;
  color: var(--muted);
}

/* Progress: a bar and its number, not a bar alone — the number is the fact. */
.prog {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  min-width: 5.5rem;
}
.prog-t {
  flex: 1;
  height: 3px;
  border-radius: 9999px;
  background: var(--bl);
  overflow: clip;
}
.prog-f {
  display: block;
  height: 100%;
  border-radius: 9999px;
  background: oklch(0.70 0.12 var(--h));
  transform-origin: left;
  transform: scaleX(var(--p));
}
.js-demo .panel [data-grow] .prog-f {
  transform: scaleX(0);
  transition: transform 900ms var(--ease-out-expo);
}
.js-demo .panel [data-grow].is-in .prog-f { transform: scaleX(var(--p)); }

/* Row badges. One shape, three meanings, colour is the only difference.
   These carry the risk vocabulary — at risk, burn ahead, waiting — so they are
   the last thing on the page that should have been set at 9px. */
.badge {
  display: inline-block;
  padding: 0.1rem 0.4rem;
  border: 1px solid currentColor;
  border-radius: var(--r4);
  font-size: 0.6875rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}
.badge.risk { color: var(--err); }
.badge.watch { color: var(--warn); }
.badge.wait { color: var(--light); }
.badge.ok { color: var(--ok); }

.due { white-space: nowrap; color: var(--muted); }
.due.late { color: var(--err); }
.due.soon { color: var(--warn); }

/* --- attention buckets --------------------------------------------------- */

.buckets { display: grid; gap: 0.9rem; }
.bucket { border-left: 2px solid var(--bl); padding-left: 0.85rem; }
.bucket.late { border-color: var(--err); }
.bucket.soon { border-color: var(--warn); }
.bucket h4 {
  margin: 0 0 0.35rem;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--light);
}
.bucket ul { margin: 0; padding: 0; list-style: none; font-size: 0.8125rem; }
.bucket li {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  padding: 0.2rem 0;
  flex-wrap: wrap;
}
/* Secondary fact on a line — always lighter and smaller than what it qualifies. */
.m { color: var(--light); font-size: 0.75rem; }

/* --- gantt -------------------------------------------------------------- */

.gantt { font-size: 0.75rem; }
.gantt-head, .gantt-row {
  display: grid;
  grid-template-columns: minmax(0, 9rem) minmax(0, 1fr);
  gap: 0.6rem;
  align-items: center;
}
.gantt-head {
  padding-bottom: 0.4rem;
  border-bottom: 1px solid var(--border);
  color: var(--light);
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.gantt-months { display: grid; grid-template-columns: repeat(4, 1fr); }
.gantt-months span { border-left: 1px solid var(--bl); padding-left: 0.35rem; }
.gantt-row { padding: 0.35rem 0; }
.gantt-row .lbl {
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The lane carries the week rules; the bar is positioned in percent so it
   scales with the container instead of needing a pixel timeline. */
.lane {
  position: relative;
  height: 1.1rem;
  background-image: repeating-linear-gradient(to right, var(--bl) 0 1px, transparent 1px 25%);
}
.bar {
  position: absolute;
  top: 0.2rem;
  height: 0.7rem;
  left: var(--x);
  width: var(--w);
  border-radius: var(--r4);
  background: oklch(0.70 0.12 var(--h));
}
.bar .done {
  display: block;
  height: 100%;
  width: var(--p);
  border-radius: var(--r4);
  background: oklch(0.85 0.065 var(--h));
}
.js-demo .panel [data-grow] .bar { transform: scaleX(0); transform-origin: left; transition: transform 700ms var(--ease-out-expo); }
.js-demo .panel [data-grow].is-in .bar { transform: none; }

.mk {
  position: absolute;
  top: -0.1rem;
  left: 74%;
  width: 0.5rem; height: 0.5rem;
  margin-left: -0.25rem;
  background: var(--text);
  transform: rotate(45deg);
}
.today {
  /* One date, so one number — today does not vary by row. */
  position: absolute;
  top: -0.35rem; bottom: -0.35rem;
  left: 30%;
  width: 1px;
  background: var(--accent);
}
/* The line runs down every lane, but it is labelled once — on the top row, and
   to the left of itself so it never sits on a month heading. */
.gantt-row:first-of-type .today::after {
  content: "today";
  position: absolute;
  bottom: 100%;
  right: 0.25rem;
  font-size: 0.625rem;
  letter-spacing: 0.04em;
  color: var(--accent);
}

/* --- forecast grid ------------------------------------------------------ */

.fc { width: 100%; border-collapse: collapse; font-size: 0.8125rem; }
.fc th, .fc td {
  padding: 0.45rem 0.5rem;
  border-bottom: 1px solid var(--bl);
  text-align: right;
  white-space: nowrap;
}
.fc th:first-child, .fc td:first-child { text-align: left; }
.fc thead th {
  border-bottom: 1px solid var(--border);
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--light);
}
.fc tbody tr:last-child td { border-bottom: 0; }
.fc .cell { color: var(--muted); }
/* A thin month is the whole point of this view, so it gets the only colour. */
.fc .cell.thin { color: var(--warn); }
.fc .cell.hot { color: var(--err); }
.fc tfoot td { border-top: 1px solid var(--border); border-bottom: 0; color: var(--text); }

.panel-note {
  margin: 0;
  padding: 0.6rem 0.9rem;
  border-top: 1px solid var(--bl);
  background: var(--surface);
  font-size: 0.75rem;
  color: var(--light);
}

/* ==========================================================================
   Monday 08:47 — a drift of near-identical sheets against one square sheet.
   The picture carries the argument; the lists only confirm it.
   ========================================================================== */

.versus {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
}

/* Three sheets, stacked and out of true. No images: each sheet is a bordered
   box ruled with a repeating gradient, which is what a spreadsheet looks like
   from six feet away. */
.sheets {
  position: relative;
  margin: 0 0 0.9rem;
  height: 9rem;
}
.sh {
  position: absolute;
  inset: 0 auto auto 0;
  width: 11rem;
  height: 8rem;
  border: 1px solid var(--border);
  border-radius: var(--r4);
  background:
    repeating-linear-gradient(to bottom, transparent 0 1.05rem, var(--bl) 1.05rem calc(1.05rem + 1px)),
    var(--bg);
  background-position: 0 1.3rem;
}
/* The two behind are dimmer and further out of true the further back they sit. */
.sh.c { transform: translate(2.6rem, 1.1rem) rotate(7.5deg); opacity: 0.35; }
.sh.b { transform: translate(1.3rem, 0.5rem) rotate(-4.5deg); opacity: 0.6; }
.sh.a { transform: none; }
/* The top sheet keeps a header rule, so it reads as a table not a notepad. */
.sh.a::before {
  content: "";
  position: absolute;
  inset: 1.25rem 0 auto;
  border-top: 1px solid var(--border);
}

/* The other side: one sheet, square to the page, with the one row that matters. */
.sheets.one .sh.a { width: 12rem; }
.sh .hl {
  position: absolute;
  left: 0.4rem; right: 0.4rem;
  top: 3.6rem;
  height: 0.75rem;
  border-radius: var(--r4);
  background: color-mix(in oklab, var(--warn) 26%, transparent);
  border-left: 2px solid var(--warn);
}

.vs-cap { font-size: 0.6875rem; color: var(--light); margin: 0 0 0.9rem; }
.vs-list { margin: 0; padding: 0; list-style: none; }
.vs-list li {
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--bl);
  color: var(--muted);
  font-size: 0.9375rem;
}
.vs.now .vs-list li { color: var(--text); }

/* Our own sentence, stated — not dressed up as a quotation from somebody. */
.pull {
  margin: clamp(1.75rem, 4vw, 3rem) 0 0;
  max-width: 40ch;
  font-size: clamp(1.125rem, 2vw, 1.375rem);
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--text);
}

/* ==========================================================================
   How it works — three marks that draw themselves, then stop
   ========================================================================== */

.hows {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.75rem);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  counter-reset: s;
}
.how { position: relative; padding-top: 0.4rem; }
.how h3 {
  margin: 0 0 0.3rem;
  font-size: 1.0625rem;
  font-weight: 600;
}
.how h3::before {
  counter-increment: s;
  content: counter(s, decimal-leading-zero) " ";
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--accent);
}
.how p { margin: 0; color: var(--muted); font-size: 0.9375rem; max-width: 34ch; }

.dmk {
  display: block;
  width: 5rem;
  height: auto;
  margin-bottom: 1.1rem;
  overflow: visible;
  color: var(--muted);
}
.dmk .dr { stroke: currentColor; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; }
.dmk .sig { stroke: var(--accent); }
.dmk .sig-f { fill: var(--accent); }
.dmk text { font-size: 8px; }

/* pathLength="1" normalises every shape to a unit length, so one dash rule
   animates a line, a circle and a rectangle alike — no measuring in JS. */
.js-demo .dmk .dr {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
.js-demo [data-in].is-in .dmk .dr {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 820ms var(--ease-out-quart) var(--d, 0ms);
}
.js-demo .dmk .fd { opacity: 0; }
.js-demo [data-in].is-in .dmk .fd {
  opacity: 1;
  transition: opacity 320ms var(--ease-out-quart) var(--d, 0ms);
}

/* ==========================================================================
   Scope — the boundary, drawn
   ========================================================================== */

.boundary {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  gap: clamp(1rem, 3vw, 2.5rem);
  align-items: stretch;
  padding: clamp(1.1rem, 2.5vw, 1.75rem);
  border: 1px solid var(--border);
  border-radius: var(--r12);
  background: var(--bg-deep);
}
.bx h3 {
  margin: 0 0 0.7rem;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
}
.bx.them h3 { color: var(--light); }
.bx ul { margin: 0; padding: 0; list-style: none; }
.bx li {
  padding: 0.3rem 0;
  font-size: 0.9375rem;
  color: var(--text);
}
.bx.them li { color: var(--light); }

/* The rule between them is the point of the diagram, so it is labelled. */
.bline {
  position: relative;
  width: 1px;
  background: repeating-linear-gradient(to bottom, var(--border) 0 4px, transparent 4px 9px);
}
.bline span {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(90deg);
  padding: 0 0.4rem;
  background: var(--bg-deep);
  font-size: 0.625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--light);
  white-space: nowrap;
}

.nots-lead {
  margin: clamp(1.5rem, 3vw, 2.25rem) 0 0.5rem;
  color: var(--muted);
}
.nots {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.5rem;
}
.nots li {
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--bl);
  border-radius: var(--r4);
  font-size: 0.8125rem;
  color: var(--light);
  /* Struck through, because that is what the sentence is doing. */
  text-decoration: line-through;
  text-decoration-color: var(--border);
}
.nots-note { margin: 1rem 0 0; color: var(--muted); max-width: 52ch; font-size: 0.9375rem; }

/* ==========================================================================
   Data & access — the titleblock, full size
   ========================================================================== */

.tb-big {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0;
  margin: 0;
  border: 1px solid var(--border);
  border-radius: var(--r4);
  overflow: clip;
}
.tb-big > div {
  padding: 1rem 1.1rem 1.15rem;
  border-right: 1px solid var(--bl);
  border-bottom: 1px solid var(--bl);
}
.tb-big dt {
  margin-bottom: 0.4rem;
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}
.tb-big dd {
  margin: 0;
  font-family: "IBM Plex Sans", ui-sans-serif, system-ui, sans-serif;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--muted);
}

/* ==========================================================================
   FAQ — native disclosure, no JS
   ========================================================================== */

.faq { max-width: 46rem; }
.faq details { border-bottom: 1px solid var(--bl); }
.faq details:first-of-type { border-top: 1px solid var(--bl); }
.faq summary {
  padding: 0.95rem 1.75rem 0.95rem 0;
  position: relative;
  cursor: pointer;
  font-weight: 500;
  list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "";
  position: absolute;
  right: 0.35rem; top: 1.35rem;
  width: 0.5rem; height: 0.5rem;
  border-right: 1px solid var(--muted);
  border-bottom: 1px solid var(--muted);
  transform: rotate(45deg);
  transition: transform 180ms var(--ease-out-quart);
}
.faq details[open] summary::after { transform: rotate(225deg); }
.faq p { margin: 0 0 1rem; color: var(--muted); max-width: 60ch; }

/* ==========================================================================
   Pilot ask — a form that degrades to the mailto it replaces
   ========================================================================== */

.ask { max-width: 34rem; }
.field { display: grid; gap: 0.3rem; margin-bottom: 0.9rem; }
.field label { font-size: 0.75rem; letter-spacing: 0.04em; text-transform: uppercase; color: var(--light); }
.field input, .field select {
  /* 16px exactly, and never smaller: iOS Safari zooms the whole page when a
     focused field is under 16px, which throws the layout out mid-form. The
     padding takes the control past a 44px touch target at the same time. */
  padding: 0.7rem 0.7rem;
  /* One rung lighter than --border (which is 1.94:1 here). A control boundary
     needs 3:1 against its background under WCAG 1.4.11; this is 3.23:1. The
     token stays where it is — only the controls that must be found by eye are
     lifted. */
  border: 1px solid var(--control-edge);
  border-radius: var(--r8);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 1rem;
}
/* The placeholder carries the only format hint on the field, so it is text and
   held to 4.5:1 (4.92:1), not to the 3:1 a decorative hint would get. */
.field input::placeholder { color: oklch(0.60 0 0); }
.pair { display: grid; gap: 0.9rem; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); }
.ask .small { font-size: 0.8125rem; color: var(--light); max-width: 40ch; }
.ask .btn { margin-top: 0.35rem; }

/* ==========================================================================
   Narrow screens — the panel stops sticking, the split stacks
   ========================================================================== */

@media (max-width: 56rem) {
  .test-grid { grid-template-columns: minmax(0, 1fr); }
  .panel { position: static; }
  /* Questions become a scroll-snap row so the panel stays in view. */
  .qs {
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    border-top: 0;
    /* The inline padding is the focus ring's clearance: :focus-visible draws at
       outline-offset 3px, and an overflow-x scroller clips the first and last
       tab's ring without it. */
    padding: 3px 3px 0.5rem;
    margin-inline: -3px;
    scroll-snap-type: x proximity;
    /* A tab cut flat at the viewport edge reads as a rendering fault. Fading it
       says "keep going" with no label. The row is 760px against a 350px
       viewport at every width this rule applies to, so it always overflows and
       the fade is never a lie. */
    mask-image: linear-gradient(to right, #000 0 82%, transparent 100%);
  }
  .q {
    flex: 0 0 11.5rem;
    scroll-snap-align: start;
    border: 1px solid var(--bl);
    border-radius: var(--r8);
    padding: 0.7rem 0.75rem;
  }
  .q::before { left: 0; top: 0; width: 100%; height: 2px; transform: scaleX(0); transform-origin: left; }
  .q[aria-selected="true"]::before { transform: scaleX(1); }
  .q[aria-selected="true"] { border-color: var(--border); }
  .q .q-t { font-size: 0.9375rem; }
  .q .q-s { display: none; }
}

@media (max-width: 34rem) {
  /* A six-column table cannot be honest at 390px, so the register stops being a
     table and becomes what it is on a phone: a name, then its facts on one
     line. Owner drops — it is the softest fact and it is an initial anyway. */
  .reg thead,
  .reg .drop { display: none; }
  .reg, .reg tbody, .reg tr, .reg td { display: block; }
  .reg tr { padding: 0.6rem 0; border-bottom: 1px solid var(--bl); }
  .reg tbody tr:last-child { border-bottom: 0; }
  .reg td { padding: 0; border: 0; text-align: left; }
  .reg td.name { margin-bottom: 0.35rem; font-size: 0.9375rem; }
  .reg td.due,
  .reg td.pg,
  .reg td.n { display: inline-block; margin-right: 0.7rem; font-size: 0.75rem; vertical-align: middle; }
  .reg td.pg .prog { width: 5.5rem; min-width: 0; }
  /* The hour figures lose their column headings, so they carry their own. */
  .reg td.pl::before { content: "plan "; color: var(--light); }
  .reg td.bn::before { content: "burn "; color: var(--light); }

  /* 6rem clipped every label to "Luminaire sche…". 7.5rem fits the longest of
     the six at 12px, so the ellipsis never fires and no row needs a tooltip
     nobody on a phone can open. */
  .gantt-head, .gantt-row { grid-template-columns: minmax(0, 7.5rem) minmax(0, 1fr); }
  .fc th, .fc td { padding: 0.45rem 0.3rem; }
  .fc td:first-child { font-size: 0.8125rem; }
  .fc td:first-child .m { display: block; }
}

@media (max-width: 44rem) {
  /* The boundary is vertical on a wide screen and horizontal on a narrow one —
     same diagram, turned through 90°. */
  .boundary { grid-template-columns: minmax(0, 1fr); }
  .bline {
    width: auto;
    height: 1px;
    background: repeating-linear-gradient(to right, var(--border) 0 4px, transparent 4px 9px);
  }
  .bline span { transform: translate(-50%, -50%); }
}

@media (prefers-reduced-motion: reduce) {
  /* Reduced does not mean none. Nothing travels — the translate goes — but the
     fade stays, because it is the fade that says "this block just arrived". */
  .js-demo [data-in] { opacity: 0; transform: none; }
  .js-demo [data-in].is-in { opacity: 1; transform: none; transition: opacity 200ms ease; }
  .js-demo .panel [data-grow] .prog-f,
  .js-demo .panel [data-grow].is-in .prog-f { transform: scaleX(var(--p)); transition: none; }
  .js-demo .panel [data-grow] .bar,
  .js-demo .panel [data-grow].is-in .bar { transform: none; transition: none; }
  /* The marks arrive drawn rather than drawing themselves. */
  .js-demo .dmk .dr { stroke-dashoffset: 0; transition: none; }
  .js-demo .dmk .fd { opacity: 1; transition: none; }
  /* The selected-question bar and the FAQ chevron snap instead of sweeping —
     both are pure movement, and both still read at their end state. */
  .q::before { transition: none; }
  .faq summary::after { transition: none; }
}

/* ===========================================================================
   Demo geometry
   ===========================================================================
   These numbers used to live in `style` attributes on the elements they
   describe, which reads better and does not survive contact with production:
   the CSP in landing/_headers omits 'unsafe-inline', so Cloudflare drops every
   inline style and the gantt renders as an empty grid. They live here instead.

   The cost is that a row's geometry is now bound to its position in the
   markup — reorder a row and its bar keeps the old row's dates. Keep each
   block in the same order as the markup in index.html, and the shots gate
   (which now serves the real CSP) will catch it if this drifts.
   ---------------------------------------------------------------------- */

/* Register — the hue tints the discipline tag, the fill drives the bar, and
   both inherit down from the row, so one rule does the pair. */
.view[data-view="register"] tbody tr:nth-child(1) { --h: var(--d-elec); --p: 0.10; }
.view[data-view="register"] tbody tr:nth-child(2) { --h: var(--d-elec); --p: 0.65; }
.view[data-view="register"] tbody tr:nth-child(3) { --h: var(--d-mech); --p: 0.45; }
.view[data-view="register"] tbody tr:nth-child(4) { --h: var(--d-mech); --p: 0.80; }
.view[data-view="register"] tbody tr:nth-child(5) { --h: var(--d-fire); --p: 0.20; }
.view[data-view="register"] tbody tr:nth-child(6) { --h: var(--d-ph);   --p: 0.30; }

/* Programme — same six deliverables, same order, drawn as bars. --x is the
   start, --w the duration, --p how much of the bar is done.

   Counting is nth-child, not nth-of-type: .gantt-head is a div like the rows
   are, so nth-of-type counts it and shifts every rule onto the wrong row. The
   header is child 1, so the six rows are children 2 through 7. */
.gantt-row:nth-child(2) .lane { --h: var(--d-elec); }
.gantt-row:nth-child(2) .bar  { --x: 2%;  --w: 24%; --p: 10%; }
.gantt-row:nth-child(3) .lane { --h: var(--d-elec); }
.gantt-row:nth-child(3) .bar  { --x: 8%;  --w: 30%; --p: 65%; }
.gantt-row:nth-child(4) .lane { --h: var(--d-mech); }
.gantt-row:nth-child(4) .bar  { --x: 14%; --w: 34%; --p: 45%; }
.gantt-row:nth-child(5) .lane { --h: var(--d-mech); }
.gantt-row:nth-child(5) .bar  { --x: 24%; --w: 28%; --p: 80%; }
.gantt-row:nth-child(6) .lane { --h: var(--d-fire); }
.gantt-row:nth-child(6) .bar  { --x: 34%; --w: 22%; --p: 20%; }
.gantt-row:nth-child(7) .lane { --h: var(--d-ph); }
.gantt-row:nth-child(7) .bar  { --x: 44%; --w: 26%; --p: 30%; }

/* The three "how it works" marks draw themselves in sequence. Each mark sets
   its own rhythm: the strokes that make the object come fast and close
   together, then a pause before the accent that says what it means. */
.how:nth-child(1) .dmk > :nth-child(2) { --d: 70ms; }
.how:nth-child(1) .dmk > :nth-child(3) { --d: 140ms; }
.how:nth-child(1) .dmk > :nth-child(4) { --d: 210ms; }
.how:nth-child(1) .dmk > :nth-child(5) { --d: 400ms; }
.how:nth-child(1) .dmk > :nth-child(6) { --d: 500ms; }
.how:nth-child(1) .dmk > :nth-child(7) { --d: 600ms; }

.how:nth-child(2) .dmk > :nth-child(2) { --d: 220ms; }
.how:nth-child(2) .dmk > :nth-child(3) { --d: 340ms; }
.how:nth-child(2) .dmk > :nth-child(4) { --d: 460ms; }
.how:nth-child(2) .dmk > :nth-child(5) { --d: 620ms; }

.how:nth-child(3) .dmk > :nth-child(2) { --d: 90ms; }
.how:nth-child(3) .dmk > :nth-child(3) { --d: 180ms; }
.how:nth-child(3) .dmk > :nth-child(4) { --d: 420ms; }
.how:nth-child(3) .dmk > :nth-child(5) { --d: 600ms; }

/* ==========================================================================
   Carry-across — a delivered job, a new job, and what crosses between them
   ========================================================================== */

.carry {
  display: grid;
  gap: clamp(1rem, 2.2vw, 1.75rem);
  grid-template-columns: minmax(0, 1fr) minmax(9rem, 0.7fr) minmax(0, 1fr);
  align-items: center;
}

.cd {
  border: 1px solid var(--bl);
  border-radius: var(--r12);
  background: var(--bg);
  overflow: clip;
}
/* The new job is the one being argued for, so it gets the ink and the border
   the delivered job does not. Same card, one rung brighter. */
.cd.is-new {
  border-color: var(--border);
  background: var(--surface);
}

.cd-h {
  display: grid;
  gap: 0.15rem;
  padding: 0.7rem 0.85rem;
  border-bottom: 1px solid var(--bl);
}
.cd-t { font-size: 0.9375rem; font-weight: 600; color: var(--text); }
.cd-s { font-size: 0.6875rem; color: var(--light); }
.cd.is-new .cd-s { color: var(--accent); }

.cd-rows { margin: 0; padding: 0.35rem 0; list-style: none; }
.cd-rows li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.85rem;
  font-size: 0.8125rem;
  color: var(--muted);
}
.cd-rows b { margin-left: auto; font-weight: 400; color: var(--light); }
.cd.is-new .cd-rows li { color: var(--text); }
.cd.is-new .cd-rows b { color: var(--muted); }

/* .disc needs a hue; these four rows are the only place it is set by class
   rather than by row position. */
.cd .disc.e { --h: var(--d-elec); }
.cd .disc.m { --h: var(--d-mech); }
.cd .disc.f { --h: var(--d-fire); }
.cd .disc.p { --h: var(--d-ph); }

.cd-foot {
  margin: 0;
  padding: 0.6rem 0.85rem;
  border-top: 1px solid var(--bl);
  font-size: 0.6875rem;
  color: var(--light);
}

/* --- the middle column ---------------------------------------------------- */

.cflow { display: grid; justify-items: center; gap: 0.6rem; text-align: center; }

/* A dashed run with an arrowhead at the end: the same drafting vocabulary as
   the gantt's today line, turned on its side. */
.cf-line {
  position: relative;
  width: 100%;
  height: 1px;
  background: repeating-linear-gradient(to right, var(--border) 0 4px, transparent 4px 9px);
}
.cf-line::after {
  content: "";
  position: absolute;
  right: 0;
  top: 50%;
  width: 0.42rem;
  height: 0.42rem;
  border-top: 1px solid var(--accent);
  border-right: 1px solid var(--accent);
  transform: translate(0, -50%) rotate(45deg);
}

.cf-tag {
  font-size: 0.6875rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--accent);
}
.cf-note {
  margin: 0;
  font-size: 0.75rem;
  line-height: 1.5;
  color: var(--light);
  max-width: 22ch;
}

@media (max-width: 52rem) {
  /* Stacked, the flow runs top-to-bottom instead of left-to-right — the arrow
     has to point at the card that is actually next, not off the side. */
  .carry { grid-template-columns: minmax(0, 1fr); }
  .cf-line {
    width: 1px;
    height: 2.5rem;
    background: repeating-linear-gradient(to bottom, var(--border) 0 4px, transparent 4px 9px);
  }
  .cf-line::after {
    right: auto;
    left: 50%;
    top: auto;
    bottom: 0;
    transform: translate(-50%, 0) rotate(135deg);
  }
  .cf-note { max-width: 40ch; }
}
