/* ============================================================
   Lee Schneidman — portfolio design system
   Structure B: full-bleed panels advanced horizontally.
   Reference: rauno.me — type-first, one accent, scrubber nav.
   ============================================================ */

:root{
  /* --- colour: palette A, "האמנם — ink & wine". Decided 2026-08-30.
     Every value comes from the poem's own colour map (data/colors.js):
     the dark surface is האמנם's colour deepened, the accent is דקירתם,
     the coloured panel is ותמתק. One accent — never add a second. --- */
  --bg:      #EDEAE3;   /* the field the panels sit on */
  --panel:   #FBFAF8;   /* panel surface */
  --ink:     #14120F;
  --ink-2:   #544E48;
  --ink-3:   #776F62;   /* darkened from var(--ink-3): labels were failing AA */
  --line-base:#DDD8CE;
  --line:    var(--line-base);
  --accent:  #A62B2B;   /* דקירתם — links, and gestures 01/02/06 */
  --accent-ink:var(--colour-ink);
  --accent-on-dark:#C88840;  /* כהלך — the accent on dark surfaces. A lightened
                                wine goes salmon and reads off-palette, so the dark
                                value is taken from the stream itself. 6.3:1 on --dark. */
  --colour:  #7A2030;   /* ותמתק — the coloured panel */
  --colour-ink:#FBF6F2;
  --dark:    #1A0E0E;   /* האמנם, deepened — the dark panels */
  --dark-ink:#EFE9E3;

  /* --- THE STREAM. The poem's own colours, in poem order, from
     data/colors.js. Everything on this site is drawn from this list: the bar
     on the first and last panels IS the list, and every panel's wash and
     baseline is one station along it. Nothing here is picked by taste. --- */
  --w-haomnam:#3D1818;  --w-od:#9090A0;       --w-yavou:#D4A843;  --w-yamim:#C8B89A;
  --w-slicha:#4169A8;   --w-hesed:#B5A895;    --w-sade:#2D5C3A;   --w-holech:#C88840;
  --w-yelatef:#743D28;  --w-shibolim:#8B7340; --w-timtak:#7A2030; --w-matar:#6B5B8A;

  /* channels, so every translucent variant stays on the palette instead of
     falling back to pure white or pure black */
  --paper-rgb:239,233,227;   /* --dark-ink  */
  --panel-rgb:251,250,248;   /* --panel     */
  --ink-rgb:20,18,15;        /* --ink       */
  --dark-rgb:26,14,14;       /* --dark      */
  --colour-rgb:122,32,48;    /* --colour    */

  /* --- type --- */
  --sans:"Inter",system-ui,-apple-system,"Helvetica Neue",sans-serif;
  --serif:"Frank Ruhl Libre",Georgia,serif;
  --mono:"JetBrains Mono",ui-monospace,Menlo,monospace;

  /* --- scale: one ratio, no improvising per panel --- */
  /* INTERIM SCALE — 2026-08-12. Was 15.7–17.4px body and 12px labels, which is
     below the 16px floor and the reason everything read as small. Bumped to the
     18–20px band. Provisional until type-lab.html settles the real system. */
  --t-display: clamp(2.1rem, 1.1rem + 3.6vw, 4.1rem);
  --t-md:      clamp(1.5rem, 1rem + 1.9vw, 2.5rem);
  --t-lead:    clamp(1.1rem, 1rem + 0.45vw, 1.32rem);
  --t-body:    clamp(1rem, .95rem + 0.28vw, 1.1rem);        /* 16 → 17.6px */
  --t-small:   0.9375rem;                                     /* 15px, labels only, never body */

  /* --- space --- */
  --pad: clamp(1.6rem, 4.5vw, 5.5rem);
  --stack: clamp(1rem, 2vw, 1.75rem);

  /* --- motion: one curve, two durations --- */
  --ease: cubic-bezier(.65,.02,.16,1);
  --fast: .22s;
  --slow: .62s;
}

@media (min-width: 110rem){
  :root{ --pad: clamp(5.5rem, 9vw, 11rem); }
}

@media (prefers-reduced-motion: reduce){
  :root{ --slow:.001s; --fast:.001s; }
}

*,*::before,*::after{box-sizing:border-box}

html,body{height:100%}
body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--sans);
  font-size:var(--t-body);
  line-height:1.6;
  overflow:hidden;                 /* the page itself never scrolls */
  -webkit-font-smoothing:antialiased;
}

/* ============ chrome ============ */

.chrome{
  position:fixed; inset:0 0 auto 0; z-index:30;
  display:grid; grid-template-columns:1fr auto 1fr; align-items:center;
  gap:1rem; padding:1rem clamp(1rem,3vw,2rem);
  mix-blend-mode:difference;
}
.chrome, .chrome a, .chrome .btn{color:var(--dark-ink)}
.chrome .btn [aria-current="true"]{color:var(--panel)}
.chrome .scrub button{background:var(--dark-ink)}
.chrome .scrub button[aria-current="true"]{border-color:var(--panel); background:transparent}
.chrome__name{
  font-size:var(--t-small); font-weight:500; letter-spacing:.02em;
  text-decoration:none; color:var(--ink); justify-self:start; white-space:nowrap;
}
@media (max-width: 48rem){
  .chrome{gap:.5rem; padding:.7rem 1rem}
  .chrome__name{font-size:.8rem}
  .btn{padding:.35rem .45rem; font-size:.8rem}
}
.chrome__right{display:flex; gap:.5rem; justify-self:end}

.btn{
  background:none; border:1px solid transparent; border-radius:2px;
  font:inherit; font-size:var(--t-small); letter-spacing:.08em; text-transform:uppercase;
  color:var(--ink-3); cursor:pointer;
  padding:.45rem .6rem;            /* real hit target — see STRUCTURE.md rule 3 */
  transition:color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.btn:hover,.btn:focus-visible{color:var(--ink); border-color:var(--line)}
.btn__sep{color:var(--line); margin-inline:.35em}
.btn [aria-current="true"]{color:var(--ink)}

/* --- scrubber: one tick per panel, current one boxed (rauno) --- */
.scrub{display:flex; align-items:center; gap:5px; justify-self:center}
.scrub button{
  width:2px; height:13px; padding:0; border:0; background:var(--ink-3);
  opacity:.45; cursor:pointer; transition:all var(--fast) var(--ease);
}
.scrub button:hover{opacity:1}
.scrub button[aria-current="true"]{
  width:22px; height:13px; background:transparent;
  border:1px solid var(--ink); opacity:1;
}

/* ============ the strip ============ */

/* A native horizontal scroll-snap container, NOT one huge translated element.
   Translating a 10 × 100vw flex row promotes a ~14,000px layer; at DPR 2 that
   exceeds the max GPU texture size and the whole strip fails to rasterise —
   a blank page on some machines. A scroll container only rasterises the tiles
   in view, and gets keyboard, trackpad and RTL behaviour for free. */
/* Panels are STACKED, not laid out in a row.
   A flex row of ten 100vw panels is a ~14,000px-wide box; the engine tries to
   rasterise it in one go, exceeds the max texture size and paints nothing —
   a blank page. Tested: with one panel it renders instantly, with ten it does
   not, and neither a scroll container nor content-visibility avoids the layout.
   Stacking keeps every box exactly one viewport wide and moves each panel on
   its own transform. Only the current panel and its neighbours are visible. */
.strip{position:relative; height:100dvh; width:100vw; overflow:hidden}

.panel{
  position:absolute; inset-block:0; inset-inline-start:0;
  width:100vw; height:100dvh;
  transform:translateX(0);
  transition:transform var(--slow) var(--ease);
  visibility:hidden;
  display:flex; flex-direction:column;
  padding:calc(var(--pad) + 2.5rem) var(--pad) var(--pad);
  /* the surface comes from the station wash at the end of this file, not from
     here — a flat background:var(--panel) on .panel would out-specify it */
  border-right:1px solid var(--line);
  overflow:auto;                    /* a single panel may scroll; the page never does */
}
html[dir="rtl"] .panel{border-right:0; border-left:1px solid var(--line)}
.panel.is-near{visibility:visible}
/* Safety net: panels are hidden until story.js marks the current one, so any
   failure in that script used to leave a blank cream page. The first panel is
   visible on its own — worst case the visitor lands on the opening and can
   still read it. */
.panel:first-of-type{visibility:visible}

/* Safe vertical centering: auto-margin spacers collapse to zero when the
   content overflows, so a tall panel scrolls from its top instead of
   clipping the kicker above the viewport (the flexbox center-overflow trap). */
.panel::before{content:""; margin-top:auto}
.panel::after{content:""; margin-bottom:auto}

.panel--accent{background:var(--colour); color:var(--colour-ink)}
.panel--accent .kicker{color:rgba(var(--paper-rgb),.72)}
.panel--accent .lead{color:var(--colour-ink)}
.panel--accent .slot{border-color:rgba(var(--paper-rgb),.45); color:rgba(var(--paper-rgb),.8)}

.panel--ending{background:var(--ink); color:var(--panel)}

/* One accent, two values. Measured: #A62B2B on #1A0E0E is 2.6:1 — unreadable.
   Redefining --accent inside dark panels fixes every rule that uses it. */
.panel--dark, .panel--posters, .panel--ending,
.panel--wall{--accent:var(--accent-on-dark)}   /* knockout text over photographs */
.panel--accent{--accent:var(--colour-ink)}
/* the contact panel takes its station wash (ובחסד) like every other slide */

/* full-bleed hero: the image IS the panel; words sit on a soft scrim */
/* The opening sits dark: the photograph carries it, the words sit in the
   ink the rest of the site is written in. Light → wine → ink → light is the
   pulse of the strip; the first slide starts it. */
.panel--hero{padding:0; justify-content:flex-end;
             color:var(--dark-ink); --accent:var(--accent-on-dark)}
.panel--hero::before,.panel--hero::after{display:none}
.hero__img{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; object-position:center 30%;
  filter:brightness(.66) contrast(1.04) saturate(.94);
}
.hero__text{
  position:relative; z-index:1;
  padding:calc(var(--pad) + 2.5rem) var(--pad) calc(var(--pad) * 1.15);
  background:linear-gradient(to top, rgba(var(--ink-rgb),.90) 0%, rgba(var(--ink-rgb),.62) 48%, rgba(var(--ink-rgb),0) 100%);
}
.hero__text .kicker{color:rgba(var(--paper-rgb),.66)}
.hero__text .sub{color:rgba(var(--paper-rgb),.84)}
.hero__text .advance{color:rgba(var(--paper-rgb),.58); padding-top:1.6rem}
.hero__text .display{max-width:22ch}
.hero__text .sub{max-width:52ch}
.hero__text .advance{margin-top:1.2rem; padding-top:0}

/* dark panel for צער בני אנוש — the uncomfortable one sits on ink */
.panel--dark{background:var(--dark); color:var(--dark-ink)}
.panel--dark .kicker{color:rgba(var(--paper-rgb),.55)}
.panel--dark .body p{color:rgba(var(--paper-rgb),.86); margin-bottom:.6em}
.panel--dark .lead{color:var(--dark-ink)}
/* Hebrew reads thinner on dark — give it more weight there (BRIEF rule) */
html[dir="rtl"] .panel--dark .body p{font-weight:500}


/* ============ the plate system ============
   Every media object on the site gets the same treatment: a tinted,
   rounded mat with equal padding, and a caption row under it.
   This is what makes a panel read as designed instead of assembled. */
:root{
  --mat:   #F2EEE6;          /* the mat behind media on paper panels */
  --mat-2: #E8E3D9;          /* its edge */
  --r:     14px;
}
.plate{
  background:var(--station-mat, rgba(var(--ink-rgb),.045)); border:0; border-radius:var(--r);
  padding:clamp(.6rem,1vw,1.1rem);
  margin-inline:auto; width:100%;
}
.plate > img, .plate > video, .plate > iframe{
  display:block; width:100%; border-radius:calc(var(--r) - 6px);
  background:transparent;   /* never letterbox media against a white slab */
}
/* the clip carries no mat at all — a pale frame around a square film on a
   warm panel was the loudest non-palette shape on the page */
.shot--clip .plate{background:transparent; padding:0}
.panel--accent .plate{background:rgba(var(--paper-rgb),.16)}
.panel--ending .plate{background:rgba(var(--paper-rgb),.07)}

/* the caption row under a plate: name at the start, meta at the end */
.meta{
  display:flex; justify-content:space-between; align-items:baseline; gap:1.2rem;
  margin:.7rem .2rem 0; font-size:var(--t-small); line-height:1.5; text-align:start;
}
.meta__t{color:var(--ink); font-weight:500}
.meta__m{color:var(--ink-3); white-space:nowrap; font-family:var(--mono); font-size:.8rem}
.panel--accent .meta__t{color:var(--colour-ink)}
.panel--accent .meta__m{color:rgba(var(--paper-rgb),.75)}

/* eyebrow: small, quiet, always above the headline */
.kicker{font-size:.82rem; letter-spacing:.18em}

/* two-tone headline — the second clause drops to grey, as in the reference */
/* The headline stays two-tone in ink and grey — Lee's call: the slide's colour
   belongs on its marks, not on its sentences. */
.dim{color:var(--ink-3)}
.panel--accent .dim{color:rgba(var(--paper-rgb),.72)}
.panel--posters .dim{color:rgba(var(--paper-rgb),.72)}
.panel--wall .dim{color:rgba(var(--paper-rgb),.82)}
.panel--wall .pw-body{color:rgba(var(--paper-rgb),.96)}

/* ============ composition: the centred plate ============
   Reference class (emilkowal.ski, paco.me): content lives in a centred
   column with symmetric margins. Nothing anchors to the viewport edge. */
.panel > .kicker, .panel > .display, .panel > .body,
.panel > .figrow, .panel > .figcards, .panel > .boards, .panel > .bookflip,
.panel > .oneline, .panel > .foldout, .panel > .reelhero, .panel > .filmlist,
.panel > .contact{ margin-inline:auto }
.panel:not(.panel--hero):not(.panel--posters):not(.panel--cols):not(.panel--sketch){
  text-align:center;
}
.panel:not(.panel--hero):not(.panel--posters):not(.panel--cols):not(.panel--sketch) .kicker{justify-content:center}
.panel:not(.panel--hero):not(.panel--posters):not(.panel--cols):not(.panel--sketch) .display{max-width:none}
.panel:not(.panel--hero):not(.panel--posters):not(.panel--cols):not(.panel--sketch) .body{max-width:62ch}
.panel:not(.panel--hero):not(.panel--posters):not(.panel--cols):not(.panel--sketch) .oneline{margin-inline:auto}
/* lists inside centred plates keep readable start alignment */
.foldout .study2col, .foldout .findings, .method{text-align:start}

/* composed grids centre as whole plates */
@media (min-width: 60rem){
  /* NEVER put max-width on .panel — it is absolutely positioned and 100vw,
     so a max-width shrinks the panel box itself and exposes the page
     background. Centre the measure with padding; the panel stays full-bleed. */
  .panel--cols, .panel--sketch{
    width:100vw; max-width:none;
    padding-inline:max(var(--pad), calc((100vw - 120rem) / 2));
  }
}

/* hero text: centred over the image */
.hero__text{text-align:center}
.hero__text .display, .hero__text .sub{margin-inline:auto}
.hero__text .kicker{justify-content:center}

/* poster wall caption: centred */
.posterwall__text{text-align:center}
.posterwall__text .kicker{justify-content:center}
.posterwall__text .display, .posterwall__text .pw-body{margin-inline:auto}

/* the persistent mail line — present on every panel, blends like the chrome */
.mailline{
  /* clears the colour stream that runs along the bottom edge of the
     first and last panels */
  position:fixed; bottom:1.55rem; inset-inline-end:clamp(1rem,3vw,2rem); z-index:30;
  font-family:var(--mono); font-size:.8rem; letter-spacing:.04em;
  color:var(--dark-ink); text-decoration:none; mix-blend-mode:difference;
}
.mailline:hover{text-decoration:underline; text-underline-offset:.25em}
html[dir="rtl"] .mailline{letter-spacing:0}

/* contact panel: the email is the display */
.mail{color:var(--ink); text-decoration-thickness:3px; text-underline-offset:.14em; text-decoration-color:var(--accent)}
.mail:hover{color:var(--accent)}
.contact--row{flex-direction:row !important; justify-content:center; gap:2.2rem !important; flex-wrap:wrap}

/* the small film index under the reel */
.filmlist--mini{justify-content:center; gap:1.4rem; margin-top:calc(var(--stack) * 1.1)}
.filmlist--mini a{width:9rem; font-size:.75rem}
.filmlist--mini img{aspect-ratio:16/9}

/* ============ type ============ */

.kicker{
  font-size:var(--t-small); letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-3); margin:0 0 var(--stack); display:flex; gap:.9em; align-items:baseline;
}
.num{font-family:var(--mono); color:var(--station-ink, var(--ink-3))}
/* Hebrew inside an otherwise-tracked English label: tracking off, always */
.nolsp{letter-spacing:0 !important}

.display{
  font-size:var(--t-display); line-height:1.02; font-weight:600;
  letter-spacing:-.032em; margin:0; max-width:16ch; text-wrap:balance;
}
.display--md{font-size:var(--t-md); max-width:19ch; line-height:1.06}
.display em{font-style:normal; color:var(--accent)}
.panel--accent .display em{color:var(--accent-ink); text-decoration:underline; text-underline-offset:.12em}

.sub{
  margin:var(--stack) 0 0; max-width:44ch; font-size:var(--t-lead);
  color:var(--ink-2); line-height:1.45;
}

.body{margin-top:var(--stack); max-width:52ch}
.body p{margin:0 0 .9em}
.body p:last-child{margin-bottom:0}
.lead{font-size:var(--t-lead); line-height:1.42; color:var(--ink); font-weight:500}

.advance{
  margin:auto 0 0; padding-top:2rem;
  font-family:var(--mono); font-size:var(--t-small); color:var(--ink-3);
}

/* Hebrew wants the serif — Inter has no Hebrew */
html[dir="rtl"] .display,
html[dir="rtl"] .display--md,
html[dir="rtl"] .manifesto,
html[dir="rtl"] .worklist__t{font-family:var(--serif); letter-spacing:0; font-weight:500}
html[dir="rtl"] body{font-family:var(--serif); line-height:1.78; word-spacing:.05em}

/* RULE, not preference: Hebrew is never letter-spaced. Hebrew letterforms are
   not built to be tracked apart and it measurably harms legibility. I had
   tracking on every kicker and label — corrected 2026-08-12. */
html[dir="rtl"] .kicker,
html[dir="rtl"] .label,
html[dir="rtl"] .num,
html[dir="rtl"] .btn,
html[dir="rtl"] .advance,
html[dir="rtl"] .colophon,
html[dir="rtl"] .stats dt,
html[dir="rtl"] .method dt,
html[dir="rtl"] .worklist__yr,
html[dir="rtl"] .slot,
html[dir="rtl"] .sub-h{letter-spacing:0 !important}

/* ============ pieces ============ */

.slot{
  margin-top:calc(var(--stack) * 1.4); padding:1.6rem; max-width:44ch;
  border:1px dashed var(--ink-3); color:var(--ink-3);
  font-family:var(--mono); font-size:var(--t-small); text-align:center;
}

/* ---- the playable miniature (panel 01) ----
   A working slice of the real composition tool: real words, real archive
   images, real researched colours. The site demonstrates the claim instead
   of describing it. Built by scripts/build_demo.py. */
.minitool{margin-top:calc(var(--stack) * 1.4); max-width:68rem}
.minitool__line{display:flex; gap:5px; flex-wrap:wrap}
.minitool__hint{
  margin:.9rem 0 0; max-width:46ch;
  font-size:var(--t-small); letter-spacing:.02em; color:var(--ink-3); line-height:1.55;
}

.mt-cell{
  position:relative; flex:1 1 8.5rem; min-width:7rem; max-width:12.5rem; aspect-ratio:3/4;
  border:1px solid var(--line); padding:0; margin:0; overflow:hidden; cursor:pointer;
  background:var(--panel) center/cover no-repeat;
  font:inherit; color:inherit;
  transition:transform var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.mt-cell:hover{transform:translateY(-2px); border-color:var(--ink-3)}
.mt-cell:focus-visible{outline:2px solid var(--accent); outline-offset:2px}

.mt-cell__w{
  position:absolute; inset-inline:0; bottom:0; padding:.45rem .5rem;
  font-family:var(--serif); font-size:clamp(.85rem,.78rem + .3vw,1.05rem);
  line-height:1.2; text-align:center; color:var(--ink);
  background:rgba(var(--panel-rgb),.86);
}
.mt-cell.is-image .mt-cell__w{
  color:var(--panel); background:linear-gradient(to top, rgba(var(--ink-rgb),.62), rgba(var(--ink-rgb),0));
  padding-top:1.6rem;
}
.mt-cell.is-color .mt-cell__w{background:rgba(var(--paper-rgb),.82)}

/* link out of a panel — one underlined line, the site's own control language */
.golink{margin-top:1.1em}
.golink a{
  color:inherit; font-weight:500;
  text-decoration-thickness:1px; text-underline-offset:.22em;
}
.golink a:hover{color:var(--accent)}
.panel--accent .golink a:hover{color:var(--accent-ink); opacity:.8}

/* stacked UI screenshots (sensitiveinjection) */
.stills{display:flex; flex-direction:column; gap:.75rem}
.stills img{
  display:block; width:100%; height:auto;
  border:1px solid var(--line); background:var(--panel);
}

/* the one big Hebrew quote on the dark panel */
.bigquote{
  font-family:var(--serif); font-weight:500;
  font-size:clamp(1.4rem, 1.15rem + 1.2vw, 2.1rem); line-height:1.45;
  margin-block:.55em;
}

/* research panel: three investigations, image + caption each */
.figcards{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));
  gap:1.4rem 1.8rem; margin-top:calc(var(--stack) * 1.1); max-width:112rem;
}
.figcards figure{margin:0}
.figcards img{
  display:block; width:100%; height:clamp(15rem,46vh,30rem);
  object-fit:cover; object-position:top; background:var(--panel); border-radius:calc(var(--r) - 6px);
}
.figcards figcaption{
  margin-top:.5rem; font-size:var(--t-small); line-height:1.6; color:var(--ink-2);
}
html[dir="rtl"] .figcards figcaption{line-height:1.7}

.figrow{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,13rem),1fr));
  gap:.75rem; margin-top:calc(var(--stack) * 1.3); max-width:62rem;
}
.figrow img{width:100%; height:clamp(9rem,26vh,17rem); object-fit:cover; display:block; background:var(--line); border-radius:calc(var(--r) - 6px)}

/* Two columns when a panel carries a tall image beside its text.
   Without this the shot stacks underneath and the panel overflows. */
@media (min-width: 60rem){
  .panel--cols{
    display:grid;
    grid-template-columns:minmax(0,1fr) minmax(0,.82fr);
    grid-template-rows:auto auto 1fr;
    column-gap:clamp(2rem,4vw,4.5rem);
    align-content:center;
  }
  /* the centering spacers are flex-only — as grid items they'd steal rows */
  .panel--cols::before,
  .panel--cols::after{display:none}
  .panel--cols > .kicker,
  .panel--cols > .display,
  .panel--cols > .body{grid-column:1}
  .panel--cols > .shot{
    grid-column:2; grid-row:1 / -1;
    align-self:center; margin:0;
  }
  .panel--cols > .shot img{max-height:76vh}
}

/* a single tall shot — the workspace is portrait, so cap it by height */
.shot{margin:calc(var(--stack) * 1.3) 0 0}
.shot img{
  display:block; max-height:44vh; width:auto; max-width:100%;
  border:1px solid rgba(var(--paper-rgb),.35); background:var(--line);
}
.panel:not(.panel--accent) .shot img{border-color:var(--line)}
.shot figcaption{
  margin-top:.7rem; max-width:44ch;
  font-size:var(--t-small); color:var(--ink-3); line-height:1.55;
}
.panel--accent .shot figcaption{color:rgba(var(--paper-rgb),.8)}

/* ---- the study: method, findings, limitation (panel 05) ---- */

.sub-h{
  margin:calc(var(--stack) * 1.2) 0 .7rem;
  font-size:var(--t-small); letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-3); font-weight:500;
}
html[dir="rtl"] .sub-h{text-transform:none}

.method{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));
  gap:1.1rem 2.2rem; margin:var(--stack) 0 0; max-width:62rem;
}
.method div{border-top:1px solid var(--line); padding-top:.6rem}
.method dt{
  font-size:var(--t-small); letter-spacing:.14em; text-transform:uppercase;
  color:var(--ink-3); margin:0 0 .3rem;
}
html[dir="rtl"] .method dt{text-transform:none}
.method dd{margin:0; font-size:var(--t-body); line-height:1.5; color:var(--ink-2); max-width:34ch}

.findings{list-style:none; margin:.4rem 0 0; padding:0; max-width:60rem; counter-reset:f}
.findings li{
  display:grid; grid-template-columns:2.6rem 1fr; gap:1rem;
  padding:.85rem 0; border-top:1px solid var(--line); align-items:baseline;
}
.findings__n{font-family:var(--mono); font-size:var(--t-small); color:var(--ink-3)}
.findings li span:last-child{max-width:56ch; line-height:1.55}
.findings strong{font-weight:600}

.limitation{
  margin-top:calc(var(--stack) * 1.1) !important;
  padding-inline-start:1rem; border-inline-start:2px solid var(--line);
  color:var(--ink-2); font-size:calc(var(--t-body) * .96);
}

.stats{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(9rem,1fr));
  gap:1.5rem 2.5rem; margin:calc(var(--stack) * 1.4) 0 0; max-width:52rem;
}
.stats div{border-top:1px solid var(--line); padding-top:.7rem}
.stats dt{font-size:var(--t-small); letter-spacing:.06em; color:var(--ink-3); margin:0 0 .25rem}
.stats dd{margin:0; font-size:clamp(1.6rem,1.1rem + 1.6vw,2.6rem); font-weight:600;
  letter-spacing:-.03em; font-variant-numeric:tabular-nums}

.worklist{list-style:none; margin:var(--stack) 0 0; padding:0; max-width:64rem}
.worklist li{
  display:grid; grid-template-columns:4.5rem minmax(9rem,14rem) 1fr; gap:1.5rem;
  padding:1.1rem 0; border-top:1px solid var(--line); align-items:baseline;
}
.worklist__yr{font-family:var(--mono); font-size:var(--t-small); color:var(--ink-3)}
.worklist__t{font-size:clamp(1.1rem,1rem + .5vw,1.45rem); font-weight:600; letter-spacing:-.02em}
.worklist__d{color:var(--ink-2); max-width:46ch}

.manifesto{
  margin:0; font-size:var(--t-md); font-weight:500; letter-spacing:-.03em;
  line-height:1.22; max-width:22ch;
}
.manifesto span{display:block; color:var(--ink-3)}
.manifesto__last{color:var(--panel) !important; margin-top:.5em}

.contact{list-style:none; margin:var(--stack) 0 0; padding:0;
  display:flex; flex-direction:column; gap:.5rem; font-size:var(--t-lead)}
.contact a{color:var(--ink); text-decoration-thickness:1px; text-underline-offset:.2em}
.contact a:hover{color:var(--accent)}
.colophon{margin:1.35rem 0 0; padding-top:.9rem; font-family:var(--mono);
  font-size:var(--t-small); color:var(--ink-3)}

/* two stacked stills must share the column height, not fight for it */
.panel--cols > .stills img{max-height:34vh; width:auto; max-width:100%}

/* the rendered clip — a real film from the real pipeline, playing */
.shot--clip video{
  display:block; max-height:72vh; width:100%;
  background:var(--dark); border-radius:calc(var(--r) - 6px);
}

/* the exhibition spread: photographs in one row of three */
.figrow--tall{grid-template-columns:repeat(3,minmax(0,1fr)); max-width:none; margin-top:calc(var(--stack) * .9)}
.figrow--tall img{height:clamp(14rem,46vh,30rem)}
@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){
  .figrow--tall{grid-template-columns:repeat(2,minmax(0,1fr))}
  .figrow--tall img{height:auto}
}

/* exhibition + study on one panel: findings left, method/limitation right */
.study2col{
  display:grid; grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);
  gap:1rem 3rem; margin-top:calc(var(--stack) * .6); max-width:74rem;
}
.study2col .sub-h{margin-bottom:.45rem}
.study2col .findings{margin-top:0}
.study2col .findings li{padding:.3rem 0}
.study2col .findings li span:last-child{line-height:1.45}
.study2col .sub-h{margin-top:0}
.study2col__notes .smallnote{
  margin:0 0 .8em; font-size:var(--t-small); line-height:1.6; color:var(--ink-2); max-width:52ch;
}
.study2col__notes .lead{font-size:var(--t-body); max-width:44ch}
@media (max-width: 60rem){ .study2col{grid-template-columns:1fr} }

/* the live process sketch, embedded beside the text */
.sketchwrap{margin-top:calc(var(--stack) * 1.2); max-width:78rem}
.sketchframe{border-radius:calc(var(--r) - 6px); 
  display:block; width:100%; height:min(62vh,34rem); border:0;
  background:var(--panel); box-shadow:0 1px 0 rgba(var(--ink-rgb),.12), 0 12px 40px rgba(var(--ink-rgb),.18);
}
@media (min-width: 60rem){
  .panel--sketch{
    display:grid;
    grid-template-columns:minmax(0,.72fr) minmax(0,1fr);
    grid-template-rows:auto auto 1fr;
    column-gap:clamp(2rem,3.5vw,4rem);
    align-content:center;
  }
  .panel--sketch::before,.panel--sketch::after{display:none}
  .panel--sketch > .kicker,
  .panel--sketch > .display,
  .panel--sketch > .body{grid-column:1}
  .panel--sketch > .sketchwrap{
    grid-column:2; grid-row:1 / -1; align-self:center; margin-top:0;
  }
  .panel--sketch .sketchframe{border-radius:calc(var(--r) - 6px); height:min(76vh,44rem)}
  .panel--sketch .body p{margin-bottom:.6em}
  .panel--sketch .lead{font-size:clamp(1.15rem,1.05rem+.5vw,1.4rem); line-height:1.35}
  .panel--sketch .display--md{font-size:clamp(1.9rem,1.25rem+2.3vw,3.1rem)}
}

/* the poster wall — three loops ARE the panel; text floats on a scrim */
.panel--posters{padding:0; background:var(--dark)}
.panel--posters::before,.panel--posters::after{display:none}
.posterwall{
  position:absolute; inset:0;
  display:grid; grid-template-columns:repeat(3,1fr); gap:2px;
}
.posterwall .pw{overflow:hidden; position:relative}
.posterwall video{width:100%; height:100%; object-fit:cover; display:block; background:var(--dark) center/cover no-repeat}

.posterwall__text{
  position:relative; z-index:1; margin-top:auto;
  padding:calc(var(--pad) * .8) var(--pad);
  background:linear-gradient(to top, rgba(var(--ink-rgb),.88) 0%, rgba(var(--ink-rgb),.55) 60%, rgba(var(--ink-rgb),0) 100%);
  color:var(--dark-ink);
}
.posterwall__text .kicker,.posterwall__text .num{color:rgba(var(--paper-rgb),.75)}
.posterwall__text .display{max-width:none; text-shadow:0 1px 24px rgba(var(--ink-rgb),.45)}
.pw-body{max-width:62ch; margin-top:.6rem; color:rgba(var(--paper-rgb),.9); font-size:var(--t-body); text-shadow:0 1px 16px rgba(var(--ink-rgb),.5)}
.posterwall__text .bigquote{margin:.5em 0 0; color:var(--dark-ink); text-shadow:0 1px 20px rgba(var(--ink-rgb),.55)}
html[dir="rtl"] .posterwall__text .pw-body{font-weight:500}
@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){
  .panel--posters{padding:0; min-height:100svh; position:relative}
  .posterwall{position:absolute}
  .posterwall__text{position:absolute; inset:auto 0 0 0}
}

/* the living posters — three portrait loops on the dark panel */
.posterrow{
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
  gap:1rem; margin-top:calc(var(--stack) * 1.1); max-width:60rem;
}
.posterrow video{
  display:block; width:100%; aspect-ratio:9/16; object-fit:cover;
  background:var(--dark); border:1px solid rgba(var(--paper-rgb),.2);
}
@media (min-width: 60rem){
  .panel--dark.has-posters{
    display:grid;
    grid-template-columns:minmax(0,.75fr) minmax(0,1.25fr);
    grid-template-rows:auto auto 1fr;
    column-gap:clamp(2rem,3.5vw,4rem);
    align-content:center;
  }
  .panel--dark.has-posters::before,.panel--dark.has-posters::after{display:none}
  .panel--dark.has-posters > .kicker,
  .panel--dark.has-posters > .display,
  .panel--dark.has-posters > .body{grid-column:1}
  .panel--dark.has-posters .display--md{font-size:clamp(1.4rem,.95rem+1.5vw,2.1rem); max-width:none}
  .panel--dark.has-posters > .posterrow{
    grid-column:2; grid-row:1 / -1; align-self:center; margin-top:0;
  }
  .panel--dark.has-posters .posterrow video{height:68vh; aspect-ratio:auto; object-fit:cover}
}

/* the showreel — one minute, front and centre */
.motiongrid{margin-top:calc(var(--stack) * 1.1)}
@media (min-width: 64rem){
  .motiongrid{display:grid; grid-template-columns:minmax(0,1fr) 19rem; gap:2rem; align-items:center; max-width:82rem}
  .motiongrid .filmlist{flex-direction:column; margin-top:0; gap:1.1rem}
  .motiongrid .filmlist a{display:grid; grid-template-columns:6.5rem 1fr; gap:.7rem; width:100%; align-items:center}
  .motiongrid .filmlist span{margin-top:0}
}
.reelhero{margin:0 auto; max-width:min(104rem,100%)}
.reelhero video{
  display:block; max-width:100%; width:auto; height:auto; max-height:46vh;
  background:transparent; border-radius:calc(var(--r) - 6px);
}
.display--onerow{max-width:none}

/* the three full films, as a quiet index under the reel */
.filmlist{display:flex; flex-wrap:wrap; gap:1rem 1.4rem; margin-top:var(--stack)}
.filmlist a{
  width:13.5rem; text-decoration:none; color:var(--ink-2);
  font-size:var(--t-small); line-height:1.5;
}
.filmlist img{
  display:block; width:100%; aspect-ratio:16/9; object-fit:cover;
  background:rgba(var(--ink-rgb),.06); border-radius:8px; padding:0;
  transition:opacity var(--fast) var(--ease);
}
.filmlist a:hover img{opacity:.85}
.filmlist span{display:block; margin-top:.45rem}
.filmlist strong{color:var(--ink)}

/* the loud call — one line, lead-size, underlined */
.cta{margin-top:1.3em}
.cta a{
  color:var(--ink); font-size:var(--t-lead); font-weight:600;
  text-decoration-thickness:2px; text-underline-offset:.22em; text-decoration-color:var(--accent);
}
.cta a:hover{color:var(--accent)}

/* four-up making row */
.figrow--four{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){
  .figrow--four{grid-template-columns:repeat(2,minmax(0,1fr))}
}

.oneline{max-width:72ch !important; color:var(--ink-2); font-size:var(--t-small)}

/* the book, leafing itself */
.bookflip{
  position:relative; margin-top:var(--stack);
  max-width:min(92rem, 100%); aspect-ratio:2/1; max-height:54vh;
}
.bookflip img{
  position:absolute; inset:0; width:100%; height:100%; object-fit:contain; border-radius:calc(var(--r) - 6px);
  object-position:left center; opacity:0; transition:opacity .3s var(--ease);
}
html[dir="rtl"] .bookflip img{object-position:right center}
.bookflip img.is-on{opacity:1}

/* paper → data → tool: the research chain inside the process column */
.chain{display:grid; grid-template-columns:repeat(3,1fr); gap:.6rem; margin:.7rem 0 .3rem; max-width:32rem}
.chain img{width:100%; height:clamp(5rem,11vh,7.5rem); object-fit:cover; object-position:top; background:var(--panel); border-radius:8px}

/* the two sketch boards — big, side by side */
.boards{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:1.2rem; margin-top:var(--stack); max-width:76rem}
.boards img{width:100%; height:clamp(20rem,62vh,42rem); object-fit:cover; object-position:center; border-radius:calc(var(--r) - 6px)}
@media (max-width:48rem), (pointer:coarse) and (max-width:60rem){ .boards img{height:auto} }

/* findings behind a quiet fold */
.foldout{margin-top:calc(var(--stack) * .7); max-width:74rem}
.foldout summary{
  cursor:pointer; list-style:none; font-size:var(--t-small);
  letter-spacing:.14em; text-transform:uppercase; color:var(--ink-2);
  padding:.55rem 0; border-top:1px solid var(--line); border-bottom:1px solid var(--line);
}
html[dir="rtl"] .foldout summary{letter-spacing:0; text-transform:none}
.foldout summary::before{content:"+"; font-family:var(--mono); margin-inline-end:.7em; color:var(--accent)}
.foldout[open] summary::before{content:"−"}
.foldout summary::-webkit-details-marker{display:none}
.foldout .study2col{margin-top:1rem}

/* three films, one row, sound on demand */
.videorow{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,13rem),1fr));
  gap:.9rem 1rem; margin-top:calc(var(--stack) * .9); max-width:64rem;
}
.videorow figure{margin:0}
.videorow video{
  display:block; width:100%; aspect-ratio:16/9; object-fit:cover;
  background:var(--dark); border:1px solid var(--line);
}
.videorow figcaption{
  margin-top:.7rem; font-size:var(--t-small); line-height:1.6; color:var(--ink-2);
}

/* ============ index sheet (the back door) ============ */

.sheet{
  position:fixed; inset:0; z-index:40; background:rgba(var(--ink-rgb),.93);
  display:grid; place-content:center;
}
.sheet[hidden]{display:none}
.sheet__inner{display:flex; flex-direction:column; gap:.15rem; padding:2rem}
.sheet__inner button{
  background:none; border:0; color:var(--ink-3); font:inherit;
  font-size:clamp(1.3rem,1rem + 1.6vw,2.2rem); font-weight:500; letter-spacing:-.02em;
  text-align:start; padding:.28rem 0; cursor:pointer;
  transition:color var(--fast) var(--ease);
}
.sheet__inner button:hover,.sheet__inner button:focus-visible{color:var(--panel)}
.sheet__inner .n{font-family:var(--mono); font-size:.6em; color:var(--ink-3); margin-inline-end:.9em}

/* ============ mobile: the deliberate vertical fallback ============ */

@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){
  body{overflow:auto}
  .strip{position:static; display:block; width:auto; height:auto; overflow:visible}
  .panel{
    position:static; width:100%; height:auto; min-height:88svh;
    transform:none !important; visibility:visible !important; transition:none;
    border-right:0; border-bottom:1px solid var(--line);
    padding:5rem var(--pad) 3.5rem;
  }
  html[dir="rtl"] .panel{border-left:0}
  .scrub{display:none}
  .advance{display:none}
  .worklist li{grid-template-columns:1fr; gap:.35rem}
  .figrow img{height:auto; aspect-ratio:4/3}
}

/* mobile: the poster wall must stay its videos' positioning context —
   this sits after the generic .panel{position:static} fallback on purpose */
@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){
  .panel--posters{position:relative; padding:0; min-height:100svh; overflow:hidden}
  .posterwall{position:absolute; inset:0}
  .posterwall__text{position:absolute; inset:auto 0 0 0; padding:1.2rem 1rem}
}

/* ============ plate integration ============ */
/* media rows sit INSIDE a plate now — the plate carries the frame */
.plate > .figrow{margin-top:0}
.plate > .bookflip{margin-top:0; max-height:52vh}
.plate--book{max-width:min(112rem,100%)}
.figcards .plate{padding:.6rem}
.sketchwrap .plate{padding:.6rem}
.sketchwrap .plate > .sketchframe{height:min(70vh,42rem); width:100%; border:0}
.reelhero .plate{max-width:min(84rem,100%)}
.shot--clip .plate{max-width:100%}

/* caption rows follow the panel's alignment */
.panel:not(.panel--hero):not(.panel--posters):not(.panel--cols):not(.panel--sketch) .meta{
  max-width:min(112rem,100%); margin-inline:auto;
}
.figcards figcaption{margin-top:.6rem; font-size:.86rem; text-align:start}
.meta-wrap{margin-top:.2rem}

/* split panels: the MEDIA is the dominant mass, not the text */
@media (min-width: 60rem){
  .panel--cols{grid-template-columns:minmax(0,.78fr) minmax(0,1.22fr)}
  .panel--sketch{grid-template-columns:minmax(0,.72fr) minmax(0,1.28fr)}
  .panel--cols .body, .panel--sketch .body{max-width:46ch}
}

/* final fit pass */
.sketchwrap .plate > .sketchframe{height:min(64vh,38rem)}
.reelhero .plate{max-width:min(96rem,100%)}
.reelhero video{max-height:42vh}
.filmlist--mini{margin-top:.9rem}

/* the split panels' text column was 40px over — trim the chain and the lead */
.chain{margin:.6rem 0 .25rem}
.chain img{height:clamp(4rem,8vh,5.6rem)}
.panel--sketch .lead{margin-top:.2rem}
.panel--sketch .golink{margin-top:.7em}

/* the composition film is SQUARE (840×840) — mat it like a square print
   instead of stretching it into a landscape box */
.shot--clip .plate{display:flex; justify-content:center}
.shot--clip video{
  width:auto; height:auto; max-width:100%; max-height:62vh;
  background:transparent;
}

/* very wide screens: --pad grows a lot, so media must give height back */
@media (min-width: 110rem){
  .plate > .bookflip{max-height:50vh}
  .sketchwrap .plate > .sketchframe{height:min(66vh,44rem)}
  .reelhero video{max-height:34vh}
  .shot--clip video{max-height:64vh}
  .figcards img{height:clamp(16rem,44vh,30rem)}
}
@media (min-width: 110rem){
  .filmlist--mini a{width:9.5rem}
}


/* ============ the wall — the treatment Lee picked ============
   Media fills the panel edge to edge; words float on a scrim at the
   bottom. Same family as .panel--posters, reusable with cell labels. */
.panel--wall{padding:0; background:var(--dark); justify-content:flex-end}
.panel--wall::before,.panel--wall::after{display:none}
.wall{position:absolute; inset:0; display:grid; gap:2px}
.wall--4{grid-template-columns:repeat(4,1fr)}
.wall--2{grid-template-columns:repeat(2,1fr)}
.wall figure{position:relative; margin:0; overflow:hidden; background:var(--dark)}
.wall img{width:100%; height:100%; object-fit:cover; display:block}
.wall figcaption{
  position:absolute; inset-inline:0; top:4.6rem; padding:.6rem 1rem; z-index:3;
  font-family:var(--mono); font-size:.72rem; letter-spacing:.1em; text-transform:uppercase;
  color:rgba(var(--paper-rgb),.9); text-align:center;
  background:none; text-shadow:0 1px 12px rgba(var(--ink-rgb),.85);
}
html[dir="rtl"] .wall figcaption{letter-spacing:0; text-transform:none; font-family:var(--sans)}
/* the wall's photographs are pale; the poster wall works because its
   footage is dark. Veil the images so white type has something to sit on. */
.wall::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  /* the scrim was letting the photographs eat the sentence — deepened, and it
     holds further up the panel so the headline sits on ink, not on an image */
  background:linear-gradient(to top, rgba(var(--ink-rgb),.97) 0%, rgba(var(--ink-rgb),.95) 34%, rgba(var(--ink-rgb),.80) 52%, rgba(var(--ink-rgb),.42) 70%, rgba(var(--ink-rgb),.30) 100%);
}
.wall__text{
  position:relative; z-index:2; text-align:center; color:var(--dark-ink);
  padding:calc(var(--pad) * .5) var(--pad) calc(var(--pad) * 1.15);
}
.wall__text .display{font-size:clamp(1.25rem,.85rem+1.35vw,2rem)}
.wall__text .pw-body{font-size:calc(var(--t-body) * .94); max-width:58ch}
.wall__text .kicker{margin-bottom:.5rem}
.wall__text .display{text-shadow:0 2px 30px rgba(var(--ink-rgb),.7)}
.wall__text .pw-body{text-shadow:0 1px 20px rgba(var(--ink-rgb),.75)}
.wall__text .kicker,.wall__text .num{color:rgba(var(--paper-rgb),.92); justify-content:center}
.wall__text .display{max-width:none; text-shadow:0 1px 24px rgba(var(--ink-rgb),.5)}
.wall__text .pw-body{margin-inline:auto; max-width:66ch; color:rgba(var(--paper-rgb),.9); text-shadow:0 1px 16px rgba(var(--ink-rgb),.55)}
html[dir="rtl"] .wall__text .pw-body{font-weight:500}
.foldout--onwall{max-width:64rem; margin-inline:auto; margin-top:.9rem}
.foldout--onwall summary{color:rgba(var(--paper-rgb),.85); border-color:rgba(var(--paper-rgb),.25)}
.foldout--onwall .findings li{border-color:rgba(var(--paper-rgb),.2); color:rgba(var(--paper-rgb),.9)}
.foldout--onwall .findings__n{color:rgba(var(--paper-rgb),.6)}
.foldout--onwall strong{color:var(--dark-ink)}
@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){
  .panel--wall{position:relative; min-height:100svh; overflow:hidden; padding:0}
  .wall{position:absolute; inset:0}
  .wall--4{grid-template-columns:repeat(2,1fr)}
  .wall__text{position:absolute; inset:auto 0 0 0; padding:1.2rem 1rem}
}

/* ============ motion: centred stage + film library ============ */
/* The reel sits on ink: video reads better against dark, and it gives the
   second half of the strip the same light → dark rhythm as the first. */
.panel--motion{padding:calc(var(--pad) + 2.5rem) var(--pad) var(--pad);
               background:var(--dark); color:var(--dark-ink);
               --accent:var(--accent-on-dark)}
.panel--motion .kicker,.panel--motion .lib__d{color:rgba(var(--paper-rgb),.55)}
.panel--motion .meta__t{color:var(--dark-ink)}
.panel--motion .meta__m{color:rgba(var(--paper-rgb),.55)}
.panel--motion .lib__h{color:rgba(var(--paper-rgb),.55)}
.panel--motion .lib__item{color:rgba(var(--paper-rgb),.78)}
.panel--motion .lib__item:hover,
.panel--motion .lib__item.is-on{background:rgba(var(--paper-rgb),.10); color:var(--dark-ink)}
.panel--motion .lib__item img{background:rgba(var(--paper-rgb),.08)}
.panel--motion .plate:not(.stage__plate){background:rgba(var(--paper-rgb),.06)}
.panel--motion .stage__plate{background:none; padding:0}
@media (min-width: 64rem){
  .panel--motion{
    display:grid; grid-template-columns:minmax(0,1fr) 17rem;
    gap:clamp(1.5rem,3vw,3.5rem); align-items:center;
  }
  .panel--motion::before,.panel--motion::after{display:none}
}
.stage{display:flex; flex-direction:column; justify-content:center; min-width:0}
.stage .kicker{justify-content:center; text-align:center}
.stage__plate{margin-inline:auto; max-width:min(72rem,100%)}
.stage__plate{display:flex; justify-content:center; background:transparent; padding:0}
.stage__plate video{
  display:block; max-width:100%; max-height:58vh; width:auto; height:auto;
  background:transparent; border-radius:calc(var(--r) - 6px);
}
.stage .meta{max-width:min(72rem,100%); margin-inline:auto}

.library{min-width:0; align-self:center}
.lib__h{
  font-size:.78rem; letter-spacing:.16em; text-transform:uppercase; font-weight:500;
  color:var(--ink-3); margin:0 0 .7rem; text-align:start;
}
html[dir="rtl"] .lib__h{letter-spacing:0; text-transform:none; font-size:.95rem}
.lib{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:.3rem;
     max-height:64vh; overflow-y:auto; padding-inline-end:.35rem}
.lib__item{
  display:grid; grid-template-columns:4.4rem 1fr auto; gap:.6rem; align-items:center;
  width:100%; padding:.3rem; border:0; border-radius:8px; background:none;
  font:inherit; text-align:start; cursor:pointer; color:var(--ink-2);
  transition:background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.lib__item:hover{background:var(--mat); color:var(--ink)}
.lib__item.is-on{background:var(--mat); color:var(--ink)}
.lib__item.is-on .lib__t{font-weight:600}
.lib__item img{width:100%; aspect-ratio:16/9; object-fit:cover; border-radius:5px; background:rgba(var(--ink-rgb),.06); display:block}
.lib__t{font-size:.82rem; line-height:1.3; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.lib__d{font-family:var(--mono); font-size:.68rem; color:var(--ink-3)}
@media (max-width: 64rem){
  .lib{flex-direction:row; overflow-x:auto; max-height:none; gap:.6rem; margin-top:1rem}
  .lib__item{grid-template-columns:1fr; width:8.5rem; flex:0 0 auto}
  .lib__d{display:none}
}

/* ============ the process: numbered step cards ============ */
.panel--process{text-align:center}
.panel--process .kicker{justify-content:center}
.panel--process .display{max-width:none; margin-inline:auto}
.steps{
  list-style:none; margin:calc(var(--stack) * 1.1) auto 0; padding:0;
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(1rem,2vw,2.2rem); max-width:100rem; text-align:start;
}
.step{position:relative; min-width:0}
.step__n{
  display:block; font-family:var(--mono); font-size:.78rem; letter-spacing:.18em;
  color:rgba(var(--paper-rgb),.7); margin-bottom:.5rem;
}
.step .plate{padding:.5rem}
.step .plate img{
  width:100%; height:clamp(9rem,26vh,17rem); object-fit:cover; object-position:top;
  border-radius:8px; background:var(--panel);
}
.step__t{margin:.7rem 0 .25rem; font-size:calc(var(--t-body) * 1.06); font-weight:600; color:var(--colour-ink)}
.step__d{margin:0; font-size:calc(var(--t-small) * .97); line-height:1.55; color:rgba(var(--paper-rgb),.86)}
html[dir="rtl"] .step__d{font-weight:400}
.cta--onaccent{margin-top:calc(var(--stack) * .9)}
.cta--onaccent a{color:var(--colour-ink); text-decoration-color:rgba(var(--paper-rgb),.9)}
.cta--onaccent a:hover{color:var(--colour-ink); opacity:.85}
@media (max-width: 64rem){
  .steps{grid-template-columns:1fr; gap:1rem}
  .step .plate img{height:clamp(7rem,18vh,11rem)}
}

/* the difference-blended chrome turns cyan on the orange panel — opt out */
.panel--accent ~ *, .panel--process{}
body:has(.panel--accent.is-near) .chrome{}
/* simpler and reliable: give the chrome a solid treatment while the accent
   panel is the current one (class set by story.js) */
html.on-accent .chrome{mix-blend-mode:normal}
html.on-accent .chrome, html.on-accent .chrome a, html.on-accent .chrome .btn{color:rgba(var(--paper-rgb),.92)}
html.on-accent .chrome .scrub button{background:rgba(var(--paper-rgb),.85)}
html.on-accent .chrome .scrub button[aria-current="true"]{border-color:var(--panel); background:transparent}
html.on-accent .mailline{mix-blend-mode:normal; color:rgba(var(--paper-rgb),.85)}

/* the step cards can be bigger — the panel had room to spare */
.step .plate img{height:clamp(11rem,32vh,21rem)}



/* ============ (5) THE GUIDING LINE ============
   Each panel is given one station on the stream, in poem order. That single
   variable drives both things you see: the wash the panel sits on, and the
   hairline along its bottom edge. Advancing through the site walks the poem's
   own palette — האמנם → יבואו → בשדה → ותמתק → בסליחה → ילטף → מטר → ובחסד —
   and on the first and last panels the line opens out into the whole stream.

   One variable per panel. Never hard-code a panel background again. */
.panel{--station:var(--w-yamim)}
#p0{--station:var(--ink); --station-word:"—"}      /* the frame is ink… */   /* האמנם  — the title word */
#p1{--station:var(--w-yavou); --station-i:3; --station-word:"יבואו"}     /* יבואו   */
#p2{--station:var(--w-sade); --station-i:8; --station-word:"בשדה"}      /* בשדה    */
#p3{--station:var(--w-timtak); --station-i:18; --station-word:"ותמתק"}    /* ותמתק  — full strength: this panel IS the colour */
#p4{--station:var(--w-slicha); --station-i:5; --station-word:"בסליחה"}    /* בסליחה  */
#p5{--station:var(--w-yelatef); --station-i:14; --station-word:"ילטף"}   /* ילטף    */
#p7{--station:var(--w-matar); --station-i:20; --station-word:"מטר"}     /* מטר     */
#p9{--station:var(--ink); --station-word:"—"}      /* …at both ends. Colour belongs to the work between them. */     /* ובחסד   */

/* The wash. :where() keeps this at zero specificity so a panel modifier
   (--accent, --dark) still wins; the modified surfaces get their own wash
   below. The flat gradient is the fallback where color-mix() is missing. */
:where(.panel){background:linear-gradient(168deg, var(--panel) 0%, var(--panel) 60%)}
@supports (background: color-mix(in oklab, red 10%, blue)){
  :where(.panel){
    background:linear-gradient(168deg,
      color-mix(in oklab, var(--station) 13%, var(--panel)) 0%, var(--panel) 62%);
  }
  .panel--dark, .panel--posters, .panel--motion, .panel--wall{
    background:linear-gradient(168deg,
      color-mix(in oklab, var(--station) 20%, var(--dark)) 0%, var(--dark) 58%);
  }
}

/* Everything else on the slide belongs to the same colour. The bottom line is
   the loudest member of the family, not a stripe on its own:
     · every hairline and divider is tinted by the station
     · the panel number at the top is the station, readable on that surface
     · the mat under media carries it too
   --station-ink is the station adjusted for the surface it sits on: deepened
   toward ink on paper, lifted toward paper on the dark and coloured panels. */
@supports (color: color-mix(in oklab, red 10%, blue)){
  .panel{
    --line:color-mix(in oklab, var(--station) 30%, var(--line-base));
    --station-ink:color-mix(in oklab, var(--station) 76%, var(--ink));
    --station-mat:color-mix(in oklab, var(--station) 9%, transparent);
  }
  .panel--dark, .panel--posters, .panel--motion, .panel--wall, .panel--accent{
    --line:color-mix(in oklab, var(--station) 38%, rgba(var(--paper-rgb),.30));
    --station-ink:color-mix(in oklab, var(--station) 42%, var(--dark-ink));
    --station-mat:color-mix(in oklab, var(--station) 16%, rgba(var(--paper-rgb),.06));
  }
}

/* Selecting text picks up the slide's colour too — the AA-safe surface, so
   white stays readable inside the selection. */
.panel ::selection{background:var(--station-surface, var(--station)); color:var(--colour-ink)}
.panel::selection{background:var(--station-surface, var(--station)); color:var(--colour-ink)}

/* the mark itself */
.stations button::before{
  content:""; position:absolute; inset-inline:0; bottom:0;
  height:2px; background:var(--seg-idle);
  transition:height var(--fast) var(--ease), background var(--fast) var(--ease);
}
.stations button:hover::before{height:4px; background:var(--seg)}
.stations button:focus-visible::before{height:4px; background:var(--seg)}
.stations button[aria-current="true"]::before{height:5px; background:var(--seg)}

/* the mark itself */
.stations button::before{
  content:""; position:absolute; inset-inline:0; bottom:0;
  height:2px; background:var(--seg-idle);
  transition:height var(--fast) var(--ease), background var(--fast) var(--ease);
}
.stations button:hover::before{height:4px; background:var(--seg)}
.stations button:focus-visible::before{height:4px; background:var(--seg)}
.stations button[aria-current="true"]::before{height:5px; background:var(--seg)}

/* each field is its own directional run: without this the Hebrew word drags
   the hex apart — it rendered as "#2 בשדה05C3A" */
.stations__read i, .stations__read em, .stations__read u{unicode-bidi:isolate; font-style:normal}
.stations__read i{font-style:normal; font-family:var(--serif); font-size:.82rem; letter-spacing:0}
.stations__read em{font-style:normal}


/* the line itself — the same colour, at full strength, along the bottom edge */
.panel{border-bottom:3px solid var(--station)}
.panel--hero, .panel--contact{border-bottom:0}   /* the full stream is already there */
/* on the wine panel the station and the surface are the same colour, so the
   line would vanish exactly where the palette is loudest — draw it in paper */
.panel--accent{border-bottom-color:rgba(var(--paper-rgb),.45)}

/* ── wall cell labels: an edge-aligned index, not floating centred text ── */
.wall figcaption{
  position:absolute; inset-inline:0; top:4.6rem;
  display:flex; align-items:baseline; gap:.6em;
  padding:0 clamp(.9rem,1.4vw,1.6rem); z-index:3;
  font-family:var(--mono); font-size:.68rem; letter-spacing:.12em; text-transform:uppercase;
  color:rgba(var(--paper-rgb),.92); text-align:start;
  text-shadow:0 1px 14px rgba(var(--ink-rgb),.9);
}
html[dir="rtl"] .wall figcaption{letter-spacing:0; text-transform:none; font-family:var(--sans); font-size:.78rem}
.wcap__n{opacity:.6}

/* the project name rides quietly behind the statement */
.kick__proj{color:var(--ink-3); opacity:.72}
.panel--accent .kick__proj,.wall__text .kick__proj,.posterwall__text .kick__proj{color:inherit; opacity:.6}
.kicker{gap:.75em; flex-wrap:wrap}

/* The practice statement sits on a solid slab of the slide's own colour, in
   white type — the same value the bar, the number and the hairlines carry.
   The number and the project name stay outside it. story.js deepens the light
   stations (gold, ובחסד) until white clears 4.5:1 on them; the hue is kept, so
   the slab still reads as that slide's colour. */
.kicker > span:not(.num):not(.kick__proj){
  padding:.3em .62em .26em;
  background:var(--station-surface, var(--station));
  color:var(--colour-ink);
}

/* ============ composition: the centred plate ============
   Reference class (emilkowal.ski, paco.me): content lives in a centred
   column with symmetric margins. Nothing anchors to the viewport edge. */
.panel > .kicker, .panel > .display, .panel > .body,
.panel > .figrow, .panel > .figcards, .panel > .boards, .panel > .bookflip,
.panel > .oneline, .panel > .foldout, .panel > .reelhero, .panel > .filmlist,
.panel > .contact{ margin-inline:auto }
.panel:not(.panel--hero):not(.panel--posters):not(.panel--cols):not(.panel--sketch){
  text-align:center;
}
.panel:not(.panel--hero):not(.panel--posters):not(.panel--cols):not(.panel--sketch) .kicker{justify-content:center}
.panel:not(.panel--hero):not(.panel--posters):not(.panel--cols):not(.panel--sketch) .display{max-width:none}
.panel:not(.panel--hero):not(.panel--posters):not(.panel--cols):not(.panel--sketch) .body{max-width:62ch}
.panel:not(.panel--hero):not(.panel--posters):not(.panel--cols):not(.panel--sketch) .oneline{margin-inline:auto}
/* lists inside centred plates keep readable start alignment */
.foldout .study2col, .foldout .findings, .method{text-align:start}

/* composed grids centre as whole plates */
@media (min-width: 60rem){
  /* NEVER put max-width on .panel — it is absolutely positioned and 100vw,
     so a max-width shrinks the panel box itself and exposes the page
     background. Centre the measure with padding; the panel stays full-bleed. */
  .panel--cols, .panel--sketch{
    width:100vw; max-width:none;
    padding-inline:max(var(--pad), calc((100vw - 120rem) / 2));
  }
}

/* hero text: centred over the image */
.hero__text{text-align:center}
.hero__text .display, .hero__text .sub{margin-inline:auto}
.hero__text .kicker{justify-content:center}

/* poster wall caption: centred */
.posterwall__text{text-align:center}
.posterwall__text .kicker{justify-content:center}
.posterwall__text .display, .posterwall__text .pw-body{margin-inline:auto}

/* the persistent mail line — present on every panel, blends like the chrome */
.mailline{
  /* clears the colour stream that runs along the bottom edge of the
     first and last panels */
  position:fixed; bottom:1.55rem; inset-inline-end:clamp(1rem,3vw,2rem); z-index:30;
  font-family:var(--mono); font-size:.8rem; letter-spacing:.04em;
  color:var(--dark-ink); text-decoration:none; mix-blend-mode:difference;
}
.mailline:hover{text-decoration:underline; text-underline-offset:.25em}
html[dir="rtl"] .mailline{letter-spacing:0}

/* contact panel: the email is the display */
.mail{color:var(--ink); text-decoration-thickness:3px; text-underline-offset:.14em; text-decoration-color:var(--accent)}
.mail:hover{color:var(--accent)}
.contact--row{flex-direction:row !important; justify-content:center; gap:2.2rem !important; flex-wrap:wrap}

/* the small film index under the reel */
.filmlist--mini{justify-content:center; gap:1.4rem; margin-top:calc(var(--stack) * 1.1)}
.filmlist--mini a{width:9rem; font-size:.75rem}
.filmlist--mini img{aspect-ratio:16/9}

/* ============ type ============ */

.kicker{
  font-size:var(--t-small); letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-3); margin:0 0 var(--stack); display:flex; gap:.9em; align-items:baseline;
}
.num{font-family:var(--mono); color:var(--station-ink, var(--ink-3))}
/* Hebrew inside an otherwise-tracked English label: tracking off, always */
.nolsp{letter-spacing:0 !important}

.display{
  font-size:var(--t-display); line-height:1.02; font-weight:600;
  letter-spacing:-.032em; margin:0; max-width:16ch; text-wrap:balance;
}
.display--md{font-size:var(--t-md); max-width:19ch; line-height:1.06}
.display em{font-style:normal; color:var(--accent)}
.panel--accent .display em{color:var(--accent-ink); text-decoration:underline; text-underline-offset:.12em}

.sub{
  margin:var(--stack) 0 0; max-width:44ch; font-size:var(--t-lead);
  color:var(--ink-2); line-height:1.45;
}

.body{margin-top:var(--stack); max-width:52ch}
.body p{margin:0 0 .9em}
.body p:last-child{margin-bottom:0}
.lead{font-size:var(--t-lead); line-height:1.42; color:var(--ink); font-weight:500}

.advance{
  margin:auto 0 0; padding-top:2rem;
  font-family:var(--mono); font-size:var(--t-small); color:var(--ink-3);
}

/* Hebrew wants the serif — Inter has no Hebrew */
html[dir="rtl"] .display,
html[dir="rtl"] .display--md,
html[dir="rtl"] .manifesto,
html[dir="rtl"] .worklist__t{font-family:var(--serif); letter-spacing:0; font-weight:500}
html[dir="rtl"] body{font-family:var(--serif); line-height:1.78; word-spacing:.05em}

/* RULE, not preference: Hebrew is never letter-spaced. Hebrew letterforms are
   not built to be tracked apart and it measurably harms legibility. I had
   tracking on every kicker and label — corrected 2026-08-12. */
html[dir="rtl"] .kicker,
html[dir="rtl"] .label,
html[dir="rtl"] .num,
html[dir="rtl"] .btn,
html[dir="rtl"] .advance,
html[dir="rtl"] .colophon,
html[dir="rtl"] .stats dt,
html[dir="rtl"] .method dt,
html[dir="rtl"] .worklist__yr,
html[dir="rtl"] .slot,
html[dir="rtl"] .sub-h{letter-spacing:0 !important}

/* ============ pieces ============ */

.slot{
  margin-top:calc(var(--stack) * 1.4); padding:1.6rem; max-width:44ch;
  border:1px dashed var(--ink-3); color:var(--ink-3);
  font-family:var(--mono); font-size:var(--t-small); text-align:center;
}

/* ---- the playable miniature (panel 01) ----
   A working slice of the real composition tool: real words, real archive
   images, real researched colours. The site demonstrates the claim instead
   of describing it. Built by scripts/build_demo.py. */
.minitool{margin-top:calc(var(--stack) * 1.4); max-width:68rem}
.minitool__line{display:flex; gap:5px; flex-wrap:wrap}
.minitool__hint{
  margin:.9rem 0 0; max-width:46ch;
  font-size:var(--t-small); letter-spacing:.02em; color:var(--ink-3); line-height:1.55;
}

.mt-cell{
  position:relative; flex:1 1 8.5rem; min-width:7rem; max-width:12.5rem; aspect-ratio:3/4;
  border:1px solid var(--line); padding:0; margin:0; overflow:hidden; cursor:pointer;
  background:var(--panel) center/cover no-repeat;
  font:inherit; color:inherit;
  transition:transform var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.mt-cell:hover{transform:translateY(-2px); border-color:var(--ink-3)}
.mt-cell:focus-visible{outline:2px solid var(--accent); outline-offset:2px}

.mt-cell__w{
  position:absolute; inset-inline:0; bottom:0; padding:.45rem .5rem;
  font-family:var(--serif); font-size:clamp(.85rem,.78rem + .3vw,1.05rem);
  line-height:1.2; text-align:center; color:var(--ink);
  background:rgba(var(--panel-rgb),.86);
}
.mt-cell.is-image .mt-cell__w{
  color:var(--panel); background:linear-gradient(to top, rgba(var(--ink-rgb),.62), rgba(var(--ink-rgb),0));
  padding-top:1.6rem;
}
.mt-cell.is-color .mt-cell__w{background:rgba(var(--paper-rgb),.82)}

/* link out of a panel — one underlined line, the site's own control language */
.golink{margin-top:1.1em}
.golink a{
  color:inherit; font-weight:500;
  text-decoration-thickness:1px; text-underline-offset:.22em;
}
.golink a:hover{color:var(--accent)}
.panel--accent .golink a:hover{color:var(--accent-ink); opacity:.8}

/* stacked UI screenshots (sensitiveinjection) */
.stills{display:flex; flex-direction:column; gap:.75rem}
.stills img{
  display:block; width:100%; height:auto;
  border:1px solid var(--line); background:var(--panel);
}

/* the one big Hebrew quote on the dark panel */
.bigquote{
  font-family:var(--serif); font-weight:500;
  font-size:clamp(1.4rem, 1.15rem + 1.2vw, 2.1rem); line-height:1.45;
  margin-block:.55em;
}

/* research panel: three investigations, image + caption each */
.figcards{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));
  gap:1.4rem 1.8rem; margin-top:calc(var(--stack) * 1.1); max-width:112rem;
}
.figcards figure{margin:0}
.figcards img{
  display:block; width:100%; height:clamp(15rem,46vh,30rem);
  object-fit:cover; object-position:top; background:var(--panel); border-radius:calc(var(--r) - 6px);
}
.figcards figcaption{
  margin-top:.5rem; font-size:var(--t-small); line-height:1.6; color:var(--ink-2);
}
html[dir="rtl"] .figcards figcaption{line-height:1.7}

.figrow{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,13rem),1fr));
  gap:.75rem; margin-top:calc(var(--stack) * 1.3); max-width:62rem;
}
.figrow img{width:100%; height:clamp(9rem,26vh,17rem); object-fit:cover; display:block; background:var(--line); border-radius:calc(var(--r) - 6px)}

/* Two columns when a panel carries a tall image beside its text.
   Without this the shot stacks underneath and the panel overflows. */
@media (min-width: 60rem){
  .panel--cols{
    display:grid;
    grid-template-columns:minmax(0,1fr) minmax(0,.82fr);
    grid-template-rows:auto auto 1fr;
    column-gap:clamp(2rem,4vw,4.5rem);
    align-content:center;
  }
  /* the centering spacers are flex-only — as grid items they'd steal rows */
  .panel--cols::before,
  .panel--cols::after{display:none}
  .panel--cols > .kicker,
  .panel--cols > .display,
  .panel--cols > .body{grid-column:1}
  .panel--cols > .shot{
    grid-column:2; grid-row:1 / -1;
    align-self:center; margin:0;
  }
  .panel--cols > .shot img{max-height:76vh}
}

/* a single tall shot — the workspace is portrait, so cap it by height */
.shot{margin:calc(var(--stack) * 1.3) 0 0}
.shot img{
  display:block; max-height:44vh; width:auto; max-width:100%;
  border:1px solid rgba(var(--paper-rgb),.35); background:var(--line);
}
.panel:not(.panel--accent) .shot img{border-color:var(--line)}
.shot figcaption{
  margin-top:.7rem; max-width:44ch;
  font-size:var(--t-small); color:var(--ink-3); line-height:1.55;
}
.panel--accent .shot figcaption{color:rgba(var(--paper-rgb),.8)}

/* ---- the study: method, findings, limitation (panel 05) ---- */

.sub-h{
  margin:calc(var(--stack) * 1.2) 0 .7rem;
  font-size:var(--t-small); letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-3); font-weight:500;
}
html[dir="rtl"] .sub-h{text-transform:none}

.method{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));
  gap:1.1rem 2.2rem; margin:var(--stack) 0 0; max-width:62rem;
}
.method div{border-top:1px solid var(--line); padding-top:.6rem}
.method dt{
  font-size:var(--t-small); letter-spacing:.14em; text-transform:uppercase;
  color:var(--ink-3); margin:0 0 .3rem;
}
html[dir="rtl"] .method dt{text-transform:none}
.method dd{margin:0; font-size:var(--t-body); line-height:1.5; color:var(--ink-2); max-width:34ch}

.findings{list-style:none; margin:.4rem 0 0; padding:0; max-width:60rem; counter-reset:f}
.findings li{
  display:grid; grid-template-columns:2.6rem 1fr; gap:1rem;
  padding:.85rem 0; border-top:1px solid var(--line); align-items:baseline;
}
.findings__n{font-family:var(--mono); font-size:var(--t-small); color:var(--ink-3)}
.findings li span:last-child{max-width:56ch; line-height:1.55}
.findings strong{font-weight:600}

.limitation{
  margin-top:calc(var(--stack) * 1.1) !important;
  padding-inline-start:1rem; border-inline-start:2px solid var(--line);
  color:var(--ink-2); font-size:calc(var(--t-body) * .96);
}

.stats{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(9rem,1fr));
  gap:1.5rem 2.5rem; margin:calc(var(--stack) * 1.4) 0 0; max-width:52rem;
}
.stats div{border-top:1px solid var(--line); padding-top:.7rem}
.stats dt{font-size:var(--t-small); letter-spacing:.06em; color:var(--ink-3); margin:0 0 .25rem}
.stats dd{margin:0; font-size:clamp(1.6rem,1.1rem + 1.6vw,2.6rem); font-weight:600;
  letter-spacing:-.03em; font-variant-numeric:tabular-nums}

.worklist{list-style:none; margin:var(--stack) 0 0; padding:0; max-width:64rem}
.worklist li{
  display:grid; grid-template-columns:4.5rem minmax(9rem,14rem) 1fr; gap:1.5rem;
  padding:1.1rem 0; border-top:1px solid var(--line); align-items:baseline;
}
.worklist__yr{font-family:var(--mono); font-size:var(--t-small); color:var(--ink-3)}
.worklist__t{font-size:clamp(1.1rem,1rem + .5vw,1.45rem); font-weight:600; letter-spacing:-.02em}
.worklist__d{color:var(--ink-2); max-width:46ch}

.manifesto{
  margin:0; font-size:var(--t-md); font-weight:500; letter-spacing:-.03em;
  line-height:1.22; max-width:22ch;
}
.manifesto span{display:block; color:var(--ink-3)}
.manifesto__last{color:var(--panel) !important; margin-top:.5em}

.contact{list-style:none; margin:var(--stack) 0 0; padding:0;
  display:flex; flex-direction:column; gap:.5rem; font-size:var(--t-lead)}
.contact a{color:var(--ink); text-decoration-thickness:1px; text-underline-offset:.2em}
.contact a:hover{color:var(--accent)}
.colophon{margin:1.35rem 0 0; padding-top:.9rem; font-family:var(--mono);
  font-size:var(--t-small); color:var(--ink-3)}

/* two stacked stills must share the column height, not fight for it */
.panel--cols > .stills img{max-height:34vh; width:auto; max-width:100%}

/* the rendered clip — a real film from the real pipeline, playing */
.shot--clip video{
  display:block; max-height:72vh; width:100%;
  background:var(--dark); border-radius:calc(var(--r) - 6px);
}

/* the exhibition spread: photographs in one row of three */
.figrow--tall{grid-template-columns:repeat(3,minmax(0,1fr)); max-width:none; margin-top:calc(var(--stack) * .9)}
.figrow--tall img{height:clamp(14rem,46vh,30rem)}
@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){
  .figrow--tall{grid-template-columns:repeat(2,minmax(0,1fr))}
  .figrow--tall img{height:auto}
}

/* exhibition + study on one panel: findings left, method/limitation right */
.study2col{
  display:grid; grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);
  gap:1rem 3rem; margin-top:calc(var(--stack) * .6); max-width:74rem;
}
.study2col .sub-h{margin-bottom:.45rem}
.study2col .findings{margin-top:0}
.study2col .findings li{padding:.3rem 0}
.study2col .findings li span:last-child{line-height:1.45}
.study2col .sub-h{margin-top:0}
.study2col__notes .smallnote{
  margin:0 0 .8em; font-size:var(--t-small); line-height:1.6; color:var(--ink-2); max-width:52ch;
}
.study2col__notes .lead{font-size:var(--t-body); max-width:44ch}
@media (max-width: 60rem){ .study2col{grid-template-columns:1fr} }

/* the live process sketch, embedded beside the text */
.sketchwrap{margin-top:calc(var(--stack) * 1.2); max-width:78rem}
.sketchframe{border-radius:calc(var(--r) - 6px); 
  display:block; width:100%; height:min(62vh,34rem); border:0;
  background:var(--panel); box-shadow:0 1px 0 rgba(var(--ink-rgb),.12), 0 12px 40px rgba(var(--ink-rgb),.18);
}
@media (min-width: 60rem){
  .panel--sketch{
    display:grid;
    grid-template-columns:minmax(0,.72fr) minmax(0,1fr);
    grid-template-rows:auto auto 1fr;
    column-gap:clamp(2rem,3.5vw,4rem);
    align-content:center;
  }
  .panel--sketch::before,.panel--sketch::after{display:none}
  .panel--sketch > .kicker,
  .panel--sketch > .display,
  .panel--sketch > .body{grid-column:1}
  .panel--sketch > .sketchwrap{
    grid-column:2; grid-row:1 / -1; align-self:center; margin-top:0;
  }
  .panel--sketch .sketchframe{border-radius:calc(var(--r) - 6px); height:min(76vh,44rem)}
  .panel--sketch .body p{margin-bottom:.6em}
  .panel--sketch .lead{font-size:clamp(1.15rem,1.05rem+.5vw,1.4rem); line-height:1.35}
  .panel--sketch .display--md{font-size:clamp(1.9rem,1.25rem+2.3vw,3.1rem)}
}

/* the poster wall — three loops ARE the panel; text floats on a scrim */
.panel--posters{padding:0; background:var(--dark)}
.panel--posters::before,.panel--posters::after{display:none}
.posterwall{
  position:absolute; inset:0;
  display:grid; grid-template-columns:repeat(3,1fr); gap:2px;
}
.posterwall .pw{overflow:hidden; position:relative}
.posterwall video{width:100%; height:100%; object-fit:cover; display:block; background:var(--dark) center/cover no-repeat}

.posterwall__text{
  position:relative; z-index:1; margin-top:auto;
  padding:calc(var(--pad) * .8) var(--pad);
  background:linear-gradient(to top, rgba(var(--ink-rgb),.88) 0%, rgba(var(--ink-rgb),.55) 60%, rgba(var(--ink-rgb),0) 100%);
  color:var(--dark-ink);
}
.posterwall__text .kicker,.posterwall__text .num{color:rgba(var(--paper-rgb),.75)}
.posterwall__text .display{max-width:none; text-shadow:0 1px 24px rgba(var(--ink-rgb),.45)}
.pw-body{max-width:62ch; margin-top:.6rem; color:rgba(var(--paper-rgb),.9); font-size:var(--t-body); text-shadow:0 1px 16px rgba(var(--ink-rgb),.5)}
.posterwall__text .bigquote{margin:.5em 0 0; color:var(--dark-ink); text-shadow:0 1px 20px rgba(var(--ink-rgb),.55)}
html[dir="rtl"] .posterwall__text .pw-body{font-weight:500}
@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){
  .panel--posters{padding:0; min-height:100svh; position:relative}
  .posterwall{position:absolute}
  .posterwall__text{position:absolute; inset:auto 0 0 0}
}

/* the living posters — three portrait loops on the dark panel */
.posterrow{
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
  gap:1rem; margin-top:calc(var(--stack) * 1.1); max-width:60rem;
}
.posterrow video{
  display:block; width:100%; aspect-ratio:9/16; object-fit:cover;
  background:var(--dark); border:1px solid rgba(var(--paper-rgb),.2);
}
@media (min-width: 60rem){
  .panel--dark.has-posters{
    display:grid;
    grid-template-columns:minmax(0,.75fr) minmax(0,1.25fr);
    grid-template-rows:auto auto 1fr;
    column-gap:clamp(2rem,3.5vw,4rem);
    align-content:center;
  }
  .panel--dark.has-posters::before,.panel--dark.has-posters::after{display:none}
  .panel--dark.has-posters > .kicker,
  .panel--dark.has-posters > .display,
  .panel--dark.has-posters > .body{grid-column:1}
  .panel--dark.has-posters .display--md{font-size:clamp(1.4rem,.95rem+1.5vw,2.1rem); max-width:none}
  .panel--dark.has-posters > .posterrow{
    grid-column:2; grid-row:1 / -1; align-self:center; margin-top:0;
  }
  .panel--dark.has-posters .posterrow video{height:68vh; aspect-ratio:auto; object-fit:cover}
}

/* the showreel — one minute, front and centre */
.motiongrid{margin-top:calc(var(--stack) * 1.1)}
@media (min-width: 64rem){
  .motiongrid{display:grid; grid-template-columns:minmax(0,1fr) 19rem; gap:2rem; align-items:center; max-width:82rem}
  .motiongrid .filmlist{flex-direction:column; margin-top:0; gap:1.1rem}
  .motiongrid .filmlist a{display:grid; grid-template-columns:6.5rem 1fr; gap:.7rem; width:100%; align-items:center}
  .motiongrid .filmlist span{margin-top:0}
}
.reelhero{margin:0 auto; max-width:min(104rem,100%)}
.reelhero video{
  display:block; max-width:100%; width:auto; height:auto; max-height:46vh;
  background:transparent; border-radius:calc(var(--r) - 6px);
}
.display--onerow{max-width:none}

/* the three full films, as a quiet index under the reel */
.filmlist{display:flex; flex-wrap:wrap; gap:1rem 1.4rem; margin-top:var(--stack)}
.filmlist a{
  width:13.5rem; text-decoration:none; color:var(--ink-2);
  font-size:var(--t-small); line-height:1.5;
}
.filmlist img{
  display:block; width:100%; aspect-ratio:16/9; object-fit:cover;
  background:rgba(var(--ink-rgb),.06); border-radius:8px; padding:0;
  transition:opacity var(--fast) var(--ease);
}
.filmlist a:hover img{opacity:.85}
.filmlist span{display:block; margin-top:.45rem}
.filmlist strong{color:var(--ink)}

/* the loud call — one line, lead-size, underlined */
.cta{margin-top:1.3em}
.cta a{
  color:var(--ink); font-size:var(--t-lead); font-weight:600;
  text-decoration-thickness:2px; text-underline-offset:.22em; text-decoration-color:var(--accent);
}
.cta a:hover{color:var(--accent)}

/* four-up making row */
.figrow--four{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){
  .figrow--four{grid-template-columns:repeat(2,minmax(0,1fr))}
}

.oneline{max-width:72ch !important; color:var(--ink-2); font-size:var(--t-small)}

/* the book, leafing itself */
.bookflip{
  position:relative; margin-top:var(--stack);
  max-width:min(92rem, 100%); aspect-ratio:2/1; max-height:54vh;
}
.bookflip img{
  position:absolute; inset:0; width:100%; height:100%; object-fit:contain; border-radius:calc(var(--r) - 6px);
  object-position:left center; opacity:0; transition:opacity .3s var(--ease);
}
html[dir="rtl"] .bookflip img{object-position:right center}
.bookflip img.is-on{opacity:1}

/* paper → data → tool: the research chain inside the process column */
.chain{display:grid; grid-template-columns:repeat(3,1fr); gap:.6rem; margin:.7rem 0 .3rem; max-width:32rem}
.chain img{width:100%; height:clamp(5rem,11vh,7.5rem); object-fit:cover; object-position:top; background:var(--panel); border-radius:8px}

/* the two sketch boards — big, side by side */
.boards{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:1.2rem; margin-top:var(--stack); max-width:76rem}
.boards img{width:100%; height:clamp(20rem,62vh,42rem); object-fit:cover; object-position:center; border-radius:calc(var(--r) - 6px)}
@media (max-width:48rem), (pointer:coarse) and (max-width:60rem){ .boards img{height:auto} }

/* findings behind a quiet fold */
.foldout{margin-top:calc(var(--stack) * .7); max-width:74rem}
.foldout summary{
  cursor:pointer; list-style:none; font-size:var(--t-small);
  letter-spacing:.14em; text-transform:uppercase; color:var(--ink-2);
  padding:.55rem 0; border-top:1px solid var(--line); border-bottom:1px solid var(--line);
}
html[dir="rtl"] .foldout summary{letter-spacing:0; text-transform:none}
.foldout summary::before{content:"+"; font-family:var(--mono); margin-inline-end:.7em; color:var(--accent)}
.foldout[open] summary::before{content:"−"}
.foldout summary::-webkit-details-marker{display:none}
.foldout .study2col{margin-top:1rem}

/* three films, one row, sound on demand */
.videorow{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,13rem),1fr));
  gap:.9rem 1rem; margin-top:calc(var(--stack) * .9); max-width:64rem;
}
.videorow figure{margin:0}
.videorow video{
  display:block; width:100%; aspect-ratio:16/9; object-fit:cover;
  background:var(--dark); border:1px solid var(--line);
}
.videorow figcaption{
  margin-top:.7rem; font-size:var(--t-small); line-height:1.6; color:var(--ink-2);
}

/* ============ index sheet (the back door) ============ */

.sheet{
  position:fixed; inset:0; z-index:40; background:rgba(var(--ink-rgb),.93);
  display:grid; place-content:center;
}
.sheet[hidden]{display:none}
.sheet__inner{display:flex; flex-direction:column; gap:.15rem; padding:2rem}
.sheet__inner button{
  background:none; border:0; color:var(--ink-3); font:inherit;
  font-size:clamp(1.3rem,1rem + 1.6vw,2.2rem); font-weight:500; letter-spacing:-.02em;
  text-align:start; padding:.28rem 0; cursor:pointer;
  transition:color var(--fast) var(--ease);
}
.sheet__inner button:hover,.sheet__inner button:focus-visible{color:var(--panel)}
.sheet__inner .n{font-family:var(--mono); font-size:.6em; color:var(--ink-3); margin-inline-end:.9em}

/* ============ mobile: the deliberate vertical fallback ============ */

@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){
  body{overflow:auto}
  .strip{position:static; display:block; width:auto; height:auto; overflow:visible}
  .panel{
    position:static; width:100%; height:auto; min-height:88svh;
    transform:none !important; visibility:visible !important; transition:none;
    border-right:0; border-bottom:1px solid var(--line);
    padding:5rem var(--pad) 3.5rem;
  }
  html[dir="rtl"] .panel{border-left:0}
  .scrub{display:none}
  .advance{display:none}
  .worklist li{grid-template-columns:1fr; gap:.35rem}
  .figrow img{height:auto; aspect-ratio:4/3}
}

/* mobile: the poster wall must stay its videos' positioning context —
   this sits after the generic .panel{position:static} fallback on purpose */
@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){
  .panel--posters{position:relative; padding:0; min-height:100svh; overflow:hidden}
  .posterwall{position:absolute; inset:0}
  .posterwall__text{position:absolute; inset:auto 0 0 0; padding:1.2rem 1rem}
}

/* ============ plate integration ============ */
/* media rows sit INSIDE a plate now — the plate carries the frame */
.plate > .figrow{margin-top:0}
.plate > .bookflip{margin-top:0; max-height:52vh}
.plate--book{max-width:min(112rem,100%)}
.figcards .plate{padding:.6rem}
.sketchwrap .plate{padding:.6rem}
.sketchwrap .plate > .sketchframe{height:min(70vh,42rem); width:100%; border:0}
.reelhero .plate{max-width:min(84rem,100%)}
.shot--clip .plate{max-width:100%}

/* caption rows follow the panel's alignment */
.panel:not(.panel--hero):not(.panel--posters):not(.panel--cols):not(.panel--sketch) .meta{
  max-width:min(112rem,100%); margin-inline:auto;
}
.figcards figcaption{margin-top:.6rem; font-size:.86rem; text-align:start}
.meta-wrap{margin-top:.2rem}

/* split panels: the MEDIA is the dominant mass, not the text */
@media (min-width: 60rem){
  .panel--cols{grid-template-columns:minmax(0,.78fr) minmax(0,1.22fr)}
  .panel--sketch{grid-template-columns:minmax(0,.72fr) minmax(0,1.28fr)}
  .panel--cols .body, .panel--sketch .body{max-width:46ch}
}

/* final fit pass */
.sketchwrap .plate > .sketchframe{height:min(64vh,38rem)}
.reelhero .plate{max-width:min(96rem,100%)}
.reelhero video{max-height:42vh}
.filmlist--mini{margin-top:.9rem}

/* the split panels' text column was 40px over — trim the chain and the lead */
.chain{margin:.6rem 0 .25rem}
.chain img{height:clamp(4rem,8vh,5.6rem)}
.panel--sketch .lead{margin-top:.2rem}
.panel--sketch .golink{margin-top:.7em}

/* the composition film is SQUARE (840×840) — mat it like a square print
   instead of stretching it into a landscape box */
.shot--clip .plate{display:flex; justify-content:center}
.shot--clip video{
  width:auto; height:auto; max-width:100%; max-height:62vh;
  background:transparent;
}

/* very wide screens: --pad grows a lot, so media must give height back */
@media (min-width: 110rem){
  .plate > .bookflip{max-height:50vh}
  .sketchwrap .plate > .sketchframe{height:min(66vh,44rem)}
  .reelhero video{max-height:34vh}
  .shot--clip video{max-height:64vh}
  .figcards img{height:clamp(16rem,44vh,30rem)}
}
@media (min-width: 110rem){
  .filmlist--mini a{width:9.5rem}
}


/* ============ the wall — the treatment Lee picked ============
   Media fills the panel edge to edge; words float on a scrim at the
   bottom. Same family as .panel--posters, reusable with cell labels. */
.panel--wall{padding:0; background:var(--dark); justify-content:flex-end}
.panel--wall::before,.panel--wall::after{display:none}
.wall{position:absolute; inset:0; display:grid; gap:2px}
.wall--4{grid-template-columns:repeat(4,1fr)}
.wall--2{grid-template-columns:repeat(2,1fr)}
.wall figure{position:relative; margin:0; overflow:hidden; background:var(--dark)}
.wall img{width:100%; height:100%; object-fit:cover; display:block}
.wall figcaption{
  position:absolute; inset-inline:0; top:4.6rem; padding:.6rem 1rem; z-index:3;
  font-family:var(--mono); font-size:.72rem; letter-spacing:.1em; text-transform:uppercase;
  color:rgba(var(--paper-rgb),.9); text-align:center;
  background:none; text-shadow:0 1px 12px rgba(var(--ink-rgb),.85);
}
html[dir="rtl"] .wall figcaption{letter-spacing:0; text-transform:none; font-family:var(--sans)}
/* the wall's photographs are pale; the poster wall works because its
   footage is dark. Veil the images so white type has something to sit on. */
.wall::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  /* the scrim was letting the photographs eat the sentence — deepened, and it
     holds further up the panel so the headline sits on ink, not on an image */
  background:linear-gradient(to top, rgba(var(--ink-rgb),.97) 0%, rgba(var(--ink-rgb),.95) 34%, rgba(var(--ink-rgb),.80) 52%, rgba(var(--ink-rgb),.42) 70%, rgba(var(--ink-rgb),.30) 100%);
}
.wall__text{
  position:relative; z-index:2; text-align:center; color:var(--dark-ink);
  padding:calc(var(--pad) * .5) var(--pad) calc(var(--pad) * 1.15);
}
.wall__text .display{font-size:clamp(1.25rem,.85rem+1.35vw,2rem)}
.wall__text .pw-body{font-size:calc(var(--t-body) * .94); max-width:58ch}
.wall__text .kicker{margin-bottom:.5rem}
.wall__text .display{text-shadow:0 2px 30px rgba(var(--ink-rgb),.7)}
.wall__text .pw-body{text-shadow:0 1px 20px rgba(var(--ink-rgb),.75)}
.wall__text .kicker,.wall__text .num{color:rgba(var(--paper-rgb),.92); justify-content:center}
.wall__text .display{max-width:none; text-shadow:0 1px 24px rgba(var(--ink-rgb),.5)}
.wall__text .pw-body{margin-inline:auto; max-width:66ch; color:rgba(var(--paper-rgb),.9); text-shadow:0 1px 16px rgba(var(--ink-rgb),.55)}
html[dir="rtl"] .wall__text .pw-body{font-weight:500}
.foldout--onwall{max-width:64rem; margin-inline:auto; margin-top:.9rem}
.foldout--onwall summary{color:rgba(var(--paper-rgb),.85); border-color:rgba(var(--paper-rgb),.25)}
.foldout--onwall .findings li{border-color:rgba(var(--paper-rgb),.2); color:rgba(var(--paper-rgb),.9)}
.foldout--onwall .findings__n{color:rgba(var(--paper-rgb),.6)}
.foldout--onwall strong{color:var(--dark-ink)}
@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){
  .panel--wall{position:relative; min-height:100svh; overflow:hidden; padding:0}
  .wall{position:absolute; inset:0}
  .wall--4{grid-template-columns:repeat(2,1fr)}
  .wall__text{position:absolute; inset:auto 0 0 0; padding:1.2rem 1rem}
}

/* ============ motion: centred stage + film library ============ */
/* The reel sits on ink: video reads better against dark, and it gives the
   second half of the strip the same light → dark rhythm as the first. */
.panel--motion{padding:calc(var(--pad) + 2.5rem) var(--pad) var(--pad);
               background:var(--dark); color:var(--dark-ink);
               --accent:var(--accent-on-dark)}
.panel--motion .kicker,.panel--motion .lib__d{color:rgba(var(--paper-rgb),.55)}
.panel--motion .meta__t{color:var(--dark-ink)}
.panel--motion .meta__m{color:rgba(var(--paper-rgb),.55)}
.panel--motion .lib__h{color:rgba(var(--paper-rgb),.55)}
.panel--motion .lib__item{color:rgba(var(--paper-rgb),.78)}
.panel--motion .lib__item:hover,
.panel--motion .lib__item.is-on{background:rgba(var(--paper-rgb),.10); color:var(--dark-ink)}
.panel--motion .lib__item img{background:rgba(var(--paper-rgb),.08)}
.panel--motion .plate:not(.stage__plate){background:rgba(var(--paper-rgb),.06)}
.panel--motion .stage__plate{background:none; padding:0}
@media (min-width: 64rem){
  .panel--motion{
    display:grid; grid-template-columns:minmax(0,1fr) 17rem;
    gap:clamp(1.5rem,3vw,3.5rem); align-items:center;
  }
  .panel--motion::before,.panel--motion::after{display:none}
}
.stage{display:flex; flex-direction:column; justify-content:center; min-width:0}
.stage .kicker{justify-content:center; text-align:center}
.stage__plate{margin-inline:auto; max-width:min(72rem,100%)}
.stage__plate{display:flex; justify-content:center; background:transparent; padding:0}
.stage__plate video{
  display:block; max-width:100%; max-height:58vh; width:auto; height:auto;
  background:transparent; border-radius:calc(var(--r) - 6px);
}
.stage .meta{max-width:min(72rem,100%); margin-inline:auto}

.library{min-width:0; align-self:center}
.lib__h{
  font-size:.78rem; letter-spacing:.16em; text-transform:uppercase; font-weight:500;
  color:var(--ink-3); margin:0 0 .7rem; text-align:start;
}
html[dir="rtl"] .lib__h{letter-spacing:0; text-transform:none; font-size:.95rem}
.lib{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:.3rem;
     max-height:64vh; overflow-y:auto; padding-inline-end:.35rem}
.lib__item{
  display:grid; grid-template-columns:4.4rem 1fr auto; gap:.6rem; align-items:center;
  width:100%; padding:.3rem; border:0; border-radius:8px; background:none;
  font:inherit; text-align:start; cursor:pointer; color:var(--ink-2);
  transition:background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.lib__item:hover{background:var(--mat); color:var(--ink)}
.lib__item.is-on{background:var(--mat); color:var(--ink)}
.lib__item.is-on .lib__t{font-weight:600}
.lib__item img{width:100%; aspect-ratio:16/9; object-fit:cover; border-radius:5px; background:rgba(var(--ink-rgb),.06); display:block}
.lib__t{font-size:.82rem; line-height:1.3; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.lib__d{font-family:var(--mono); font-size:.68rem; color:var(--ink-3)}
@media (max-width: 64rem){
  .lib{flex-direction:row; overflow-x:auto; max-height:none; gap:.6rem; margin-top:1rem}
  .lib__item{grid-template-columns:1fr; width:8.5rem; flex:0 0 auto}
  .lib__d{display:none}
}

/* ============ the process: numbered step cards ============ */
.panel--process{text-align:center}
.panel--process .kicker{justify-content:center}
.panel--process .display{max-width:none; margin-inline:auto}
.steps{
  list-style:none; margin:calc(var(--stack) * 1.1) auto 0; padding:0;
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(1rem,2vw,2.2rem); max-width:100rem; text-align:start;
}
.step{position:relative; min-width:0}
.step__n{
  display:block; font-family:var(--mono); font-size:.78rem; letter-spacing:.18em;
  color:rgba(var(--paper-rgb),.7); margin-bottom:.5rem;
}
.step .plate{padding:.5rem}
.step .plate img{
  width:100%; height:clamp(9rem,26vh,17rem); object-fit:cover; object-position:top;
  border-radius:8px; background:var(--panel);
}
.step__t{margin:.7rem 0 .25rem; font-size:calc(var(--t-body) * 1.06); font-weight:600; color:var(--colour-ink)}
.step__d{margin:0; font-size:calc(var(--t-small) * .97); line-height:1.55; color:rgba(var(--paper-rgb),.86)}
html[dir="rtl"] .step__d{font-weight:400}
.cta--onaccent{margin-top:calc(var(--stack) * .9)}
.cta--onaccent a{color:var(--colour-ink); text-decoration-color:rgba(var(--paper-rgb),.9)}
.cta--onaccent a:hover{color:var(--colour-ink); opacity:.85}
@media (max-width: 64rem){
  .steps{grid-template-columns:1fr; gap:1rem}
  .step .plate img{height:clamp(7rem,18vh,11rem)}
}

/* the difference-blended chrome turns cyan on the orange panel — opt out */
.panel--accent ~ *, .panel--process{}
body:has(.panel--accent.is-near) .chrome{}
/* simpler and reliable: give the chrome a solid treatment while the accent
   panel is the current one (class set by story.js) */
html.on-accent .chrome{mix-blend-mode:normal}
html.on-accent .chrome, html.on-accent .chrome a, html.on-accent .chrome .btn{color:rgba(var(--paper-rgb),.92)}
html.on-accent .chrome .scrub button{background:rgba(var(--paper-rgb),.85)}
html.on-accent .chrome .scrub button[aria-current="true"]{border-color:var(--panel); background:transparent}
html.on-accent .mailline{mix-blend-mode:normal; color:rgba(var(--paper-rgb),.85)}

/* the step cards can be bigger — the panel had room to spare */
.step .plate img{height:clamp(11rem,32vh,21rem)}



/* ============ (5) THE GUIDING LINE ============
   Each panel is given one station on the stream, in poem order. That single
   variable drives both things you see: the wash the panel sits on, and the
   hairline along its bottom edge. Advancing through the site walks the poem's
   own palette — האמנם → יבואו → בשדה → ותמתק → בסליחה → ילטף → מטר → ובחסד —
   and on the first and last panels the line opens out into the whole stream.

   One variable per panel. Never hard-code a panel background again. */
.panel{--station:var(--w-yamim)}
#p0{--station:var(--ink); --station-word:"—"}      /* the frame is ink… */   /* האמנם  — the title word */
#p1{--station:var(--w-yavou); --station-i:3; --station-word:"יבואו"}     /* יבואו   */
#p2{--station:var(--w-sade); --station-i:8; --station-word:"בשדה"}      /* בשדה    */
#p3{--station:var(--w-timtak); --station-i:18; --station-word:"ותמתק"}    /* ותמתק  — full strength: this panel IS the colour */
#p4{--station:var(--w-slicha); --station-i:5; --station-word:"בסליחה"}    /* בסליחה  */
#p5{--station:var(--w-yelatef); --station-i:14; --station-word:"ילטף"}   /* ילטף    */
#p7{--station:var(--w-matar); --station-i:20; --station-word:"מטר"}     /* מטר     */
#p9{--station:var(--ink); --station-word:"—"}      /* …at both ends. Colour belongs to the work between them. */     /* ובחסד   */

/* The wash. :where() keeps this at zero specificity so a panel modifier
   (--accent, --dark) still wins; the modified surfaces get their own wash
   below. The flat gradient is the fallback where color-mix() is missing. */
:where(.panel){background:linear-gradient(168deg, var(--panel) 0%, var(--panel) 60%)}
@supports (background: color-mix(in oklab, red 10%, blue)){
  :where(.panel){
    background:linear-gradient(168deg,
      color-mix(in oklab, var(--station) 13%, var(--panel)) 0%, var(--panel) 62%);
  }
  .panel--dark, .panel--posters, .panel--motion, .panel--wall{
    background:linear-gradient(168deg,
      color-mix(in oklab, var(--station) 20%, var(--dark)) 0%, var(--dark) 58%);
  }
}

/* Everything else on the slide belongs to the same colour. The bottom line is
   the loudest member of the family, not a stripe on its own:
     · every hairline and divider is tinted by the station
     · the panel number at the top is the station, readable on that surface
     · the mat under media carries it too
   --station-ink is the station adjusted for the surface it sits on: deepened
   toward ink on paper, lifted toward paper on the dark and coloured panels. */
@supports (color: color-mix(in oklab, red 10%, blue)){
  .panel{
    --line:color-mix(in oklab, var(--station) 30%, var(--line-base));
    --station-ink:color-mix(in oklab, var(--station) 76%, var(--ink));
    --station-mat:color-mix(in oklab, var(--station) 9%, transparent);
  }
  .panel--dark, .panel--posters, .panel--motion, .panel--wall, .panel--accent{
    --line:color-mix(in oklab, var(--station) 38%, rgba(var(--paper-rgb),.30));
    --station-ink:color-mix(in oklab, var(--station) 42%, var(--dark-ink));
    --station-mat:color-mix(in oklab, var(--station) 16%, rgba(var(--paper-rgb),.06));
  }
}

/* Selecting text picks up the slide's colour too — the AA-safe surface, so
   white stays readable inside the selection. */
.panel ::selection{background:var(--station-surface, var(--station)); color:var(--colour-ink)}
.panel::selection{background:var(--station-surface, var(--station)); color:var(--colour-ink)}

/* THE BAR — eight segments, one per slide, and it stays quiet.
   At rest every segment is a neutral hairline: no rainbow, nothing competing
   with the page. Colour appears only where you are — the slide you are on
   shows its own station, at full strength, and its name on hover. That way the
   bar says one thing at a time instead of seventy. */
.stations{
  position:fixed; inset-inline:0; bottom:0; z-index:35;
  display:flex; gap:1px; height:1.5rem; align-items:flex-end;
  --seg-idle:rgba(var(--ink-rgb),.20);
}
html.on-dark .stations, html.on-accent .stations{--seg-idle:rgba(var(--paper-rgb),.28)}
html[dir="rtl"] .stations{flex-direction:row-reverse}

.stations button{
  flex:1; position:relative;
  height:.7rem; padding:0 0 .16rem; box-sizing:content-box;   /* hit area below the mark */
  border:0; margin:0; background:none; cursor:pointer;
  -webkit-appearance:none; appearance:none;
}
/* the mark itself */
.stations button::before{
  content:""; position:absolute; inset-inline:0; bottom:0;
  height:2px; background:var(--seg-idle);
  transition:height var(--fast) var(--ease), background var(--fast) var(--ease);
}
.stations button:hover::before{height:4px; background:var(--seg)}
.stations button:focus-visible::before{height:4px; background:var(--seg)}
.stations button[aria-current="true"]::before{height:5px; background:var(--seg)}

/* each field is its own directional run: without this the Hebrew word drags
   the hex apart — it rendered as "#2 בשדה05C3A" */
.stations__read i, .stations__read em, .stations__read u{unicode-bidi:isolate; font-style:normal}
.stations__read i{font-style:normal; font-family:var(--serif); font-size:.82rem; letter-spacing:0}
.stations__read em{font-style:normal}


/* the line itself — the same colour, at full strength, along the bottom edge */
.panel{border-bottom:3px solid var(--station)}
.panel--hero, .panel--contact{border-bottom:0}   /* the full stream is already there */
/* on the wine panel the station and the surface are the same colour, so the
   line would vanish exactly where the palette is loudest — draw it in paper */
.panel--accent{border-bottom-color:rgba(var(--paper-rgb),.45)}

/* ── wall cell labels: an edge-aligned index, not floating centred text ── */
.wall figcaption{
  position:absolute; inset-inline:0; top:4.6rem;
  display:flex; align-items:baseline; gap:.6em;
  padding:0 clamp(.9rem,1.4vw,1.6rem); z-index:3;
  font-family:var(--mono); font-size:.68rem; letter-spacing:.12em; text-transform:uppercase;
  color:rgba(var(--paper-rgb),.92); text-align:start;
  text-shadow:0 1px 14px rgba(var(--ink-rgb),.9);
}
html[dir="rtl"] .wall figcaption{letter-spacing:0; text-transform:none; font-family:var(--sans); font-size:.78rem}
.wcap__n{opacity:.6}

/* the project name rides quietly behind the statement */
.kick__proj{color:var(--ink-3); opacity:.72}
.panel--accent .kick__proj,.wall__text .kick__proj,.posterwall__text .kick__proj{color:inherit; opacity:.6}
.kicker{gap:.75em; flex-wrap:wrap}


/* ── the swipe: one poem, every archive, cycling like the piece itself ── */
.swipe{position:absolute; inset:0}
.swipe img{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  opacity:0; transition:opacity .55s var(--ease);
}
.swipe img.is-on{opacity:1}


/* ============================================================
   SIGNATURE GESTURES — the three marks, and how often each is allowed.
   (01 המקף, the connector, was removed on Lee's call 2026-08-30. Its drawing
   code survives in gestures.js and tools/gesture-lab.html if it comes back.)
     02 התא         the cell — everywhere: index, scrubber, lists
     04 סימני דפוס  crop marks + the poem's palette — TWO panels only
     06 הערת שוליים the redline — ONCE in the entire site
   The frequencies are the design. Break them and a fingerprint
   turns into decoration.
   ============================================================ */

/* --- 02 התא · the cell ------------------------------------- */
.cell{display:inline-block; width:.58em; height:.58em; flex:none;
      border:1px solid currentColor; opacity:.5}
.cell--on{background:var(--accent); border-color:var(--accent); opacity:1}

/* the index and the contact list take the cell as their marker */
.contact li::before{
  content:""; display:inline-block; width:.55em; height:.55em;
  border:1px solid currentColor; opacity:.4; margin-inline-end:.75em;
}

/* the scrubber's current tick is the same square, not a wide box */
.scrub button[aria-current="true"]{width:13px}

/* --- 04 סימני דפוס · print marks + the poem's palette ------- */
.printmarks{position:absolute; inset:0; width:100%; height:100%; pointer-events:none; z-index:1}
.printmarks path{fill:none; stroke:currentColor; stroke-width:1; opacity:.45;
                 vector-effect:non-scaling-stroke}

/* --- 06 הערת שוליים · the redline --------------------------
   Once. On one number. It is handwriting, and handwriting that
   repeats is a template. */
.redline{position:relative; display:inline-block; padding:0 .06em}
.redline__ring{position:absolute; inset:-.28em -.42em -.22em; width:auto; height:auto;
               pointer-events:none; overflow:visible}
.redline__ring path{fill:none; stroke:var(--station-ink, var(--accent)); stroke-width:1.5;
                    stroke-linecap:round; vector-effect:non-scaling-stroke}


/* ============================================================
   Additions — 2026-08-28
   ============================================================ */

/* --- the chapter turn ---------------------------------------
   Once in the whole site, at panel 04, where the register changes:
   from the thing that shipped to the two that argue with the world.
   A rule and one quiet sentence — the way a book announces a new
   part, not a new page. Deliberately NOT tracked and NOT uppercase,
   so it reads as a whisper against the kicker directly beneath it. */
.pivot{
  margin:0 0 calc(var(--stack) * .9);
  padding-top:.9rem;
  border-top:1px solid rgba(var(--ink-rgb),.20);
  font-size:var(--t-small);
  line-height:1.55;
  letter-spacing:.01em;
  color:var(--ink-3);
  max-width:62ch;
}
html[dir="rtl"] .pivot{letter-spacing:0}

@media (min-width: 60rem){
  /* the rule spans the whole panel: the break is the panel's, not the column's */
  .panel--sketch{grid-template-rows:auto auto auto 1fr}
  .panel--sketch > .pivot{grid-column:1 / -1; grid-row:1; max-width:none}
  .panel--sketch > .sketchwrap{grid-row:2 / -1}
}

/* --- selection ----------------------------------------------
   Anyone who highlights a sentence to copy it gets דקירתם, the same
   accent as every link. --accent is redefined per panel (see the two-
   value note above), so the knockout has to follow it: on the dark
   panels the accent is כהלך and needs ink on top, and on the coloured
   panel the accent IS the paper, so the pair inverts. Measured: every
   combination below clears 4.5:1. */
::selection{background:var(--accent); color:var(--colour-ink)}
.panel--dark ::selection, .panel--posters ::selection,
.panel--ending ::selection, .panel--wall ::selection{color:var(--dark)}
.panel--accent ::selection{background:var(--colour-ink); color:var(--colour)}

/* --- the scrubber, grouped ----------------------------------
   The ticks were one undifferentiated run, so the site read as
   eight equal slides. Extra space after the panels marked
   data-group-end makes the three movements visible in the
   navigation — האמנם · the speculative work · everything after —
   without spending a whole screen on a divider. */
.scrub button.is-groupend{margin-inline-end:14px}

/* --- images resolve out of their word's colour ---------------
   The piece asks whether a colour can stand in for a word where a
   photograph would. The site answers with its loading behaviour:
   every figure on the wall is first the researched colour of a word
   from the poem, and the photograph dissolves in over it.
   Colours are stream tokens — nothing here is picked by taste. */
.wall figure{background:var(--fig-colour, var(--dark))}
.wall--4 figure:nth-child(1){--fig-colour:var(--w-sade)}      /* בשדה     */
.wall--4 figure:nth-child(2){--fig-colour:var(--w-slicha)}    /* בסליחה   */
.wall--4 figure:nth-child(3){--fig-colour:var(--w-holech)}    /* כהלך     */
.wall--4 figure:nth-child(4){--fig-colour:var(--w-yelatef)}   /* ילטף     */
/* the hidden state is set by story.js, never by the stylesheet — a broken
   script must never be able to leave the wall blank */
.wall img{transition:opacity .6s var(--ease)}
@media (prefers-reduced-motion: reduce){
  .wall img{transition:none}
}


/* The marks on a slide carry its colour — the circle around the one number,
   and the + that opens the findings. (The headline does not: see .dim.) */
.foldout summary::before{color:var(--station-ink, var(--accent))}

/* The photograph titles get the same slab as the numbered title above them:
   solid station, white type, the number left outside it. */
.wall figcaption > span:not(.wcap__n){
  background:var(--station-surface, var(--station));
  color:var(--colour-ink);
  padding:.26em .55em .22em;
  text-shadow:none;
}
.wcap__n{opacity:.75; text-shadow:0 1px 14px rgba(var(--ink-rgb),.9)}

/* A marked sentence: the same slab as the numbered title, but following the
   text line by line (box-decoration-break) so it reads as a mark over a
   sentence rather than a box around a paragraph. */
mark{
  background:var(--station-surface, var(--station));
  color:var(--colour-ink);
  padding:.14em .36em;
  box-decoration-break:clone; -webkit-box-decoration-break:clone;
}

/* the link's rule takes the slide's colour too, instead of the site accent */
.cta a{text-decoration-color:var(--station-ink, var(--accent))}
.cta a:hover{color:var(--station-ink, var(--accent))}
.golink a:hover{color:var(--station-ink, var(--accent))}

/* The languages a piece is built in carry the slide's colour — it is the one
   line on the panel that is purely about the code. Timecodes and dates keep
   the neutral .meta__m grey, which is why this has its own class. */
.meta__stack{color:var(--station-ink, var(--ink-3)); opacity:1}

/* The closing line takes the colour as type, not as a slab — a coloured
   sentence where the marks elsewhere are filled. It is the last thing read on
   the panel, so it carries the colour without carrying a block. */
.posterwall__text .bigquote{
  color:var(--dark-ink);   /* white again, Lee's call: over full-colour posters
                              the tinted version lost the line */
  background:none;
}

/* The name of the film playing, and the heading over the library — both are
   names, so both take the filled slab like every other title on the site.
   Set in CSS rather than markup because story.js rewrites the film name as
   text when you pick a different film. */
.stage .meta__t,
.lib__h{
  display:inline-block;
  background:var(--station-surface, var(--station));
  color:var(--colour-ink);
  padding:.24em .55em .2em;
}

/* the closing paragraph: the last thing read before the email */
.closing{
  max-width:52ch; margin-inline:auto; margin-bottom:calc(var(--stack) * .22);
  font-size:var(--t-body); line-height:1.45; color:var(--ink-2); font-weight:400;
}
html[dir="rtl"] .closing{max-width:40ch; line-height:1.75}

/* ============ opening, variant A: type only ============
   Reached with ?hero=type. No photograph: the site's argument is that she
   designs and builds, so the opening is set type and structure, and the
   photographs start on the next slide where they are evidence. */
html.hero-type .panel--hero{
  background:linear-gradient(168deg,
    color-mix(in oklab, var(--station) 13%, var(--panel)) 0%, var(--panel) 62%);
  color:var(--ink);
  justify-content:center;
}
html.hero-type .hero__img{display:none}
html.hero-type .hero__text{
  background:none;
  padding-inline:var(--pad);
  padding-block:0;
}
html.hero-type .hero__text .kicker{color:var(--ink-3)}
html.hero-type .hero__text .sub{display:none}          /* thirty-three words was the problem */
html.hero-type .hero__text .display{
  font-size:clamp(2.4rem, 1.1rem + 4.6vw, 5.2rem);
  max-width:20ch; color:var(--ink);
}
html.hero-type .hero__text .advance{color:var(--ink-3); padding-top:2.6rem}

/* the line that hands the visitor over: colour as type, no slab — the same
   treatment as the closing line on the posters panel */
.closing__line{
  max-width:48ch; margin-inline:auto; margin-bottom:calc(var(--stack) * .35);
  color:var(--ink);   /* not the accent: the red read as unrelated to the page */
  font-size:var(--t-body); line-height:1.42;
}
html[dir="rtl"] .closing__line{max-width:38ch; line-height:1.7}

/* The three verbs of making, set in the code face — the same mono the
   colophon and the numbers use. Mono runs wider and sits high, so it is
   scaled down and nudged to keep the baseline honest. In Hebrew the mono has
   no glyphs, so those words take the serif instead: a different voice, same
   idea. */
.mono-word{
  font-family:var(--mono); font-weight:400;
  font-size:.82em; letter-spacing:-.02em;
}
/* In Hebrew the headline is already the serif, so swapping to serif changed
   nothing — the second voice there has to be the grotesque. Mono stays a
   Latin-only convention; Hebrew gets two voices instead of three. */
html[dir="rtl"] .mono-word{
  font-family:var(--sans); font-weight:500;
  font-size:.92em; letter-spacing:-.01em;
}

/* ============ hybrid typography ============
   Three faces, and each one means something:
     sans  (Inter)             — the designed thing
     serif (Frank Ruhl Libre)  — the words, the poem, the research
     mono  (JetBrains Mono)    — the code, the instrument
   So a sentence can carry the argument in its type: the verbs of making are
   mono in the headline, and each noun below is set in the face of its own
   discipline. Hebrew has no mono glyphs, so there mono becomes the serif —
   two voices instead of three, same idea. */
.t-sans{font-family:var(--sans)}
.t-serif{font-family:var(--serif); font-size:1.06em}
.t-mono{font-family:var(--mono); font-size:.88em; letter-spacing:-.01em}
html[dir="rtl"] .t-mono{font-family:var(--sans); font-size:.95em; letter-spacing:-.01em; font-weight:500}
html[dir="rtl"] .t-sans{font-family:var(--sans)}
html[dir="rtl"] .t-serif{font-family:var(--serif); font-size:1.02em}

.nouns{
  margin:var(--stack) 0 0; font-size:var(--t-lead); color:var(--ink-2);
  letter-spacing:-.01em;
}
html.hero-type .hero__text .nouns{color:var(--ink-2)}

/* ============ THE INDEX ============
   It was a floating list of chapter names with empty squares beside them,
   which read as an unfilled form, and the panel behind bled through it.
   It is a table of contents now: opaque ink, one row per slide, ruled, with
   each slide's own colour standing at the head of its row. */
.sheet{
  background:var(--ink);   /* opaque: at 98.5% the slide behind still read through */
  display:grid; place-content:stretch; place-items:center;
  padding:clamp(1.5rem,6vh,5rem) clamp(1rem,5vw,3rem);
}
.sheet__inner{
  display:block; width:100%; max-width:40rem; padding:0;
  align-self:center;
}
.sheet__inner::before{
  content:"Index"; display:block;
  font-family:var(--mono); font-size:.68rem; letter-spacing:.18em; text-transform:uppercase;
  color:rgba(var(--paper-rgb),.42); padding-bottom:.9rem;
  border-bottom:1px solid rgba(var(--paper-rgb),.16);
}
.sheet__inner button{
  display:flex; align-items:baseline; gap:1.1rem; width:100%;
  padding:.62rem .2rem; margin:0;
  font-size:clamp(.92rem,.82rem + .35vw,1.06rem); font-weight:500; letter-spacing:-.01em;
  color:rgba(var(--paper-rgb),.62);
  border-bottom:1px solid rgba(var(--paper-rgb),.12);
  transition:color var(--fast) var(--ease), padding-inline-start var(--fast) var(--ease);
}
/* the slide's colour, standing at the head of its row */
.sheet__inner button::before{
  content:""; flex:none; width:3px; align-self:stretch;
  background:var(--seg); opacity:.55;
  transition:opacity var(--fast) var(--ease), width var(--fast) var(--ease);
}
.sheet__inner button:hover,
.sheet__inner button:focus-visible{color:var(--panel); padding-inline-start:.6rem}
.sheet__inner button:hover::before,
.sheet__inner button:focus-visible::before{opacity:1; width:5px}
.sheet__inner button[aria-current="true"]{color:var(--panel)}
.sheet__inner button[aria-current="true"]::before{opacity:1; width:5px}
.sheet__inner .n{
  font-family:var(--mono); font-size:.72em; color:rgba(var(--paper-rgb),.42);
  min-width:2.4em;
}
.sheet__inner .t{flex:none}
/* the piece the claim is evidenced by, riding quietly behind it */
.sheet__inner .p{
  flex:1; text-align:start;
  font-size:.82em; font-weight:400; letter-spacing:0;
  color:rgba(var(--paper-rgb),.34);
}
.sheet__inner button:hover .p,
.sheet__inner button[aria-current="true"] .p{color:rgba(var(--paper-rgb),.52)}
.sheet__inner::after{
  content:"Esc to close"; display:block;
  font-family:var(--mono); font-size:.62rem; letter-spacing:.14em; text-transform:uppercase;
  color:rgba(var(--paper-rgb),.3); padding-top:1.1rem;
}

/* The poster wall shows at full colour — the veil was dimming the work to make
   room for type, which is backwards on the one panel whose images are the
   point. The closing line carries its own shadow instead. */
.panel--posters .posterwall video{opacity:1; filter:none}
.posterwall__text{background:linear-gradient(to top,
  rgba(var(--ink-rgb),.92) 0%, rgba(var(--ink-rgb),.72) 46%, rgba(var(--ink-rgb),0) 100%)}
.posterwall__text .bigquote{color:var(--dark-ink); text-shadow:0 1px 3px rgba(var(--ink-rgb),.95), 0 2px 26px rgba(var(--ink-rgb),.85)}

/* 3. On the wine panel the slab and the surface were the same colour, so the
   title had nothing to sit on. Inverted there: paper surface, wine type. */
.panel--accent .kicker > span:not(.num):not(.kick__proj){
  background:var(--colour-ink);
  color:var(--colour);
}

/* No orphans: the browser balances the last lines instead of dropping a single
   word onto its own. The final two words are also joined with a non-breaking
   space in the markup, so it holds in browsers without text-wrap: pretty. */
p, .display, .lead, .closing, .closing__line, .pw-body, .body p, .step__d, .findings li{
  text-wrap:pretty;
}

/* ============ the type tuner (only visible with ?tune) ============ */
#tuner{
  position:fixed; top:1rem; inset-inline-end:1rem; z-index:200;
  width:19rem; max-height:92vh; overflow:auto;
  background:#141310; color:#e9e5de; border:1px solid #2e2a24;
  font-family:var(--mono); font-size:11px; line-height:1.5;
  padding:.7rem .8rem 0.8rem; border-radius:3px;
  box-shadow:0 18px 60px rgba(0,0,0,.45);
}
#tuner.is-min > *:not(header){display:none}
#tuner header{
  display:flex; justify-content:space-between; align-items:center;
  font-size:10px; letter-spacing:.16em; text-transform:uppercase;
  color:#8d867a; padding-bottom:.6rem; border-bottom:1px solid #2e2a24; margin-bottom:.6rem;
}
#tuner header button{background:none;border:0;color:#8d867a;font-size:15px;cursor:pointer;padding:0 .2rem}
#tuner .row{display:grid; grid-template-columns:4.6rem 1fr 3.4rem; gap:.5rem; align-items:center; margin:.42rem 0}
#tuner .row > span:first-child{color:#8d867a}
#tuner select{width:100%; background:#1e1c18; color:#e9e5de; border:1px solid #34302a;
  font:inherit; padding:.25rem; border-radius:2px}
#tuner input[type=range]{width:100%; accent-color:#C88840}
#tuner .row b{font-weight:400; color:#C88840; text-align:end}
#tuner .fam{background:#1e1c18; color:#e9e5de; border:1px solid #34302a; font:inherit;
  padding:.2rem .4rem; margin-inline-end:.25rem; cursor:pointer; border-radius:2px}
#tuner .fam:hover{border-color:#C88840}
#tuner textarea{width:100%; margin-top:.6rem; background:#0f0e0c; color:#b9b2a6;
  border:1px solid #2e2a24; font:inherit; font-size:10px; padding:.5rem; border-radius:2px; resize:vertical}
#tuner .btns{display:flex; gap:.4rem; margin-top:.5rem}
#tuner .btns button{flex:1; background:#C88840; color:#141310; border:0; font:inherit;
  padding:.4rem; cursor:pointer; border-radius:2px}
#tuner .btns button.ghost{background:none; color:#8d867a; border:1px solid #34302a}

/* ============================================================
   Lee's typography, set in the tuner on the closing slide.
   The kicker rules are scoped to that panel: they were judged
   while looking at CONTACT, and unscoped they would resize the
   title row on all eight slides.
   ============================================================ */
.closing{
  line-height:1.56;
  font-size:1.01rem;
  letter-spacing:0.07em;
  font-weight:500;
  max-width:62ch;
  font-family:var(--sans);
}
.closing__line{
  font-size:1.2rem;
  line-height:1.48;
  letter-spacing:0.025em;
  font-weight:600;
  max-width:65ch;
  margin-bottom:2.8rem;
  font-family:var(--sans);
}
.contact{line-height:2.4}
.colophon{font-size:1.15rem}
.panel--contact .display{
  max-width:29ch;
  font-weight:400;
  font-size:1.28rem;
  letter-spacing:0.03em;   /* Lee's size and tracking kept; the face goes back to
                              the site's sans — mono is for numbers, labels and
                              the colophon, never for display type */
}
.panel--contact .kicker{line-height:1.73; font-size:2.02rem}
.panel--contact .kicker > span:not(.num):not(.kick__proj){font-size:0.89rem}


/* ============================================================
   MOBILE — the vertical edition.            2026-08-31
   ------------------------------------------------------------
   Lee's call: the phone should behave like the web version —
   you scroll, and the slide SWAPS. Not one endless column.
   So: every slide is at least one screen tall and snaps at its
   own edge. The three slides that hold more than a phone screen
   (03 the process, 04 sensitiveinjection, 07 contact) are left
   taller on purpose — you scroll through them and the next
   slide clicks in at the boundary. Nothing is cut.

   ⚠ THIS BLOCK IS LAST IN THE FILE ON PURPOSE.
   story.css still carries the duplicated region (272–1155 is
   repeated at ~1160–2050, the old mobile fallback included) and
   the per-panel #pN washes sit near the end. Appending here is
   the only position that cannot lose a specificity or order
   race to either of them. When the dedupe pass finally happens,
   keep this block at the bottom.
   ============================================================ */
/* The close button is mobile-only furniture; story.js always builds it. */
.sheet__close{display:none}

@media (max-width: 48rem), (pointer: coarse) and (max-width: 60rem){

  /* ---- 1 · the mechanism: one slide per screen, snap per edge ---- */
  /* The snap container is the viewport. A panel taller than the
     screen is a snap AREA larger than the snapport, which the spec
     lets you rest anywhere inside — that is what buys "scroll
     through it, then swap" without trapping the middle. */
  html{scroll-snap-type:y mandatory; scroll-behavior:smooth}
  body{overflow:auto}

  .strip{position:static; display:block; width:auto; height:auto; overflow:visible}

  .panel{
    position:static; width:100%; height:auto;
    min-height:100svh;
    scroll-snap-align:start;
    scroll-snap-stop:always;           /* one slide per gesture — no skipping */
    transform:none !important; visibility:visible !important; transition:none;
    border-right:0; border-bottom:0;
    /* top clears the chrome, bottom clears the station bar */
    padding:4.9rem var(--pad) 4rem;
  }
  html[dir="rtl"] .panel{border-left:0}

  .scrub{display:none}
  .advance{display:none}
  /* the floating email overprinted body copy on every slide, and on the
     closing slide it sat 20px under the real one. The contact slide owns it. */
  .mailline{display:none}

  /* ---- 2 · the chrome stops printing over the type ---- */
  /* It was transparent with mix-blend-mode:difference, so it collided with
     whatever scrolled under it. On a scrolling page it needs a ground. */
  .chrome{
    /* The scrubber is hidden here, so it is no longer a grid item — which let
       .chrome__right auto-place into the middle "auto" column and sit in the
       middle of the header. Its justify-self:end was aligning to the end of
       the WRONG column. Two columns on the phone: name, then controls, hard
       right against the padding. */
    grid-template-columns:1fr auto;
    mix-blend-mode:normal;
    background:rgba(var(--panel-rgb),.90);
    -webkit-backdrop-filter:blur(12px) saturate(1.08);
    backdrop-filter:blur(12px) saturate(1.08);
    border-bottom:1px solid var(--line);
    padding:.8rem var(--pad);
  }
  .chrome, .chrome a, .chrome .btn, .chrome__name{color:var(--ink)}
  html.on-dark .chrome{
    background:rgba(var(--dark-rgb),.86);
    border-bottom-color:rgba(var(--paper-rgb),.14);
  }
  html.on-dark .chrome, html.on-dark .chrome a,
  html.on-dark .chrome .btn, html.on-dark .chrome__name{color:rgba(var(--paper-rgb),.92)}
  html.on-accent .chrome{
    background:rgba(var(--colour-rgb),.90);
    border-bottom-color:rgba(var(--paper-rgb),.18);
  }
  html.on-accent .chrome, html.on-accent .chrome a,
  html.on-accent .chrome .btn, html.on-accent .chrome__name{color:rgba(var(--paper-rgb),.94)}

  /* ---- 3 · the station bar keeps its look, gains a thumb ---- */
  /* The mark stays a hairline; only the hit area grows. */
  .stations{height:auto; align-items:flex-end}
  .stations button{height:.55rem; padding:2rem 0 .5rem}
  .stations button::before{height:2px}
  .stations button[aria-current="true"]::before{height:5px}

  /* ---- 4 · slides 02 and 05: media band, then words ---- */
  /* Both were full-bleed media with the text absolutely floated on a scrim.
     That works on a wide screen. On a phone the text block is over half the
     panel, so it landed on faces and pale photographs, and slide 02's
     second row of figcaptions (top:4.6rem inside each figure) printed
     straight across the title slab. On mobile the media becomes a band and
     the words sit on the panel's own dark ground — legible, no scrim needed. */
  .panel--wall, .panel--posters{
    position:relative; overflow:visible;
    display:flex; flex-direction:column; justify-content:flex-start;
    padding:4.9rem 0 4rem; min-height:100svh;
  }
  .panel--wall{padding-bottom:3.4rem}
  .panel--posters{padding-bottom:3.4rem}
  .wall, .posterwall{
    position:relative; inset:auto;
    flex:0 0 auto; height:30svh;
  }
  /* 2 x 2. The rows must be explicit: with auto rows the second pair sized
     to its own content and fell outside the band, so figures 03 and 04 (the
     archive swipe and the book spread) were simply not on the phone. */
  .wall--4{grid-template-columns:repeat(2,1fr); grid-template-rows:repeat(2,1fr); height:33svh}
  /* captions belong to their own figure again */
  .wall figcaption{top:auto; bottom:0; padding:.45rem .6rem; font-size:.62rem}
  /* the scrim existed to rescue type off the photographs; the type has left */
  .wall::after{
    background:linear-gradient(to top, rgba(var(--ink-rgb),.55) 0%, rgba(var(--ink-rgb),0) 42%);
  }
  .wall__text, .posterwall__text{
    position:relative; inset:auto; margin-top:0; z-index:2;
    flex:1 1 auto; display:flex; flex-direction:column; justify-content:center;
    background:none; padding:1.15rem var(--pad) 0;
  }
  .wall__text .kicker, .posterwall__text .kicker{margin-bottom:.35rem; gap:.4em .75em}
  /* shadows were doing the scrim's job — on a flat dark ground they only muddy */
  .wall__text .display, .wall__text .pw-body, .wall__text .kicker,
  .posterwall__text .display, .posterwall__text .pw-body,
  .posterwall__text .bigquote{text-shadow:none}
  .posterwall{grid-template-columns:repeat(3,1fr); height:26svh}
  /* 05 carries the longest paragraph on the site; a hair off the body size is
     what lands the whole slide on one screen without touching the display type */
  .posterwall__text .pw-body{font-size:calc(var(--t-body) * .95); margin-top:.4rem}
  .posterwall__text .bigquote{margin-top:.35em}
  .wall__text .pw-body, .posterwall__text .pw-body{max-width:none}
  .foldout--onwall{margin-top:.7rem}

  /* ---- 5 · slide 06: the film library becomes a real swipe row ---- */
  /* .lib already asked for flex-direction:row + overflow-x:auto at ≤64rem,
     but nothing capped its width, so it laid out 1598px wide and — because
     .library is align-self:center — centred at x:-611. Eight of eleven films
     sat off-screen with no way to reach them. Capping the width is the fix;
     the row then scrolls as intended, bleeding to both edges like a shelf. */
  .panel--motion{padding:4.9rem var(--pad) 4rem}
  .library{align-self:stretch; width:100%; max-width:100%; min-width:0}
  .lib{
    /* width:auto (not 100%) so the negative margins on BOTH sides widen the
       row to the full screen — with width:100% it only bled to the left. */
    width:auto; max-width:none;
    margin-inline:calc(var(--pad) * -1);
    padding-inline:var(--pad);
    padding-block:.2rem;
    scroll-padding-inline:var(--pad);
    overscroll-behavior-x:contain;
  }
  .lib__item{width:9.5rem}
  /* the caption and the library heading were 2px apart and read as one block */
  .stage .meta{margin-bottom:0}
  .lib__h{margin:1.6rem 0 .6rem}
  .stage__plate video{max-height:38svh}

  /* ---- 6 · slide 04: the live piece has to be usable, not cropped ---- */
  /* The frame was 305×520 showing a 280px sidebar + a 25px chat column.
     sensitiveinjection/index.html now collapses its sidebar under 700px,
     the same thing Gemini itself does on a phone, so the frame shows the
     conversation at full width and you can actually type into it. */
  .sketchframe{height:min(66svh,32rem)}
  .sketchwrap{margin-top:calc(var(--stack) * .9)}

  /* ---- 7 · the index sheet: fits, and can be closed by thumb ---- */
  /* The project column ran to 455px inside a 375px sheet ("sensitiveinjection"
     showed as "ser"), and the only way out was "ESC TO CLOSE" — a key a phone
     does not have. STRUCTURE.md rule 3: a visible affordance for every control. */
  /* The rows are flex and .t is flex:none, so the title pushed the project
     name off the sheet — "sensitiveinjection" ran to 459px inside 375. Let
     the row wrap and give the project its own line, indented under the title. */
  .sheet__inner button{flex-wrap:wrap; gap:.15rem .9rem; padding-block:.7rem}
  .sheet__inner .t{flex:1 1 auto; min-width:0}
  .sheet__inner .p{flex:1 0 100%; padding-inline-start:calc(2.4em + .9rem); font-size:.76em}
  /* the Esc hint is desktop's affordance; the phone gets the button below */
  .sheet__inner::after{display:none}
  .sheet__close{
    display:block; margin:1.6rem auto 0;
    background:none; border:1px solid rgba(var(--paper-rgb),.3); border-radius:2px;
    color:rgba(var(--paper-rgb),.8); font:inherit;
    font-family:var(--mono); font-size:.78rem; letter-spacing:.14em; text-transform:uppercase;
    padding:.7rem 1.6rem; cursor:pointer;
  }

  /* ---- 8 · the opening fills the screen ---- */
  .panel--hero{min-height:100svh}
}

