/* ==== base/tokens.css ==== */
/* ==========================================================================
   A · TOKENS
   --------------------------------------------------------------------------
   The whole palette, one place. Everything below this file in the bundle is
   allowed to assume these exist and is not allowed to invent new ones.

   THE TEXT TOKENS ALL CLEAR WCAG 2.2 AA (4.5:1) against all four page grounds
   — bone, bone-2, #ece0c9, #f3edde. An earlier pass had small text sitting at
   2.3–3.9:1: the topnav, the kickers, tags, map labels and
   signoff were every one of them failing. 0xac is the alpha floor (4.65:1 on
   the darkest ground). Do not reintroduce a lighter alpha for TEXT.

   The rule tokens are separate on purpose. A 1px non-text boundary needs 3:1,
   not 4.5:1, and hairlines set at text contrast look like underlines. Use
   --rule / --rule-2 for borders and separators, never for a glyph.
   ========================================================================== */
:root{
  /* Scroll progress rest state. The engine (main.js) writes --p per .sticky
     stage every frame, but only once it has booted — so on first paint, and on
     any element read before the first tick, a BARE var(--p) is invalid and its
     calc() collapses to the property's initial value. For #hero .germ that
     initial is opacity:1, which flashed the Germania woodcut to a full-strength
     multiply mass (read as "the building flashes black") before snapping to its
     .13 rest. A global 0 default makes every var(--p) resolve to the at-rest
     look until the stage that owns it overrides with a real value. */
  --p:0;

  --bone:#efe7d7;
  --ink:#1b2436;
  --night:#0b1020;

  /* text */
  --ink-70:#1b2436b3;       /* editorial body — 5.29:1 */
  --ink-60:#1b2436b8;       /* 5.33:1 */
  --ink-55:#1b2436b0;       /* 4.86:1 */
  --ink-45:#1b2436ac;       /* 4.65:1 — smallest type on the page */
  --ink-40:#1b2436ac;       /* 4.65:1 */

  /* non-text */
  --rule:#1b243638;
  --rule-2:#1b243673;
  --ink-22:#1b243638;       /* deprecated alias of --rule */

  --bone-2:#e7dcc7;
  --oxblood:#8a3324;
  --gold:#e9c46a;

  --mono:"iA Writer Mono S",monospace;
  --body:"Amberes Grotesk",sans-serif;

  --display:"Neutical","Iowan Old Style",Palatino,Georgia,serif;

  --pad:8vw;
  --mx:0; --my:0;           /* pointer, -1..1, written by the engine */

  /* THE RAIL GUTTER — now permanently 0, and kept only as a name.

     It used to be the width of the column the fixed chapter rail owned: the
     rail was position:fixed, so it was outside flow and content knew nothing
     about it, and between about 820 and 1180px it landed inside live text —
     the contact address, the menu prices, the origin paragraph. Reserving a
     92/114px lane on the right was the fix.

     The rail is gone, so the lane is too, and every right-hand inset now
     matches its left-hand partner: the page is symmetrical again and the
     editorial frame centres in the whole viewport rather than in what was left
     of it. The three names below are load-bearing across a dozen section
     stylesheets, so the token stays at 0 rather than being deleted — one line
     to re-open a right-hand lane if anything ever needs one again. */
  --rail-gutter:0px;
  --pad-r:calc(var(--pad) + var(--rail-gutter));

  /* THE EDITORIAL FRAME — ordinary left- or right-aligned narrative shares one
     1180px frame, centred in the viewport. Below that width the familiar --pad
     inset still wins; centred cards, captions and stage furniture continue to
     use --pad / --pad-r instead. */
  --content-max:1180px;
  --frame-start:max(var(--pad),calc((100vw - var(--rail-gutter) - var(--content-max))/2));
  --frame-end:calc(var(--frame-start) + var(--rail-gutter));
}


/* ==== base/fonts.css ==== */
/* MUSE: display (Neutical), body (Amberes Grotesk) and utility (iA Writer Mono S). */
/* Neutical (Heinzel Std), the display serif from site-v9 on: regular and
   italic for headings and lines, light and light italic for the largest
   sizes where the regular reads a touch heavy. */
@font-face{
  font-family:"Neutical";font-weight:400;font-style:normal;font-display:swap;
  src:url("/site-tests/site-v9/fonts/neutical-regular.woff2") format("woff2");
}
@font-face{
  font-family:"Neutical";font-weight:400;font-style:italic;font-display:swap;
  src:url("/site-tests/site-v9/fonts/neutical-italic.woff2") format("woff2");
}
@font-face{
  font-family:"Neutical";font-weight:300;font-style:normal;font-display:swap;
  src:url("/site-tests/site-v9/fonts/neutical-light.woff2") format("woff2");
}
@font-face{
  font-family:"Neutical";font-weight:300;font-style:italic;font-display:swap;
  src:url("/site-tests/site-v9/fonts/neutical-light-italic.woff2") format("woff2");
}
@font-face{
  font-family:"Amberes Grotesk";font-weight:300;font-style:normal;font-display:swap;
  src:url("/site-tests/site-v9/fonts/amberes-grotesk-light.woff2") format("woff2");
}
@font-face{
  font-family:"iA Writer Mono S";font-weight:400;font-style:normal;font-display:swap;
  src:url("/site-tests/site-v9/fonts/ia-writer-mono-s-regular.woff2") format("woff2");
}


/* ==== base/reset.css ==== */
/* ==========================================================================
   A · RESET
   Deliberately three rules. A full normalize would be more code than the
   difference it makes on a page whose every element is styled here anyway.
   ========================================================================== */
*{box-sizing:border-box;margin:0;padding:0}
/* NO scroll-behavior:smooth HERE. It was global, and the page is 20 screens: a
   header click from the hero to the visit section animated ~18,000px as one
   uninterruptible ride, which is a long time to watch the site flick past and
   no way to tell where you ended up. Distance is the deciding factor and CSS
   cannot see distance, so the choice moved to the delegated click handler in
   main.js — smooth for a hop of two screens or less, instant beyond that.
   With JS off every link is an ordinary instant jump, which is the correct
   fallback rather than a degraded one. */
html{background:var(--bone)}
body{
  background:var(--bone);
  color:var(--ink);
  font-family:var(--body);font-weight:300;
  overflow-x:hidden;
}
svg{display:block;color:currentColor}

/* Shared brand roles; section-specific labels can override heading defaults. */
:root{font-synthesis:none}
:where(h1,h2,h3,h4,h5,h6){font-family:var(--display);font-weight:400}
em,i{font-family:var(--display);font-weight:400}
button,input,select,textarea{font-family:var(--mono);font-weight:400}


/* ==== base/chrome.css ==== */
/* ==========================================================================
   B · FIXED CHROME — wordmark, header links
   markup: partials/chrome.eta   ·   copy: site.json → nav

   The `.dark` class is written on <body> by the engine when an ink-ground
   section owns the viewport, and every flip in this file hangs off it. That is
   the entire mechanism: one class, set from the section registry's `dark`
   field, and the chrome inverts.
   ========================================================================== */

/* ---------------- skip link ----------------
   First thing in the tab order, invisible until focused. Cheaper than it was
   now that the chapter rail is gone — three header links rather than fifteen —
   but a keyboard reader still shouldn't have to tab the header to reach copy. */
.skip{position:fixed;top:-100px;left:var(--pad);z-index:100;
   font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;
   background:var(--ink);color:var(--bone);padding:.85rem 1.3rem;text-decoration:none;
   border-radius:2px;transition:top .18s ease;font-weight:400;}
.skip:focus-visible{top:26px;outline:2px solid var(--gold);outline-offset:2px}
/* the skip target. It takes focus so the NEXT tab continues from the content
   rather than from the top of the header, but it is a 20-screen-tall wrapper and
   a ring drawn around it would be a border around the whole page. */
#main:focus{outline:none}

/* ---------------- fixed mark ----------------
   The mark and the topnav are fixed and sit directly on whatever section is
   behind them — no plate, no scrim. body.dark flips their ink. */
.mark{position:fixed;top:26px;left:var(--pad);z-index:80;line-height:0}
.mark img{width:clamp(52px,4.4vw,68px);height:auto;mix-blend-mode:multiply;
   transition:filter .6s,opacity .6s}
/* on the ink-ground sections the ink wordmark would vanish — flip it to cream */
.dark .mark img{mix-blend-mode:screen;filter:invert(1) brightness(1.6)}
.mark:focus-visible{outline:2px solid var(--oxblood);outline-offset:6px}

/* ---------------- header links (balance the mark) ----------------
   inset to var(--pad) so they mirror the wordmark on the left; the 36px flex
   height matches the mark's box so both sit on one axis. */
.topnav{position:fixed;top:26px;right:var(--pad);z-index:80;
   height:36px;display:flex;align-items:center;gap:clamp(1.1rem,2.2vw,2rem)}
/* THE INK IS 10.5px; THE TARGET IS 44px. These are two different measurements
   and only the first one is a design decision. The links were 34×12 and 42×12
   — a third of the 44×44 minimum in both axes — because the box was the glyph.
   Padding grows the box without touching the type; the negative margin keeps
   the row's optical alignment where it was, so nothing moved on screen. */
/* THE CHROME'S INK IS ITS OWN TOKEN, because the chrome is the only place on
   the page where the ground is not a constant. --ink-45 is stated once in
   tokens.css and its comment gives its contrast as 4.65:1 — which is measured
   against bone, and true for every OTHER place it is used (the kicker numeral,
   the caption, the contact labels) because all of those sit on a section's own
   flat ground.

   The chrome does not. #night crossfades its ground, so the plate behind these
   links moves too, and the engine now clamps it at 30% of that fade (main.js,
   see the note beside ch.now). At the clamp the plate is rgb(171,166,160) and
   --ink-45 gives 3.05:1 on it — measured on the built page, not derived.

   Full-strength ink on the same plate is 6.43:1, and on ordinary bone it is
   12.63:1 rather than 4.89. So this is not "make it darker to pass a check":
   the 45% alpha exists to hold 10.5px of mono BACK from the copy it sits
   beside, and the chrome has no copy beside it — it sits in open margin over
   whatever the page happens to be doing. There is nothing here for it to
   defer to. The weight it was buying is bought instead by the size, the
   letterspacing and the caps.

   Kept as a variable rather than inlined so the two places the chrome states
   its ink cannot drift apart. */
.topnav{--chrome-ink:var(--ink)}
.topnav a{font-family:var(--mono);font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;
   color:var(--chrome-ink);text-decoration:none;transition:color .4s;
   display:flex;align-items:center;min-height:44px;padding:0 .35rem;margin:0 -.35rem;font-weight:400;}
.topnav a:hover{color:var(--oxblood)}
.topnav a:focus-visible{outline:2px solid var(--oxblood);outline-offset:4px}
.dark .topnav a{color:#efe7d7d8}
.dark .topnav a:hover{color:var(--gold)}
.dark .topnav a:focus-visible{outline-color:var(--gold)}
/* On /press and /hiring the page's own name sits last in the row, current. */
.topnav a[aria-current="page"]{color:var(--oxblood)}
.topnav a[aria-current="page"]::before{content:"\00b7";margin-right:1rem;color:var(--rule-2)}

/* THE CHAPTER RAIL IS GONE. It was a fixed column of twelve links down the
   right-hand margin, and everything it needed is removed with it: the per-link
   feathered plates (each asking what was behind ITSELF, because a 418px column
   straddles chapter boundaries), the .on / .over-dark states main.js wrote per
   frame, and --rail-gutter, the 114px lane every content column had to leave
   empty from 761px up. The gutter token survives at 0 in tokens.css so the
   --pad-r / --frame-end names still resolve; see the note there. */


/* ---------------- the mark over the cover ----------------
   The cover carries the lockup, centred, so the fixed wordmark would put the
   name on screen twice. main.js writes body.at-cover while the cover owns
   the chrome band; the mark fades out there and back in after. */
body.at-cover .mark{opacity:0;pointer-events:none}
.mark{transition:opacity .4s ease}


/* ==== base/chapter.css ==== */
/* ==========================================================================
   C · CHAPTER SHELL — the sticky-stage mechanic every chapter shares
   markup: page.eta (the <section> wrapper is written there, from the registry)

   A chapter with a `height` in the registry gets a runway that tall and one
   screen pinned inside it. Scroll through the runway, the pinned screen stays,
   and --p runs 0→1 across it. That is the only animation primitive on the site;
   every section's motion is a different reading of the same number.
   ========================================================================== */
.chapter{position:relative}
.sticky{position:sticky;top:0;height:100vh;overflow:hidden;display:flex;align-items:center}
.stage{position:absolute;inset:0;z-index:1;pointer-events:none}
/* The generic copy shell uses the viewport/stage insets. Ordinary narrative
   opts into .editorial so it shares the capped frame while cards, captions and
   centred compositions keep their authored geometry. */
.copy{position:relative;z-index:20;width:100%;padding:0 var(--pad-r) 0 var(--pad)}
.copy.editorial{padding-inline:var(--frame-start) var(--frame-end)}
.copy.center{text-align:center;padding-inline:var(--pad) var(--pad-r)}
.copy.center .body{margin-inline:auto}

/* placement modifiers — so the frame moves chapter to chapter, not just the
   mechanic. Without these every section is the same shot at a different speed. */
.copy.high{align-self:flex-start;padding-top:13vh}
.copy.low{align-self:flex-end;padding-bottom:14vh}
.copy.right{text-align:right}
.copy.right .body{margin-left:auto}
/* caption: type recedes to a label so the stage owns the frame */
.copy.caption{align-self:flex-end;padding-bottom:12vh;text-align:center}
.copy.caption .body{margin-inline:auto}
.copy.caption h2{font-size:clamp(1.8rem,3.6vw,2.7rem)}
.copy.caption .sub{font-size:clamp(.95rem,1.3vw,1.1rem)}

/* ---- the layer system ----
   .layer  = pointer parallax (depth --d, in px per unit of pointer travel)
   .motion = scroll/effect, written per section
   .anchor = centring, so an element that centres itself does NOT also carry
             .layer's transform. That collision is real: an ID rule's
             translate(-50%,-50%) silently wins and kills the depth. #collection
             .obj / .pmot is the same split, which is why the collage reads. */
.layer{position:absolute;will-change:transform;
  transform:translate3d(calc(var(--mx)*var(--d,10)*1px), calc(var(--my)*var(--d,10)*1px), 0)}
.anchor{position:absolute;left:var(--ax,50%);top:var(--ay,50%);width:var(--aw,auto);
  transform:translate(-50%,-50%)}
.anchor > .layer{position:relative;left:auto;top:auto;right:auto;bottom:auto;width:100%}
.drift{animation:drift var(--dur,18s) ease-in-out infinite}
@keyframes drift{
  0%,100%{transform:translateY(-3px) rotate(var(--rot,0deg))}
  50%{transform:translateY(3px) rotate(0deg)}
}


/* ==== base/type.css ==== */
/* ==========================================================================
   D · SHARED TYPE
   The classes every section is allowed to use without declaring anything. A
   section may re-scale these (§3 holds h2 down to 3.4rem because it carries a
   sentence, not a title) but should not re-invent them.
   ========================================================================== */
.kicker{font-family:var(--mono);font-size:11.5px;letter-spacing:.32em;text-transform:uppercase;
   color:var(--oxblood);margin-bottom:1.1rem;font-weight:400;}
.kicker .n{color:var(--ink-45)}

/* ---- .ink, NOT .dark ------------------------------------------------------
   THE INVERTED TYPE IN THIS FILE HANGS OFF `.ink`, WHICH THE ENGINE WRITES ON
   EACH CHAPTER, NOT OFF `.dark`, WHICH IT WRITES ON <body>.

   They are not the same question. body.dark means "the section under the fixed
   chrome is ink" — it exists for the wordmark and the topnav, which float over
   whatever is at the top of the screen. A section's own heading is not floating
   over anything; it is inside one section and should follow that section.

   Reading body.dark here was a bug that only a phone could show. On desktop
   every dark chapter is a 100vh sticky stage, so the viewport owner IS the only
   section on screen and the two agree. At 390px they stop agreeing: sections
   are as tall as their content and two share the screen, so when the ink
   #footer took the viewport centre the bone #contact plate was still half
   visible — and every rule below fired on it. "COME IN." went cream on bone and
   effectively disappeared; the kicker went gold on bone beside it.

   `.ink` is per chapter and set from the same threshold, so a dark section
   inverts its own type whether or not it owns the middle of the screen, and a
   light section never inverts because of its neighbour.
   -------------------------------------------------------------------------- */
.ink .kicker .n{color:#efe7d7c4}
/* THE KICKER'S OWN COLOUR INVERTS TOO, and it is this file's job rather than
   each dark section's. Every other class here has an .ink pair below; .kicker
   had one for its .n child and none for itself, so oxblood stayed oxblood on
   ink. #ceiling and #rooms each patched it to gold locally and looked fine,
   which is exactly what hid the hole: #night never patched it, and its kicker
   sat at 4.42:1 halfway through the bone→night transition and 3.09:1 at the
   end of it. Both fail AA 4.5:1, measured off rendered pixels rather than off
   the declared token — the token was never the problem.

   Gold, not cream: the two sections that already solved this chose gold, it is
   the accent the dark half of the page uses everywhere else (the 1877
   constellations, .hand b), and it holds 9.3–10.8:1 on ink. A local
   override is still allowed — this is the floor, not a ceiling. */
.ink .kicker{color:var(--gold)}


/* SENTENCE CASE, NOT CAPS. v5 set every title in capitals at line-height .84.
   v6's titles are sentences — "Small things, eaten standing up." — and a
   sentence in caps reads as a sign. Mixed case at .98 leading, a hair tight.
   One italic phrase is allowed in at most two headings on the page; it is an
   emphasis, not a formula. */
h1,h2{font-family:var(--display);font-weight:400;text-transform:none;
   line-height:1.1;letter-spacing:0}
h1{font-size:clamp(2.6rem,7.6vw,6.2rem)}
h2{font-size:clamp(2rem,4.8vw,3.9rem)}
h2 em{font-style:italic;color:inherit}

.sub{font-style:italic;font-weight:300;color:var(--ink-60);font-size:clamp(1rem,1.5vw,1.2rem);margin-top:.7rem;font-family:var(--display);font-weight:400;}
.body{max-width:34ch;margin-top:1.4rem;font-size:1.08rem;line-height:1.6;color:#1b2436c0}
/* An outlined or filled call to action, mono caps on a 44px target. Two on
   the whole page: Keep me posted and Directions, both in the arrival. */
.cta{display:inline-flex;align-items:center;gap:.6em;min-height:44px;padding:0 1.25rem;
   font-family:var(--mono);font-size:11px;letter-spacing:.2em;text-transform:uppercase;
   text-decoration:none;border:1px solid var(--ink);color:var(--ink);border-radius:2px;
   transition:background .3s,color .3s,border-color .3s;font-weight:400;}
.cta:hover{background:var(--ink);color:var(--bone)}
.cta:focus-visible{outline:2px solid var(--oxblood);outline-offset:3px}
.cta.fill{background:var(--oxblood);border-color:var(--oxblood);color:var(--bone)}
.cta.fill:hover{filter:brightness(1.12);background:var(--oxblood)}
.ink .cta{border-color:#efe7d7cc;color:#efe7d7}
.ink .cta:hover{background:#efe7d7;color:var(--ink)}
/* The maker's caption under a photograph: mono, small, never under 12px. */
.capt{font-family:var(--mono);font-size:12px;letter-spacing:.1em;text-transform:uppercase;
   color:var(--ink-45);line-height:1.6;font-weight:400;}
.ink .capt{color:#efe7d7a6}
.tag{margin-top:1.1rem;font-family:var(--mono);font-size:10px;letter-spacing:.06em;
   color:var(--ink-45);text-transform:uppercase;font-weight:400;}

/* An unanswered fact, marked as one. Not a design element — these are meant to
   be conspicuous until someone fills them in. */
.tk{font-family:var(--mono);font-size:.86em;letter-spacing:.08em;
    text-transform:uppercase;color:var(--oxblood);
    border-bottom:1px dashed currentColor;padding-bottom:1px;font-weight:400;}

/* A hyphenated PROPER NOUN, held on one line. A plain U+002D is a break
   opportunity, and no CSS property refuses it — hyphens, word-break and
   overflow-wrap were each measured against "Over-the-Rhine" at 390px and all
   six values broke it identically, because none of them governs an explicit
   hyphen. Only marking the span does.

   Scoped to a class rather than applied to every hyphen on the page, because
   most of them SHOULD break: "sixteen-foot ceilings", "a hundred-voice singing
   society" and "twenty-eight rooms" all break at 320px and are correctly set
   that way — they are compounds in running prose, and refusing them would cost
   a ragged line to fix nothing. A neighbourhood's name is not a compound. */
.nb{white-space:nowrap}

.ink h1,.ink h2{color:#f2ecdd}
.ink .sub{color:#efe7d7aa}
.ink .body{color:#efe7d7bb}
.ink .tag{color:#efe7d7c4}

.cue{position:absolute;bottom:28px;white-space:nowrap;left:50%;transform:translateX(-50%);z-index:30;
     font-family:var(--mono);font-size:10.5px;letter-spacing:.28em;color:var(--ink-45);
     text-transform:uppercase;font-weight:400;}
.ink .cue{color:#efe7d7c4}

/* ---- settling in on arrival ----
   Anything carrying data-hang starts a little low and faint and settles once
   it crosses into the viewport (main.js writes .seen). --i staggers siblings.
   With no script nothing is ever hidden. */
.js [data-hang]{opacity:0;transform:translateY(22px);
   transition:opacity .9s ease,transform .9s cubic-bezier(.2,.7,.2,1);
   transition-delay:calc(var(--i,0)*90ms)}
.js [data-hang].seen{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){ .js [data-hang]{opacity:1;transform:none;transition:none} }


/* ==== base/scene.css ==== */
/* ==========================================================================
   S · THE SCENE — one full-bleed picture, centred type
   used by: partials/scene.eta, sections/cover.eta, ceiling.eta, footer.eta

   The whole page is this object repeated. The picture fills the stage and
   comes a little closer as --p runs (scale only); a wash rises from the foot
   so cream type sits on dark ground; the heading and the line are centred in
   the lower third. Nothing is framed, labelled or numbered.
   ========================================================================== */
.chapter.ink .sticky{background:var(--night)}
.sstage{position:absolute;inset:0;z-index:1;overflow:hidden;background:var(--night)}
.sphoto{position:absolute;inset:0;display:block}
.sphoto img{display:block;width:100%;height:100%;object-fit:cover;object-position:var(--focus,50% 50%);
   will-change:transform;transform-origin:50% 60%;
   transform:scale(calc(1.02 + var(--p,0)*.10)) translate3d(calc(var(--mx,0)*-5px),calc(var(--my,0)*-3px),0)}
body:not(.js) .sphoto img{transform:scale(1.04)}
.swash{position:absolute;inset:0;pointer-events:none;
   background:
     linear-gradient(0deg,#0b1020f0 0%,#0b1020a6 26%,#0b102033 52%,transparent 72%),
     linear-gradient(180deg,#0b102080 0%,transparent 22%)}

.scopy{position:absolute;left:var(--pad);right:var(--pad-r);bottom:14vh;z-index:20;
   text-align:center;color:var(--bone)}
.scopy h2{color:#f2ecdd;font-size:clamp(1.9rem,4.2vw,3.7rem);line-height:1.1;max-width:18ch;margin:0 auto;
   text-wrap:balance;text-shadow:0 2px 40px #0b1020}
.scopy .line{margin:1.1rem auto 0;max-width:44ch;font-family:var(--display);font-style:italic;font-weight:300;
   font-size:clamp(1.05rem,1.5vw,1.3rem);line-height:1.4;color:#efe7d7d0;text-wrap:balance;
   text-shadow:0 2px 30px #0b1020}
/* a painting's own name, small, in the corner */
.scredit{position:absolute;right:var(--pad-r);bottom:3.2vh;z-index:20;margin:0;
   font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:#efe7d77a}
.scredit em{font-family:var(--mono);font-style:normal;color:#efe7d7a6}

/* the chapter's settle-in: the type arrives over the first third of the runway */
.scopy{transform:translateY(calc((1 - clamp(0,calc(var(--p,0)*3),1))*3vh));
   opacity:calc(.25 + clamp(0,calc(var(--p,0)*3),1)*.75)}
body:not(.js) .scopy{transform:none;opacity:1}

@media (max-height:760px){ .scopy{bottom:10vh} }
@media (max-width:760px){
  .sphoto img{object-position:var(--focus-n,var(--focus,50% 50%))}
  .scopy{bottom:11vh}
  .scopy h2{font-size:clamp(1.7rem,7.2vw,2.3rem)}
  .scopy .line{font-size:1.02rem}
  .scredit{display:none}
}
@media (prefers-reduced-motion:reduce){ .scopy{transform:none;opacity:1} }


/* ==== sections/cover.css ==== */
/* ==========================================================================
   THE COVER — the lockup on two people
   markup: sections/cover.eta   ·   copy: 01-cover.json
   ========================================================================== */
#cover{--ground:var(--night)}
#cover .sticky{display:block}
#cover .sphoto img{transform-origin:62% 30%}
/* a deeper wash than a scene, because the lockup stands in the middle */
#cover .cover-wash{background:
   radial-gradient(60% 70% at 50% 58%,#0b1020d9 0%,#0b1020a0 45%,#0b102040 75%,transparent 100%),
   linear-gradient(0deg,#0b1020f0 0%,#0b102080 30%,transparent 60%),
   linear-gradient(180deg,#0b102099 0%,transparent 26%)}

#cover .lockup{position:absolute;inset:0;z-index:20;display:flex;flex-direction:column;
   align-items:center;justify-content:center;text-align:center;padding:12vh var(--pad) 10vh;color:var(--bone)}
/* the emblem and the wordmark are one drawing in two parts: both ink on
   nothing, both inverted to cream the same way */
#cover .emblem{width:clamp(110px,15vh,170px);height:auto;filter:invert(1) brightness(1.6);opacity:.95;
   will-change:transform;transform:translate3d(calc(var(--mx,0)*-3px),calc(var(--my,0)*-3px),0)}
.wordmark-h1{font-size:0;line-height:0;letter-spacing:0;margin:1.4vh 0 0}
#cover .wordmark{width:clamp(180px,22vw,290px);height:auto;display:block;filter:invert(1) brightness(1.6)}
#cover .hero-line{margin-top:3vh;font-family:var(--display);font-style:italic;font-weight:300;
   font-size:clamp(1.15rem,1.9vw,1.55rem);line-height:1.3;color:#f2ecdd;max-width:26ch;text-wrap:balance}
#cover .hero-where{margin-top:1.2rem;font-family:var(--mono);font-size:11.5px;letter-spacing:.22em;
   text-transform:uppercase;color:#efe7d7c4;font-weight:400}
#cover .hero-status{margin-top:.5rem;font-size:1.02rem;line-height:1.5;color:#efe7d7aa}

#cover .phasing{margin-top:2.4vh;list-style:none;display:flex;flex-wrap:wrap;justify-content:center;gap:.5rem 0}
#cover .ph{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
   color:#efe7d7a6;padding:0 1.3rem;position:relative;font-weight:400}
#cover .ph:not(:last-child)::after{content:"";position:absolute;right:0;top:50%;width:1px;height:26px;
   background:#efe7d73a;transform:translateY(-50%)}
#cover .ph b{color:#f2ecdd;font-weight:400;font-family:var(--body);font-style:normal;
   font-size:1rem;letter-spacing:0;text-transform:none;display:block;margin-bottom:.2rem}
#cover .ph .now{color:var(--gold)}
#cover .actions{margin-top:3vh;display:flex;flex-wrap:wrap;justify-content:center;gap:.7rem}
#cover .cta{border-color:#efe7d7cc;color:#efe7d7}
#cover .cta:hover{background:#efe7d7;color:var(--ink)}
#cover .cta.fill{background:var(--oxblood);border-color:var(--oxblood);color:var(--bone)}
#cover .cue{color:#efe7d7a6}

@media (max-height:760px){
  #cover .emblem{width:clamp(90px,12vh,130px)}
  #cover .hero-line{margin-top:1.6vh}
  #cover .phasing{margin-top:1.6vh}
  #cover .actions{margin-top:2vh}
}
@media (max-width:760px){
  #cover .lockup{padding:14vh var(--pad) 12vh;justify-content:flex-end}
  #cover .emblem{width:26vw}
  #cover .wordmark{width:50vw}
  #cover .hero-line{font-size:1.1rem}
  #cover .hero-where{font-size:10.5px;letter-spacing:.16em}
  #cover .hero-status{font-size:.95rem}
  #cover .phasing{gap:.3rem .6rem}
  #cover .ph{padding:0 .5rem}
  #cover .ph::after{display:none}
  #cover .ph b{display:inline;margin:0 .3em 0 0;font-size:.92rem}
  #cover .cta{font-size:10px;padding:0 .9rem;min-height:40px}
  #cover .cue{display:none}
}


/* ==== sections/ceiling.css ==== */
/* ==========================================================================
   §2.5 · THE CEILING — you look up into the painting
   markup: sections/ceiling.eta   ·   copy: 03-ceiling.json   ·   data: fresco-bands.json

   The one photograph on the site that behaves like a place rather than a
   picture. The section identifies the ceiling and its painter while scrolling
   dollies a camera into the fresco.

   WHAT MAKES IT A DOLLY AND NOT A ZOOM
   The depth in the image is the depth the artist PAINTED — the vortex. So the
   plate is sliced into nine concentric shells about the vortex's eye, each
   scaled about that same eye. Every shell grows as you scroll, but the OUTER
   ones grow more, so they sweep outward past the camera while the deep centre
   barely moves. That differential is the parallax; there are no lateral
   offsets at all.

   Nothing is cut out of the plate. The band alphas are a partition of unity —
   they sum to 1 everywhere — so at zero motion the nine shells recomposite to
   exactly the source photograph. No holes, no inpainting, no ghost sockets.

   THE VIGNETTE IS A SIBLING OF .cscene, NOT A CHILD — deliberately.
   Only .cscene takes the dolly and the pointer tilt. Nesting .cgrade inside it
   would make the vignette inherit those transforms and swim with the ceiling;
   it must stay nailed to the viewport so the frame holds still while the
   ceiling opens through it.
   ========================================================================== */
#ceiling{--ground:#14161a;position:relative;background:#14161a;color:var(--bone)}

/* Overscan AND aspect. Every shell is positioned as a percentage of this box,
   so the box must carry the plate's own 4:3 (1448×1086) or the whole fresco is
   stretched to whatever shape the viewport happens to be. An earlier version
   used inset:-9%, which inherits the viewport ratio — barely visible on a
   laptop, and on a 390×844 phone it smeared the vortex into a vertical column.
   So: cover-fit the plate, then overscan by 18%, because the dolly pulls outer
   edges inward and the corners must never go black.
     width  = max(118vw, 118vh × 4/3)
     height = max(118vh, 118vw × 3/4)
   Centred with the `translate` property, not transform — the tilt writes
   cscene.style.transform every frame and would clobber it. */
#ceiling .cscene{position:absolute;left:50%;top:50%;translate:-50% -50%;
   width:max(118vw,157.334vh);height:max(118vh,88.5vw);z-index:1;
   perspective:1400px;transform-style:preserve-3d}
#ceiling .clayer{position:absolute;will-change:transform,filter;
   transform-origin:50% 50%;pointer-events:none;backface-visibility:hidden}
#ceiling .clayer img{display:block;width:100%;height:100%}

/* vignette + a warm bloom at the eye. Siblings — see the note above. */
#ceiling .cbloom{position:absolute;inset:0;z-index:2;pointer-events:none;
   background:radial-gradient(60% 45% at 46% 46%,rgba(255,225,190,.10),rgba(0,0,0,0) 70%);
   mix-blend-mode:screen}
#ceiling .cgrade{position:absolute;inset:0;z-index:3;pointer-events:none;
   background:
     /* the main vignette — .90 at the corners is the principal lever */
     radial-gradient(115% 88% at 50% 50%,rgba(0,0,0,0) 28%,rgba(6,5,9,.62) 72%,rgba(4,3,7,.90) 100%),
     /* a second, tighter pass so the four corners fall off faster than the edge
        midpoints. That difference is what reads as a lens rather than a fade. */
     radial-gradient(78% 70% at 50% 50%,rgba(0,0,0,0) 55%,rgba(3,2,6,.55) 100%),
     linear-gradient(180deg,rgba(20,14,30,.26),rgba(0,0,0,0) 34%);
   mix-blend-mode:multiply}
/* A FLOOR UNDER THE COPY — AND THE COPY IS TALLER THAN THE FLOOR WAS.
   The bottom gradient alone was transparent above 48% of the frame. The copy
   block starts at 70% (measured: kicker at 70.2%, h2 at 66.7%, .sub at 47.6%,
   all of it in a 900px viewport), so the three largest things in the section
   — including the title — were sitting directly on unmodified fresco. It read
   as fine at any single scroll position and was luck rather than design: the
   ground under one line of that title measured 1.05:1 in one place and 13.9:1
   in another, because the dolly moves cloud through it. The most variable
   surface on the site was carrying the most important type on it.

   So there are two layers now, doing two different jobs:

   1 · THE POOL is the copy's own ground — an ellipse struck at the
       bottom-left where the copy actually lives, tall enough to reach over the
       kicker and feathered to nothing by 88% so it never shows an edge. It is
       off-centre on purpose: the copy column is left-aligned and the vortex's
       eye is right of centre, so the shadow falls where the words are and
       leaves the painting's subject alone.

   2 · THE FLOOR is the original full-width bottom wash, kept for .hand and
       .cue, which sit outside the pool's reach at the foot of the frame.

   Both in the same layered `background` rather than a second element: this is
   already a sibling of .cscene for the reason at the head of this file, and one
   more absolutely-positioned overlay for a job a comma can do would be a third
   thing to keep nailed to the viewport. */
#ceiling .cfloor{position:absolute;inset:0;z-index:4;pointer-events:none;
   background:
     radial-gradient(66% 60% at 19% 63%,#0b0a09cf 0%,#0b0a09a6 40%,#0b0a0952 70%,transparent 88%),
     linear-gradient(0deg,#0b0a09d9 0%,#0b0a0966 24%,transparent 48%)}

#ceiling .scopy{z-index:20}
#ceiling .kicker{color:var(--gold)}
#ceiling .kicker .n{color:#efe7d7c4}
#ceiling h2{color:#f2ecdd}
#ceiling .sub{color:#efe7d7aa}
#ceiling .body{color:#efe7d7bb;max-width:34ch}
#ceiling .cue{color:#efe7d7c4}

/* the attribution, set as an engraved caption rather than body copy */
#ceiling .hand{margin-top:1.5rem;font-family:var(--mono);font-size:10px;
   letter-spacing:.16em;text-transform:uppercase;color:#efe7d799;line-height:1.7;
   max-width:26ch;font-weight:400;}
#ceiling .hand b{color:var(--gold);font-weight:400}

/* ---- reduced motion ------------------------------------------------------
   The shells stop dead. NOT display:none and not a still frame of the
   animation — the nine bands are a partition of unity, so with every transform
   removed they recomposite to exactly the source photograph. */
@media (prefers-reduced-motion:reduce){
  #ceiling .clayer{transform:none !important;filter:none !important}
  #ceiling .cscene{transform:none !important}
}


/* ==== sections/next.css ==== */
/* ==========================================================================
   IN ORDER — the three phases, the hours, the hiring box. Cream, centred.
   markup: sections/next.eta   ·   copy: 09-next.json
   ========================================================================== */
#next{--ground:var(--bone);background:var(--bone);padding:14vh var(--pad-r) 12vh var(--pad);text-align:center}
#next .nwrap{max-width:var(--content-max);margin:0 auto}
#next h2{font-size:clamp(2rem,4.2rem,3.6rem)}
#next .phases{list-style:none;margin:7vh auto 0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:4vw;
   max-width:1040px}
#next .phase{display:flex;flex-direction:column;align-items:center}
#next .pdraw{height:clamp(90px,11vw,150px);display:flex;align-items:flex-end;justify-content:center;opacity:.85;mix-blend-mode:multiply}
#next .pdraw img{height:100%;width:auto;display:block}
#next .pdraw.tall img{height:auto;width:clamp(170px,18vw,260px);max-height:none}
#next .pdraw.tall{height:auto}
#next .pwhen{margin-top:1.6rem;font-family:var(--mono);font-size:11px;letter-spacing:.22em;text-transform:uppercase;color:var(--oxblood);font-weight:400}
#next .is-now .pwhen{color:var(--oxblood)}
#next .phase h3{font-family:var(--display);font-size:clamp(1.3rem,1.9vw,1.65rem);line-height:1.15;margin-top:.5rem}
#next .phase p{margin-top:.8rem;font-size:1.02rem;line-height:1.55;color:var(--ink-70);max-width:30ch}

#next .hours{margin:7vh auto 0;padding-top:1.4rem;border-top:1px solid var(--rule-2);max-width:1040px;
   font-family:var(--display);font-style:italic;font-weight:300;font-size:clamp(1rem,1.5vw,1.25rem);color:var(--ink-70)}
#next .hours .lbl{font-family:var(--mono);font-style:normal;font-size:11px;letter-spacing:.22em;
   text-transform:uppercase;color:var(--oxblood);margin-right:1rem;font-weight:400}

#next .hbox{margin:6vh auto 0;max-width:720px;padding:clamp(1.6rem,3vw,2.6rem);border:1px solid var(--ink);
   display:grid;justify-items:center;gap:1rem}
#next .hbox .kicker{margin:0}
#next .hline{font-family:var(--display);font-size:clamp(1.15rem,1.8vw,1.45rem);line-height:1.25;color:var(--ink);max-width:30ch}

@media (max-width:900px){
  #next{padding:12vh var(--pad) 10vh}
  #next .phases{grid-template-columns:1fr;gap:6vh}
}


/* ==== sections/visit.css ==== */
/* ==========================================================================
   §10 · VISIT (site-v6: #visit) — engraved map, details & mailing list (the close)
   markup: sections/contact.eta + partials/signup.eta   ·   copy: 11-contact.json

   The plate rises into place as the runway scrolls, and everything inside it is
   drawn: the map is an SVG engraving, not a tile service, so this page loads no
   third-party script and hands nobody a visitor log.
   ========================================================================== */
#visit{--ground:#ede2ce;background:radial-gradient(120% 100% at 50% 0%, #f3edde 0%, #e7dcc7 72%)}
#visit .relic img{width:100%;height:auto;mix-blend-mode:multiply;opacity:.13}

/* Both terms of that min() are measured against the VIEWPORT, and the parent
   .copy is not the viewport — it is inset by --pad on the left and --pad-r on
   the right. So the plate could be wider than the space it was given, and below
   ~1200px it was: `margin:auto` resolves to zero when a box is over-constrained,
   so the surplus all went to the right and pushed the address, the heading and
   the signup button off centre and past the right inset. (While the chapter rail
   existed they landed under its links, which is how this was found.)

   `100%` is the third term, and it is the only one that knows about the parent's
   insets, because .copy already accounts for them. Nothing subtracts
   --rail-gutter here: that would deduct it twice and pull the plate off centre. */
#visit .plate{position:relative;z-index:20;
   width:min(94vw,1060px,100%);margin:0 auto;
   display:grid;grid-template-columns:1.08fr .92fr;
   background:#efe7d7;border:1px solid var(--ink);
   box-shadow:0 34px 70px -34px #1b243577, 0 2px 0 #1b243622;
   transform:translateY(calc((1 - var(--p))*36px));opacity:calc(.62 + var(--p)*.38)}
/* one hairline, not two: the plate is a map, not a frame */
#visit .plate::before{display:none}
#visit .mapwrap{position:relative;border-right:1.5px solid var(--ink);min-width:0}

/* ---- the map, as a link -------------------------------------------------
   The anchor is the whole map cell, so the target is a 400px square rather than
   a line of text — no 44px minimum to think about, and no doubt about what is
   clickable. The 18px padding moved here off .mapwrap so the hit area includes
   the plate's inner margin instead of stopping at the drawing's edge.

   A FLEX COLUMN, CENTRED, RATHER THAN A BLOCK: the plate is a two-column grid
   and the details side is the taller of the two, so the map cell is stretched
   to match it. As a block the drawing sat at the top of that cell with a stripe
   of empty paper under it, which reads as the map having failed to fill its
   frame. Centred, the square drawing sits on the plate's optical middle.

   A DRAWN MAP THAT NAVIGATES HAS TO SAY SO. Nothing about an engraving suggests
   it is a control, so a hint sits under it in the site's mono and the whole
   plate lifts very slightly on hover — enough to answer "is this a button?",
   not enough to make the map look like one. */
#visit .maplink{display:flex;flex-direction:column;justify-content:center;
   height:100%;padding:18px;text-decoration:none;color:inherit;
   transition:background .35s ease}
#visit .maplink:hover{background:#1b24360a}
#visit .maplink:focus-visible{outline:2px solid var(--oxblood);outline-offset:-6px}
#visit .mapwrap svg{display:block;width:100%;height:auto;transition:transform .5s ease}
#visit .maplink:hover svg{transform:translateY(-2px)}
#visit .maphint{display:block;margin-top:.85rem;text-align:center;
   font-family:var(--mono);font-size:9.5px;letter-spacing:.22em;text-transform:uppercase;
   color:var(--ink-45);transition:color .35s;font-weight:400;}
#visit .maplink:hover .maphint{color:var(--oxblood)}

#visit .info{padding:clamp(1.4rem,2.6vw,2.2rem) clamp(1.8rem,3.4vw,3rem);display:flex;flex-direction:column;justify-content:center}
#visit .info .kicker{margin-bottom:.5rem}
#visit .info h2{font-size:clamp(1.5rem,2.4vw,2rem);line-height:1.1;max-width:none}
/* the three phases, one line under the heading: bar first, then the rest */
#visit .phases{margin-top:1rem;display:flex;flex-wrap:wrap;align-items:baseline;gap:.2rem .6rem;
   font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-55);font-weight:400;}
#visit .phases .lbl{color:var(--oxblood);margin-right:.3rem}
#visit .phases .ph b{font-weight:400;color:var(--ink)}
#visit .phases .ph .now{color:var(--oxblood)}
#visit .phases .sep{color:var(--rule-2)}
#visit .rows{margin-top:1.2rem;border-top:1px solid var(--rule-2)}
#visit .row{display:grid;grid-template-columns:82px 1fr;gap:1rem;align-items:baseline;
   padding:.7rem 0;border-bottom:1px solid var(--rule-2)}
#visit .row .lbl{font-family:var(--mono);font-size:10px;letter-spacing:.22em;
   text-transform:uppercase;color:var(--oxblood);font-weight:400;}
#visit .row .val{font-size:1rem;color:#1b2436d8;line-height:1.45}

/* The second half of "make the map active": the same destination as a plain
   text link, in the details column, for anyone who does not think to click a
   picture and for anyone reading this page as a list of links. Its own line
   rather than a phrase inside the address, so it is findable at a glance and
   cannot be mistaken for part of the street name. */
#visit .dirlink{display:flex;align-items:center;min-height:36px;margin-top:.1rem;width:fit-content;
   font-family:var(--mono);font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;
   color:var(--ink-70);text-decoration:none;
   border-bottom:1px solid var(--rule-2);transition:color .35s,border-color .35s;font-weight:400;}
#visit .dirlink::after{content:"\2197";margin-left:.5em;font-size:1.1em;line-height:0}
#visit .dirlink:hover{color:var(--oxblood);border-bottom-color:currentColor}
#visit .dirlink:focus-visible{outline:2px solid var(--oxblood);outline-offset:3px}

/* ---- the signup, and the only joke on the page ----
   The crane and the mask are the two states of this form. Get it right and she
   releases the paper crane; mistype and she is holding a mask over her own
   face. Nothing is labelled; it pays off only for people who mistype. */
#visit .siglabel{display:block;margin-top:1.2rem;margin-bottom:.5rem;
   font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;
   color:var(--ink-55);font-weight:400;}
#visit .signup{display:flex;gap:.55rem;flex-wrap:wrap;position:relative}
#visit .signup input{flex:1;font-family:var(--body);font-size:1rem;padding:.72rem .95rem;min-width:170px;
   background:#f6f0e2;border:1px solid var(--rule-2);color:var(--ink);border-radius:2px}
#visit .signup input::placeholder{color:var(--ink-45)}
#visit .signup input:focus-visible,#visit .signup button:focus-visible{
   outline:2px solid var(--oxblood);outline-offset:2px}
#visit .signup input[aria-invalid="true"]{border-color:var(--oxblood)}
/* min-height 44, not the 36 the padding alone produced. The one button on the
   page that converts anything should not be the hardest thing on it to hit. */
#visit .signup button{font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;
   padding:.72rem 1.3rem;min-height:44px;background:var(--oxblood);color:var(--bone);border:none;border-radius:2px;
   cursor:pointer;transition:filter .3s;font-weight:400;}
#visit .signup input{min-height:44px}
#visit .signup button:hover{filter:brightness(1.12)}

/* The crane or the mask, swapped by a class the SERVER writes. Whole figures
   rather than a square emblem, so this is sized off HEIGHT and sits on the
   baseline of the form — she stands next to it. Same multiply treatment as
   every other woodcut on the bone ground; no inversion, the source art is
   already ink. The two poses are not the same aspect ratio, which is fine
   precisely because height is what's pinned. */
#visit .mask{position:absolute;right:-4px;bottom:calc(100% - 2px);
   height:clamp(92px,11vw,132px);opacity:0;transform:translateY(8px) scale(.96);
   transform-origin:100% 100%;
   transition:opacity .25s ease,transform .25s ease;pointer-events:none}
#visit .mask img{height:100%;width:auto;display:block;mix-blend-mode:multiply}
#visit .signup.is-comedy .mask,#visit .signup.is-tragedy .mask{
   opacity:.9;transform:translateY(0) scale(1)}

/* the message is real text, not colour alone (WCAG 1.4.1) */
#visit .sigmsg{margin-top:.6rem;font-size:.94rem;color:var(--oxblood);min-height:1.2em}
#visit .sigmsg:empty{min-height:0}
/* success is not an error — say it in ink, not in the error colour */
#visit .signup.is-comedy ~ .sigmsg{color:var(--ink-70)}

/* Instagram + sister venues. Same mono register as the signoff, one step
   brighter so the links read as links. */
#visit .fmeta{margin-top:1.1rem;display:flex;flex-direction:column;gap:0}
#visit .frow{display:flex;align-items:center;flex-wrap:wrap;gap:0 .85rem;
   font-family:var(--mono);font-size:10px;letter-spacing:.18em;text-transform:uppercase;font-weight:400;}
#visit .frow .lbl{color:var(--ink-45)}
/* 10px of ink, 44px of target — see the note on .topnav a. The underline is
   drawn on an inner span-height box rather than the padded one, so growing the
   hit area does not drop the rule away from the word. */
#visit .frow a{color:var(--ink-70);text-decoration:none;
   display:inline-flex;align-items:center;min-height:38px;
   box-shadow:inset 0 -1px 0 0 transparent;transition:color .35s}
#visit .frow a>span{border-bottom:1px solid var(--rule);padding-bottom:1px;
   transition:border-color .35s}
#visit .frow a:hover{color:var(--oxblood)}
#visit .frow a:hover>span{border-bottom-color:currentColor}
#visit .frow a:focus-visible{outline:2px solid var(--oxblood);outline-offset:-4px;border-radius:2px}
/* A social channel and its glyph. `.soc` is used by BOTH branches of the markup
   — the <a> when there is a URL and a <span> when there isn't — so the two
   states sit on exactly the same baseline and the row does not reflow when a
   missing address is filled in. (This replaced `.ig`, which named the one
   channel that existed rather than the shape it was.) */
#visit .frow .soc{display:inline-flex;align-items:center;gap:.45em}
#visit .frow .soc .ic{width:12px;height:12px;display:block;flex:none}
#visit .frow .soc.is-pending{color:var(--ink-45);min-height:44px}
#visit .frow .soc.is-pending .tk{margin-left:.15em}
#visit .frow .sep{color:var(--rule-2)}

#visit .signoff{display:none;margin-top:1.7rem;font-family:var(--mono);font-size:10px;letter-spacing:.2em;
   text-transform:uppercase;color:var(--ink-45);font-weight:400;}

/* ---- map internals ---- */
#visit .map .blk{fill:url(#mapHatch);stroke:var(--ink);stroke-width:1}
#visit .map .park{fill:url(#mapDot);stroke:var(--ink);stroke-width:1}
#visit .map .canal{fill:none;stroke:var(--ink);stroke-width:8;opacity:.32;stroke-linecap:round}
#visit .map .canal-c{fill:none;stroke:var(--ink);stroke-width:1;opacity:.5;stroke-dasharray:2 4}
#visit .map .stlbl{font-family:var(--mono);font-size:8px;letter-spacing:.12em;fill:var(--ink-45);font-weight:400;}
#visit .map .cface{font-family:var(--mono);font-size:9px;letter-spacing:.1em;fill:var(--oxblood);font-weight:400;}
#visit .map .scl{font-family:var(--mono);font-size:8px;letter-spacing:.06em;fill:var(--ink-45);font-weight:400;}
#visit .map .ctitle{font-style:italic;font-size:20px;fill:var(--ink);font-family:var(--display);font-weight:400;}
#visit .map .csub{font-family:var(--mono);font-size:8px;letter-spacing:.26em;fill:var(--ink-45);font-weight:400;}
#visit .map .mkr{font-family:var(--mono);font-size:9px;letter-spacing:.1em;fill:var(--ink);font-weight:400;}
#visit .map .mkr2{font-style:italic;font-size:9.5px;fill:var(--ink-60);font-family:var(--display);font-weight:400;}
#visit .map .pin{fill:var(--oxblood)}
#visit .map .pinring{fill:none;stroke:var(--oxblood);stroke-width:1.4;
   transform-box:fill-box;transform-origin:center;animation:pingp 3.4s ease-out infinite}
@keyframes pingp{0%{transform:scale(.45);opacity:.8}75%{opacity:0}100%{transform:scale(2.6);opacity:0}}

/* ---- phone: THE CHAPTER UNPINS HERE --------------------------------------
   Once the plate stacks to one column it is taller than a phone screen, and a
   sticky stage is `height:100vh; overflow:hidden`: the map was cut off at the
   top and the form at the bottom, with no scroll position that showed either.
   So on a phone this becomes an ordinary block as tall as its own content. The
   !important is against page.eta's inline runway height from the registry. */
/* The same un-pinning on a SHORT viewport: at 1024×768 or 1440×700 the plate
   is taller than the stage and its heading sits under the chrome. Only the
   pin goes; the two columns stay until the phone breakpoint below. */
@media (max-width:760px),(max-height:820px){
  #visit{height:auto !important}
  #visit .sticky{position:static;height:auto;overflow:visible;padding:14vh 0 12vh}
  #visit .copy{position:static}
  #visit .plate{transform:none;opacity:1}
  #visit .relic{opacity:.5}
}
@media (max-width:760px){
  #visit .plate{grid-template-columns:1fr}
  #visit .mapwrap{border-right:none;border-bottom:1.5px solid var(--ink)}
}
@media (prefers-reduced-motion:reduce){
  #visit .map .pinring{animation:none !important}
}


/* ==== sections/footer.css ==== */
/* ==========================================================================
   THE FOOT — the painted emblem under the signature
   markup: sections/footer.eta   ·   copy: 11-footer.json
   ========================================================================== */
#footer{--ground:var(--night);position:relative;min-height:88vh;background:var(--night);color:var(--bone);
   display:grid;place-items:center;padding:14vh var(--pad-r) 12vh var(--pad);overflow:hidden}
#footer .sphoto img{transform:scale(1.04) translate3d(calc(var(--mx,0)*-5px),calc(var(--my,0)*-3px),0)}
#footer .foot-wash{background:
   radial-gradient(60% 60% at 50% 70%,#0b1020d0 0%,#0b102080 50%,transparent 100%),
   linear-gradient(0deg,#0b1020f0 0%,#0b102060 40%,transparent 70%)}
#footer .fwrap{position:relative;z-index:20;max-width:44rem;text-align:center}
#footer .fmark{width:clamp(120px,14vw,180px);height:auto;filter:invert(1) brightness(1.6);opacity:.95;
   will-change:transform;transform:translate3d(calc(var(--mx,0)*3px),calc(var(--my,0)*3px),0)}
#footer .fline{margin:2rem 0 0;font-family:var(--display);font-style:italic;
   font-weight:300;font-size:clamp(1.15rem,2vw,1.55rem);line-height:1.3;color:#f2ecdd;text-wrap:balance}
#footer .fwhere{margin:1rem 0 0;font-family:var(--mono);font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:#efe7d7a6;font-weight:400}
#footer .flinks{margin:2rem 0 0;display:flex;justify-content:center;align-items:center;gap:.8rem;
   font-family:var(--mono);font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:#efe7d77a;font-weight:400}
#footer .flinks a{color:#efe7d7c4;text-decoration:none;display:inline-flex;align-items:center;min-height:44px;
   border-bottom:1px solid #efe7d733;transition:color .3s,border-color .3s}
#footer .flinks a:hover{color:var(--gold);border-bottom-color:currentColor}
#footer .flinks a:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
#footer .scredit{position:static;margin-top:3rem;text-align:center}
@media (max-width:760px){ #footer{min-height:80vh} #footer .scredit{display:block;font-size:9.5px} }


/* ==== base/page.css ==== */
/* ==========================================================================
   Q · THE PRACTICAL PAGES — /press and /hiring
   markup: sections/press.eta, sections/hiring.eta

   One narrow editorial column with the site's type and nothing else: no stage,
   no runway. A reporter or an applicant came here for a name and an address,
   and the page gives it to them above the fold.
   ========================================================================== */
body.page{background:var(--bone)}
.pg{--ground:var(--bone);background:var(--bone);min-height:100vh;
   padding:clamp(120px,18vh,180px) var(--pad) 12vh}
.pg .wrap{max-width:760px;margin:0 auto}
.pg h1{font-size:clamp(2rem,4.6vw,3.5rem);line-height:1.1;letter-spacing:0;margin-top:.2rem}
.pg .lede{margin-top:1.4rem;font-size:clamp(1.1rem,1.7vw,1.3rem);line-height:1.55;color:var(--ink-70);max-width:52ch}
.pg .rows{margin-top:2.6rem;border-top:1px solid var(--rule-2)}
.pg .row{display:grid;grid-template-columns:150px 1fr;gap:1.2rem;align-items:baseline;
   padding:1.05rem 0;border-bottom:1px solid var(--rule-2)}
.pg .row .lbl{font-family:var(--mono);font-size:11px;letter-spacing:.22em;text-transform:uppercase;
   color:var(--oxblood);font-weight:400;}
.pg .row .val{font-size:1.06rem;line-height:1.55;color:#1b2436d8;max-width:58ch}
.pg .row .val a{color:var(--ink);text-decoration:none;border-bottom:1px solid var(--rule-2);transition:border-color .3s}
.pg .row .val a:hover{border-bottom-color:currentColor}
.pg .row .val .sub{display:block;margin-top:.2rem;font-family:var(--mono);font-size:11px;letter-spacing:.12em;
   text-transform:uppercase;color:var(--ink-45);font-style:normal}
.pg .row .val .tk{font-size:.8em}
.pg .fig{float:right;width:clamp(72px,9vw,110px);margin:0 0 1rem 2rem;mix-blend-mode:multiply;opacity:.9}
.pg .fig img{width:100%;height:auto}
.pg .back{display:inline-flex;align-items:center;min-height:44px;margin-top:2.6rem;
   font-family:var(--mono);font-size:11px;letter-spacing:.2em;text-transform:uppercase;
   color:var(--ink-70);text-decoration:none;border-bottom:1px solid var(--rule-2);font-weight:400;}
.pg .back:hover{color:var(--oxblood);border-bottom-color:currentColor}
.pg .note{margin-top:2rem;font-size:1rem;line-height:1.6;color:var(--ink-70);max-width:56ch}
@media (max-width:760px){
  .pg{padding-top:150px}
  .pg .row{grid-template-columns:1fr;gap:.3rem}
  .pg .fig{float:none;margin:0 0 1.4rem}
}


/* ==== sections/press.css ==== */


/* ==== sections/hiring.css ==== */


/* ==== base/responsive.css ==== */
/* ==========================================================================
   Z · RESPONSIVE & REDUCED MOTION — the GENERIC rules only

   MUST STAY LAST IN THE BUNDLE: a few rules here re-declare selectors from
   earlier files at equal specificity and win on source order.

   v5 kept every section's media queries in this one file, keyed by #id. When
   sections were renamed for v6 those rules would have died silently — nothing
   warns about a dead #id in base/. So each section's breakpoints now live at
   the END of its own sections/<id>.css, and this file carries only what is
   true of the whole page: the pad, the chrome, the wordmark, Reduce Motion.
   ========================================================================== */

/* ---- phone -------------------------------------------------------------- */
@media (max-width:760px){
  :root{--pad:7vw}

  /* The chrome is fixed, so long copy scrolls underneath it. A scrim only
     hides that. Instead the chrome scrolls away with the page at this width —
     the header links are reachable again from the foot of the page. */
  .mark,.topnav{position:absolute}
  .mark img{width:44px}
  /* Six links on a page (five sections plus the page's own name) do not fit
     one row beside the mark at 390px; they wrap, right-aligned, under it. */
  .topnav{top:30px;gap:0 .8rem;flex-wrap:wrap;justify-content:flex-end;height:auto;
     max-width:calc(100vw - 2*var(--pad) - 64px)}
  .topnav a{font-size:9.5px;letter-spacing:.14em;min-height:36px}
  h2{font-size:clamp(1.7rem,7.2vw,2.3rem)}
  .body{font-size:1.02rem}
}

/* ---- reduced motion -----------------------------------------------------
   Everything stops. The engine pins --p to 1, so every chapter rests at its
   settled state; the per-section exceptions (the ceiling rests at 0, the
   chart is pre-drawn) live beside the rules they override. */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
  .drift{animation:none !important}
}
