/* ============================================================
   Ilse Marchand — sound & architecture
   Newsreader (essay, titles) + Spline Sans Mono (measurements)
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;1,6..72,300;1,6..72,400&family=Spline+Sans+Mono:wght@400;500&display=swap');

:root{
  --paper:#ECEDEA;
  --ink:#1A1C1B;
  --muted:#5C615D;
  --quiet:#616661;      /* AA-passing secondary (4.99:1 on paper) */
  --rule:#CBCEC8;
  --cue:#2A5648;

  --serif:"Newsreader","Iowan Old Style",Georgia,serif;
  --mono:"Spline Sans Mono",ui-monospace,"SF Mono",Menlo,monospace;

  --nav-w:13rem;
  --essay-w:22rem;
  --pad:2.25rem;
  --gutter:4rem;

  --t:340ms cubic-bezier(.2,.6,.2,1);
}

@media (prefers-color-scheme:dark){
  :root{
    --paper:#131412;
    --ink:#E8E9E4;
    --muted:#9CA199;
    --quiet:#868B84;
    --rule:#34362F;
    --cue:#8FC7B0;
  }
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}

body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--serif);
  font-optical-sizing:auto;
  font-size:1.0625rem;
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
}

a{color:inherit;text-decoration:none}
img{max-width:100%;display:block}

.mono{
  font-family:var(--mono);
  font-size:.75rem;
  line-height:1.5;
}

.skip{position:absolute;left:-9999px;top:0;background:var(--ink);color:var(--paper);padding:.6rem 1rem;z-index:60}
.skip:focus{left:.5rem;top:.5rem}

:focus-visible{outline:1.5px solid var(--cue);outline-offset:3px}
.plate:focus{outline:none}
.plate:focus-visible{outline:1.5px solid var(--cue);outline-offset:6px}

/* ============================================================
   Shell
   ============================================================ */

.shell{
  display:grid;
  grid-template-columns:var(--nav-w) minmax(0,1fr) var(--essay-w);
  gap:var(--gutter);
  align-items:start;
  padding:var(--pad) var(--pad) 8rem;
  max-width:112rem;
  margin:0 auto;
}

/* ---------- left index ---------- */

.index{position:sticky;top:var(--pad);align-self:start;font-size:.9375rem;line-height:1.45}
.index__name{font-style:italic;font-weight:300;margin:0 0 1.6em;font-size:1rem}
.index__toggle{display:none}
.index ul{list-style:none;margin:0 0 1.6em;padding:0}
.index li{display:grid;grid-template-columns:1fr auto;gap:.5rem;align-items:baseline}

.index a{display:block;padding:.05em 0;color:var(--muted)}
.index a:hover{color:var(--ink)}
.index [aria-current="page"]{color:var(--ink)}

/* year sits with the title so the index scales past a handful of works */
.index__yr{color:var(--muted);font-family:var(--mono);font-size:.625rem;letter-spacing:.06em;font-variant-numeric:tabular-nums}

/* unbuilt pages: legible, and labelled in words, not only colour */
.index__stub{color:var(--muted);cursor:default}
.index__legend{color:var(--quiet);font-family:var(--mono);font-size:.6875rem;line-height:1.5;margin:-.9em 0 1.6em;max-width:11rem}

.index__counter{
  color:var(--muted);border-top:1px solid var(--rule);
  padding-top:.7em;margin-top:2.2em;font-variant-numeric:tabular-nums;
}
.index__counter b{font-weight:500;color:var(--cue)}

/* ---------- centre ---------- */

.plates{min-width:0}

.masthead{margin:0 0 3.5rem}
.masthead h1{
  font-size:clamp(2.1rem,4.2vw,3.4rem);
  font-weight:300;font-style:italic;line-height:1.02;
  margin:0 0 .5rem;letter-spacing:-.01em;
}
.masthead__venue{margin:0 0 1.4rem;font-size:1rem}

.specs{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(8rem,1fr));
  gap:.4rem 1.5rem;
  border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);
  padding:.7rem 0;color:var(--muted);max-width:44rem;
}
.specs div span{display:block;color:var(--ink)}

.plate{margin:0 0 3.25rem;scroll-margin-top:var(--pad)}

.plate__frame{position:relative;background:#DCDDD9;overflow:hidden;border:1px solid var(--rule)}
.plate--void .plate__frame::after{
  content:"";position:absolute;inset:0;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/></filter><rect width='120' height='120' filter='url(%23n)' opacity='.35'/></svg>");
  mix-blend-mode:multiply;opacity:.18;pointer-events:none;
}
/* a portrait-shot photo (phone documentation, not a wide slide) must never dominate the
   page the way a normal landscape plate does — cap it to a screenful and letterbox rather
   than stretch: width:100% + a max-height together do not preserve ratio without this */
.plate__frame > img{display:block;width:100%;height:auto;max-height:72vh;object-fit:contain;margin:0 auto}

/* documentation clips: silent, looping, playing only while in view — never a surprise */
.plate__video{display:block;width:100%;height:auto;max-height:72vh;object-fit:contain;margin:0 auto;background:var(--paper)}
.plate__playtoggle{
  position:absolute;right:.6rem;bottom:.6rem;
  background:color-mix(in srgb, var(--paper) 80%, transparent);
  border:1px solid var(--rule);color:var(--ink);
  padding:.3rem .65rem;cursor:pointer;
  font-family:var(--mono);font-size:.6875rem;
}
.plate__playtoggle:hover{border-color:var(--quiet)}
.plate__playtoggle[aria-pressed="true"]{opacity:.5}
.plate__frame:hover .plate__playtoggle,
.plate__playtoggle:focus-visible{opacity:1}
.plate__frame > i{
  display:block;aspect-ratio:var(--ar,3/2);
  background:
    radial-gradient(120% 90% at var(--x,30%) var(--y,15%), var(--hi,#F4F4F1) 0%, transparent 60%),
    linear-gradient(var(--ang,168deg), var(--a,#C8CAC4) 0%, var(--b,#9EA29B) 55%, var(--c,#7C807A) 100%);
}

/* The caption is a plate label, not body copy — the narrative lives in the essay
   column, so this stays to one quiet line and lets the images carry the page. */
.plate__caption{
  margin:.6rem 0 0;display:grid;
  grid-template-columns:2.6rem 1fr auto;gap:0 .75rem;
  align-items:baseline;max-width:44rem;
}
.plate__no{color:var(--muted);font-variant-numeric:tabular-nums}
.plate__text{margin:0;font-size:.9375rem;color:var(--muted)}
.plate__text cite{font-style:italic;font-weight:300}
.plate[data-cued="true"] .plate__no{color:var(--cue)}

/* a plate standing in for something not shown: NDA, unbuilt, or not photographed */
.plate--void .plate__frame > i{
  background:linear-gradient(168deg,#D5D7D1 0%,#BFC2BB 55%,#A9ACA5 100%);
}
.plate--void .plate__frame > i{width:100%}
.plate--void .plate__frame > span{
  position:absolute;inset:0;display:grid;place-items:center;
  color:#4A4E4A;text-align:center;padding:0 2rem;
  font-family:var(--mono);font-size:.8125rem;line-height:1.7;
}

/* ---------- lightbox: these plates are documents, they have to be readable ---------- */
.plate__frame img{cursor:zoom-in}
.lb{
  position:fixed;inset:0;z-index:100;display:grid;place-items:center;
  background:color-mix(in srgb, var(--paper) 94%, #000);
  padding:2.5rem 1.25rem 4rem;
}
.lb[hidden]{display:none}
.lb img{max-width:100%;max-height:100%;object-fit:contain;border:1px solid var(--rule)}
.lb__cap{
  position:absolute;left:1.25rem;right:1.25rem;bottom:1.4rem;
  display:flex;gap:1rem;justify-content:space-between;align-items:baseline;
  color:var(--muted);
}
.lb__close{
  background:none;border:0;padding:.2rem .1rem;color:var(--ink);cursor:pointer;
  font-family:var(--mono);font-size:.6875rem;
  border-bottom:1px solid var(--quiet);
}

/* principles — his own four, used as a real tag on each project */
.tags{display:flex;flex-wrap:wrap;gap:.35rem .9rem;margin:0;padding:0;list-style:none;color:var(--muted)}

/* a quote from someone who used or assessed the work */
.pull{
  margin:0 0 4.5rem;max-width:38rem;
  border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:1.6rem 0;
}
.pull blockquote{margin:0;font-size:1.25rem;line-height:1.4;font-weight:300;text-wrap:pretty}
.pull figcaption{margin:.9rem 0 0;color:var(--muted)}

/* text-led page (research, writing) — no plate column */
.doc{max-width:38rem}
.doc h2{font-size:1.35rem;font-weight:300;font-style:italic;margin:2.8rem 0 .6rem}
.doc p{margin:0 0 1.1em;text-wrap:pretty}
.doc ul{margin:0 0 1.3em;padding-left:1.1rem}
.doc li{margin:0 0 .35em}

/* mobile-only jump from a plate to the paragraph about it */
.plate__note{display:none;color:var(--muted);border-bottom:1px solid var(--quiet);background:none;border-width:0 0 1px;font-family:var(--mono);font-size:.6875rem;padding:0;cursor:pointer}

/* ---------- right: essay ---------- */

.essay{
  min-width:0;font-size:.9375rem;line-height:1.62;
  position:sticky;top:var(--pad);align-self:start;
  max-height:calc(100vh - var(--pad) * 2);
  overflow-y:auto;overscroll-behavior:contain;
  scrollbar-width:thin;scrollbar-color:var(--rule) transparent;
  padding-left:1rem;margin-left:-1rem;width:100%;
  padding-bottom:2.5rem;
}
.essay > h2{
  font-family:var(--mono);font-size:.75rem;
  color:var(--muted);font-weight:400;margin:0 0 1.6em;
}
.essay p{margin:0 0 1.15em;text-wrap:pretty}

.essay p[data-cue]{
  border-left:1px solid transparent;
  padding-left:1rem;margin-left:-1rem;width:100%;
  transition:border-color var(--t),color var(--t);
  color:var(--muted);
}
.essay p[data-cue][data-cued="true"]{border-left-color:var(--cue);color:var(--ink)}
.no-js .essay p[data-cue],
.essay:not([data-live]) p[data-cue]{color:var(--ink)}

.cue{
  /* a button that must wrap like the running text around it */
  display:inline;text-align:inherit;
  font:inherit;background:none;border:0;padding:0;margin:0;
  font-style:italic;color:inherit;cursor:pointer;
  border-bottom:1px solid var(--quiet);
}
.cue:hover{border-bottom-color:var(--cue);color:var(--cue)}

.colophon{margin-top:3rem;padding-top:.7rem;border-top:1px solid var(--rule);color:var(--muted)}

/* ============================================================
   Index page — the list previews itself
   ============================================================ */

/* text-wrap:pretty keeps the last line from ending on a single orphaned word,
   at any width — safer than tuning the measure by hand */
.lede{
  font-size:clamp(1.45rem,2.1vw,1.95rem);line-height:1.28;font-weight:300;
  max-width:30ch;margin:0 0 3.5rem;letter-spacing:-.005em;text-wrap:pretty;
}
.lede em{font-style:italic}

.worklist{list-style:none;margin:0;padding:0;max-width:52rem}
.worklist li{border-top:1px solid var(--rule)}
.worklist li:last-child{border-bottom:1px solid var(--rule)}

.worklist a,.worklist .stub{
  display:grid;grid-template-columns:2.6rem 1fr 10rem 3.5rem;gap:1rem;
  align-items:baseline;padding:.95rem 0;
}
.worklist a:hover cite,.worklist a:focus-visible cite{color:var(--cue)}
.worklist .stub{color:var(--muted)}
.worklist cite{font-style:italic;font-weight:300;font-size:1.35rem;line-height:1.1}
.worklist .m,.worklist .no{color:var(--muted)}
.worklist .stub .m{color:var(--muted)}

.preview{position:sticky;top:var(--pad)}
.preview__frame{position:relative;background:#DCDDD9;overflow:hidden;border:1px solid var(--rule)}
.preview__frame > img{display:block;width:100%;height:auto}
.preview__cap{margin:.7rem 0 0;color:var(--muted)}
.preview__note{margin:2.5rem 0 0;padding-top:.7rem;border-top:1px solid var(--rule);color:var(--quiet)}
.preview__cap b{display:block;color:var(--ink);font-weight:400;font-style:italic;font-family:var(--serif);font-size:.9375rem;letter-spacing:0;text-transform:none;margin-bottom:.15rem}

/* CV */
.prose{max-width:34rem}
.cv{margin:0}
.cv__row{display:grid;grid-template-columns:8.5rem 1fr;gap:.2rem 1.25rem;border-top:1px solid var(--rule);padding:.7rem 0}
.cv__row:last-child{border-bottom:1px solid var(--rule)}
.cv dt{color:var(--muted)}
.cv dd{margin:0}
.cv dd b{font-weight:400}
.cv__note{color:var(--muted);display:block;margin-top:.15em}
.label{font-family:var(--mono);font-size:.75rem;color:var(--muted);font-weight:400;margin:3rem 0 .8rem}

/* ============================================================
   Motion
   ------------------------------------------------------------
   Deliberately almost nothing. Only three things move, and each
   one is load-bearing rather than decorative:

     1. the parallel-read cue (.essay p[data-cue]) — the mechanism
        that ties the essay column to the plate you are looking at
     2. the passcode gate dissolving into the site — a genuine
        change of state between two different screens
     3. scrolling triggered by the reader (cue jumps, essay sync)

   Everything else — the page-load settle, hover nudges on the work
   list, colour fades on nav links, gate field transitions — was cut.
   Those fired constantly during ordinary browsing and added nothing
   but motion. Hover and focus still respond; they just respond now
   instead of easing.
   ============================================================ */

@media (prefers-reduced-motion:reduce){
  *{scroll-behavior:auto !important;animation:none !important;transition:none !important}
}

/* ============================================================
   Responsive
   ============================================================ */

@media (max-width:1180px){
  :root{--gutter:2.5rem;--nav-w:11rem;--essay-w:19rem}
}

@media (max-height:620px){
  .essay{position:static;max-height:none;overflow:visible}
}

@media (max-width:900px){
  :root{--pad:1.25rem}
  .shell{grid-template-columns:1fr;gap:2.5rem;padding-bottom:5rem}

  .index{position:static;border-bottom:1px solid var(--rule);padding-bottom:1rem}
  .index__counter{display:none}
  .index__toggle{
    display:block;width:100%;text-align:left;background:none;border:0;padding:0;
    font-family:var(--mono);font-size:.6875rem;
    color:var(--muted);cursor:pointer;
  }
  .index__toggle::after{content:" +"}
  .index[data-open="true"] .index__toggle::after{content:" —"}
  .index__lists{display:none;padding-top:1.2rem}
  .index[data-open="true"] .index__lists{display:block}
  .index__name{margin-bottom:.9em}

  .essay{position:static;max-height:none;overflow:visible;max-width:40rem;padding-left:0;margin-left:0;width:auto}
  .plate__note{display:inline-block;justify-self:end;align-self:baseline}
  .plate{margin-bottom:3rem}

  /* index number stays in the narrow gutter (col 1); title and metadata stack in col 2,
     so a wrapped title never fights the number or the meta text for space */
  .worklist a,.worklist .stub{grid-template-columns:2.2rem 1fr;row-gap:.2rem;align-items:start}
  .worklist cite,.worklist .m{grid-column:2}
  .worklist cite{margin-top:-.1em}
  .preview{display:none}
  .lede{font-size:1.45rem;max-width:24ch}
}

/* ============================================================
   Passcode Gate
   ============================================================ */

/* Hide the page until unlocked to prevent any content flash. The overture is
   listed alongside .shell because it lives outside it, being full-bleed. */
html:not(.unlocked) .shell,
html:not(.unlocked) #overture {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}

html.unlocked .shell,
html.unlocked #overture {
  opacity: 1;
  visibility: visible;
  transition: opacity 450ms cubic-bezier(.2,.6,.2,1);
}

.gate {
  position: fixed;
  inset: 0;
  z-index: 10000;
  background: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  transition: opacity 400ms cubic-bezier(.2,.6,.2,1), visibility 400ms cubic-bezier(.2,.6,.2,1);
}

html.unlocked .gate {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.gate__card {
  width: 100%;
  max-width: 22rem;
  text-align: center;
  padding: 2.75rem 2rem 2.25rem;
  border: 1px solid var(--rule);
  background: var(--paper);
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.03);
}

.gate__author {
  font-size: 1.45rem;
  font-weight: 300;
  font-style: italic;
  margin: 0 0 0.35rem;
  color: var(--ink);
}

.gate__subtitle {
  color: var(--muted);
  font-size: 0.75rem;
  margin: 0 0 2rem;
}

.gate__form {
  margin: 0 auto;
}

.gate__field {
  display: flex;
  gap: 0.5rem;
  align-items: stretch;
  justify-content: center;
}

.gate__input {
  width: 9.5rem;
  height: 2.75rem;
  padding: 0 0.75rem;
  font-family: var(--mono);
  font-size: 1.25rem;
  letter-spacing: 0.3em;
  text-align: center;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 0;
  outline: none;
  -webkit-appearance: none;
}

.gate__input::placeholder {
  color: var(--rule);
  letter-spacing: 0.2em;
  opacity: 0.8;
}

.gate__input:focus {
  border-color: var(--cue);
  outline: none;
  box-shadow: 0 0 0 1px var(--cue);
}

.gate__submit {
  height: 2.75rem;
  padding: 0 1.15rem;
  background: var(--ink);
  color: var(--paper);
  border: 1px solid var(--ink);
  border-radius: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: 0.75rem;
}

.gate__submit:hover {
  opacity: 0.85;
}

.gate__error {
  min-height: 1.4rem;
  margin: 0.9rem 0 0;
  color: #a33;
  font-family: var(--mono);
  font-size: 0.75rem;
}

@media (prefers-color-scheme: dark) {
  .gate__card {
    box-shadow: 0 4px 30px rgba(0, 0, 0, 0.4);
  }
  .gate__error {
    color: #e57373;
  }
}

.gate__hint {
  color: var(--quiet);
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  margin: 1.75rem 0 0;
}

.gate__input.is-invalid {
  animation: gate-shake 360ms cubic-bezier(.36,.07,.19,.97) both;
  border-color: #a33 !important;
}

@keyframes gate-shake {
  10%, 90% { transform: translate3d(-1px, 0, 0); }
  20%, 80% { transform: translate3d(2px, 0, 0); }
  30%, 50%, 70% { transform: translate3d(-4px, 0, 0); }
  40%, 60% { transform: translate3d(4px, 0, 0); }
}

/* ============================================================
   Overture — the landing page's first screen
   ------------------------------------------------------------
   One viewport, and nothing in it but the mark, a drifting reel
   of paintings, and the way down. The site proper begins one
   scroll later in normal document flow — no scroll-jacking and
   no pinned overlay, so a wheel flick or a tap on End still works.

   Ported from a separate sketch, with two things left behind:

     1. its fonts and its pure-white ground. A Fraunces / Space
        Grotesk hero on #FFF would announce a different site than
        the Newsreader one it reveals a scroll later, so this uses
        the site's own tokens and inherits dark mode for free.
     2. its wireframe placeholder boxes, which read as unfinished
        on a real portfolio.

   What was kept is the mechanic: a slow horizontal drift at mixed
   frame sizes, bottom-aligned on a shared shelf, that stops while
   you hold it.

   Sizing note: only the HEIGHT varies, in four steps. Width follows
   each painting's own aspect ratio, so the reel gets its rhythm from
   a salon hang rather than from cropping — cropping a painting to
   fit a box costs more than it buys.
   ============================================================ */

.overture{
  height:100svh;
  min-height:100svh;
  display:flex;
  flex-direction:column;
  overflow:hidden;
}

/* Same max-width, centring and padding as .shell. Without this the bar spans
   the full window while the shell centres itself inside 112rem, so past that
   width the mark drifts out of line with the column that follows it. */
.overture__bar{
  flex:none;
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:1rem;
  width:100%;
  max-width:112rem;
  margin:0 auto;
  padding:var(--pad) var(--pad) 0;
}
.overture__mark{
  margin:0;
  font-style:italic;
  font-weight:300;
  font-size:1rem;
}
.overture__down{
  font-family:var(--mono);
  font-size:1.5rem;
  color:var(--muted);
  white-space:nowrap;
  line-height:1;
}
.overture__down:hover{color:var(--ink)}

/* ---------- the reel ---------- */

.overture__reel{
  position:relative;
  flex:1 1 auto;
  display:flex;
  align-items:flex-end;
  overflow:hidden;
  min-height:0;
  user-select:none;
  -webkit-user-select:none;
}
.overture__strip{
  display:flex;
  align-items:flex-end;
  width:max-content;
  /* No padding at all. Horizontal padding would land in scrollWidth without
     belonging to the repeating set, and translateX(-50%) would then overshoot
     the loop period by that much and visibly jump at the seam; bottom padding
     left a dead band under the pictures once the frames came off. */
  padding:0;
}

/* the drift needs JS to have cloned the set, or the second half of the
   loop is empty space — so it is gated on both .js and the clone flag */
.js .overture__strip[data-looped="true"]{
  animation:overture-drift 78s linear infinite;
}
.overture__reel[data-held="true"] .overture__strip{animation-play-state:paused}
/* don't composite a 5000px strip while the reader is further down the page */
.overture__reel[data-seen="false"] .overture__strip{animation-play-state:paused}

@keyframes overture-drift{
  from{transform:translateX(0)}
  to{transform:translateX(-50%)}
}

/* ---------- a frame ---------- */

/* No frame, no mount, no gutter: the paintings butt straight up against one
   another and read as one continuous band. They still never overlap — each is
   a flex item at its own width. */
.frame{
  flex:none;
  margin:0;
  padding:0;
}
/* height is the variable; width comes from --ar, so nothing is cropped */
.frame__mount{
  position:relative;
  display:block;
  height:var(--h);
  aspect-ratio:var(--ar);
  width:auto;
}
.frame__mount img{
  width:100%;
  height:100%;
  object-fit:cover;
  display:block;
}

/* four height steps, bottom-aligned: the shelf they stand on is the rhythm */
.frame--t{--h:min(clamp(15rem,34vw,25rem),58svh)}
.frame--l{--h:min(clamp(12rem,26vw,20rem),50svh)}
.frame--m{--h:min(clamp(9rem,19vw,14.5rem),40svh)}
.frame--s{--h:min(clamp(7rem,14vw,11rem),30svh)}

/* On a phone the rem floors above win over the vw terms and each frame fills
   most of the screen, which stops the reel reading as a stream — three frames
   in view is the point of it. Lower the floors rather than the whole scale. */
@media (max-width:640px){
  .frame--t{--h:min(clamp(10rem,46vw,15rem),40svh)}
  .frame--l{--h:min(clamp(8.5rem,38vw,12rem),34svh)}
  .frame--m{--h:min(clamp(6.5rem,29vw,9rem),26svh)}
  .frame--s{--h:min(clamp(5rem,22vw,7rem),20svh)}
}

/* The landing page shows the name in the overture and again in the masthead, so
   the index column's copy is redundant there — but simply removing it shifts the
   whole column up by its height, and since the router swaps .shell in place that
   shift is visible every time you arrive at the index from another page. Keep the
   box, hide the text. Keyed off the overture, which exists only on the landing
   page, so no other page is affected. */
.overture ~ .shell .index__name{visibility:hidden}

/* the site proper starts here — a hairline says so.
   min-height matters: the index's own content is only ~600px tall, so without
   it the document is shorter than overture + viewport and the last ~300px of
   the overture can never be scrolled away — the reveal would never complete. */
.overture + .shell{
  border-top:1px solid var(--rule);
  min-height:100svh;
}

/* with motion off, the reel stops being a marquee and becomes a shelf you
   can push — the global reduce rule already killed the animation */
@media (prefers-reduced-motion:reduce){
  .overture__reel{overflow-x:auto;overscroll-behavior-x:contain}
}
