/* The short format (the hook). Base copied from Design Phase 03 (which carries Phase 02's base and the Phase 03 board);
   the hook's own rules are at the end.
   Single light (paper) theme by choice.
   Layout: the plan sits straight on a sheet of drawing paper, pinned over a tall scroll track. No window chrome:
   progress pills on the right, the plan filling the sheet, step notes beneath it, the command line appearing only
   while a command runs, and the X / Y readout in the bottom-right corner. */
:root {
  --paper: #f8f7f3;       /* drawing paper, near white (also the maths mask colour in build_venue.py) */
  --ink: #20252a;         /* the drawing set's ink */
  --grey: #5a6268;
  --faint: #c3c8cb;
  --pale: #e2e4e3;
  --con: #0a6a8d;         /* construction layer: the maths */
  --con-ink: #07506b;     /* construction text, a step darker so it reads over the drawing */
  --rule: #c8301e;        /* the four rules: a red warmed toward amber */
  --cursor: #20252a;
  --display: "Archivo", "Arial Narrow", Arial, sans-serif;
  --body: "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, Menlo, Consolas, monospace;
  --step-h: 75vh;         /* scroll distance per step (story.js reads the same value) */
  --rail: 3.25rem;        /* width kept clear for the progress pills (right edge) */
  color-scheme: light;
}

* { box-sizing: border-box; }
html, body { margin: 0; }
body {
  color: var(--ink); font: 400 1rem/1.5 var(--body); -webkit-font-smoothing: antialiased;
  background-color: var(--paper);
  /* paper grain: fine fractal noise plus a softer, larger fibre layer */
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='2.4 0 0 0 -0.7 2.4 0 0 0 -0.7 2.4 0 0 0 -0.7 0 0 0 0 1'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.012 .03' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='1.2 0 0 0 -0.1 1.2 0 0 0 -0.1 1.2 0 0 0 -0.1 0 0 0 0 1'/%3E%3C/filter%3E%3Crect width='600' height='600' filter='url(%23f)'/%3E%3C/svg%3E");
  background-attachment: fixed;
  background-blend-mode: soft-light, soft-light;   /* grain lightens and darkens around the paper colour, so no grey cast */
}

/* ---------------------------------------------------------------- scroll track + pinned sheet */
.track { position: relative; height: calc(var(--step-h) * 6 + 100vh); }
.app {
  position: sticky; top: 0; height: 100vh; height: 100dvh; margin: 0;
  display: grid; grid-template-rows: auto minmax(0, 1fr) auto;
  padding-left: max(20px, env(safe-area-inset-left, 0px));
  padding-right: calc(var(--rail) + env(safe-area-inset-right, 0px));
  padding-block: max(14px, env(safe-area-inset-top, 0px)) calc(2.6rem + env(safe-area-inset-bottom, 0px));
}
/* persistent masthead: quieter than the step headings, so the story stays the loudest text */
.masthead { display: flex; justify-content: space-between; align-items: baseline; gap: 0.5rem 1.5rem; flex-wrap: wrap; padding-bottom: 0.35rem; }
.ident { min-width: 0; }
.title { font: 800 1.05rem/1.1 var(--display); font-stretch: 112%; text-transform: uppercase; letter-spacing: 0.02em; margin: 0; }
.subtitle { font: 400 0.8125rem/1.35 var(--body); color: var(--grey); margin: 0.15rem 0 0; }
.phase { font: 500 0.6875rem/1 var(--mono); letter-spacing: 0.06em; color: var(--grey); margin: 0; }
/* the site bar in the masthead, on every screen: home (the title), then the project tabs (build_crane.tabs) */
.mside { display: flex; flex-direction: column; align-items: flex-end; gap: 0.1rem; }
.mtabs ol { justify-content: flex-end; gap: 0 1.1rem; }
.masthead .mtabs a { font-size: 0.6875rem; min-height: 1.75rem; padding: 0.3rem 0 0.25rem; }
.ptab-home { margin-right: 0.4rem; }
.ptabs .ptab-home a { color: var(--ink); font-weight: 600; letter-spacing: 0.08em; }
@media (max-width: 1100px) {                             /* narrower: the tabs by number, the current one by name */
  .mtabs .ptab-name { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .mtabs a[aria-current="page"] .ptab-name { position: static; width: auto; height: auto; clip-path: none; }
}

.drawing { min-height: 0; display: flex; }
#venue { display: block; width: 100%; height: 100%; }

/* ---------------------------------------------------------------- step band, set out like the SET 01 sheet footer:
   an ink rule across the top, grey uppercase section headers, vertical ink rules between sections. The row is the
   sheet footer mirrored: title block | working | notes, so the heading is read first. Title block as on the sheet:
   code with the step slot on the same row (like "GA-B4 ... REVISION G"), the name, a thin rule, the phase line. */
.panel { position: relative; border-top: 1.5px solid var(--ink); margin-top: 0.35rem; }
.step {
  display: grid; grid-template-columns: minmax(15rem, 1fr) minmax(13rem, 1fr) minmax(0, 2.2fr);
  grid-template-areas: "tblock work notes"; gap: 0 2.5rem; align-items: start; padding: 0.75rem 0 0;
}
.step-wide { grid-template-columns: minmax(15rem, 1fr) minmax(0, 3.4fr); grid-template-areas: "tblock notes"; }
.js .step:not(.is-active) { display: none; }
.step.is-active { animation: settle 0.45s ease both; }
@keyframes settle { from { opacity: 0; transform: translateY(6px); } }
.sec { min-width: 0; }
.sec-notes { grid-area: notes; }
.sec-work { grid-area: work; border-right: 1.5px solid var(--ink); padding-right: 1.25rem; align-self: stretch; }
.sec-h { font: 600 0.6875rem/1.2 var(--body); letter-spacing: 0.07em; text-transform: uppercase; color: var(--grey); margin: 0 0 0.45rem; }
.step-body { margin: 0; max-width: 64ch; font-size: 0.9375rem; line-height: 1.55; }
.eq { margin: 0; font: 500 0.875rem/1.5 var(--mono); color: var(--con-ink); font-variant-numeric: tabular-nums; }

/* word-by-word notes: a quick stagger as each step arrives */
.w { display: inline-block; }
.words-in .w { animation: word-in 0.34s cubic-bezier(.2,.7,.2,1) both; animation-delay: calc(var(--i) * 26ms); }
.words-in .notes li { animation: word-in 0.45s cubic-bezier(.2,.7,.2,1) both; animation-delay: calc(var(--i) * 140ms); }
@keyframes word-in { from { opacity: 0; transform: translateY(0.35em); filter: blur(2px); } }

/* rolling results: each digit is a 0-9 strip that rolls to its value when the plan's maths is finished */
.roll { display: inline-flex; vertical-align: bottom; }
.roll .dg { display: inline-block; height: 1.5em; overflow: hidden; user-select: none; }
.roll .sep { user-select: none; }
.roll .strip { display: flex; flex-direction: column; transform: translateY(calc(var(--d) * -1.5em));
  transition: transform 0.9s cubic-bezier(.2,.8,.2,1); transition-delay: calc(var(--i) * 80ms); }
.roll .strip span, .roll .sep { display: block; height: 1.5em; line-height: 1.5em; }
.roll.zero .strip { transform: translateY(0); transition: none; }
/* a working line waits off until its result is worked out, then fades in as the digits roll (no "000" placeholder) */
.eq { transition: opacity 0.35s ease; }
.eq:has(.roll.zero) { opacity: 0; transition: none; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

.tblock { grid-area: tblock; border-right: 1.5px solid var(--ink); padding-right: 1.25rem; min-width: 0; align-self: stretch; }
.tb-top { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 0.2rem 1rem; margin-bottom: 0.45rem; }
.code { font: 800 1.7rem/1 var(--display); font-stretch: 112%; text-transform: uppercase; margin: 0; }
.tb-step { margin: 0; font: 400 0.75rem/1 var(--body); letter-spacing: 0.06em; text-transform: uppercase; color: var(--grey); white-space: nowrap; }
.code { color: var(--rule); }
.tblock h2 { font: 600 1rem/1.3 var(--body); margin: 0; text-wrap: balance; }
.tb-foot {
  margin: 0.55rem 0 0; padding-top: 0.4rem; border-top: 1px solid var(--faint);
  font: 600 0.625rem/1 var(--body); letter-spacing: 0.07em; text-transform: uppercase;
}
.notes { margin: 0; padding: 0; list-style: none; counter-reset: n; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 1.25rem; }
.open { margin: 0.6rem 0 0; font-size: 0.8125rem; color: var(--grey); }
.notes li { counter-increment: n; display: grid; grid-template-columns: 1.6rem 1fr; gap: 0.55rem; font-size: 0.9375rem; line-height: 1.4; }
.notes li::before {          /* numbered circle, matching the markers on the plan */
  content: counter(n); width: 1.5rem; height: 1.5rem; border-radius: 50%; background: var(--ink); color: var(--paper);
  display: grid; place-items: center; font: 600 0.75rem/1 var(--mono);
}
.notes strong { display: block; }

/* ---------------------------------------------------------------- command line: only there while a command runs */
.cmd {
  position: absolute; left: max(20px, env(safe-area-inset-left, 0px)); bottom: max(10px, env(safe-area-inset-bottom, 0px));
  display: flex; align-items: baseline; gap: 0.5rem; max-width: calc(100% - var(--rail) - 11rem);
  font: 400 0.8125rem/1.2 var(--mono); color: var(--grey); white-space: nowrap; overflow: hidden;
  opacity: 0; transform: translateY(8px); transition: opacity 0.25s ease, transform 0.25s ease;
}
.cmd-live .cmd { opacity: 1; transform: none; }
.cmd-text { color: var(--ink); overflow: hidden; text-overflow: ellipsis; }
.caret { width: 0.55em; height: 1em; background: var(--ink); align-self: center; animation: blink 1.05s steps(1) infinite; flex: none; }
@keyframes blink { 50% { opacity: 0; } }

.xy {
  position: absolute; right: max(14px, env(safe-area-inset-right, 0px)); bottom: max(10px, env(safe-area-inset-bottom, 0px));
  margin: 0; font: 400 0.75rem/1.2 var(--mono); color: var(--grey); font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* ---------------------------------------------------------------- progress pills on the right, names on hover */
.tabs {
  position: absolute; right: calc(0.9rem + env(safe-area-inset-right, 0px)); top: 50%; transform: translateY(-50%);
  margin: 0; padding: 0.5rem 0 0.5rem 0.75rem; align-items: flex-end; list-style: none; display: flex; flex-direction: column; gap: 0.55rem;
  z-index: 3;
}
.tabs li { display: flex; flex-direction: row-reverse; align-items: center; gap: 0.7rem; height: 0.9rem; }
.tabs li::before {
  content: ""; flex: none; width: 1.25rem; height: 0.375rem; border-radius: 3px; background: var(--ink);
  opacity: 0.32; transition: opacity 0.3s ease, width 0.3s ease;
}
.tabs li.done::before { opacity: 0.6; }
.tabs li[aria-current="step"]::before { opacity: 1; width: 1.75rem; }
.tabs span {
  font: 500 0.6875rem/1 var(--mono); letter-spacing: 0.04em; color: var(--ink); white-space: nowrap;
  background: var(--paper); padding: 0.15rem 0.35rem; border-radius: 3px;
  opacity: 0; transform: translateX(4px); transition: opacity 0.2s ease, transform 0.2s ease; pointer-events: none;
}
.tabs:hover span { opacity: 0.55; transform: none; }
.tabs:hover li[aria-current="step"] span { opacity: 1; }

/* ---------------------------------------------------------------- the drawing */
#venue text { font-family: var(--body); }
.idle-hover #venue { cursor: none; }
.wall { fill: none; stroke: var(--ink); stroke-width: 4.5; stroke-linejoin: miter; }
.poche { fill: url(#ansi31); stroke: none; }
.hatchline { stroke: var(--grey); stroke-width: 2; }
.cut { fill: #000; stroke: none; }
.leaf { fill: none; stroke: var(--ink); stroke-width: 3.5; }
.arc, .thin { fill: none; stroke: var(--grey); stroke-width: 2; }
.lbl { fill: var(--grey); font-size: 40px; font-weight: 600; letter-spacing: 3px; }
.grid { fill: none; stroke: var(--faint); stroke-width: 2.5; stroke-dasharray: 60 18 8 18; }
.bub { fill: var(--paper); stroke: var(--ink); stroke-width: 2.5; }
.bubt { fill: var(--ink); font-size: 30px; font-weight: 600; }
.col { fill: var(--paper); stroke: var(--ink); stroke-width: 4.5; }   /* paper backing hides the grid; hatch = .poche */
.roomfill { fill: var(--pale); fill-opacity: 0.8; }
.part { fill: var(--faint); stroke: var(--ink); stroke-width: 2.5; }
.ghost { fill: none; stroke: var(--grey); stroke-width: 3; stroke-dasharray: 26 14; }
.ghostt { fill: var(--grey); font-size: 36px; font-weight: 600; letter-spacing: 3px; }

/* the moves: the design is drawn in ink and grey; red stays the problem, blue stays the working */
.lbls { fill: var(--ink); font-size: 28px; font-weight: 600; letter-spacing: 2px; }
.hatchfaint { stroke: var(--faint); stroke-width: 2; fill: none; }
.dotfill { fill: var(--grey); opacity: 0.55; }
.street { fill: url(#dots); stroke: none; }
.streetline { fill: none; stroke: var(--grey); stroke-width: 2.5; stroke-dasharray: 30 14; }
.lockf { fill: var(--paper); stroke: none; }
.screen { fill: none; stroke: var(--ink); stroke-width: 9; }
.scrim { fill: none; stroke: var(--grey); stroke-width: 5; stroke-dasharray: 6 7; }
.arrow { fill: none; stroke: var(--ink); stroke-width: 3.5; stroke-linejoin: round; }
.thinarrow { fill: none; stroke: var(--ink); stroke-width: 2.5; }
.route { fill: none; stroke: var(--ink); stroke-width: 3; stroke-dasharray: 16 10; }
.back { fill: url(#ansi37); stroke: none; }
.drape { fill: none; stroke: var(--grey); stroke-width: 3; stroke-dasharray: 22 10; }
.stage { fill: var(--pale); stroke: var(--ink); stroke-width: 5; }
.led { fill: var(--ink); stroke: none; }
.counter { fill: var(--faint); stroke: var(--ink); stroke-width: 4; }
.qzone { fill: none; stroke: var(--grey); stroke-width: 2.5; stroke-dasharray: 10 10; }
.art { fill: url(#dots); stroke: none; }
.artl { fill: none; stroke: var(--ink); stroke-width: 3.5; stroke-linejoin: miter; }
.pocket { fill: none; stroke: var(--grey); stroke-width: 2.5; stroke-dasharray: 10 10; }
.seats { fill: url(#dots); stroke: var(--ink); stroke-width: 2; }
.deck { fill: var(--paper); stroke: var(--ink); stroke-width: 3.5; }
.wsrow { fill: none; stroke: var(--grey); stroke-width: 2.5; stroke-dasharray: 10 8; }
.pod { fill: var(--faint); stroke: var(--ink); stroke-width: 3.5; }
.stair { fill: url(#treads); stroke: var(--ink); stroke-width: 2.5; }
.lamp { fill: var(--ink); stroke: none; }
.pool { fill: none; stroke: var(--grey); stroke-width: 2.5; stroke-dasharray: 12 10; }
.led2 { fill: none; stroke: var(--ink); stroke-width: 2.5; }

/* Start: faint survey underlay, traced over in step 1, gone once the walls are drawn */
.underlay { opacity: 0; transition: opacity 0.6s ease; }
.underlay path { fill: none; stroke: var(--grey); stroke-width: 2; stroke-dasharray: 14 12; fill-rule: evenodd; }
.underlay text { fill: var(--grey); font: 500 34px var(--mono); letter-spacing: 2px; }
.js .fig[data-cur="0"] .underlay { opacity: 0.55; }

/* construction layer: the maths, erased once worked out. Text sits on a paper mask so it never blends into lines. */
.k { fill: none; stroke: var(--con); stroke-width: 3; }
.kt { fill: var(--con-ink); font-family: var(--mono) !important; font-size: 46px; font-weight: 600; }
.kt.on { filter: url(#mask); }
.kt.big { font-size: 62px; }
.tgt { stroke: var(--con); stroke-width: 16; stroke-linecap: round; }
.ray { stroke-width: 1.4; opacity: 0.5; }
.floor { stroke: var(--faint); stroke-width: 6; stroke-linecap: round; }

/* constraints in the rule colour. --lw scales line weight: earlier rules are drawn lighter (see drafting states). */
.shadow { stroke: var(--rule); stroke-width: calc(6px * var(--lw, 1)); stroke-linecap: round; opacity: 0.7; }
.flow { fill: none; stroke: var(--ink); stroke-width: calc(3.5px * var(--lw, 1)); stroke-linejoin: round; }
.pinch { fill: none; stroke: var(--rule); stroke-width: calc(6px * var(--lw, 1)); stroke-linejoin: round; }
.walker, .late { fill: var(--rule); }
.js .walker:not(.moving), .js .late:not(.moving) { opacity: 0; }
.crowd { stroke: var(--grey); stroke-width: calc(15px * var(--lw, 1)); stroke-linecap: round; }
.doorline { fill: none; stroke: var(--ink); stroke-width: calc(4px * var(--lw, 1)); stroke-dasharray: 40 18; }
.arrival { fill: none; stroke: var(--rule); stroke-width: calc(3px * var(--lw, 1)); }
.clash { fill: none; stroke: var(--rule); stroke-width: calc(5px * var(--lw, 1)); }
.q { fill: none; stroke: var(--grey); stroke-width: calc(4px * var(--lw, 1)); }
.q.spill { fill: var(--rule); stroke: var(--rule); }
.blocked { fill: none; stroke: var(--rule); stroke-width: calc(26px * var(--lw, 1)); opacity: 0.3; }
.mk circle { fill: var(--ink); }
.mk text { fill: var(--paper); font: 600 40px var(--mono); }
#cur { pointer-events: none; }
#cur path { stroke: var(--cursor); stroke-width: 2; }
#cur rect { fill: none; stroke: var(--cursor); stroke-width: 2.5; }

/* ---------------------------------------------------------------- drafting states (story.js) */
.js #venue [data-s]:not(.on) { visibility: hidden; }
.drawing #venue .rules { pointer-events: none; }
.js [data-a="array"] { transform-box: fill-box; transform-origin: center; }
#cur { visibility: hidden; }
.drafting #cur, .idle-hover #cur { visibility: visible; }
.mk { display: none; }
.no-js .mk, .settled .mk { display: inline; }
#venue [data-s] { transition: opacity 0.5s ease; }
/* Phase 01's rules: faded (earlier-rule weight) until a move answers them; in focus while that move is drafted,
   gone once it is done (story.js sets .focus / .gone from data-x). Rule 4 stays faded: it is left to the simulation. */
.rule { opacity: 0.4; --lw: 0.45; transition: opacity 0.5s ease; }
.rule.focus { opacity: 0.9; --lw: 1; }
.rule.gone { opacity: 0; }
.zone { display: none; fill: var(--grey); font: 600 34px var(--body); letter-spacing: 6px; }
.settled .zone, .no-js .zone { display: inline; }

/* no script: an ordinary page with every step written out */
.no-js .track { height: auto; }
.no-js .app { position: static; height: auto; grid-template-rows: auto; }
.no-js .drawing { aspect-ratio: 3680 / 2260; }
.no-js .tabs, .no-js .cmd { display: none; }

/* ---------------------------------------------------------------- phones and narrow windows */
@media (max-width: 860px) {
  /* narrow: the working line (the key number) comes before the notes */
  .step, .step-wide { grid-template-columns: minmax(0, 1fr); grid-template-areas: "tblock" "work" "notes"; gap: 0.6rem; }
  .step-wide { grid-template-areas: "tblock" "notes"; }
  .tblock { border-right: 0; padding-right: 0; }
  .tb-top { margin-bottom: 0.2rem; }
  .code { font-size: 1.2rem; }
  .sec-work { border-right: 0; padding-right: 0; }
  .tb-foot { display: none; }
  .notes { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.6rem 0.9rem; }
  .open { font-size: 0.75rem; }
  .notes li { font-size: 0.8125rem; grid-template-columns: 1.3rem 1fr; gap: 0.4rem; }
  .notes li::before { width: 1.25rem; height: 1.25rem; font-size: 0.6875rem; }
}
@media (max-width: 760px) {
  /* portrait phones: the plan is width-limited, so it takes its natural height and the notes take the rest */
  :root { --rail: 1.9rem; }
  .app { grid-template-rows: auto auto minmax(0, 1fr); padding-left: max(12px, env(safe-area-inset-left, 0px)); }
  .drawing { aspect-ratio: 3680 / 2260; }
  .panel { overflow-y: auto; padding-top: 0.6rem; }
  .title { font-size: 0.95rem; }
  .subtitle { font-size: 0.75rem; }
  .phase { font-size: 0.625rem; }
  .mside { width: 100%; flex-direction: row; justify-content: space-between; align-items: center; }
  .mtabs ol { justify-content: flex-start; gap: 0 0.9rem; }
  .masthead .mtabs a { min-height: 1.6rem; }
  .mtabs a[aria-current="page"] .ptab-name { position: absolute; width: 1px; height: 1px; clip-path: inset(50%); }   /* the title above names it */
  .tabs { right: calc(0.45rem + env(safe-area-inset-right, 0px)); gap: 0.5rem; }
  .cmd { left: max(12px, env(safe-area-inset-left, 0px)); }
  .tabs li::before { width: 0.85rem; }
  .tabs li[aria-current="step"]::before { width: 1.15rem; }
  .tblock h2 { font-size: 0.9375rem; }
  .step-body { font-size: 0.875rem; line-height: 1.5; }   /* the longer notes (status, access, the stress test) fit sooner */
  /* the band scrolls on phones: the working line stays pinned at its top while the notes pass beneath (no background,
     so the paper grain runs through; user's choice) */
  .sec-work { position: sticky; top: -0.6rem; z-index: 1; padding: 0.6rem 0 0.45rem;
    border-bottom: 1px solid var(--faint); }
  .eq { font-size: 0.8125rem; }
  .cmd { font-size: 0.6875rem; max-width: calc(100% - var(--rail) - 8rem); }
  .xy { font-size: 0.6875rem; }
  .lbl, .ghostt { font-size: 50px; letter-spacing: 1px; }
  .lbls { font-size: 36px; letter-spacing: 1px; }
  .zone { font-size: 42px; letter-spacing: 3px; }
  .kt { font-size: 66px; }
  .kt.big { font-size: 78px; }
  .bubt { font-size: 36px; }
}

@media (prefers-reduced-motion: reduce) {
  .caret { animation: none; }
  #venue [data-s], .rule, .cmd, .tabs li::before, .tabs span { transition: none; }
  .step.is-active, .words-in .w, .words-in .notes li { animation: none; }
  .roll .strip { transition: none; }
}
:focus-visible { outline: 2px solid var(--con); outline-offset: 3px; }

/* ================================================================ shared with Design Phase 03: the track, the band's rise
   (the hook's Options board, built from Phase 03's sheets, is retired: Options is now three questions on the plan) */
.track { height: calc(var(--step-h) * 6 + 100vh); }
.drawing { position: relative; }

/* the intro: the whole band rises into place from the bottom of the sheet (as Phase 01) */
.panel.rise { animation: band-rise 0.9s cubic-bezier(.3,0,.2,1) both; }
.panel.rise .step.is-active { animation: none; }
@keyframes band-rise { from { transform: translateY(calc(100% + 3rem)); } }

/* the drafting cursor, in HTML so it rides above every layer */
.hcur { position: absolute; left: 0; top: 0; width: 0; height: 0; z-index: 30000; visibility: hidden; }
.hcur svg { position: absolute; left: -40px; top: -40px; width: 80px; height: 80px; overflow: visible; }
.hcur path { stroke: var(--cursor); stroke-width: 1.25; fill: none; }
.hcur rect { fill: none; stroke: var(--cursor); stroke-width: 1.25; }
.drafting .hcur, .idle-hover .hcur { visibility: visible; }
.idle-hover .drawing { cursor: none; }

@media (prefers-reduced-motion: reduce) {
  .panel.rise { animation: none; transition: none; }
}

/* ================================================================ the short format
   Five screens, all on the plan (#venue); the simulation's three on its own wider plan (#simplan). */
.track { height: calc(var(--step-h) * 7 + 100vh); }   /* five design screens + three simulation screens */
#venue { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; transition: opacity 0.25s ease; }
.drawing { aspect-ratio: auto; }
.no-js .drawing { aspect-ratio: 3680 / 2260; }
@media (max-width: 760px) { .drawing { aspect-ratio: 3680 / 2260; } }

/* the result: a way into the long format */
.more { margin: 0.7rem 0 0; display: flex; flex-wrap: wrap; gap: 0.4rem 1.6rem; font-size: 0.875rem; }
.more a { color: var(--ink); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.more a::after { content: " →"; }
.more a:hover { text-decoration-thickness: 2px; }
.notes { grid-template-columns: repeat(5, minmax(0, 1fr)); }
@media (max-width: 860px) { .notes { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* the column shadows belong to the problem: softened on The Lock (bars and art sit in them), gone after */
.fig[data-cur="2"] #venue [data-m="p1"] { opacity: 0.4; }
.fig:is([data-cur="3"], [data-cur="4"], [data-cur="5"], [data-cur="6"], [data-cur="7"]) #venue [data-m="p1"] { display: none; }
/* the opening drafts the hall itself (p0); every other screen uses the static hall */
.js .fig[data-cur="0"] #venue .hall { visibility: hidden; }
.fig:not([data-cur="0"]) #venue [data-m="p0"] { display: none; }

/* one focal point at a time: while a move is drawn, the hall and everything already drawn wait at 40% (story.js sets
   data-move); all comes back to full strength when the screen settles */
#venue .hall { transition: opacity 0.3s ease; }
.fig[data-move="p1"] #venue .hall, .fig[data-move="p1"] #venue [data-s].on:not([data-m="p1"]),

.fig[data-move="1"] #venue .hall, .fig[data-move="1"] #venue [data-s].on:not([data-m="1"]),

.fig[data-move="2"] #venue .hall, .fig[data-move="2"] #venue [data-s].on:not([data-m="2"]),

.fig[data-move="3"] #venue .hall, .fig[data-move="3"] #venue [data-s].on:not([data-m="3"]),

.fig[data-move="4"] #venue .hall, .fig[data-move="4"] #venue [data-s].on:not([data-m="4"]),

.fig[data-move="5"] #venue .hall, .fig[data-move="5"] #venue [data-s].on:not([data-m="5"]) { opacity: 0.4; }
.fig[data-move="p1"] #venue .hall { opacity: 0.55; }       /* the columns cast the shadows: kept readable */

/* the notes follow the drawing: the sentence being drawn is lit, the others wait at reduced strength */
.cue { transition: opacity 0.3s ease; }
.cueing .cue { opacity: 0.55; }
.cueing .cue.now { opacity: 1; }

/* The Lock's moment: arrivals walking in through the lock, then splitting east and west (ink: design intent, not a rule) */
.walkpath { fill: none; stroke: none; }
.walker-in { fill: var(--ink); }
.mk { transform-box: fill-box; transform-origin: center; }
@media (prefers-reduced-motion: reduce) { .cue, #venue .hall { transition: none; } }

/* Options: three questions on the plan (build_hook.decisions), one rule set. The answer set aside is dashed in rule
   red, the one kept is in ink, the deciding number is in construction blue (the working). They belong to this screen
   only: The Lock answers the third and drafts the rest itself. */
.fig:not([data-cur="1"]) #venue [data-s="1"] { display: none; }
.fig[data-cur="1"] #venue [data-m="p1"] { opacity: 0.18; }   /* the problem stays in view, quietly: red here is "set aside" */
.dec-in { fill: var(--pale); stroke: var(--ink); stroke-width: 5; }
.dec-bar { stroke-width: 4; }
.dec-out { fill: none; stroke: var(--rule); stroke-width: 4.5; stroke-dasharray: 22 14; }
.dec-q { fill: none; stroke: var(--grey); stroke-width: 2.5; stroke-dasharray: 10 10; }
.dec-out.dec-q { stroke: var(--rule); opacity: 0.7; }
.dec-route { fill: none; stroke: var(--ink); stroke-width: 3.5; stroke-dasharray: 16 10; stroke-linejoin: round; }
.dec-arrow { fill: none; stroke-width: 4.5; stroke-linejoin: round; }
.dec-lbl { fill: var(--ink); font-size: 34px; font-weight: 600; letter-spacing: 3px; }
.dec-lbl-out { fill: var(--rule); }
.dec-lbl-s { font-size: 26px; }
.dec-num { fill: var(--con-ink); font-family: var(--mono) !important; font-size: 40px; font-weight: 600; }
.dec-num.on { filter: url(#mask); }
.dmk circle { fill: var(--ink); }
.dmk text { fill: var(--paper); font: 600 40px var(--mono); }
.dmk { transform-box: fill-box; transform-origin: center; }
/* one question at a time: the others wait at 40% while it is drawn */
.fig[data-move="d1"] #venue [data-s="1"].on:not([data-m="d1"]),
.fig[data-move="d2"] #venue [data-s="1"].on:not([data-m="d2"]),
.fig[data-move="d3"] #venue [data-s="1"].on:not([data-m="d3"]) { opacity: 0.4; }
#venue [data-s="1"] { transition: opacity 0.3s ease; }

/* ================================================================ the simulation (screens 5-7, built by build_sim.py)
   Its own plan (#simplan: The Lock in a wider frame, the approach outside the loading door included) replaces #venue;
   the walked paths are drawn on two canvases laid exactly over it (story.js maps plan units to pixels from the svg's
   own matrix): .paths keeps every line drawn so far (the long exposure), .heads is redrawn each frame (the guests). */
#simplan, .paths, .heads { position: absolute; inset: 0; width: 100%; height: 100%; }
#simplan { z-index: 1; opacity: 0; transition: opacity 0.3s ease; pointer-events: none; }
.paths, .heads { z-index: 2; pointer-events: none; opacity: 0; transition: opacity 0.3s ease; }
.fig.sim:not(.zoomout) #simplan, .fig.sim:not(.zoomout) .paths, .fig.sim:not(.zoomout) .heads { opacity: 1; }
.fig.sim:not(.zoomout) #venue { opacity: 0; }
.fig.zoomout #venue { z-index: 2; transition: none; }
#simplan .under { opacity: 0.42; }
#simplan .zone { display: inline; }
.fig.sim .hcur { visibility: hidden !important; }       /* the replay has no drafting cursor; the readout still follows */
.fig.sim .drawing, .fig.sim.idle-hover .drawing { cursor: crosshair; }
.no-js #simplan, .no-js .paths, .no-js .heads { display: none; }
/* the simulation's result (screen 7): back on the clean plan, the long exposure gone; the design's zones and move
   markers give way to one numbered point per answer and the 5 x 5 m door square the times are measured in */
.rmk, .rsq { display: none; }
.fig.res .rmk, .fig.res .rsq { display: inline; }
.fig.res .mk, .fig.res .zone { display: none; }
.fig.res #venue { overflow: visible; }                      /* the door square reaches 0.2 m past the frame */
.rmk circle { fill: var(--ink); }
.rmk text { fill: var(--paper); font: 600 40px var(--mono); }
.rmk { transform-box: fill-box; transform-origin: center; }
.rsq { fill: none; stroke: var(--con); stroke-width: 10; stroke-dasharray: 34 22; }

/* the key, in plan units beside the approach */
.keyh { fill: var(--grey); font: 600 40px var(--body); letter-spacing: 4px; }
.keyt { fill: var(--ink); font: 500 40px var(--body); }
.keyn { fill: var(--grey); font: 500 32px var(--mono); }
.key-arrive { stroke: var(--ink); stroke-width: 4; fill: none; }
.key-leave { stroke: var(--ink); stroke-width: 4; fill: none; stroke-dasharray: 12 14; }
.key-watch { fill: #9aa0a4; stroke: none; }
.key-stop { fill: var(--rule); stroke: none; opacity: 0.85; }
.key-chair { fill: var(--ink); stroke: none; }
@media (max-width: 760px) { #simplan .key { display: none; } }   /* too small on a phone: the notes say the same */

.notes-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 860px) { .notes-3 { grid-template-columns: minmax(0, 1fr); } }
.notes-3 li { grid-template-columns: 1fr; }
.notes-3 li::before { display: none; }
.notes-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }          /* four answers in a row, like the five moves */
@media (max-width: 1000px) { .notes-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* mid widths: the summary bands' title block gives its spare width to the notes (code and slot wrap, as when narrow) */
@media (min-width: 861px) and (max-width: 1180px) { .step-wide { grid-template-columns: minmax(10.5rem, 0.7fr) minmax(0, 4fr); } }
@media (min-width: 861px) and (max-width: 1180px) {
  .step-sim .step-body.intent { font-size: 0.9375rem; }
  .notes-4 li { font-size: 0.875rem; line-height: 1.35; }
  .step-sim .verdict { font-size: 0.875rem; }
}
/* the end result: the intent in one line above the answers, the verdict in one sentence below them */
.step-body.intent { margin: 0 0 0.6rem; max-width: 110ch; }
.verdict { margin: 0.6rem 0 0; font-weight: 600; font-size: 0.9375rem; line-height: 1.4; max-width: 110ch; }
.open .deck-link { color: var(--ink); font-weight: 600; white-space: nowrap; text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.open .deck-link::after { content: " →"; }
.open .deck-link:hover { text-decoration-thickness: 2px; }
@media (max-width: 860px) { .verdict { font-size: 0.875rem; } .step-body.intent { font-size: 0.875rem; } }

/* a long step code (COUNTERFLOW) takes a smaller size so it stays inside its title block */
.code-long { font-size: 1.3rem; line-height: 1.3; }
@media (max-width: 860px) { .code-long { font-size: 1.05rem; } }

/* pills in two groups: the current group's steps, the other folded into one thicker pill (named on hover) */
.tabs li.grp::before { height: 0.6rem; border-radius: 4px; }
.fig:not(.sim, .res) .tabs li[data-g="sim"]:not(.grp), .fig:is(.sim, .res) .tabs li[data-g="design"]:not(.grp),
.fig:not(.sim, .res) .tabs li.grp[data-g="design"], .fig:is(.sim, .res) .tabs li.grp[data-g="sim"] { display: none; }
.fig:is(.sim, .res) .tabs li.grp[data-g="design"]::before { opacity: 0.6; }

/* ---------------------------------------------------------------- the title opening (title.js; build_title.py)
   The one place off the paper theme (see SKILL.md): The Lock is drafted in chalk on black, built in 3D, finished as
   a white model on paper, and the camera flies through the lock to the name. The section is a tall scroll with the
   canvas pinned; at its end the canvas clears to the paper beneath, and the hook's screen 0 starts on that paper.
   No WebGL: the name in type on black, one screen tall. Reduced motion: one still, one screen tall.
   Its classes are opening-*, never .title (the masthead's h1 is .title). */
.opening { position: relative; height: 170vh; background: #050506; transition: background-color 0.6s ease; }
.opening.lit { background: transparent; }
.opening:focus { outline: none; }          /* takes focus from Skip as it hides; not in the tab order */
.opening:not(.gl), .opening.still { height: 100vh; height: 100dvh; }
.opening-pin { position: sticky; top: 0; height: 100vh; height: 100dvh; overflow: hidden; }
.opening-gl { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.opening-name {
  position: absolute; inset: 0 0 16% 0; margin: 0; display: grid; place-items: center; padding: 0 20px; text-align: center;
  font: 800 clamp(2.4rem, 9vw, 7rem)/1 var(--display); font-stretch: 112%; text-transform: uppercase;
  letter-spacing: 0.01em; color: #f3f0e8;
}
.opening.gl .opening-name { position: absolute; inset: auto; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; padding: 0; }

/* the project tabs under the name (build_crane.tabs): 01 the case study below, 02 the crane set, 03 About. The one
   line under the row describes the tab under the pointer or focus (title.js), else the first. title.js sets
   --name-bottom from the name as drawn, so the row sits just under the letters at any size. */
.opening-tabs {
  position: absolute; left: 50%; top: var(--name-bottom, calc(50% + max(4.5rem, 11vh))); transform: translateX(-50%);
  width: min(46rem, calc(100% - 40px)); display: grid; justify-items: center; text-align: center; z-index: 2;
  padding: 0.25rem 1rem 0.7rem; border-radius: 3px;
  background: rgba(248, 247, 243, 0.88);       /* paper backing: the model's lines don't run through the text */
  opacity: 0; pointer-events: none; transition: opacity 0.5s ease;
}
.opening:not(.lit) .opening-tabs { background: transparent; }
.opening.named .opening-tabs, .opening.still .opening-tabs, .opening:not(.gl) .opening-tabs, .opening-tabs:focus-within {
  opacity: 1; pointer-events: auto;
}
.ptabs ol { display: flex; flex-wrap: wrap; justify-content: center; gap: 0 1.6rem; margin: 0; padding: 0; list-style: none; }
.ptabs a {
  display: inline-flex; align-items: baseline; gap: 0.45rem; min-height: 2.5rem; padding: 0.75rem 0 0.5rem;
  font: 500 0.75rem/1.2 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--grey);
  text-decoration: none; border-bottom: 1.5px solid transparent; transition: color 0.6s ease, border-color 0.6s ease;
}
.ptabs a:hover, .ptabs a:focus-visible { color: var(--ink); border-bottom-color: var(--faint); }
.ptabs a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--ink); }
.ptab-n { color: var(--grey); transition: color 0.6s ease; }
.ptab-desc { margin: 0.5rem 0 0; min-height: 2.9em; max-width: 32rem; font: 400 0.875rem/1.45 var(--body); color: var(--grey); }
.opening:not(.lit) .ptabs a, .opening:not(.lit) .ptab-n, .opening:not(.lit) .ptab-desc { color: #c3c8cb; }
.opening:not(.lit) .ptabs a:hover, .opening:not(.lit) .ptabs a:focus-visible,
.opening:not(.lit) .ptabs a[aria-current="page"] { color: #f3f0e8; border-bottom-color: #f3f0e8; }
.opening:not(.lit) .ptabs a:focus-visible { outline-color: #e9e7e0; }
@media (max-width: 600px) {
  .opening-tabs ol { flex-direction: column; align-items: center; }   /* three tabs don't fit one line: one a row */
  .ptabs a { font-size: 0.6875rem; letter-spacing: 0.08em; min-height: 2.75rem; padding: 0.85rem 0 0.55rem; }
  .ptab-desc { font-size: 0.8125rem; }
}
@media (prefers-reduced-motion: reduce) { .ptabs a, .ptab-n { transition: none; } }

.opening-cmd {
  position: absolute; left: max(20px, env(safe-area-inset-left, 0px)); bottom: calc(1.1rem + env(safe-area-inset-bottom, 0px));
  margin: 0; font: 500 0.75rem/1.2 var(--mono); letter-spacing: 0.06em; color: #c3c8cb; white-space: pre;
  transition: color 0.6s ease;
}
.opening-cmd:not(:empty)::before { content: "Command:  "; color: #8a9196; }
.opening.lit .opening-cmd { color: var(--ink); }
.opening.lit .opening-cmd:not(:empty)::before { color: var(--grey); }
.opening-skip {
  position: absolute; right: max(20px, env(safe-area-inset-right, 0px)); bottom: calc(0.8rem + env(safe-area-inset-bottom, 0px));
  font: 500 0.75rem/1 var(--mono); letter-spacing: 0.06em; text-transform: uppercase; color: #e9e7e0;
  background: transparent; border: 1px solid #6d757b; border-radius: 3px; padding: 0.6rem 0.85rem; cursor: pointer;
}
.opening-skip:hover { border-color: #e9e7e0; }
.opening-skip:focus-visible { outline: 2px solid #e9e7e0; outline-offset: 3px; }
.opening-skip[hidden], .opening-hint[hidden], .opening:not(.gl) .opening-skip { display: none; }
.opening-hint {
  position: absolute; left: 50%; bottom: calc(1rem + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%);
  margin: 0; font: 500 0.6875rem/1 var(--mono); letter-spacing: 0.18em; text-transform: uppercase; color: var(--grey);
  display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
}
.opening-hint::after { content: ""; width: 1px; height: 1.6rem; background: currentColor; transform-origin: top; animation: hint 1.8s ease-in-out 3; }
@keyframes hint { 0%, 100% { transform: scaleY(0.3); } 50% { transform: scaleY(1); } }
.opening.still .opening-hint { display: none; }   /* shown once the camera has landed on the name: scroll goes on to the case study */
.opening:not(.lit) .opening-hint { color: #c3c8cb; }
@media (max-width: 600px) {
  .opening-hint { bottom: calc(2.9rem + env(safe-area-inset-bottom, 0px)); }
  .opening.named .opening-hint { display: none; }   /* the stacked tabs need the room */
}
@media (prefers-reduced-motion: reduce) {
  .opening-hint::after { animation: none; }
  .opening, .opening-cmd, .opening-tabs { transition: none; }
}

/* ---------------------------------------------------------------- before delivery (after the eight screens)
   The open items as a schedule in the sheet footer's style: an ink rule across the top, small grey capitals for the
   heads, ink text, faint rules between rows. Static: no drafting, nothing moves. Phones: each row stacks. */
.open .deck-link[href="#before-delivery"]::after { content: " ↓"; }
.delivery { position: relative; padding: 4rem max(20px, env(safe-area-inset-right, 0px)) 5rem max(20px, env(safe-area-inset-left, 0px)); }
.delivery-in { max-width: 72rem; margin: 0 auto; border-top: 1.5px solid var(--ink); padding-top: 1rem; }
.delivery h2 { margin: 0 0 0.35rem; font: 600 1.375rem/1.25 var(--body); }
.delivery-lede { margin: 0 0 1.4rem; max-width: 70ch; color: var(--grey); font-size: 0.9375rem; }
.delivery-t { width: 100%; border-collapse: collapse; font-size: 0.9375rem; line-height: 1.45; }
.delivery-t thead th { font: 600 0.6875rem/1.2 var(--body); letter-spacing: 0.07em; text-transform: uppercase; color: var(--grey);
  text-align: left; padding: 0 1.25rem 0.55rem 0; border-bottom: 1px solid var(--ink); }
.delivery-t td, .delivery-t tbody th { text-align: left; vertical-align: top; padding: 0.8rem 1.25rem 0.8rem 0; border-bottom: 1px solid var(--faint); }
.delivery-t tbody th { font-weight: 600; width: 28%; }
.delivery-t td:nth-child(2) { width: 26%; color: var(--grey); }
.delivery-foot { margin: 1.4rem 0 0; font-size: 0.875rem; }
.delivery-foot a { color: var(--ink); text-underline-offset: 3px; text-decoration-thickness: 1px; }
.delivery-foot a:hover { text-decoration-thickness: 2px; }
@media (max-width: 760px) {
  .delivery { padding-top: 2.5rem; padding-bottom: 3.5rem; }
  .delivery h2 { font-size: 1.2rem; }
  .delivery-t thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .delivery-t, .delivery-t tbody, .delivery-t tr, .delivery-t th, .delivery-t td { display: block; width: auto; }
  .delivery-t tr { padding: 0.8rem 0; border-bottom: 1px solid var(--faint); }
  .delivery-t td, .delivery-t tbody th, .delivery-t td:nth-child(2) { border: 0; padding: 0.15rem 0; width: auto; }
  .delivery-t td:nth-child(2)::before { content: "Who: "; font-weight: 600; color: var(--grey); }
}
