/* ============================================================================
   BODKIN & PRESS — v2
   The site is a book. It has a cover and it has pages.

   Palette derivation: COLOR.md     Graphic language: GRAPHICS.md
   Register entry:     ../PALETTES.md

   Token tiers, unchanged from v1 because the architecture was right:
     primitive  (--c-buckram, --s-4)      raw values, never used in components
     semantic   (--ground, --text)        meaning; this is what themes override
     component  (--panel-pad)             local, scoped

   The one hard rule of this stylesheet: NO ROUNDED CORNERS, ANYWHERE, and no
   diagonals. A ruled page has neither. Every divider is the motif's linear
   form; there is not a single `<hr>` or `border-radius` in the file.
   ========================================================================= */

/* ---------------------------------------------------------------- 1. RESET */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; color-scheme: light; scroll-behavior: auto; scrollbar-gutter: stable; overscroll-behavior-y: none; }
/* The gutter keeps the layout width on classic scrollbars. No rubber band at
   either end: scrolling up at the title used to pull the whole window down
   and let it spring back (owner, 30 Sep) — book.js also holds the wheel
   there, for browsers that ignore this. */
body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; overscroll-behavior-y: none; }
img, svg, video, canvas { display: block; max-width: 100%; }
button, input, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; padding: 0; }
del { text-decoration: none; }

/* ------------------------------------------------- 2. PRIMITIVE TOKENS */
:root {
  /* Every value below is sampled from one physical object: a hardbound
     account book. See COLOR.md for the derivation of each. */
  --c-buckram:      #071509;   /* the dyed cloth binding */
  --c-buckram-deep: #030b05;   /* the same cloth at the spine, in shadow */
  --c-buckram-lift: #102217;   /* the cloth catching light */
  --c-bar:          #d9e4ca;   /* account-book paper, flat — was the printed band */
  --c-bar-deep:     #c7d7b7;   /* the same paper in shadow */
  --c-sheet:        #eef0e4;   /* the paper between the bars */
  --c-sheet-hi:     #f7f8f1;   /* the same paper catching the lamp */
  --c-ink:          #131d18;   /* registrar's iron-gall ink — green-black */
  --c-ink-2:        #3d4a41;   /* the same ink, thinned */
  --c-ink-3:        #5f6b62;   /* thinner again, and faded */
  --c-rule:         #a3ba90;   /* the printed ruling */
  --c-rule-soft:    #c2d3b2;   /* ruling seen under the bar */
  --c-manila:       #cdb287;   /* a case-file folder */
  --c-manila-ink:   #7a6134;   /* written on the manila tab */
  --c-proof:        #b8322a;   /* a proofreader's correction pen */

  /* Space — 4px base */
  --s-1: 4px;  --s-2: 8px;   --s-3: 12px;  --s-4: 16px;
  --s-5: 24px; --s-6: 32px;  --s-7: 48px;  --s-8: 64px;
  --s-9: 96px; --s-10: 128px; --s-11: 176px; --s-12: 240px;

  /* The ruling rhythm. Everything vertical is a multiple of this, because a
     account-book page has one rhythm and everything on it obeys it. */
  --bar-h: 44px;

  /* Type. Fraunces carries an optical-size axis, which is used properly:
     large sizes get the display cut, body gets the text cut. Archivo has a
     real width axis. Neither is the Inter/Playfair default. */
  --f-display: "Literata", "Iowan Old Style", Georgia, serif;
  --f-ui: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --f-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, "Cascadia Mono", monospace;

  --t-micro: clamp(0.6875rem, 0.66rem + 0.14vw, 0.75rem);
  --t-small: clamp(0.8125rem, 0.78rem + 0.16vw, 0.875rem);
  --t-body:  clamp(0.9375rem, 0.9rem + 0.2vw, 1.0625rem);
  --t-lead:  clamp(1.0625rem, 0.98rem + 0.44vw, 1.3125rem);
  --t-h4:    clamp(1.125rem, 1rem + 0.62vw, 1.5rem);
  --t-h3:    clamp(1.5rem, 1.18rem + 1.3vw, 2.375rem);
  --t-h2:    clamp(1.875rem, 1.22rem + 2.75vw, 3.875rem);
  --t-h1:    clamp(2.125rem, 0.95rem + 4.2vw, 5.125rem);
  --t-mega:  clamp(2.5rem, 0.72rem + 8vw, 9rem);

  /* Motion. Personality: ruled, not floaty. Things are drawn or set down.
     Nothing bounces, nothing overshoots, nothing floats. */
  --e-out:   cubic-bezier(0.22, 1, 0.36, 1);
  --e-fast:  cubic-bezier(0.16, 1, 0.30, 1);
  --e-move:  cubic-bezier(0.40, 0, 0.20, 1);
  --d-micro: 180ms;
  --d-hover: 260ms;
  --d-std:   600ms;
  --d-large: 880ms;
  --d-cine:  1250ms;

  --page-max: 1560px;
  --gutter: clamp(20px, 5vw, 84px);

  /* ------------------------------------------ 3. SEMANTIC TOKENS (page) */
  --ground:        var(--c-bar);
  --surface:       var(--c-sheet);
  --surface-hi:    var(--c-sheet-hi);
  --surface-deep:  var(--c-bar-deep);
  --line:          var(--c-rule);
  --line-soft:     var(--c-rule-soft);
  --text:          var(--c-ink);
  --text-2:        var(--c-ink-2);
  --text-3:        var(--c-ink-3);
  --mark:          var(--c-proof);
  --focus:         var(--c-ink);
}

/* The cover. A scoped theme, exactly like the six panel themes — the same
   mechanism, so nothing below reads a primitive directly. */
.cover-theme,
.t-cover {
  --ground:       var(--c-buckram);
  --surface:      var(--c-buckram-lift);
  --surface-hi:   #182b1f;
  --surface-deep: var(--c-buckram-deep);
  --line:         #2c4534;
  --line-soft:    #172a1d;
  --text:         var(--c-sheet-hi);
  --text-2:       #b6c4b2;
  --text-3:       #8b9a89;
  --mark:         #e0705f;
  --focus:        var(--c-sheet-hi);
}

/* --------------------------------------------------------- 4. BASE TYPE */
body {
  font-family: var(--f-ui);
  font-size: var(--t-body);
  font-variation-settings: "wght" 400;
  line-height: 1.62;
  color: var(--text-2);
  background: var(--ground);
  overflow-x: hidden;
  font-feature-settings: "kern" 1, "liga" 1;
}

h1, h2, h3, h4 {
  font-family: var(--f-display);
  font-weight: 400;
  color: var(--text);
  line-height: 1.0;
  letter-spacing: -0.014em;
  text-wrap: balance;
  /* Literata, replacing Newsreader on 21 Sep (which had replaced Fraunces on
     30 Aug): the client read Newsreader as the typeface every AI-built site
     wears. Literata is a book face — made for reading long text on screens —
     with real italics, a conventional f, and an optical-size axis of 7–72,
     so every opsz value below still lands inside the range. */
  font-variation-settings: "opsz" 72;
}
h1 { font-size: var(--t-h1); letter-spacing: -0.025em; }
h2 { font-size: var(--t-h2); letter-spacing: -0.021em; }
h3 { font-size: var(--t-h3); font-variation-settings: "opsz" 48; }
h4 { font-size: var(--t-h4); line-height: 1.14; font-variation-settings: "opsz" 24; }

p { text-wrap: pretty; }
strong, b { color: var(--text); font-variation-settings: "wght" 550; font-weight: 400; }

.lead {
  font-size: var(--t-lead);
  line-height: 1.44;
  color: var(--text-2);
  max-width: 34ch;
  letter-spacing: -0.008em;
}

/* The label — mono, tracked, the site's connective tissue. Never below 11px
   and never in --text-3, which does not clear AA at this size. */
.label {
  font-family: var(--f-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--text-2);
  font-weight: 400;
}
.num { font-family: var(--f-mono); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }

/* ============================================================ 5. THE MOTIF */
/* The ruled cell, and its family. GRAPHICS.md documents the construction:
   1px stroke, 16px grid, square corners only, 90° angles only. */

/* --- the ground. The green-bar REPEAT was removed on 30 Aug: alternating
   bands across a full page fight body text, which is the one place this
   skill's own rules say pattern must never go. The motif survives in the
   rules, the cells and the corner brackets — the members that carry meaning.
   The paper keeps its colour; it just stops striping. */
.ruled { background-color: var(--ground); }

/* --- the linear form. Replaces <hr> everywhere. Draws left to right. */
.rule {
  height: 1px;
  background: var(--line);
  transform-origin: left center;
  width: 100%;
}
.rule--draw { transform: scaleX(0); transition: transform var(--d-cine) var(--e-out); }
.is-in .rule--draw, .rule--draw.is-in { transform: scaleX(1); }

/* --- the cell: the primary mark. One horizontal rule, one vertical,
   meeting bottom-left. Drawn with borders so it costs nothing. */
.cell {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-left: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  flex: none;
  position: relative;
}
/* the entry mark inside the cell — verified */
.cell--check::after {
  content: "";
  position: absolute;
  left: 3px; bottom: 3px;
  width: 5px; height: 9px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transform-origin: center;
}
/* the entry mark inside the cell — struck */
.cell--struck::after {
  content: "";
  position: absolute;
  left: 2px; top: 6px;
  width: 12px; height: 1.5px;
  background: currentColor;
}

/* --- the corner form: a quarter cell, for framing the client plates */
.corner {
  position: absolute;
  width: 15px; height: 15px;
  pointer-events: none;
  z-index: 3;
  border-color: var(--line);
}
.corner--tl { top: -1px; left: -1px; border-top: 1.5px solid; border-left: 1.5px solid; }
.corner--tr { top: -1px; right: -1px; border-top: 1.5px solid; border-right: 1.5px solid; }
.corner--bl { bottom: -1px; left: -1px; border-bottom: 1.5px solid; border-left: 1.5px solid; }
.corner--br { bottom: -1px; right: -1px; border-bottom: 1.5px solid; border-right: 1.5px solid; }

/* --------------------------------------------------------- 6. STRUCTURE */
.wrap {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.section { position: relative; padding-block: clamp(72px, 11vh, 172px); }
.section--tight { padding-block: clamp(52px, 7vh, 104px); }

/* A sheet: content set down on the paper between the bars. This is the
   composition change v1 never made — the page has two levels, not one. */
.sheet {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  padding: clamp(24px, 3.4vw, 56px);
}
.sheet--hi { background: var(--surface-hi); }

.eyebrow { display: flex; align-items: center; gap: var(--s-4); margin-bottom: var(--s-5); }
.eyebrow::after {
  content: "";
  flex: 1; height: 1px; background: var(--line);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--d-cine) var(--e-out) 120ms;
}
.is-in .eyebrow::after { transform: scaleX(1); }

/* --------------------------------------------------- 7. REVEAL PRIMITIVE */
[data-reveal] { will-change: transform, opacity; }
[data-reveal="up"] { opacity: 0; transform: translate3d(0, 22px, 0); }
[data-reveal="fade"] { opacity: 0; }
[data-reveal="clip"] { clip-path: inset(0 0 101% 0); }
[data-reveal].is-in {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 -8% 0);
  will-change: auto;
  transition:
    opacity var(--d-std) var(--e-out) var(--reveal-delay, 0ms),
    transform var(--d-std) var(--e-out) var(--reveal-delay, 0ms),
    clip-path var(--d-large) var(--e-out) var(--reveal-delay, 0ms);
}

/* Line-masked display type. The lines are authored in the markup, so a
   screen reader reads the heading exactly as written. */
.split { display: block; }
/* The mask has to clear the deepest descender in the face, not a guess: at
   --t-mega the q in "a question." was being cut by its own reveal mask. */
.split__line { display: block; overflow: hidden; padding-bottom: 0.18em; margin-bottom: -0.18em; }
.split__line > span {
  display: block;
  transform: translate3d(0, 105%, 0);
  transition: transform var(--d-cine) var(--e-out);
  transition-delay: calc(var(--i, 0) * 80ms);
}
.is-in .split__line > span { transform: none; }

/* ------------------------------------------------------- 8. LINKS & CTA */
.link { position: relative; display: inline-block; color: var(--text); padding-bottom: 2px; }
.link::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 1px;
  background: currentColor; transform: scaleX(var(--u, 1)); transform-origin: right;
  transition: transform var(--d-hover) var(--e-fast);
}
.link:hover::after, .link:focus-visible::after { --u: 0; }

.btn {
  --btn-fg: var(--surface-hi);
  --btn-bg: var(--text);
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  padding: 14px var(--s-6);
  font-family: var(--f-mono);
  font-size: var(--t-micro);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--btn-fg);
  background: var(--btn-bg);
  border: 1px solid var(--btn-bg);
  overflow: hidden;
  isolation: isolate;
  transition: color var(--d-hover) var(--e-fast);
}
/* The fill is ruled in from the left, like a pen stroke. */
.btn::before {
  content: ""; position: absolute; inset: 0;
  background: var(--ground);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--d-hover) var(--e-move);
  z-index: -1;
}
.btn:hover, .btn:focus-visible { color: var(--text); }
.btn:hover::before, .btn:focus-visible::before { transform: scaleX(1); }
.btn .cell { width: 11px; height: 11px; }

.btn--ghost { --btn-fg: var(--text); --btn-bg: transparent; border-color: var(--line); }
.btn--ghost::before { background: var(--text); }
.btn--ghost:hover, .btn--ghost:focus-visible { color: var(--surface-hi); border-color: var(--text); }

:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
.skip {
  position: absolute; left: var(--s-4); top: var(--s-4);
  padding: var(--s-3) var(--s-5);
  background: var(--c-ink); color: var(--c-sheet-hi);
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.1em; text-transform: uppercase;
  z-index: 200; transform: translateY(-200%);
  transition: transform var(--d-micro) var(--e-fast);
}
.skip:focus { transform: none; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ================================================================ 9. NAV */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  padding-block: var(--s-4);
  transition: transform var(--d-std) var(--e-move), background-color var(--d-std) var(--e-move);
  color: var(--c-sheet-hi);
}
.nav::after {
  content: ""; position: absolute; inset: 0;
  background: color-mix(in oklab, var(--c-bar) 88%, transparent);
  border-bottom: 1px solid var(--c-rule);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  opacity: 0; transition: opacity var(--d-std) var(--e-move);
  z-index: -1; pointer-events: none;
}
/* On the cover the nav is bleached paper; once onto the page it becomes ink. */
.nav.is-stuck { color: var(--c-ink); }
.nav.is-stuck::after { opacity: 1; }
.nav.is-hidden { transform: translateY(-100%); }
/* Off the screen entirely while the deck has the viewport. Each style page is
   a composition that runs to all four edges, and a bar with somebody else's
   wordmark across the top of it is the one thing guaranteed to break the
   illusion that you are looking at that kind of site. It comes back the moment
   the deck lets go — and immediately for anyone who tabs into it, which is why
   this is `focus-within` and not `display: none`. */
.nav.is-away { transform: translateY(-100%); pointer-events: none; }
.nav.is-away:focus-within { transform: none; pointer-events: auto; }
.nav__inner { display: flex; align-items: center; justify-content: space-between; gap: var(--s-5); }

.mark {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--f-display);
  font-size: 1.3125rem; letter-spacing: -0.018em; line-height: 1;
  font-variation-settings: "opsz" 28;
  color: currentColor;
}
.mark .cell { width: 13px; height: 13px; }
/* the logo, Thread (18 Sep 2026): the ampersand as a thread ending in the bodkin */
.mark__logo { width: 20px; height: 24px; flex: none; margin-top: -2px; }

.nav__links { display: flex; align-items: center; gap: var(--s-6); }
.nav__link {
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.11em; text-transform: uppercase;
  position: relative; padding-block: 4px; opacity: .74;
  transition: opacity var(--d-hover) var(--e-fast);
}
.nav__link::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: left;
  transition: transform var(--d-hover) var(--e-fast);
}
.nav__link:hover, .nav__link:focus-visible { opacity: 1; }
.nav__link:hover::after, .nav__link:focus-visible::after { transform: scaleX(1); }
.nav__cta {
  padding: 10px var(--s-5);
  --btn-fg: var(--c-buckram); --btn-bg: var(--c-sheet-hi);
}
.nav__cta::before { background: transparent; }
.nav__cta:hover, .nav__cta:focus-visible { color: var(--c-buckram); }
.nav.is-stuck .nav__cta { --btn-fg: var(--c-sheet-hi); --btn-bg: var(--c-ink); }
.nav.is-stuck .nav__cta:hover { color: var(--c-ink); }
.nav.is-stuck .nav__cta::before { background: var(--c-bar); }
@media (max-width: 900px) { .nav__links .nav__link { display: none; } }

/* The opening. The cover states the name; this states the business. It is the
   first page of the book, and it carries the copy and the two routes that used
   to sit at the foot of the cover. */
.opening { padding: clamp(64px, 11vh, 128px) 0 clamp(48px, 8vh, 92px); }
.opening__h {
  font-size: var(--t-h1); max-width: 20ch;
  margin: var(--s-5) 0 var(--s-6);
}
.opening__h .q { color: var(--text-3); }
.opening__actions { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-6); }

/* ====================================================== 10. THE COVER ==
   The book's cover. One fixed canvas renders the buckram cloth, the
   blind-stamped cell, and a raking lamp; scroll lifts it off the page.
   The CSS underneath is a complete, deliberate composition on its own —
   if WebGL never initialises nobody can tell, because the fallback uses
   the same colours and the same stamped geometry. */
.cover {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: clamp(96px, 14vh, 156px) var(--s-6) clamp(96px, 13vh, 150px);
  overflow: hidden;
  background: var(--c-buckram);
  isolation: isolate;
}
.cover__fallback {
  position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(130% 90% at 24% 12%, #16281c 0%, transparent 58%),
    repeating-linear-gradient(90deg, rgb(255 255 255 / .012) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(0deg, rgb(0 0 0 / .045) 0 1px, transparent 1px 3px),
    var(--c-buckram);
}
/* The binder's panel, for when the shader never runs — a phone, no WebGL2,
   reduced motion, a lost context. Same geometry the shader stamps: a double
   rule with the cell at each corner, drawn flat rather than debossed, because
   CSS has no raking light to catch an impression with. Both rules and all
   four corners hang off one set of variables so the composition stays whole
   when it is retuned for a narrow screen. */
.cover__fallback {
  --pnl-y: 28.5%; --pnl-x: 23.2%; --pnl-gap: 14px; --pnl-cnr: 20px;
  --pnl-ink: rgb(255 255 255 / .13);
}
.cover__fallback::before {
  content: "";
  position: absolute; inset: var(--pnl-y) var(--pnl-x);
  border: 1px solid rgb(255 255 255 / .10);
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / .34),
              inset 0 0 0 var(--pnl-gap) transparent,
              inset 0 0 0 calc(var(--pnl-gap) + 1px) rgb(255 255 255 / .05);
}
.cover__fallback::after {
  content: "";
  position: absolute;
  inset: calc(var(--pnl-y) + var(--pnl-gap) + 12px) calc(var(--pnl-x) + var(--pnl-gap) + 12px);
  background:
    linear-gradient(var(--pnl-ink), var(--pnl-ink)) left  top    / 1px var(--pnl-cnr) no-repeat,
    linear-gradient(var(--pnl-ink), var(--pnl-ink)) left  top    / var(--pnl-cnr) 1px no-repeat,
    linear-gradient(var(--pnl-ink), var(--pnl-ink)) right top    / 1px var(--pnl-cnr) no-repeat,
    linear-gradient(var(--pnl-ink), var(--pnl-ink)) right top    / var(--pnl-cnr) 1px no-repeat,
    linear-gradient(var(--pnl-ink), var(--pnl-ink)) left  bottom / 1px var(--pnl-cnr) no-repeat,
    linear-gradient(var(--pnl-ink), var(--pnl-ink)) left  bottom / var(--pnl-cnr) 1px no-repeat,
    linear-gradient(var(--pnl-ink), var(--pnl-ink)) right bottom / 1px var(--pnl-cnr) no-repeat,
    linear-gradient(var(--pnl-ink), var(--pnl-ink)) right bottom / var(--pnl-cnr) 1px no-repeat;
}
/* A portrait screen wants a portrait panel, but not a narrow one — the
   sub-line has to sit inside the rules, not run through them. */
@media (max-width: 760px) {
  .cover__fallback { --pnl-y: 21%; --pnl-x: 7%; --pnl-gap: 9px; --pnl-cnr: 14px; }
}
.cover__canvas {
  position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%;
  opacity: 0; transition: opacity 1400ms var(--e-out);
}
.cover__canvas.is-live { opacity: 1; }
.cover__veil {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: linear-gradient(to bottom,
    rgb(4 12 6 / .46) 0%, rgb(4 12 6 / 0) 22%,
    rgb(4 12 6 / .32) 72%, rgb(4 12 6 / .76) 100%);
}
.cover__inner { position: relative; z-index: 3; width: 100%; }

/* The name, and nothing else. A book's cover carries its title; the case
   for the studio starts on the first page, not on the board. */
.cover__name {
  font-family: var(--f-display);
  font-size: clamp(2.25rem, 0.4rem + 6.2vw, 6.75rem);
  font-variation-settings: "opsz" 72;
  line-height: 1.0;
  letter-spacing: -0.022em;
  color: var(--text);
  margin: 0;
}
/* One unbroken hairline. It carried the cell in the middle until 30 Aug —
   the mark interrupted the rule instead of finishing it, and it arrived on
   its own delay, so the eye caught it moving into a gap. */
.cover__rule {
  display: flex; justify-content: center;
  margin: clamp(20px, 3.2vh, 34px) 0 clamp(16px, 2.4vh, 26px);
}
.cover__rule::before {
  content: ""; height: 1px; width: clamp(72px, 13vw, 190px); background: var(--line);
  transform: scaleX(0); transform-origin: center;
  transition: transform 900ms var(--e-out) var(--reveal-delay, 0ms);
}
.cover__rule.is-in::before { transform: scaleX(1); }
.cover__sub { color: var(--text-3); margin: 0; }

/* The cover moves as one block. Splitting the name into letters cost the
   kerning between them and made the page busy; the type now simply arrives,
   and scroll lifts the whole composition. */
.cover__inner { will-change: transform, opacity; }

.cover__foot {
  position: absolute; z-index: 3; left: 50%; transform: translateX(-50%);
  bottom: clamp(26px, 4.5vh, 52px);
}

/* The scroll cue is a rule being drawn and erased, forever. Mechanical is
   correct here — it is the only looping animation on the site. */
.cue { display: flex; align-items: center; gap: var(--s-4); }
.cue__track { width: 58px; height: 1px; background: var(--line); overflow: hidden; }
.cue__track::after {
  content: ""; display: block; height: 100%; width: 100%;
  background: var(--text); transform-origin: left;
  animation: cue 2600ms var(--e-move) infinite;
}
@keyframes cue {
  0%   { transform: scaleX(0); transform-origin: left; }
  46%  { transform: scaleX(1); transform-origin: left; }
  54%  { transform: scaleX(1); transform-origin: right; }
  100% { transform: scaleX(0); transform-origin: right; }
}

/* =================================================== 11. THE FIRST PAGE */

/* ====================================================== 12. THE ENTRIES ==
   The claim register. v2's first draft failed for two reasons the client named:
   it was argued before the visitor knew who the studio was, and the mechanic
   was not legible — a struck marketing phrase requires the reader to infer
   whose phrase it was, that it was rejected, and why. Three inferences.

   Rebuilt as a two-column account-book entry: what was found on the client's own
   site, and what was done about it. The finding is concrete and quoted, so
   nothing has to be inferred. */
.entries__head {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr);
  gap: var(--s-8); align-items: end; margin-bottom: clamp(36px, 5vh, 72px);
}
@media (max-width: 900px) { .entries__head { grid-template-columns: 1fr; gap: var(--s-6); } }

.entries { border-top: 1px solid var(--line); }
.entry {
  display: grid;
  grid-template-columns: 3.25rem minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--s-6);
  padding-block: clamp(24px, 3vh, 40px);
  border-bottom: 1px solid var(--line);
  position: relative;
}
/* the ruled cell edge marking each entry */
.entry::before {
  content: ""; position: absolute; left: 0; bottom: -1px;
  width: 3.25rem; height: 1px; background: var(--text);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--d-large) var(--e-out) 100ms;
}
.entry.is-in::before { transform: scaleX(1); }
.entry__n {
  font-family: var(--f-mono); font-size: var(--t-micro);
  color: var(--text-2); letter-spacing: 0.1em; padding-top: 0.4em;
}
.entry__label {
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--text-2); margin-bottom: var(--s-3);
  display: flex; align-items: center; gap: var(--s-2);
}
.entry__label .cell { width: 10px; height: 10px; }

/* The specimen: the thing as it was actually found, quoted verbatim and
   struck, because none of it shipped in that form. */
.entry__spec {
  position: relative; width: fit-content; max-width: 100%;
  font-family: var(--f-display);
  font-size: var(--t-h4); line-height: 1.18;
  color: var(--text); letter-spacing: -0.012em;
  font-variation-settings: "opsz" 28;
  transition: color var(--d-large) var(--e-out) 220ms;
  margin-bottom: var(--s-3);
}
.entry__spec--mono {
  font-family: var(--f-mono); font-size: var(--t-body);
  letter-spacing: 0.02em; font-variant-numeric: tabular-nums;
}
.entry__spec::after {
  content: ""; position: absolute;
  left: -0.06em; right: -0.06em; top: 53%; height: 2px;
  background: var(--mark);
  transform: scaleX(0); transform-origin: left center;
  transition: transform var(--d-cine) var(--e-out) 180ms;
}
.entry.is-in .entry__spec::after { transform: scaleX(1); }
.entry.is-in .entry__spec { color: var(--text-2); }

.entry__note { font-size: var(--t-small); color: var(--text-2); line-height: 1.6; max-width: 42ch; }

.entry__did {
  opacity: 0; transform: translate3d(0, 8px, 0);
  transition: opacity var(--d-std) var(--e-out) 620ms, transform var(--d-std) var(--e-out) 620ms;
}
.entry.is-in .entry__did { opacity: 1; transform: none; }
.entry__act {
  font-family: var(--f-display); font-size: var(--t-h4);
  font-variation-settings: "opsz" 28;
  color: var(--text); line-height: 1.18; margin-bottom: var(--s-3);
}
.entry__why { font-size: var(--t-small); color: var(--text-2); line-height: 1.62; max-width: 46ch; }
.entry__why b { color: var(--text); font-variation-settings: "wght" 550; }

@media (max-width: 900px) {
  .entry { grid-template-columns: 2.5rem 1fr; gap: var(--s-4); }
  .entry::before { width: 2.5rem; }
  .entry__did { grid-column: 2; padding-top: var(--s-4); border-top: 1px solid var(--line-soft); }
}

/* On the studio page the trades are a plain list of what the studio knows,
   not specimens found and corrected: two columns, nothing struck through. */
.trades .entries { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(32px, 5vw, 96px); }
.trades .entry { grid-template-columns: 3.25rem minmax(0, 1fr); align-content: start; }
.trades .entry__spec::after { display: none; }
.trades .entry.is-in .entry__spec { color: var(--text); }
.trades .entry__why, .trades .entry__note { max-width: 52ch; }
.trades .entries__foot { grid-column: 1 / -1; display: block; font-size: var(--t-small); max-width: 62ch; }
@media (max-width: 900px) {
  .trades .entries { grid-template-columns: 1fr; }
  .trades .entry { grid-template-columns: 2.5rem 1fr; }
}

.entries__foot {
  margin-top: clamp(32px, 4.5vh, 56px);
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-5);
  justify-content: space-between;
}
.entries__foot p { font-size: var(--t-small); max-width: 62ch; }

/* ======================================================= 13. THE DECK ==
   Six full-viewport pages on the document's own scroll: a runway one viewport
   tall per page, a stage stuck to the viewport for the length of it, and the
   page shown chosen from the scroll position alone. See `.deck-stage` below.
   ========================================================================= */
.deck-wrap { position: relative; background: var(--c-buckram); }

/* The run's introduction: a screen of its own in the cover's cloth, above
   the styles. It is the run's first stop, so one gesture takes the reader
   from it to the first style — the complaint it was briefly shortened for
   was the scrolling it took to clear, not its size. */
.deck-intro {
  min-height: 100svh;
  display: grid; align-content: center;
  padding: clamp(96px, 14vh, 180px) var(--gutter) clamp(80px, 11vh, 140px);
  color: var(--text-2);
}
.deck-intro h2 { font-size: var(--t-h2, var(--t-h1)); color: var(--text); }

.deck-intro__grid { width: 100%; max-width: var(--page-max); margin-inline: auto; 
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.62fr);
  gap: clamp(28px, 5vw, 90px);
  align-items: end;
}
@media (max-width: 900px) { .deck-intro__grid { grid-template-columns: 1fr; gap: var(--s-5); align-items: start; } }
.deck-intro__note {
  margin-top: var(--s-5); padding-top: var(--s-4);
  border-top: 1px solid var(--line);
  font-family: var(--f-mono); font-size: var(--t-micro);
  line-height: 1.85; letter-spacing: 0.02em; color: var(--text-2);
  max-width: 48ch;
}

/* The deck is five ordinary full-viewport sections in the document's own
   flow. Nothing is sticky, nothing is absolutely positioned, nothing is
   hidden waiting for a script — which is the whole point: a page cannot be
   "scrolled past before it loads" if it was never hidden, and there is no
   state that can be left wrong by a reload, a fast run back up, or a
   restored scroll position.

   The turn of a page is a settle in site.js §4: when the scroll has been
   still for a moment inside the deck, the next page in the direction of
   travel is brought flush. CSS scroll snapping was tried first and removed —
   `proximity` re-snaps anything inside its own threshold, so a plain mouse
   wheel (about 100px a notch) could not move off a page at all, and
   `mandatory` on the root dragged the whole site into the deck from as far
   away as the cover.

   The introduction above the run is a screen of its own and the run's first
   stop, so one gesture takes the reader from it to the first style. */
.deck { position: relative; }
.deck-stage { position: relative; }
.deck-on .deck__rail { opacity: 1; pointer-events: auto; }
.deck-on .deck__foot { opacity: 1; }
.deck__rail, .deck__foot { transition: opacity 420ms var(--e-out); }
.deck:focus-visible { outline: 2px solid var(--c-sheet-hi); outline-offset: -3px; }

.style-page {
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: clamp(64px, 9vh, 104px) var(--gutter) clamp(72px, 10vh, 112px);
  background: var(--ground);
  color: var(--text-2);
  position: relative;
  overflow: hidden;
}

.sp__n {
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--text-2); display: block; margin-bottom: var(--s-4);
}
.sp__name {
  line-height: 1.0;
  letter-spacing: -0.026em;
  color: var(--text);
}
.sp__def { color: var(--text); letter-spacing: -0.008em; }
.sp__for { font-size: var(--t-small); line-height: 1.6; color: var(--text-2); }
.sp__for b { color: var(--text); font-variation-settings: "wght" 550; }
.traits { border-top: 1px solid var(--line-soft); }
.trait {
  display: grid; grid-template-columns: 8ch 1fr; gap: var(--s-3);
  align-items: baseline; padding-block: 9px;
  border-bottom: 1px solid var(--line-soft);
  font-size: var(--t-small); line-height: 1.5; color: var(--text-2);
}
.trait b { color: var(--text); font-variation-settings: "wght" 550; }
/* each style's traits are a plain spec sheet (owner, 5 Oct: "less AI"): a word, then the fact */
.trait dt { color: var(--text); font-family: var(--f-ui); font-variation-settings: "wght" 550; }
.sp--gallery .trait dt { margin-bottom: 2px; }
.trait .cell { width: 10px; height: 10px; margin-top: 4px; }
.sp__built {
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.05em; line-height: 1.7; color: var(--text-2);
}
.sp__built b { color: var(--text); font-weight: 400; }

/* The arrow out to a working example. Drawn in the motif's language —
   square, ruled, no curves — and it is the only element that repeats
   identically across all five, because it is chrome, not style. */
.sp__see {
  display: inline-flex; align-items: center; gap: var(--s-4);
  padding: 13px var(--s-5);
  border: 1px solid var(--text);
  background: transparent;
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.13em; text-transform: uppercase;
  text-wrap: balance;                 /* on a phone the demo's name wraps; never "DEMO" alone on a line */
  color: var(--text);
  position: relative; overflow: hidden; isolation: isolate;
  transition: color var(--d-hover) var(--e-fast);
}
.sp__see::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--text); transform: scaleX(0); transform-origin: left;
  transition: transform var(--d-hover) var(--e-move);
}
.sp__see:hover, .sp__see:focus-visible { color: var(--ground); }
.sp__see:hover::before, .sp__see:focus-visible::before { transform: scaleX(1); }
.sp__arrow { position: relative; width: 26px; height: 8px; flex: none; }
.sp__arrow::before {
  content: ""; position: absolute; left: 0; top: 3.5px;
  width: 100%; height: 1.5px; background: currentColor;
  transform-origin: left; transition: transform var(--d-hover) var(--e-out);
}
.sp__arrow::after {
  content: ""; position: absolute; right: 0; top: 0;
  width: 8px; height: 8px;
  border-top: 1.5px solid currentColor; border-right: 1.5px solid currentColor;
  transform: rotate(45deg); transform-origin: center;
}
.sp__see:hover .sp__arrow::before { transform: scaleX(1.25); }

/* ════════════════════════════ THE FIVE EFFECTS ════════════════════════════
   Each page is set IN the style it names — the page is the specimen. Five
   genuinely separate compositions on shared class names, each built around
   one effect a site can have on the person reading it. No numbers anywhere:
   the run is open-ended and is described as such. */

/* the themes: each derived from the thing the style is named after */
.t-reel    { --ground:#0e1012; --surface:#16191c; --surface-hi:#1d2125; --surface-deep:#08090a; --line:#363d43; --line-soft:#23282c; --text:#f1ede4; --text-2:#b3ada2; --text-3:#7c7871; --mark:#e8552c; --focus:#f1ede4; }
.t-curtain { --ground:#1a0c10; --surface:#27151a; --surface-hi:#341c22; --surface-deep:#0f0507; --line:#5c3139; --line-soft:#3b2027; --text:#f7ece6; --text-2:#cdb2aa; --text-3:#9a7c7e; --mark:#d9a75b; --focus:#f7ece6; }
/* the Gallery is a white cube and the Estate a club library: they were two
   creams with a dark serif, and read as one style twice */
.t-gallery { --ground:#ffffff; --surface:#f5f5f4; --surface-hi:#ffffff; --surface-deep:#ebebea; --line:#e2e2e2; --line-soft:#efefef; --text:#0f0f0f; --text-2:#555555; --text-3:#767676; --mark:#0f0f0f; --focus:#0f0f0f; }
.t-poster  { --ground:#d8ff3d; --surface:#ffffff; --surface-hi:#ffffff; --surface-deep:#c2ea2a; --line:#0b0b0f; --line-soft:#0b0b0f; --text:#0b0b0f; --text-2:#1d1d24; --text-3:#3b3b45; --mark:#ff2d8a; --cobalt:#2b3cff; --focus:#0b0b0f; }
.t-estate  { --ground:#15291f; --surface:#1b3327; --surface-hi:#21392d; --surface-deep:#0f1f17; --line:#4b5a40; --line-soft:#2c4034; --text:#efe6cf; --text-2:#cfc6ad; --text-3:#a39d86; --mark:#c6a15e; --focus:#efe6cf; }

/* shared: a text column and a visual, side by side; the visual goes first on a phone */
.sp--reel .style-page__inner,
.sp--curtain .style-page__inner,
.sp--poster .style-page__inner {
  display: grid; width: 100%; max-width: 1280px; margin-inline: auto;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: clamp(28px, 4vw, 72px); align-items: center;
}
.sp__text { min-width: 0; }
.sp__name { font-size: clamp(2.5rem, 1.3rem + 4.2vw, 5.5rem); margin-bottom: var(--s-4); }
.sp__def { font-size: var(--t-lead); max-width: 30ch; margin-bottom: var(--s-4); }
.sp__for { max-width: 52ch; margin-bottom: var(--s-5); }
.sp__foot { margin-top: var(--s-5); display: flex; flex-wrap: wrap; gap: var(--s-4); align-items: center; }
@media (max-width: 900px) {
  .sp--reel .style-page__inner, .sp--curtain .style-page__inner, .sp--poster .style-page__inner { grid-template-columns: 1fr; gap: var(--s-6); }
  .sp__strip, .sp__stage, .sp__stack { order: -1; }
}

/* ── THE REEL: a filmstrip with a playhead that runs down it ─────────── */
.sp--reel .sp__n { color: var(--mark); }
.sp__strip {
  position: relative; margin: 0; justify-self: center;
  width: min(100%, 300px); aspect-ratio: 3 / 4; max-height: 62vh;
  padding: 0 22px; background: var(--surface);
  border: 1px solid var(--line);
  /* sprocket holes, both edges */
  background-image:
    repeating-linear-gradient(to bottom, transparent 0 14px, var(--ground) 14px 24px, transparent 24px 34px),
    repeating-linear-gradient(to bottom, transparent 0 14px, var(--ground) 14px 24px, transparent 24px 34px);
  background-size: 8px 34px, 8px 34px; background-repeat: repeat-y;
  background-position: 6px 0, calc(100% - 6px) 0;
}
.sp__strip__frames { display: grid; grid-template-rows: repeat(5, 1fr); height: 100%; gap: 8px; padding: 10px 0; }
.sp__frame { position: relative; display: block; border: 1px solid var(--line); background: var(--ground); overflow: hidden; opacity: .32; }
.sp__frame i { position: absolute; left: 12%; right: 12%; bottom: 14%; height: calc(var(--h, .5) * 70%); background: var(--text); opacity: .85; transform-origin: bottom; }
.sp__frame::after { content: ""; position: absolute; left: 12%; top: 14%; width: 30%; height: 3px; background: var(--mark); }
.sp__playhead { position: absolute; left: 0; right: 0; top: 0; height: 2px; background: var(--mark); box-shadow: 0 0 12px var(--mark); }
.sp__stripCap { position: absolute; left: 50%; bottom: -30px; transform: translateX(-50%); white-space: nowrap; font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-3); }
@keyframes sp-head  { from { top: 2%; } to { top: 98%; } }
@keyframes sp-frame { 0%, 12% { opacity: .32; } 20%, 100% { opacity: 1; } }
.sp--reel.is-live .sp__playhead { animation: sp-head 7s linear infinite; }
.sp--reel.is-live .sp__frame { animation: sp-frame 7s linear infinite; }
.sp--reel.is-live .sp__frame:nth-child(1) { animation-delay: -6.6s; }
.sp--reel.is-live .sp__frame:nth-child(2) { animation-delay: -5.2s; }
.sp--reel.is-live .sp__frame:nth-child(3) { animation-delay: -3.8s; }
.sp--reel.is-live .sp__frame:nth-child(4) { animation-delay: -2.4s; }
.sp--reel.is-live .sp__frame:nth-child(5) { animation-delay: -1.0s; }

/* ── THE CURTAIN: two drapes part, and a small stage runs through its wipes ── */
.sp__drape {
  position: absolute; top: 0; bottom: 0; width: 51%; z-index: 4;
  background: var(--surface-deep);
  background-image: repeating-linear-gradient(to right, transparent 0 26px, rgb(255 255 255 / .035) 26px 30px);
  pointer-events: none;
}
.sp__drape--l { left: 0; border-right: 1px solid var(--mark); }
.sp__drape--r { right: 0; border-left: 1px solid var(--mark); }
.js .sp--curtain.is-live .sp__drape--l { animation: sp-part-l 1100ms cubic-bezier(.7, 0, .2, 1) both; }
.js .sp--curtain.is-live .sp__drape--r { animation: sp-part-r 1100ms cubic-bezier(.7, 0, .2, 1) both; }
.js .sp--curtain:not(.is-live) .sp__drape { transform: none; }
.no-js .sp__drape, html:not(.js) .sp__drape { display: none; }
@keyframes sp-part-l { to { transform: translate3d(-101%, 0, 0); } }
@keyframes sp-part-r { to { transform: translate3d(101%, 0, 0); } }
.sp--curtain .sp__name { font-style: italic; letter-spacing: -0.02em; }
.sp--curtain .sp__n { color: var(--mark); }
.sp__stage {
  position: relative; margin: 0; justify-self: center;
  width: min(100%, 360px); aspect-ratio: 4 / 5; max-height: 58vh;
  border: 1px solid var(--line); background: var(--surface); overflow: hidden;
}
.sp__slide {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--f-display); font-size: clamp(2rem, 1rem + 3vw, 3.5rem); font-style: italic;
  color: var(--text); clip-path: inset(0 0 0 100%);
}
.sp__slide b { font-weight: 400; }
.sp__slide--1 { background: var(--surface-hi); }
.sp__slide--2 { background: var(--mark); color: var(--surface-deep); }
.sp__slide--3 { background: var(--surface-deep); }
.sp__stageCap { position: absolute; left: 50%; bottom: -30px; transform: translateX(-50%); white-space: nowrap; font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-3); }
/* each slide wipes in from the right, holds, and is wiped over by the next */
@keyframes sp-wipe-cycle {
  0%   { clip-path: inset(0 0 0 100%); }
  10%  { clip-path: inset(0 0 0 0); }
  43%  { clip-path: inset(0 0 0 0); }
  53%  { clip-path: inset(0 100% 0 0); }
  100% { clip-path: inset(0 100% 0 0); }
}
.sp--curtain.is-live .sp__slide { animation: sp-wipe-cycle 7.5s cubic-bezier(.7, 0, .2, 1) infinite; }
.sp--curtain.is-live .sp__slide--1 { animation-delay: 0s; }
.sp--curtain.is-live .sp__slide--2 { animation-delay: 2.5s; }
.sp--curtain.is-live .sp__slide--3 { animation-delay: 5s; }

/* ── THE GALLERY: the name, a rule, and a great deal of nothing ───────── */
.sp--gallery .style-page__inner {
  display: grid; width: 100%; max-width: 1320px; margin-inline: auto; height: 100%;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.75fr);
  grid-template-rows: auto minmax(0, 1fr);
  column-gap: clamp(28px, 5vw, 96px); align-items: end;
}
.sp--gallery .sp__head { grid-column: 1 / -1; grid-row: 1; }
.sp--gallery .sp__n { letter-spacing: 0.3em; color: var(--mark); }
.sp--gallery .sp__name { font-family: var(--f-ui); font-size: clamp(3rem, 1.4rem + 6.4vw, 8rem); font-weight: 300; letter-spacing: -0.045em; margin-bottom: var(--s-4); }
.sp__rule { display: block; height: 1px; background: var(--mark); transform-origin: left; }
.sp--gallery .sp__text { grid-column: 1; grid-row: 2; align-self: end; padding-top: clamp(20px, 3.5vh, 44px); }
.sp--gallery .sp__def { font-family: var(--f-ui); font-weight: 400; font-size: clamp(1.25rem, 1rem + 1vw, 1.75rem); letter-spacing: -0.02em; max-width: 24ch; }
.sp--gallery .sp__for { max-width: 46ch; }
.sp--gallery .traits { border-top: 0; columns: 2; column-gap: var(--s-6); max-width: 60ch; }
.sp--gallery .trait { display: block; border: 0; padding: 0 0 var(--s-3); break-inside: avoid; font-size: var(--t-small); }
.sp--gallery .trait b { font-family: var(--f-ui); }
.sp--gallery .sp__see { border-color: var(--mark); color: var(--text); }
.sp--gallery .sp__see::before { background: var(--mark); }
.sp--gallery .sp__see:hover, .sp--gallery .sp__see:focus-visible { color: var(--surface-hi); }
/* ── Round 24 (owner, 30 Sep: "the gallery style is still boring. what about
   it is really unique?"). Not the white: the LIGHT. A white cube is never a
   flat white — it is a wall under track lights, graded from a bright pool
   to a soft grey at the corners, and the one thing on it stands off the
   wall in its own shadow, labelled. So the page is that wall: the lights
   come up as the page arrives (--lit), the pool follows the cursor slowly
   (site.js §4b, --bx/--by), and the work's shadow falls away from it
   (--sx/--sy). The work is drawn, not photographed: a hand-ruled canvas,
   the studio's ruled paper hung as a painting. */
.sp--gallery {
  --bx: 72%; --by: 30%; --sx: 0px; --sy: 16px;
  background: radial-gradient(120% 100% at 60% 22%, #f7f7f5 0%, #ebeae6 52%, #d9d7d1 100%);
}
.sp__dim, .sp__beam { position: absolute; inset: 0; pointer-events: none; }
/* the room before the lights come up */
.sp__dim { background: #2a2925; opacity: 0.2; transition: opacity 1800ms cubic-bezier(.4, 0, .2, 1) 150ms; }
/* the pool of one track light on the wall: a bright core, a long soft edge */
.sp__beam {
  background:
    radial-gradient(21% 30% at var(--bx) calc(var(--by) + 8%), rgb(255 255 255 / 1) 0%, rgb(255 255 255 / .92) 38%, rgb(255 255 255 / .45) 62%, rgb(255 255 255 / 0) 78%),
    radial-gradient(36% 58% at var(--bx) calc(var(--by) + 14%), rgb(255 251 242 / .75) 0%, rgb(255 251 242 / .3) 55%, rgb(255 251 242 / 0) 80%),
    radial-gradient(9% 7% at var(--bx) calc(var(--by) - 13%), rgb(255 255 255 / .55) 0%, rgb(255 255 255 / 0) 100%);
  opacity: 0; transition: opacity 2200ms cubic-bezier(.4, 0, .2, 1) 450ms;
}
.sp--gallery.is-live .sp__dim { opacity: 0; }
.sp--gallery.is-live .sp__beam { opacity: 1; }
.sp--gallery .style-page__inner { position: relative; z-index: 1; }

/* the work, standing 4 cm off the wall: its shadow falls away from the light */
.sp__hang { grid-column: 2; grid-row: 2; margin: 0 clamp(30px, 3.6vw, 56px) 0 0; align-self: center; justify-self: end;
  position: relative; display: grid; grid-template-columns: auto; gap: var(--s-4); width: min(100%, 360px, 42vh); padding-top: clamp(20px, 3.5vh, 44px); }
.sp__work { position: relative; display: block; width: 100%; aspect-ratio: 1;
  box-shadow: var(--sx) var(--sy) 34px -10px rgb(30 28 24 / .30), calc(var(--sx) * .3) calc(var(--sy) * .35) 6px -2px rgb(30 28 24 / .14), 0 0 0 1px rgb(30 28 24 / .05);
  transition: box-shadow 1200ms cubic-bezier(.22, 1, .36, 1); }
.sp__art { display: block; width: 100%; height: 100%; }
/* the canvas's own turned edge, catching the light */
.sp__work::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to bottom, rgb(255 255 255 / .35), rgb(255 255 255 / 0) 4%, rgb(0 0 0 / 0) 94%, rgb(0 0 0 / .06)); }
/* the wall label: small, exact, the same distance from the work every time;
   and the red dot a gallery puts beside a work that has sold */
.sp__label { font-family: var(--f-ui); font-size: var(--t-micro); line-height: 1.55; letter-spacing: 0.01em; color: var(--text-2); }
.sp__label b { font-weight: 500; color: var(--text); }
.sp__label::before { content: ""; float: right; width: 9px; height: 9px; margin: 4px 0 0 var(--s-4); border-radius: 50%; background: #d21f2a; }
/* the art handler's pencil line, at the centre the work was hung on */
.sp__mark { position: absolute; right: calc(100% + 14px); top: 50%; display: flex; align-items: center; gap: 8px;
  font-family: var(--f-ui); font-size: 10px; letter-spacing: .08em; color: rgb(30 28 24 / .38); white-space: nowrap; transform: translateY(-50%); }
.sp__mark i { display: block; width: 46px; height: 1px; background: rgb(30 28 24 / .28); }
@media (max-width: 900px) {
  .sp--gallery .style-page__inner { grid-template-columns: 1fr; grid-template-rows: auto auto auto; height: auto; }
  .sp--gallery .sp__text { grid-row: 3; }
  .sp__hang { grid-column: 1; grid-row: 2; justify-self: start; margin: 0; width: min(62vw, 240px); grid-template-columns: 1fr; }
  .sp__mark { display: none; }
  .sp--gallery .traits { columns: 1; }
}

/* ── THE POSTER: a ticker, a stack of cards, a spinning sticker ───────── */
.sp--poster { padding-top: clamp(84px, 12vh, 130px); }
.sp__ticker {
  position: absolute; left: 0; right: 0; top: 0; z-index: 3;
  display: flex; overflow: hidden; white-space: nowrap;
  background: var(--text); color: var(--ground);
  font-family: var(--f-mono); font-size: var(--t-small); letter-spacing: 0.14em; text-transform: uppercase;
  padding: 10px 0; border-bottom: 3px solid var(--text);
}
.sp__ticker span { flex: none; padding-right: 0; }
@keyframes sp-ticker { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(-100%, 0, 0); } }
.sp--poster.is-live .sp__ticker span { animation: sp-ticker 16s linear infinite; }
.sp--poster .sp__n { color: var(--text); font-weight: 600; }
.sp--poster .sp__name { font-family: var(--f-ui); font-variation-settings: "wght" 600; text-transform: uppercase; letter-spacing: -0.045em; line-height: .9; font-size: clamp(3rem, 1.2rem + 7vw, 8rem); }
.sp--poster .sp__def { display: inline-block; background: var(--mark); color: var(--text); padding: 6px 12px; font-family: var(--f-ui); font-variation-settings: "wght" 600; text-transform: uppercase; letter-spacing: -0.01em; font-size: clamp(1rem, .9rem + .7vw, 1.375rem); max-width: none; }
.sp--poster .traits { border-top: 2px solid var(--text); display: grid; grid-template-columns: 1fr 1fr; gap: 0; }
.sp--poster .trait { grid-template-columns: 1fr; border-bottom: 2px solid var(--text); padding: 10px 12px 12px 0; }
.sp--poster .trait:nth-child(odd) { border-right: 2px solid var(--text); padding-right: 12px; }
.sp--poster .trait:nth-child(even) { padding-left: 12px; }
.sp--poster .sp__see { background: var(--cobalt); color: #fff; border-color: var(--cobalt); transform: rotate(-1.5deg); transition: transform var(--d-hover) var(--e-out), color var(--d-hover) var(--e-fast); }
.sp--poster .sp__see::before { background: var(--text); }
.sp--poster .sp__see:hover, .sp--poster .sp__see:focus-visible { color: var(--ground); transform: rotate(0) translateY(-2px); }
.sp__stack { position: relative; margin: 0; justify-self: center; width: min(100%, 340px); aspect-ratio: 1; max-height: 56vh; }
.sp__card {
  position: absolute; left: 6%; right: 6%; top: 8%; bottom: 8%;
  display: flex; align-items: flex-end; padding: 18px;
  font-family: var(--f-ui); font-variation-settings: "wght" 600; text-transform: uppercase; letter-spacing: -0.03em;
  font-size: clamp(2rem, 1rem + 3vw, 3.5rem); line-height: .9;
  border: 3px solid var(--text); box-shadow: 8px 8px 0 var(--text);
  transform-origin: 50% 90%;
}
.sp__card--a { background: var(--mark); color: var(--text); transform: rotate(-7deg); }
.sp__card--b { background: var(--cobalt); color: #fff; transform: rotate(3deg); }
.sp__card--c { background: var(--surface); color: var(--text); transform: rotate(-1deg); }
@keyframes sp-shuffle-a { 0%, 100% { transform: rotate(-7deg) translateY(0); } 50% { transform: rotate(-9deg) translateY(-10px); } }
@keyframes sp-shuffle-b { 0%, 100% { transform: rotate(3deg) translateY(0); } 50% { transform: rotate(5deg) translateY(-6px); } }
@keyframes sp-shuffle-c { 0%, 100% { transform: rotate(-1deg) translateY(0); } 50% { transform: rotate(1deg) translateY(-4px); } }
.sp--poster.is-live .sp__card--a { animation: sp-shuffle-a 5s ease-in-out infinite; }
.sp--poster.is-live .sp__card--b { animation: sp-shuffle-b 5s ease-in-out .4s infinite; }
.sp--poster.is-live .sp__card--c { animation: sp-shuffle-c 5s ease-in-out .8s infinite; }
.sp__sticker { position: absolute; right: -8%; top: -10%; width: 34%; height: auto; transform-origin: center; }
@keyframes sp-spin { to { transform: rotate(360deg); } }
.sp--poster.is-live .sp__sticker { animation: sp-spin 14s linear infinite; }

/* ── THE ESTATE: centred, engraved, in no hurry ───────────────────────── */
.sp--estate .style-page__inner { width: 100%; max-width: 760px; margin-inline: auto; text-align: center; }
.sp__crest { width: clamp(84px, 12vh, 120px); height: auto; margin: 0 auto var(--s-4); color: var(--mark); }
.sp__crest path, .sp__crest circle { stroke-dasharray: 1; stroke-dashoffset: 1; }
@keyframes sp-engrave { to { stroke-dashoffset: 0; } }
.sp--estate.is-live .sp__crest path, .sp--estate.is-live .sp__crest circle { animation: sp-engrave 2200ms cubic-bezier(.4, 0, .2, 1) both; }
.sp--estate.is-live .sp__crest circle:nth-child(2) { animation-delay: 300ms; }
.sp--estate.is-live .sp__crest path:nth-child(3) { animation-delay: 600ms; }
.sp--estate.is-live .sp__crest path:nth-child(4) { animation-delay: 1000ms; }
.sp--estate.is-live .sp__crest path:nth-child(5) { animation-delay: 1300ms; }
.sp--estate .sp__n { color: var(--mark); letter-spacing: 0.34em; margin-bottom: var(--s-3); }
.sp--estate .sp__name { font-size: clamp(2.25rem, 1.2rem + 3.4vw, 4.5rem); font-weight: 400; letter-spacing: 0.04em; text-transform: uppercase; font-variant-numeric: lining-nums; margin-bottom: var(--s-4); }
.sp__rules { display: block; width: min(100%, 420px); margin: 0 auto var(--s-5); height: 5px; border-top: 2px solid var(--mark); border-bottom: 1px solid var(--mark); transform-origin: center; }
/* lamplight on the green, and a brass double rule round the page like a bookplate */
.sp--estate { background: radial-gradient(120% 85% at 50% 28%, var(--surface-hi) 0%, var(--ground) 64%); }
.sp--estate::before { content: ""; position: absolute; inset: clamp(10px, 1.8vw, 22px); border: 1px solid var(--line); outline: 1px solid var(--line); outline-offset: -6px; pointer-events: none; }
/* phones: the Estate has to fit one screen (owner, 27 Sep), and the frame would need room it has not got */
@media (pointer: coarse), (max-width: 760px) { .sp--estate::before { display: none; } }
.sp--estate .sp__def { font-family: var(--f-display); font-style: italic; font-size: clamp(1.25rem, 1rem + 1vw, 1.75rem); max-width: none; margin: 0 auto var(--s-4); }
.sp--estate .sp__for { max-width: 58ch; margin: 0 auto var(--s-5); }
.sp--estate .traits { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--s-6); text-align: left; padding: var(--s-3) 0; max-width: 640px; margin: 0 auto; }
.sp--estate .trait { grid-template-columns: 7.6ch 1fr; gap: var(--s-3); border: 0; padding-block: 6px; }
.sp--estate .trait dt { font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.2em; text-transform: uppercase; color: var(--mark); padding-top: 3px; }
.sp--estate .sp__foot { justify-content: center; }
.sp--estate .sp__see { border-color: var(--mark); }
.sp--estate .sp__see::before { background: var(--mark); }
@media (max-width: 640px) { .sp--estate .traits { grid-template-columns: 1fr; } }

/* ── short viewports: the air comes out before the type ─────────────── */
@media (max-height: 800px) {
  .sp__name { margin-bottom: var(--s-3); }
  .sp__def { margin-bottom: var(--s-3); }
  .sp__for { margin-bottom: var(--s-4); }
  .sp__foot { margin-top: var(--s-4); }
  .sp__strip, .sp__stage, .sp__stack { max-height: 50vh; }
  .sp--gallery .sp__name { font-size: clamp(2.5rem, 1.2rem + 5vw, 6rem); margin-bottom: var(--s-3); }
  .sp--gallery .sp__text, .sp__hang { padding-top: clamp(14px, 2.4vh, 28px); }
  .sp__hang { width: min(100%, 300px, 32vh); }
  .sp__crest { width: clamp(64px, 9vh, 96px); }
}
@media (max-height: 700px) {
  .style-page { padding-block: clamp(26px, 4vh, 40px) clamp(28px, 4.4vh, 44px); }
  .sp__for { font-size: 0.9375rem; line-height: 1.5; }
  .trait { padding-block: 6px; font-size: 0.9375rem; line-height: 1.42; }
  .sp__see { padding: 10px var(--s-4); }
  .sp__name { font-size: clamp(2.25rem, 1.2rem + 3.4vw, 4.25rem); }
  .sp--poster .sp__name { font-size: clamp(2.5rem, 1rem + 5.6vw, 6rem); }
  .sp--gallery .sp__name { font-size: clamp(2.25rem, 1rem + 4.2vw, 5rem); }
  .sp--estate .sp__name { font-size: clamp(1.875rem, 1rem + 2.8vw, 3.5rem); }
  .sp--estate .sp__for { font-size: 0.9375rem; }
  .sp__strip, .sp__stage, .sp__stack { max-height: 44vh; }
  .sp__hang { width: min(100%, 260px, 27vh); }
  .sp--gallery .sp__def { font-size: 1.25rem; }
  .sp__crest { width: clamp(56px, 8vh, 80px); margin-bottom: var(--s-3); }
  .sp--estate .traits { padding: var(--s-2) 0; }
  .sp--estate .trait { padding-block: 4px; }
  .sp--poster { padding-top: clamp(70px, 10vh, 100px); }
}

/* ── the pages arrive: hidden until live, with script only ──────────── */
@keyframes sp-rise { from { opacity: 0; transform: translate3d(0, 18px, 0); } to { opacity: 1; transform: none; } }
@keyframes sp-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes sp-rule { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes sp-settle { from { opacity: 0; transform: scale(1.03); } to { opacity: 1; transform: none; } }
@keyframes sp-drop { from { opacity: 0; transform: translate3d(0, -14px, 0); } to { opacity: 1; transform: none; } }
.js .style-page:not(.is-live) .sp__n,
.js .style-page:not(.is-live) .sp__name,
.js .style-page:not(.is-live) .sp__def,
.js .style-page:not(.is-live) .sp__for,
.js .style-page:not(.is-live) .trait,
.js .style-page:not(.is-live) .sp__foot,
.js .style-page:not(.is-live) .sp__strip,
.js .style-page:not(.is-live) .sp__stage,
.js .style-page:not(.is-live) .sp__stack,
.js .style-page:not(.is-live) .sp__hang,
.js .style-page:not(.is-live) .sp__rule,
.js .style-page:not(.is-live) .sp__rules,
.js .style-page:not(.is-live) .sp__ticker { opacity: 0; }
.js .style-page:not(.is-live) .sp__crest { opacity: 0; }
/* the traits' rule arrives with the traits, not alone on an empty page */
@media (prefers-reduced-motion: no-preference) {
  .js .style-page:not(.is-live) .traits { border-color: transparent; }
  .js .style-page.is-live .traits { transition: border-color 500ms var(--e-out) 340ms; }
}

/* The Reel: the strip is there first, then the words, quickly — a cut, not a fade */
.sp--reel.is-live .sp__strip { animation: sp-fade 300ms var(--e-out) both; }
.sp--reel.is-live .sp__n    { animation: sp-rise 500ms var(--e-out) 120ms both; }
.sp--reel.is-live .sp__name { animation: sp-rise 600ms var(--e-out) 180ms both; }
.sp--reel.is-live .sp__def  { animation: sp-rise 600ms var(--e-out) 260ms both; }
.sp--reel.is-live .sp__for  { animation: sp-rise 600ms var(--e-out) 320ms both; }
.sp--reel.is-live .trait    { animation: sp-rise 500ms var(--e-out) both; }
.sp--reel.is-live .trait:nth-child(1) { animation-delay: 380ms; }
.sp--reel.is-live .trait:nth-child(2) { animation-delay: 440ms; }
.sp--reel.is-live .trait:nth-child(3) { animation-delay: 500ms; }
.sp--reel.is-live .trait:nth-child(4) { animation-delay: 560ms; }
.sp--reel.is-live .sp__foot { animation: sp-rise 500ms var(--e-out) 640ms both; }

/* The Curtain: the drapes part first (1100ms), then the lines drop in, heavy and slow */
.sp--curtain.is-live .sp__stage { animation: sp-fade 900ms var(--e-out) 700ms both; }
.sp--curtain.is-live .sp__n    { animation: sp-drop 800ms var(--e-out) 800ms both; }
.sp--curtain.is-live .sp__name { animation: sp-drop 900ms var(--e-out) 900ms both; }
.sp--curtain.is-live .sp__def  { animation: sp-drop 900ms var(--e-out) 1050ms both; }
.sp--curtain.is-live .sp__for  { animation: sp-drop 900ms var(--e-out) 1150ms both; }
.sp--curtain.is-live .trait    { animation: sp-drop 800ms var(--e-out) both; }
.sp--curtain.is-live .trait:nth-child(1) { animation-delay: 1250ms; }
.sp--curtain.is-live .trait:nth-child(2) { animation-delay: 1350ms; }
.sp--curtain.is-live .trait:nth-child(3) { animation-delay: 1450ms; }
.sp--curtain.is-live .trait:nth-child(4) { animation-delay: 1550ms; }
.sp--curtain.is-live .sp__foot { animation: sp-drop 800ms var(--e-out) 1700ms both; }

/* The Gallery: nothing faster than a breath */
.sp--gallery.is-live .sp__n    { animation: sp-fade 1400ms var(--e-out) both; }
.sp--gallery.is-live .sp__name { animation: sp-fade 1600ms var(--e-out) 200ms both; }
.sp--gallery.is-live .sp__rule { animation: sp-rule 1600ms var(--e-out) 500ms both; }
.sp--gallery.is-live .sp__def  { animation: sp-fade 1400ms var(--e-out) 900ms both; }
.sp--gallery.is-live .sp__for  { animation: sp-fade 1400ms var(--e-out) 1100ms both; }
.sp--gallery.is-live .trait    { animation: sp-fade 1400ms var(--e-out) 1300ms both; }
.sp--gallery.is-live .sp__foot { animation: sp-fade 1400ms var(--e-out) 1600ms both; }
.sp--gallery.is-live .sp__hang { animation: sp-hang 2400ms cubic-bezier(.22, 1, .36, 1) 250ms both; }
@keyframes sp-hang { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

/* The Poster: everything at once, fast, with a little overshoot in the cards */
.sp--poster.is-live .sp__ticker { animation: sp-fade 300ms both; }
.sp--poster.is-live .sp__n    { animation: sp-rise 400ms var(--e-out) 60ms both; }
.sp--poster.is-live .sp__name { animation: sp-rise 450ms var(--e-out) 100ms both; }
.sp--poster.is-live .sp__def  { animation: sp-rise 450ms var(--e-out) 180ms both; }
.sp--poster.is-live .sp__for  { animation: sp-rise 450ms var(--e-out) 240ms both; }
.sp--poster.is-live .trait    { animation: sp-rise 400ms var(--e-out) 300ms both; }
.sp--poster.is-live .sp__foot { animation: sp-rise 400ms var(--e-out) 380ms both; }
.sp--poster.is-live .sp__stack { animation: sp-settle 500ms var(--e-out) 120ms both; }

/* The Estate: the crest is engraved, the rules are ruled, the words fade up over more than a second */
.sp--estate.is-live .sp__crest { animation: sp-fade 600ms both; }
.sp--estate.is-live .sp__n     { animation: sp-fade 1400ms var(--e-out) 800ms both; }
.sp--estate.is-live .sp__name  { animation: sp-fade 1600ms var(--e-out) 1000ms both; }
.sp--estate.is-live .sp__rules { animation: sp-rule 1400ms var(--e-out) 1200ms both; }
.sp--estate.is-live .sp__def   { animation: sp-fade 1400ms var(--e-out) 1500ms both; }
.sp--estate.is-live .sp__for   { animation: sp-fade 1400ms var(--e-out) 1700ms both; }
.sp--estate.is-live .trait     { animation: sp-fade 1400ms var(--e-out) 1900ms both; }
.sp--estate.is-live .sp__foot  { animation: sp-fade 1400ms var(--e-out) 2200ms both; }

@media (prefers-reduced-motion: reduce) {
  .js .style-page:not(.is-live) .sp__n, .js .style-page:not(.is-live) .sp__name, .js .style-page:not(.is-live) .sp__def,
  .js .style-page:not(.is-live) .sp__for, .js .style-page:not(.is-live) .trait, .js .style-page:not(.is-live) .sp__foot,
  .js .style-page:not(.is-live) .sp__strip, .js .style-page:not(.is-live) .sp__stage, .js .style-page:not(.is-live) .sp__stack,
  .js .style-page:not(.is-live) .sp__hang, .js .style-page:not(.is-live) .sp__rule, .js .style-page:not(.is-live) .sp__rules,
  .js .style-page:not(.is-live) .sp__ticker, .js .style-page:not(.is-live) .sp__crest { opacity: 1; }
  .style-page.is-live *, .style-page.is-live *::before, .style-page.is-live *::after { animation: none !important; }
  .sp__drape { display: none; }
  .sp__crest path, .sp__crest circle { stroke-dashoffset: 0; }
  .sp__slide { clip-path: none; }
  .sp__slide--2, .sp__slide--3 { display: none; }
  .sp__playhead { top: 40%; }
  .sp__frame { opacity: 1; }
}

/* Below about 940px of viewport the compositions run past the bottom of their
   own pages, and `overflow: hidden` clips them silently. Nothing is removed;
   the air is taken back first, then the type. The threshold was 820px until
   the plates went in — a 1600×860 window sat just above it and was clipping
   by 108px, which is exactly the kind of gap a round-number breakpoint
   leaves. */
@media (max-height: 940px) {
  .style-page { padding-block: clamp(40px, 6vh, 72px) clamp(44px, 6.5vh, 78px); }
}

/* The rail sits on top of five different compositions, so at rest it is a
   number and a tick in the gutter and nothing else — no plate, no names, about
   50px wide. The names arrive on hover or keyboard focus, with the plate that
   makes them legible. Nothing is removed; it is folded away.

   Collapsed it needs no plate of its own: `paintChrome` gives the rail the
   active page's theme, so `--text-2` is already the colour that page's own
   ground was designed against. The 1.08:1 measurement that put the plate here
   was taken before the themes were applied, when the rail held one fixed
   colour across all five grounds. */
.deck__rail {
  /* fixed, not absolute: the deck is six viewports of ordinary page now, and
     an absolute rail would sit once in the middle of all six. `html.deck-on`
     is set by site.js while the deck owns the screen. */
  position: fixed; z-index: 5; opacity: 0; pointer-events: none;
  right: var(--gutter); top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; gap: 2px;
  align-items: stretch;
  background: transparent;
  border: 1px solid transparent;
  padding: var(--s-3);
  /* Neither the plate nor the border is transitioned. Chrome holds a
     background-color transition when the only thing that changed is the custom
     property it references, so the plate froze on the first page's colour
     while `--surface` underneath updated correctly. Measured: --surface tracked
     all five themes, the painted background tracked none. Padding is constant
     for the same reason a jump is worse than a pop — the box must not resize
     when it gains its plate. */
}
.deck__rail:hover,
.deck__rail:focus-within {
  background: var(--surface);
  border-color: var(--line);
}
.deck__dot {
  display: flex; align-items: center; justify-content: flex-end; gap: var(--s-3);
  padding: 5px var(--s-2);
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.1em;
  color: var(--text-2);
}
/* Clipped, never `display: none` — the name and the number are what the button
   is called, and they have to stay in the accessible name whether or not they
   are on screen. Collapsed, the rail is five ticks: the number is already at
   the foot of the deck as `03 / 05`, so repeating it here bought width and
   nothing else. */
.deck__dot__name,
.deck__dot__n {
  max-width: 0; opacity: 0; overflow: hidden; white-space: nowrap; flex: none;
  transition: max-width var(--d-std) var(--e-out), opacity var(--d-std) var(--e-out);
}
.deck__rail:hover .deck__dot__name,
.deck__rail:focus-within .deck__dot__name { max-width: 14ch; opacity: 1; }
.deck__rail:hover .deck__dot__n,
.deck__rail:focus-within .deck__dot__n { max-width: 4ch; opacity: 1; }
/* the gap only exists once there is something to sit beside the tick */
.deck__dot { gap: 0; }
.deck__rail:hover .deck__dot,
.deck__rail:focus-within .deck__dot { gap: var(--s-3); }
.deck__dot::after {
  content: ""; width: 20px; height: 1px; background: currentColor;
  flex: none;
  transform: scaleX(0.4); transform-origin: right;
  transition: transform var(--d-std) var(--e-out);
}
.deck__dot[aria-current="true"] { color: var(--text); }
.deck__dot[aria-current="true"]::after { transform: scaleX(1); }
.deck__dot:hover, .deck__dot:focus-visible { color: var(--text); }
@media (max-width: 760px) {
  .deck__rail { right: 6px; padding: var(--s-2); }
  .deck__rail:hover .deck__dot__name,
  .deck__rail:focus-within .deck__dot__name { max-width: 10ch; }
}

/* The page counter and the hint, on their own plate at the foot of the deck. */
.deck__foot {
  /* Bottom centre, flush to the edge, no plate: every composition ends with
     a full-width foot row whose middle is empty, and at the left it collided
     with the "built in this style" line on any screen under 800px tall. */
  position: fixed; z-index: 5; opacity: 0;
  left: 50%; transform: translateX(-50%); bottom: 0;
  display: flex; align-items: center; gap: var(--s-4);
  pointer-events: none;
  padding: 5px var(--s-4) 6px;
  border-top: 1px solid var(--line); border-inline: 1px solid var(--line);
  background: var(--surface);
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.11em; text-transform: uppercase;
  color: var(--text-2);
}
.deck__count b { color: var(--text); font-weight: 400; }
.deck__hint { display: flex; align-items: center; gap: var(--s-3); }
.deck__hint i {
  width: 24px; height: 1px; background: currentColor; display: block;
  transform-origin: left; animation: cue 2600ms var(--e-move) infinite;
}
@media (max-width: 760px) { .deck__hint { display: none; } }

/* Phones: the deck pages were clipping. At 375x812 the inner column measured
   754–814px against 658px of usable height, and `.style-page` is
   `overflow: hidden`, so between 97 and 156 pixels of every page — the end of
   the traits list and the "built in this style" line — was being cut off with
   no scrollbar to reveal it.

   Two fixes, because one is not enough on its own: the padding and internal
   spacing come down so the content genuinely fits, AND the page is allowed to
   grow past the viewport rather than clip if it ever does not. Snap still
   aligns to the top of each page either way. */
@media (max-width: 760px) {
  .style-page {
    min-height: 76svh;
    overflow: visible;
    padding: clamp(40px, 6vh, 56px) var(--gutter) clamp(52px, 8vh, 68px);
  }
  .sp__name { margin-bottom: var(--s-4); }
  .sp__def { margin-bottom: var(--s-4); }
  .sp__for { margin-bottom: var(--s-4); }
  .trait { padding-block: 7px; font-size: var(--t-micro); }
  .sp__built { font-size: 0.6875rem; }
  .sp__see { padding: 11px var(--s-4); }
  /* the figure captions sit in the flow here, not hung below the figure,
     where they ran into the text that follows */
  .sp__stripCap, .sp__stageCap { position: static; transform: none; margin-top: 10px; text-align: center; }
}

/* Reduced motion, and anything narrow enough that a full-viewport page would
   clip its own content: the deck stops being a viewport-height scroller and
   becomes an ordinary stack of sections. Native snap is dropped with it, so
   there is nothing left to fight. */
/* 680px, not 620px: at 660 the two busiest pages were still 30px and 2px over
   after every tightening tier, and compressing type further to save a browser
   window nobody uses in that shape is the wrong trade. Below this the deck is
   an ordinary stack of sections, which is the designed fallback.
   `mqShort` in site.js holds the same number — change both or neither. */
@media (prefers-reduced-motion: reduce), (max-height: 600px), (max-width: 760px) {
  .deck { overflow: visible; }
  .style-page { min-height: 76svh; }
  .deck__rail, .deck__foot { display: none; }
}

/* ========================================================== 13b. THE WORK
   Six builds, three to a row, each opening a flip-through of its own screens.
   The status tag is not decoration: five of these six are concept studies, and
   a gallery that reads as six signed clients would be the one lie this site
   cannot afford. It is on every tile, at full contrast, not in a footnote. */
.work {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));   /* four builds, two by two */
  gap: clamp(16px, 2.2vw, 32px);
  margin-top: clamp(28px, 5vh, 56px);
}
.work__tile {
  position: relative; display: block; width: 100%;
  padding: 0; text-align: left; background: var(--surface);
  color: inherit; text-decoration: none;   /* a link now: each tile opens its site in a new tab */
  border: 1px solid var(--line);
  cursor: pointer; overflow: hidden;
  transition: border-color var(--d-hover) var(--e-fast);
}
.work__tile:hover, .work__tile:focus-visible { border-color: var(--text); }
.work__tile:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.work__shot { display: block; overflow: hidden; border-bottom: 1px solid var(--line); }
.work__shot img {
  display: block; width: 100%; height: clamp(190px, 30vh, 340px);
  object-fit: cover; object-position: 50% 0;
  transition: transform 900ms var(--e-out);
}
.work__tile:hover .work__shot img,
.work__tile:focus-visible .work__shot img { transform: scale(1.035); }
.work__bar { display: block; padding: var(--s-4) var(--s-4) var(--s-5); }
.work__name {
  display: block; font-family: var(--f-display);
  font-size: clamp(1.0625rem, 0.9rem + 0.5vw, 1.375rem);
  line-height: 1.16; color: var(--text); margin-bottom: 6px;
}
.work__meta {
  display: block; font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.08em; color: var(--text-2);
  padding-right: 6.5rem;   /* the screen count sits bottom-right; keep clear of it */
}
.work__tag {
  position: absolute; top: 0; left: 0;
  padding: 5px var(--s-3);
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.14em; text-transform: uppercase;
  background: var(--surface); color: var(--text-2);
  border-right: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.work__tag[data-status="Signed client"] { background: var(--text); color: var(--ground); border-color: var(--text); }
.work__count {
  position: absolute; right: var(--s-4); bottom: var(--s-4);
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.1em; color: var(--text-3);
}
@media (max-width: 900px) { .work { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .work { grid-template-columns: 1fr; } }

/* ======================================================== 14. THE METHOD */
.method__grid {
  display: grid; grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  gap: clamp(36px, 5.5vw, 100px); align-items: start;
}
@media (max-width: 980px) { .method__grid { grid-template-columns: 1fr; gap: var(--s-7); } }
.method__aside { position: sticky; top: clamp(88px, 15vh, 176px); }
@media (max-width: 980px) { .method__aside { position: static; } }

.steps { border-top: 1px solid var(--line); }
.step {
  display: grid; grid-template-columns: 3.25rem 1fr; gap: var(--s-5);
  padding-block: clamp(18px, 2.6vh, 30px);
  border-bottom: 1px solid var(--line);
  position: relative;
}
.step::before {
  content: ""; position: absolute; left: 0; bottom: -1px;
  height: 1px; width: 3.25rem; background: var(--text);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--d-large) var(--e-out) 100ms;
}
.step.is-in::before { transform: scaleX(1); }
.step__n { font-family: var(--f-mono); font-size: var(--t-micro); color: var(--text-2); letter-spacing: 0.1em; padding-top: 0.45em; }
.step__t {
  font-family: var(--f-display); font-size: var(--t-h4); color: var(--text);
  margin-bottom: 5px; line-height: 1.1;
  font-variation-settings: "opsz" 24;
}
.step__d { font-size: var(--t-small); line-height: 1.6; max-width: 52ch; }

/* ================================================== 14b. THE PROCESS ==
   A spiral ladder. The canvas draws two rails winding round one axis and a
   rung for every item in the list beside it, at that item's exact height;
   the ladder turns with the scroll and slowly on its own, and whichever rung
   is squarest to the reader is the one lit in the list. The list is the
   content; the canvas is aria-hidden and the page reads without it. */
.process__grid {
  display: grid; grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.28fr);
  gap: clamp(36px, 5.5vw, 100px); align-items: start;
}
@media (max-width: 980px) { .process__grid { grid-template-columns: 1fr; gap: var(--s-7); } }
.process__aside { position: sticky; top: clamp(88px, 15vh, 176px); }
@media (max-width: 980px) { .process__aside { position: static; } }

/* The spiral ladder. Without JS, under reduced motion or on a narrow screen
   it is this: a ruled list, one item per rung. With `is-run` (site.js §7) it
   becomes a runway with a stage stuck inside it, the canvas draws a spiral
   staircase of six treads round one pole, and the list items are the words
   on the treads — placed, scaled and faded by the scroll every frame, so the
   whole thing turns as the reader scrolls and each part fades in from behind
   the pole and out again. */
.helix { position: relative; }
.helix__stage { position: relative; }
.helix__canvas { display: none; position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.helix__rungs {
  position: relative; z-index: 1;
  border-top: 1px solid var(--line);
}
.helix__rung {
  position: relative;
  padding: clamp(16px, 2.4vh, 26px) 0 clamp(16px, 2.4vh, 26px) var(--s-6);
  border-bottom: 1px solid var(--line);
  font-size: var(--t-small); line-height: 1.6; color: var(--text-2);
  max-width: 52ch;
  transition: color var(--d-std) var(--e-out);
}
.helix__rung b {
  display: block; font-family: var(--f-display); font-weight: 400;
  font-size: var(--t-h4); line-height: 1.1; color: var(--text);
  font-variation-settings: "opsz" 24; margin-bottom: 5px;
  transition: color var(--d-std) var(--e-out);
}
/* the cell at the head of each rung: the rung's end, drawn in the same mark */
.helix__rung::before {
  content: ""; position: absolute; left: 0; top: calc(50% - 5px);
  width: 10px; height: 10px;
  border-left: 1.5px solid var(--text-3); border-bottom: 1.5px solid var(--text-3);
}
.helix__rung::after {
  content: ""; position: absolute; left: 0; bottom: -1px;
  width: 100%; height: 1px; background: var(--mark);
  transform: scaleX(var(--u, 0)); transform-origin: left;   /* --u is set by the scroll, every frame */
}

/* the run */
.helix.is-run {
  --helix-stage: clamp(440px, 76vh, 760px);
  height: calc(var(--helix-stage) + (var(--helix-n, 6) - 1) * var(--helix-step, 55vh));
}
.helix.is-run .helix__stage {
  position: sticky; top: calc((100vh - var(--helix-stage)) / 2);
  height: var(--helix-stage); overflow: hidden;
}
.helix.is-run .helix__canvas { display: block; }
.helix.is-run .helix__rungs { position: absolute; inset: 0; border: 0; z-index: auto; }
.helix.is-run .helix__rung {
  position: absolute; left: 0; top: 0;
  width: clamp(190px, 32%, 30ch); max-width: none;
  padding: 6px 10px 10px; border: 0;
  background: var(--ground);         /* a plate the colour of the page: the rail passes behind the words, not through them */
  opacity: 0; transform-origin: 0 0; will-change: transform, opacity;
  color: var(--text-3);
}
/* only the tread at the front carries its paragraph; the others turn past
   as titles. --k is how nearly at the front it is, set by the scroll */
.helix.is-run .helix__more {
  display: block; overflow: hidden;
  max-height: calc(var(--k, 0) * var(--mh, 11em)); opacity: var(--k, 0);
  padding-top: calc(var(--k, 0) * 4px);
}
.helix.is-run .helix__rung b { margin-bottom: 0; }
.helix.is-run .helix__rung b { color: var(--text-2); }
.helix.is-run .helix__rung.is-front { color: var(--text-2); }
.helix.is-run .helix__rung.is-front b { color: var(--text); }
.helix.is-run .helix__rung::before { display: none; }   /* the tread is on the canvas */
.helix.is-run .helix__rung::after { bottom: 0; left: 10px; width: calc(100% - 20px); }

/* The stairwell (stair.js, storyboard beat 6). Wider than 900px the section
   is a scene that fills the screen behind the words for as long as the
   process runs: the heading and the six steps stand at the left over the
   page's own ground, and the well turns on the right. The runway and the
   choreography are the ladder's; only the drawing changed. */
.process:not(.is-spin) .spin { display: none; }
.spin {
  position: sticky; top: 0; height: 100vh; margin-bottom: -100vh;
  z-index: 0; overflow: hidden; pointer-events: none;
  animation: spin-in 900ms var(--e-out) both;
}
@keyframes spin-in { from { opacity: 0; } }
.spin__gl { position: relative; display: block; width: 100%; height: 100%; opacity: 0; transition: opacity 900ms var(--e-out); }
.spin.is-ready .spin__gl { opacity: 1; }   /* the books arrive on a sky that was already there */
.spin.is-instant .spin__gl { transition: none; }
/* the page's ground behind the heading at the top of the stairs, going as it goes */
.spin::after {
  content: ""; position: absolute; inset: 0; opacity: var(--head, 1);
  background: radial-gradient(75% 65% at 0% 0%, var(--ground) 0%, color-mix(in srgb, var(--ground) 85%, transparent) 42%, transparent 74%);
}
/* Round 24 (owner, 30 Sep: "make the background the same color as the
   background of the home page"): the stairwell stands in the cover's sky —
   the same gradient, behind a clear canvas whose depths fade into it
   (stair.js) — and type on it is the cover's ink. At the foot, as the camera
   falls into the light, the sky gives way to the prices' paper (--exit), so
   the page that follows arrives on its own ground. */
.process.is-spin {
  --ground: var(--c-sky); --surface: var(--c-sky-hi); --surface-hi: #cfe6fa; --surface-deep: var(--c-sky-deep);
  --line: rgb(14 53 88 / .32); --line-soft: rgb(14 53 88 / .16);
  --text: var(--c-ink); --text-2: #13304c; --text-3: #1b3a5a; --mark: var(--c-proof); --focus: var(--c-ink);
}
.gl-ready #method.is-spin { background: var(--c-bar); }
/* the sky from the section's very edge, not below its padding */
.process.is-spin .spin { margin-top: calc(-1 * clamp(72px, 11vh, 172px)); margin-bottom: calc(clamp(72px, 11vh, 172px) - 100vh); }
.spin { background: var(--sky, var(--c-sky)) var(--c-sky); }
.spin::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: var(--c-bar); opacity: var(--exit, 0);
}
.process.is-spin .process__grid { position: relative; z-index: 1; grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.28fr); }
.process.is-spin .process__aside,
.process.is-spin .helix { grid-column: 1; grid-row: 1; }
.process.is-spin .process__aside { position: sticky; top: clamp(88px, 15vh, 176px); z-index: 2; }
.process.is-spin .helix.is-run { --helix-stage: 100vh; height: calc(100vh + var(--spin-run, 6.7) * var(--helix-step, 90vh)); }
.process.is-spin .helix.is-run .helix__stage { overflow: visible; }
.process.is-spin .helix.is-run .helix__canvas { display: none; }
/* one card in the middle of the screen, the size of the longest step, and
   every step's words arrive in it in turn (site.js §7 sizes and centres it
   once, and fades the words; owner, 29 Sep: "each text appears in the same
   place… the user shouldn't have to move their eyes") */
.process.is-spin .helix.is-run .helix__rungs {
  inset: auto; left: 0; top: 0; width: min(560px, 42vw); height: var(--frame-h, auto);
  transform: translate3d(var(--fx, 0px), var(--fy, 0px), 0);
  /* a leaf of the book's paper, laid on the sky */
  background: #fbf8ef;
  border: 1px solid rgb(14 53 88 / .22);
  outline: 1px solid rgb(14 53 88 / .10); outline-offset: -6px;
  box-shadow: 0 30px 60px -26px rgb(14 53 88 / .55), 0 2px 8px rgb(14 53 88 / .16);
  opacity: 0; will-change: opacity;
}
.process.is-spin .helix.is-run .helix__rung {
  left: 0; right: 0; top: 0; width: auto; min-height: var(--frame-h, 0px);
  padding: 26px 32px 38px; background: none; border: 0;
  transform-origin: 50% 50%; color: var(--text-2);
}
.process.is-spin .helix.is-run .helix__rung::before {
  content: attr(data-rung); display: block; position: static; width: auto; height: auto; border: 0;
  font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--mark); margin-bottom: 12px;
}
.process.is-spin .helix.is-run .helix__rung b { color: var(--text); font-size: clamp(1.75rem, 1.1rem + 1.5vw, 2.6rem); line-height: 1.08; }
.process.is-spin .helix.is-run .helix__more {
  max-height: none; opacity: 1; padding-top: 14px;
  font-size: clamp(1.02rem, 0.94rem + 0.32vw, 1.22rem); line-height: 1.55; color: var(--text-2);
}
.process.is-spin .helix.is-run .helix__rung::after { left: 32px; width: calc(100% - 64px); bottom: 18px; height: 2px; }

/* ======================================================== 15. THE PRICES */
.prices__head {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr);
  gap: var(--s-8); align-items: end; margin-bottom: clamp(36px, 5.5vh, 72px);
}
@media (max-width: 900px) { .prices__head { grid-template-columns: 1fr; gap: var(--s-5); } }

/* Four now, not three. Below 1180px they go to two — four columns of a price
   list at 1024 leaves a measure nobody can read. */
.tiers { display: grid; grid-template-columns: repeat(4, 1fr); border: 1px solid var(--line); background: var(--surface); }
@media (max-width: 1180px) { .tiers { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .tiers { grid-template-columns: 1fr; } }
/* the floor tier is quieter than the rest: it is the least of what is on offer,
   and the page should not sell it hardest just because it is cheapest */
.tier--starter .tier__price { color: var(--text-2); }
.tier {
  padding: clamp(26px, 3.2vw, 44px);
  border-left: 1px solid var(--line);
  display: flex; flex-direction: column; position: relative;
  transition: background-color var(--d-hover) var(--e-move);
}
.tier:first-child { border-left: 0; }
@media (max-width: 980px) {
  .tier { border-left: 0; border-top: 1px solid var(--line); }
  .tier:first-child { border-top: 0; }
}
.tier:hover { background: var(--surface-hi); }
/* the chosen tier is the one with the manila tab on it */
.tier--mid { background: var(--surface-hi); }
.tier--mid::before {
  content: ""; position: absolute; inset: -1px -1px auto -1px; height: 3px;
  background: var(--c-manila);
}
.tier__name {
  display: flex; align-items: center; gap: var(--s-2);
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.15em; text-transform: uppercase;
  color: var(--text-2); margin-bottom: var(--s-6);
}
.tier--mid .tier__name { color: var(--c-manila-ink); }
.tier__price {
  font-family: var(--f-display);
  font-size: clamp(2rem, 1.35rem + 2.05vw, 2.875rem);
  line-height: 0.94; color: var(--text);
  font-variation-settings: "opsz" 60;
  letter-spacing: -0.028em; font-variant-numeric: tabular-nums;
  margin-bottom: var(--s-3);
}
.tier__for { font-size: var(--t-small); color: var(--text-2); margin-bottom: var(--s-6); min-height: 3.2em; }
.tier__list { border-top: 1px solid var(--line-soft); margin-bottom: var(--s-7); }
.tier__list li {
  padding-block: 9px; border-bottom: 1px solid var(--line-soft);
  font-size: var(--t-small);
  display: grid; grid-template-columns: 14px 1fr; gap: var(--s-3);
  align-items: start; color: var(--text-2);
}
.tier__list li .cell { width: 10px; height: 10px; margin-top: 5px; opacity: .8; }
.tier__cta { margin-top: auto; }

.care {
  margin-top: var(--s-6); padding: var(--s-6);
  border: 1px solid var(--line);
  display: flex; flex-wrap: wrap; gap: var(--s-5);
  align-items: center; justify-content: space-between;
}
.care p { font-size: var(--t-small); max-width: 58ch; }

/* =========================================================== 16. THE FAQ */
.faq { border-top: 1px solid var(--line); }
.faq__item { border-bottom: 1px solid var(--line); }
.faq__q {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-5); padding-block: clamp(18px, 2.4vh, 26px); text-align: left;
  font-family: var(--f-display); font-size: var(--t-h4);
  font-variation-settings: "opsz" 24;
  color: var(--text); line-height: 1.16;
  transition: color var(--d-hover) var(--e-fast);
}
.faq__q:hover { color: var(--text-2); }
.faq__sign { position: relative; width: 14px; height: 14px; flex: none; }
.faq__sign::before, .faq__sign::after {
  content: ""; position: absolute; background: currentColor;
  transition: transform var(--d-hover) var(--e-move), opacity var(--d-hover) var(--e-move);
}
.faq__sign::before { inset: 6px 0 auto 0; height: 1.5px; }
.faq__sign::after { inset: 0 6px auto auto; width: 1.5px; height: 14px; }
.faq__q[aria-expanded="true"] .faq__sign::after { transform: scaleY(0); opacity: 0; }
.faq__a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--d-std) var(--e-out); }
.faq__q[aria-expanded="true"] + .faq__a { grid-template-rows: 1fr; }
.faq__a > div { overflow: hidden; }
.faq__a p { padding-bottom: var(--s-6); max-width: 68ch; font-size: var(--t-small); line-height: 1.68; }
.faq__a p + p { padding-top: var(--s-3); }

/* ======================================================= 17. THE CLOSING */
/* The back cover. Same buckram as the front, so the book closes. */
.contact { background: var(--c-buckram); }
.contact__mega {
  font-family: var(--f-display);
  /* was --t-mega, which is 127px at 1440 — larger than the studio's own name on
     the cover. A closing heading should not out-shout the front of the book. */
  font-size: clamp(2rem, 1rem + 4.2vw, 5rem);
  /* 0.86 was tighter than the face's own ascenders, so the top of the first
     line was being cut by its reveal mask and sat up against the section
     above it. The mask cannot clip what fits inside the line box. */
  line-height: 1.0; letter-spacing: -0.038em; color: var(--text);
  padding-top: 0.06em;
  font-variation-settings: "opsz" 72;
  margin-bottom: clamp(28px, 4.5vh, 56px);
}
.contact__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
  gap: var(--s-6); border-top: 1px solid var(--line); padding-top: var(--s-6);
}
.contact__item { display: flex; flex-direction: column; gap: var(--s-2); }
.contact__val { font-size: var(--t-lead); color: var(--text); letter-spacing: -0.008em; }
.contact__note { margin-top: var(--s-7); font-size: var(--t-small); color: var(--text-2); max-width: 60ch; }

/* --- the brief: a form set like an account-book page. Every field is a ruled
   line, not a box; the choices are cells; the whole thing is one colour
   family with the cover. */
.contact__layout {
  display: grid; grid-template-columns: minmax(0, 0.74fr) minmax(0, 1.26fr);
  gap: clamp(40px, 6vw, 112px); align-items: start;
}
@media (max-width: 1000px) { .contact__layout { grid-template-columns: 1fr; gap: var(--s-8); } }
.contact__side { position: sticky; top: clamp(88px, 15vh, 176px); }
@media (max-width: 1000px) { .contact__side { position: static; } }
.contact__side .contact__grid { grid-template-columns: 1fr; gap: var(--s-5); margin-top: var(--s-7); }
.contact__side .contact__val { overflow-wrap: anywhere; }
@media (max-width: 1000px) { .contact__side .contact__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .contact__side .contact__grid { grid-template-columns: 1fr; } }

.brief { border-top: 3px double var(--line); }
.brief__pick {
  margin: var(--s-5) 0 0; padding: var(--s-4) var(--s-5);
  border: 1px solid var(--line); border-left: 3px solid var(--mark);
  font-size: var(--t-small); color: var(--text-2); background: var(--surface);
}
.brief__pick b { color: var(--text); font-variation-settings: "wght" 560; }
.brief__pick i { font-style: normal; color: var(--text); }
.contact__sub { font-size: var(--t-small); color: var(--text-3); line-height: 1.55; max-width: 34ch; }
.brief__set { border: 0; padding: clamp(24px, 3.4vh, 40px) 0; margin: 0; border-bottom: 3px double var(--line); min-width: 0; }
.brief__legend {
  float: left; width: 100%;                 /* a legend is drawn on the border edge; floated it sits in the flow */
  display: flex; align-items: center; gap: var(--s-4);
  font-family: var(--f-display); font-size: var(--t-h4); color: var(--text);
  font-variation-settings: "opsz" 24; line-height: 1.1;
  padding: 0; margin-bottom: var(--s-5);
}
.brief__num {
  font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.13em;
  color: var(--text-3); padding-top: 0.2em;
}
.brief__legend + * { clear: both; }
.brief__row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-6); }
@media (max-width: 640px) { .brief__row { grid-template-columns: 1fr; gap: 0; } }

.field { display: block; position: relative; margin-bottom: var(--s-5); }
.field__label {
  display: flex; align-items: baseline; gap: var(--s-3);
  font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.13em;
  text-transform: uppercase; color: var(--text-2); margin-bottom: var(--s-2);
}
.field__label i { font-style: normal; text-transform: none; letter-spacing: 0.04em; color: var(--text-3); }
.field__input {
  display: block; width: 100%;
  /* a cell to write in: lighter than the page, with a firm rule as its
     baseline — so it cannot be read as one of the rules between sections */
  background: var(--surface-hi); border: 0; border-bottom: 1.5px solid var(--text-3);
  padding: 10px 12px 12px; color: var(--text);
  font-family: var(--f-ui); font-size: var(--t-body); line-height: 1.5;
  transition: border-color var(--d-hover) var(--e-fast), box-shadow var(--d-hover) var(--e-fast);
  outline: none;
}
.field__input::placeholder { color: var(--text-3); opacity: 1; }
.field__input:focus-visible { border-color: var(--text); box-shadow: 0 1px 0 0 var(--text); outline: none; }
textarea.field__input { resize: vertical; min-height: 7.5em; line-height: 1.6; }
select.field__input {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 28px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 13px) 55%, calc(100% - 8px) 55%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
select.field__input option { color: var(--c-ink); background: var(--c-sheet-hi); }
.field__err {
  display: none; margin-top: var(--s-2);
  font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.04em;
  color: var(--mark);
}
.field.is-bad .field__input { border-color: var(--mark); box-shadow: 0 1px 0 0 var(--mark); }
.field.is-bad .field__err, .brief__set.is-bad .field__err--group { display: block; }

/* the choices: cells, one selected */
.choices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
.choices--row { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.choices--five { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.choices--five .choice__body > span { padding-right: 0; }
@media (max-width: 1100px) { .choices--five { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 760px) { .choices--row, .choices--five { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) { .choices, .choices--row { grid-template-columns: 1fr; } }
.choice { position: relative; display: block; cursor: pointer; }
.choice--wide { grid-column: 1 / -1; }
.choice input { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.choice__body {
  position: relative; display: block; min-height: 100%;
  padding: 14px 16px 14px 34px;
  border: 1px solid var(--line); background: transparent;
  font-size: var(--t-small); line-height: 1.5; color: var(--text-2);
  transition: background var(--d-hover) var(--e-fast), border-color var(--d-hover) var(--e-fast), color var(--d-hover) var(--e-fast);
}
.choice__body b { display: block; color: var(--text); font-variation-settings: "wght" 560; }
.choice__body em {
  position: absolute; right: 16px; top: 15px; font-style: normal;
  font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.08em; color: var(--text-2);
}
.choice__body > span { display: block; margin-top: 3px; color: var(--text-3); padding-right: 6ch; }
.choice--wide .choice__body > span { padding-right: 0; }
/* the cell, at the left of every choice; the check is drawn in when chosen */
.choice__body::before {
  content: ""; position: absolute; left: 14px; top: 17px; width: 10px; height: 10px;
  border-left: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; opacity: .7;
}
.choice__body::after {
  content: ""; position: absolute; left: 17px; top: 15px; width: 4px; height: 8px;
  border-right: 1.5px solid var(--mark); border-bottom: 1.5px solid var(--mark);
  transform: rotate(45deg) scale(0); transform-origin: center;
  transition: transform var(--d-hover) var(--e-out);
}
.choice:hover .choice__body { border-color: var(--text-3); background: var(--surface); }
.choice input:focus-visible + .choice__body { outline: 2px solid var(--focus); outline-offset: 2px; }
.choice input:checked + .choice__body { background: var(--surface-hi); border-color: var(--text); color: var(--text-2); box-shadow: inset 3px 0 0 var(--mark); }
.choice input:checked + .choice__body::after { transform: rotate(45deg) scale(1); }
.choice input:checked + .choice__body::before { opacity: 1; }

.brief__hp { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }
.brief__foot {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--s-5); padding-top: clamp(24px, 3.4vh, 40px);
}
.brief__fine { font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.04em; line-height: 1.7; color: var(--text-3); max-width: 44ch; }
.brief__fine b { color: var(--text-2); font-weight: 400; }
.brief__send { flex: none; }
.brief__send.is-busy { opacity: .6; pointer-events: none; }
.brief__status { margin-top: var(--s-4); font-size: var(--t-small); color: var(--text-2); max-width: 60ch; }
.brief__status:empty { display: none; }
.brief__status a { text-decoration: underline; text-underline-offset: 3px; }
.brief__copy {
  display: block; width: 100%; margin-top: var(--s-3);
  background: var(--surface); border: 1px solid var(--line); color: var(--text-2);
  padding: var(--s-4); font-family: var(--f-mono); font-size: var(--t-micro); line-height: 1.6;
  min-height: 12em; resize: vertical;
}
/* after sending */
.brief__done { padding: clamp(28px, 4vh, 48px) 0; }
.brief__done h3 {
  font-family: var(--f-display); font-size: var(--t-h3); color: var(--text);
  font-variation-settings: "opsz" 40; line-height: 1.05; margin-bottom: var(--s-4);
}
.brief__done p { max-width: 54ch; }
.brief__done p + p { margin-top: var(--s-3); }

/* ========================================================== 18. COLOPHON */
.footer { background: var(--c-buckram-deep); color: var(--c-sheet-hi); border-top: 1px solid #3c5044; padding-block: var(--s-7) var(--s-6); position: relative; overflow: hidden; }
/* The one large moment: the motif at scale, cropped off the edge, very quiet.
   This is the only element on the site that fails the removal test and it is
   kept deliberately, once, at 6% contrast. */
.footer__mark {
  position: absolute; right: -40px; bottom: -70px;
  width: 300px; height: 363px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='22 8 76 92'%3E%3Cpath d='M 73 77 C 64 68, 58 62, 52 56 C 44 47, 30 40, 30 30 C 30 16, 46 12, 52 20 C 58 28, 46 40, 38 50 C 28 62, 26 80, 40 88 C 54 96, 66 88, 70 78' fill='none' stroke='%23fff' stroke-width='4.5' stroke-linecap='square'/%3E%3Cpath d='M68.3 67.7 87.8 87.2 92 96 83.2 91.8 63.7 72.3Z M67.37 72.71 71.89 77.24A.95.95 0 0 0 73.24 75.89L68.71 71.37A.95.95 0 0 0 67.37 72.71Z' fill='%23fff' fill-rule='evenodd'/%3E%3C/svg%3E") no-repeat center / contain;
  opacity: 0.06; pointer-events: none;
}
.footer__row { position: relative; display: flex; flex-wrap: wrap; gap: var(--s-5); justify-content: space-between; align-items: flex-start; }
.footer__disclosure {
  font-family: var(--f-mono); font-size: var(--t-micro);
  line-height: 1.75; color: #b6c4b2; max-width: 74ch; letter-spacing: 0.01em;
}
.footer__disclosure b { color: var(--c-sheet-hi); font-weight: 400; }

/* ================================================== 19. REDUCED MOTION ==
   A designed variant, not the animation switched off. Travel is replaced by
   value change; the composition survives; every mark that carries meaning is
   still drawn, just already drawn. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  [data-reveal] { opacity: 1 !important; transform: none !important; clip-path: none !important; }
  .split__line > span { transform: none !important; }
  .entry__claim::after { transform: scaleX(1) !important; }
  .entry__why { opacity: 1 !important; transform: none !important; }
  .rule--draw, .eyebrow::after, .step::before, .entry::before { transform: scaleX(1) !important; }
  .js .helix.is-run .helix__rung, .js .helix.is-run .helix__rung b { color: var(--text-2); }
  .js .helix.is-run .helix__rung b { color: var(--text); }
  .cover__canvas { opacity: 1; }
  .cue__track::after { display: none; }
  .plate img { filter: none; transform: none; }
}

/* Print — someone will print the price page. See the a11y skill's print.md. */
@media print {
  *,*::before,*::after { background:#fff !important; color:#000 !important;
    box-shadow:none !important; text-shadow:none !important;
    -webkit-print-color-adjust:economy; print-color-adjust:economy; }
  nav,.nav,.cover,canvas,form,button,video,iframe,[aria-hidden="true"] { display:none !important; }
  * { position:static !important; }
  [data-reveal],.reveal,.is-out { opacity:1 !important; transform:none !important;
    visibility:visible !important; }
  body { font-size:11pt; line-height:1.45; }
  a { text-decoration:none; color:#000 !important; }
  a[href^="http"]::after { content:" (" attr(href) ")"; font-size:8.5pt; word-break:break-all; }
  a[href^="tel:"]::after,a[href^="mailto:"]::after,a[href^="#"]::after { content:"" !important; }
  h1,h2,h3 { break-after:avoid-page; page-break-after:avoid; }
  .tier,li,tr,figure { break-inside:avoid; page-break-inside:avoid; }
  @page { margin:1.5cm; }
}

/* ===================================================== 20. THE LEGAL PAGES
   Plain prose on the account-book paper. No new palette, no new type — a page whose
   whole job is to be read and believed should not look designed at anybody. */
.legal__wrap { max-width: 72ch; }
.legal__h {
  font-size: clamp(1.875rem, 1.2rem + 2.6vw, 3.25rem);
  line-height: 1.04; margin: var(--s-5) 0 var(--s-5);
}
.legal__lead { max-width: 60ch; }
.legal__date {
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.1em; color: var(--text-2);
  padding-bottom: var(--s-5); margin-bottom: var(--s-6);
  border-bottom: 1px solid var(--line);
}
.legal h2 {
  font-size: clamp(1.125rem, 0.95rem + 0.7vw, 1.5rem);
  margin: var(--s-7) 0 var(--s-4); line-height: 1.2;
}
.legal p { max-width: 68ch; margin-bottom: var(--s-4); color: var(--text-2); }
.legal p b { color: var(--text); font-variation-settings: "wght" 600; }
.legal code {
  font-family: var(--f-mono); font-size: 0.92em;
  background: var(--surface); padding: 1px 5px; border: 1px solid var(--line-soft);
}
.legal__list { max-width: 68ch; margin: 0 0 var(--s-4); padding: 0; list-style: none; }
.legal__list li {
  position: relative; padding-left: var(--s-5); margin-bottom: var(--s-3);
  color: var(--text-2);
}
.legal__list li::before {
  content: ""; position: absolute; left: 0; top: 0.55em;
  width: 10px; height: 10px;
  border-left: 1px solid var(--line); border-bottom: 1px solid var(--line);
}

/* the legal row under every footer */
.work__disclaim {
  max-width: 72ch; margin-top: var(--s-5);
  padding-top: var(--s-4); border-top: 1px solid var(--line-soft);
  font-size: var(--t-small); line-height: 1.62; color: var(--text-2);
}

.footer__legal {
  display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-6);
  padding-top: var(--s-5); margin-top: var(--s-5);
  border-top: 1px solid var(--line-soft);
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.1em; text-transform: uppercase;
}
.footer__legal a { color: #b6c4b2; }   /* the footer is dark cloth; --text-2 is the paper's ink (2:1 here). Same as the disclosure: 10.9:1 */
.footer__legal a:hover, .footer__legal a:focus-visible { color: var(--c-sheet-hi); }

@media (max-height: 700px) {
  .style-page { padding-block: clamp(26px, 4vh, 40px) clamp(28px, 4.4vh, 44px); }
  .sp__for { font-size: 0.9375rem; line-height: 1.5; }
  .trait { padding-block: 6px; font-size: 0.9375rem; line-height: 1.42; }
  .sp__see { padding: 10px var(--s-4); }
}


/* ============================================= PHONES: TOUCH AND READING
   Measured in real iOS Safari (iPhone 17) and Chrome for Android (Pixel 8a),
   30 Sep 2026. No field under 16 px — below that iOS Safari zooms the whole
   page in on every tap into the form (they were 15.2). Every control a thumb
   aims at is at least 44 px tall (Apple's minimum; WCAG 2.5.5); links inside
   sentences keep WCAG's inline exception. The mono labels read at 12 px, not
   11 — the form's field names are among them. */
.field__input { font-size: max(16px, var(--t-body)); }
@media (max-width: 900px), (pointer: coarse) {
  :root { --t-micro: 0.75rem; }
  .mark, .nav__cta, .sp__see { min-height: 44px; }
  .contact__val { display: inline-block; padding-block: 8px; }
  .entry__spec .link { padding-block: 11px; }
  /* the opening's two buttons stay side by side at 12 px, so the lines above
     them keep their distance from the header */
  .opening__actions .btn { padding-inline: 18px; }
  .footer__legal { row-gap: 0; }
  .footer__legal a { display: inline-block; padding-block: 13px; }
}

/* ── Round 24: measure and size (the type audit, 30 Sep) ──────────────────
   Running text no longer than about 70 characters a line at any width, and
   never under 13 px on a phone. Labels set in capitals stay at 12 px: they
   are labels, not reading. */
p.entries__foot, .entries__foot > p { max-width: 62ch; }
.work__disclaim { max-width: 62ch; }
.footer__disclosure { max-width: 64ch; }
.faq__a p { max-width: 60ch; }
.sp--reel .trait dd, .sp--object .trait dd { max-width: 58ch; }
@media (max-width: 760px), (pointer: coarse) {
  .trait, .trait dd { font-size: 0.8125rem; }
  .deck-intro__note, .brief__fine, .footer__disclosure, .sp__label { font-size: 0.8125rem; }
}
/* the tiles keep each site's headline: they are cropped from the top left, where every one of them starts (crop check, 30 Sep) */
.work__shot img { object-position: 0 0; }
