/* ───────────────────────────────────────────── faces
   Split by unicode-range the way Google serves them: a browser fetches the
   latin-ext file only on a page that actually needs a glyph from it, so the
   English page never pays for the French one. */
@font-face{font-family:"Instrument Serif";src:url(/fonts/instrument-serif.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Instrument Serif";src:url(/fonts/instrument-serif-ext.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap;unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:"Instrument Serif";src:url(/fonts/instrument-serif-italic.woff2) format("woff2");font-weight:400;font-style:italic;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Instrument Serif";src:url(/fonts/instrument-serif-italic-ext.woff2) format("woff2");font-weight:400;font-style:italic;font-display:swap;unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:"Geist";src:url(/fonts/geist.woff2) format("woff2");font-weight:300 600;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Geist";src:url(/fonts/geist-ext.woff2) format("woff2");font-weight:300 600;font-style:normal;font-display:swap;unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:"Geist Mono";src:url(/fonts/geist-mono.woff2) format("woff2");font-weight:400 500;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Geist Mono";src:url(/fonts/geist-mono-ext.woff2) format("woff2");font-weight:400 500;font-style:normal;font-display:swap;unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}

/* ───────────────────────────────────────────── system */
:root{
  /* Two constants that never change meaning. Everything else is an assignment
     of one of them to a role, which is what makes the dark scheme a swap
     rather than a second palette to keep in sync. */
  --cream:#EDE7DA;
  --charcoal:#14110C;

  --paper:var(--cream);
  --ink:var(--charcoal);
  --graphite:#5A5449;
  --copper:#9C4F2A;
  /* 11px letterspaced mono never reaches its nominal colour once anti-aliased.
     Rules and large type keep --copper; small labels get this, computed to
     land above 4.5:1 after that loss rather than before it. */
  --copper-text:#753B20;
  --rule:rgba(20,17,12,.16);
  --rule-soft:rgba(20,17,12,.09);

  /* Three papers from the same drawer, dyed. Matched in L* to within 0.4 so
     scrolling past them does not strobe; each mark clears 5:1 on its own
     ground and on the base paper. Copper stays reserved for the brand. */
  /* The plate is always the opposite of the page. In light it is charcoal on
     cream; in dark it is cream on charcoal. That makes the inversion a rule
     the reader can learn rather than the one odd surface on the site. */
  --plate-bg:var(--charcoal);
  --plate-fg:var(--cream);
  --plate-mute:rgba(237,231,218,.62);
  --plate-line:rgba(237,231,218,.34);
  --plate-hair:rgba(237,231,218,.18);
  --plate-key:#E09A6C;

  --flax:#E5E8D8;   --flax-mark:#4D5432;
  --slate:#E1E9F0;  --slate-mark:#485461;
  --clay:#F7E4DC;   --clay-mark:#6B4C3E;

  --display:"Instrument Serif",Georgia,"Times New Roman",serif;
  --text:"Geist",ui-sans-serif,system-ui,-apple-system,sans-serif;
  --mono:"Geist Mono",ui-monospace,"SF Mono",Menlo,monospace;

  --rail:8.5rem;
  --gut:clamp(1.5rem,5vw,4.5rem);
  --measure:38rem;

  --ease:cubic-bezier(.22,.61,.36,1);

  /* One 140px turbulence tile the browser rasterises once and repeats. A
     full-bleed SVG filter would repaint on every scroll instead. */
  --grain:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.055'/%3E%3C/svg%3E");
}


*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--text);
  font-size:clamp(1rem,.96rem + .18vw,1.0625rem);
  font-weight:350;
  line-height:1.65;
  letter-spacing:-.006em;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
/* Paper grain, under the content layer, so it textures the plain paper. */
body::before{
  content:"";position:fixed;inset:0;z-index:0;pointer-events:none;
  opacity:.55;mix-blend-mode:multiply;background-image:var(--grain);
}
::selection{background:var(--copper);color:var(--paper)}
a{color:inherit}
:focus-visible{outline:2px solid var(--copper);outline-offset:3px;border-radius:1px}

.skip{position:absolute;left:-9999px;top:0;background:var(--ink);color:var(--paper);padding:.75rem 1rem;font-family:var(--mono);font-size:.75rem;z-index:99}
.skip:focus{left:.5rem;top:.5rem}
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* mono label — the annotation voice */
.lbl{
  font-family:var(--mono);
  font-size:.6875rem;
  font-weight:500;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--graphite);
  line-height:1.4;
  font-variant-ligatures:none;
}
/* for labels whose casing carries meaning — iOS, Node.js */
.lbl--cased{text-transform:none;letter-spacing:.08em}

/* ───────────────────────────────────────────── document header */
.doc{
  position:fixed;inset:0 0 auto 0;z-index:40;
  display:flex;justify-content:space-between;align-items:baseline;
  padding:1.15rem var(--gut);
  pointer-events:none;
}
.doc__mark{font-family:var(--mono);font-size:.6875rem;letter-spacing:.22em;text-transform:uppercase;color:var(--ink);transition:color .5s var(--ease)}
.doc.is-inverted .doc__mark{color:var(--plate-fg)}

/* ───────────────────────────────────────────── the spine */
.spine{
  position:fixed;top:50%;left:var(--gut);transform:translateY(-50%);
  z-index:30;display:none;
}
@media (min-width:60rem){.spine{display:block}}
.spine ol{list-style:none;margin:0;padding:0;display:grid;gap:.35rem}
.spine a{
  display:grid;grid-template-columns:1.5rem auto;align-items:center;gap:.6rem;
  text-decoration:none;color:var(--graphite);
  font-family:var(--mono);font-size:.6875rem;letter-spacing:.12em;text-transform:uppercase;
  transition:color .4s var(--ease);
  /* padding rather than a taller line-height: it grows the hit area past the
     24px minimum without moving the text. */
  padding-block:.28rem;
}
.spine a::before{
  content:"";height:1px;width:.9rem;background:currentColor;opacity:.4;
  transition:width .45s var(--ease),opacity .45s var(--ease),background .45s var(--ease);
}
.spine a:hover{color:var(--ink)}
.spine a[aria-current="true"]{color:var(--copper)}
.spine a[aria-current="true"]::before{width:1.5rem;opacity:1;background:var(--copper)}
.spine.is-inverted a{color:var(--plate-mute)}
.spine.is-inverted a:hover{color:var(--plate-fg)}
.spine.is-inverted a[aria-current="true"]{color:var(--plate-key)}
.spine.is-inverted a[aria-current="true"]::before{background:var(--plate-key)}

/* mobile: the spine becomes a hairline of progress */
.progress{
  position:fixed;top:0;left:0;height:2px;width:100%;transform-origin:0 50%;
  background:var(--copper);z-index:41;transform:scaleX(0);
}
@media (min-width:60rem){.progress{display:none}}

/* ───────────────────────────────────────────── page frame */
main{position:relative;z-index:10}
.band{padding-inline:var(--gut)}
@media (min-width:60rem){.band{padding-left:calc(var(--gut) + var(--rail))}}
/* width:100% matters — .wrap is a flex item inside .hero, and an auto
   inline-margin on a stretch-aligned flex item shrink-wraps it instead. */
.wrap{width:100%;max-width:64rem;margin-inline:auto}

.sec{padding-block:clamp(5rem,13vh,9rem);position:relative}
.sec + .sec{border-top:1px solid var(--rule-soft)}
.sec__head{display:flex;align-items:baseline;gap:1rem;margin-bottom:2.75rem}
.sec__num{font-family:var(--mono);font-size:.6875rem;font-weight:500;letter-spacing:.14em;color:var(--copper-text)}
.sec__rule{flex:1;height:1px;background:var(--rule);transform-origin:0 50%}
.sec__name{font-family:var(--mono);font-size:.6875rem;letter-spacing:.18em;text-transform:uppercase;color:var(--graphite)}

h1,h2,h3{margin:0;font-weight:400;letter-spacing:-.02em;line-height:.98}
h2{font-family:var(--display);font-size:clamp(2.25rem,1.4rem + 3.4vw,3.75rem);letter-spacing:-.025em;line-height:1.02}
h3{font-family:var(--display);font-size:clamp(1.5rem,1.2rem + 1.2vw,2rem);letter-spacing:-.02em;line-height:1.08}
p{margin:0 0 1.25rem}
p:last-child{margin-bottom:0}

/* ───────────────────────────────────────────── 00 index */
.hero{
  min-height:100svh;display:flex;flex-direction:column;justify-content:center;
  padding-block:clamp(6rem,14vh,8rem) clamp(4rem,10vh,5.5rem);
  position:relative;isolation:isolate;
}
/* The first screen is where the three dyed papers are introduced, far too
   faintly to name — they are the reason the hero has depth, and the reason
   the coloured sections further down feel like they belong. */
.hero__field{
  position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:
    radial-gradient(110% 80% at 4% 8%,   var(--clay)  0%, transparent 60%),
    radial-gradient(90% 72% at 97% 84%,  var(--flax)  0%, transparent 64%),
    radial-gradient(46% 44% at 88% 12%,  var(--slate) 0%, transparent 66%),
    var(--paper);
  -webkit-mask-image:linear-gradient(to bottom,#000 58%,transparent 100%);
          mask-image:linear-gradient(to bottom,#000 58%,transparent 100%);
}
.hero__field::after{
  content:"";position:absolute;inset:0;
  opacity:.55;mix-blend-mode:multiply;background-image:var(--grain);
}
.hero__mark{
  font-family:var(--display);font-weight:400;
  font-size:clamp(3.75rem,.5rem + 18vw,17rem);
  line-height:.84;letter-spacing:-.035em;margin:0;
  display:flex;flex-wrap:wrap;
}
.hero__mark span{display:inline-block;will-change:transform,opacity}
.hero__rule{height:1px;background:var(--ink);margin:clamp(1.75rem,4vh,2.75rem) 0 clamp(1.5rem,3vh,2rem);transform-origin:0 50%;opacity:.85}
.hero__thesis{
  font-family:var(--display);font-style:italic;
  font-size:clamp(1.5rem,1.1rem + 1.7vw,2.375rem);
  line-height:1.15;letter-spacing:-.02em;margin:0 0 1.5rem;max-width:22ch;
}
.hero__sub{max-width:34rem;color:var(--graphite);margin:0}
/* Not aria-hidden any more: the left half says what the company sells and
   that it has not launched, which a screen reader should hear on the first
   screen rather than one section later. Only "Scroll" is decoration. */
.hero__foot{position:absolute;left:var(--gut);right:var(--gut);bottom:2rem;display:flex;justify-content:space-between;gap:1rem;align-items:baseline}
.hero__note{margin:0;flex:1 1 auto;min-width:0}
@media (min-width:60rem){.hero__foot{left:calc(var(--gut) + var(--rail))}}

/* ───────────────────────────────────────────── marginalia */
.note{position:relative}
.note__mark{display:block;margin-bottom:.55rem}
@media (min-width:82rem){
  .note__mark{
    position:absolute;left:calc(-1 * (var(--rail) + .25rem));top:.5rem;
    width:calc(var(--rail) - 1.25rem);text-align:right;margin:0;
  }
}

/* ───────────────────────────────────────────── 01 work */
.work{border-top:1px solid var(--rule);margin-top:2.75rem}
.entry{
  display:grid;gap:1.25rem 2.5rem;grid-template-columns:1fr;
  padding-block:2.25rem;border-bottom:1px solid var(--rule);
  position:relative;text-decoration:none;color:inherit;
  transition:padding-left .5s var(--ease);
}
@media (min-width:48rem){.entry{grid-template-columns:11rem 1fr;padding-block:2.75rem}}
.entry::before{
  content:"";position:absolute;top:-1px;left:0;height:1px;width:0;background:var(--copper);
  transition:width .6s var(--ease);
}
.entry:hover::before,.entry:focus-visible::before{width:100%}
@media (hover:hover){.entry:hover{padding-left:.75rem}}
.entry__meta{display:grid;gap:.4rem;align-content:start}
.entry__title{font-family:var(--display);font-size:clamp(1.75rem,1.4rem + 1.4vw,2.5rem);line-height:1.02;letter-spacing:-.025em;margin:0 0 .65rem}
.entry__title em{font-style:italic;color:var(--copper)}
.entry__body{max-width:var(--measure)}
.entry__facts{list-style:none;margin:1.25rem 0 0;padding:0;display:grid;gap:.45rem}
/* not a two-column grid: any inline child (a <strong> lead-in) would become
   its own grid item and push the rest of the sentence into the 0.9rem column,
   one character per line. */
.entry__facts li{position:relative;padding-left:1.55rem;font-size:.9375rem;color:var(--graphite);line-height:1.55}
.entry__facts li::before{content:"";position:absolute;left:0;top:.7em;height:1px;width:.9rem;background:var(--copper);opacity:.75}
.entry__facts strong{font-weight:500;color:var(--ink)}

/* the goods block states rather than links — no hover lift, no arrow */
.entry--static{cursor:default}
.entry--static::before{display:none}

/* the stage note is set apart rather than dressed up: a claim about what is
   not true yet earns a rule of its own. */
.status{
  display:grid;gap:.45rem;margin:2.75rem 0 0;max-width:var(--measure);
  padding-left:1.25rem;border-left:1px solid var(--copper);
  color:var(--graphite);font-size:.9375rem;line-height:1.6;
}
.status__mark{color:var(--copper-text);font-weight:500}
.entry__go{display:inline-flex;align-items:center;gap:.45rem;margin-top:1.5rem}
.entry__go .lbl{color:var(--ink)}
.entry__go svg{transition:transform .45s var(--ease)}
.entry:hover .entry__go svg{transform:translateX(4px)}

/* ───────────────────────────────────────────── 02 method */
.rules{list-style:none;margin:3rem 0 0;padding:0;display:grid;gap:clamp(2.25rem,5vh,3.25rem);counter-reset:none}
.rules > li{display:grid;gap:.75rem}
.rules h3 em{font-style:italic;color:var(--copper)}
.rules p{color:var(--graphite);max-width:var(--measure)}

/* signature: the plate */
/* An inserted plate, not a change of page. It used to bleed to both edges,
   which read as the site switching rather than a figure being laid down; the
   paper stays visible around it now, and the inversion becomes a convention
   the reader recognises from printed documents. */
.plate{
  background:var(--plate-bg);color:var(--plate-fg);
  margin:clamp(3.5rem,8vh,5.5rem) 0 0;
  padding:clamp(2rem,4.5vw,3.25rem) clamp(1.5rem,4vw,3rem) clamp(2.5rem,5vw,3.5rem);
  position:relative;overflow:hidden;isolation:isolate;
}

.plate__lamp{
  position:absolute;inset:0;z-index:0;pointer-events:none;opacity:0;
  background:radial-gradient(26rem 26rem at var(--lx,50%) var(--ly,50%),rgba(224,154,108,.18),rgba(224,154,108,.05) 42%,transparent 68%);
  transition:opacity .8s var(--ease);
}
.plate__inner{position:relative;z-index:1}
.plate__head{display:flex;align-items:baseline;gap:1rem;margin-bottom:2.25rem}
.plate__head .lbl{color:var(--plate-mute)}
.plate__head .sec__rule{background:var(--plate-hair)}
.plate__cap{font-family:var(--display);font-size:clamp(1.375rem,1.1rem + 1vw,1.875rem);letter-spacing:-.02em;line-height:1.15;margin:0 0 .5rem;color:var(--plate-fg)}
.plate__sub{color:var(--plate-mute);max-width:34rem;font-size:.9375rem;margin:0}
.diagram{width:100%;height:auto;margin:2.5rem 0 0;display:block;overflow:visible}
.diagram--wide{max-width:52rem}
.diagram--tall{display:none;max-width:22rem}
@media (max-width:47.99rem){
  .diagram--wide{display:none}
  .diagram--tall{display:block}
  .diagram--tall text{font-size:11px}
  .diagram--tall text.dim{font-size:9.5px}
}
.diagram text{font-family:var(--mono);fill:var(--plate-fg);font-size:9.5px;letter-spacing:.07em;text-transform:uppercase}
.diagram text.dim{fill:var(--plate-mute);font-size:8.5px}
.diagram .box{fill:none;stroke:var(--plate-line);stroke-width:1}
.diagram .box--key{stroke:var(--plate-key)}
.diagram .wire{fill:none;stroke:var(--plate-line);stroke-width:1}
.diagram .wire--key{stroke:var(--plate-key);stroke-width:1.15}
.diagram .pkt{fill:var(--plate-key)}
.diagram .node-end{fill:var(--plate-key)}
.plate__foot{margin-top:2.25rem}
.plate__foot .lbl{color:var(--plate-mute)}

/* ───────────────────────────────────────────── 03 contact */
.contact__lead{font-family:var(--display);font-size:clamp(1.75rem,1.3rem + 2vw,2.75rem);line-height:1.1;letter-spacing:-.025em;max-width:20ch;margin:0 0 1.25rem}
.contact__note{color:var(--graphite);max-width:var(--measure);margin:0 0 2.75rem}
.links{border-top:1px solid var(--rule);max-width:38rem}
.links a{
  display:flex;justify-content:space-between;align-items:baseline;gap:1rem;
  padding:1.15rem 0;border-bottom:1px solid var(--rule);
  text-decoration:none;position:relative;
}
.links a::after{content:"";position:absolute;left:0;bottom:-1px;height:1px;width:0;background:var(--copper);transition:width .55s var(--ease)}
.links a:hover::after,.links a:focus-visible::after{width:100%}
.links__name{font-size:1.0625rem}
.links__val{font-family:var(--mono);font-size:.8125rem;letter-spacing:.04em;color:var(--graphite);transition:color .4s var(--ease)}
.links a:hover .links__val{color:var(--copper)}

footer{padding:2.5rem var(--gut) 3rem;border-top:1px solid var(--rule-soft)}
@media (min-width:60rem){footer{padding-left:calc(var(--gut) + var(--rail))}}
.foot__row{display:flex;flex-wrap:wrap;gap:.75rem 2rem;justify-content:space-between;max-width:64rem;margin-inline:auto}
.foot__legal{max-width:64rem;margin:.9rem auto 0;opacity:.65}
.foot__link{text-decoration:none;position:relative;padding:.3rem 0;margin-block:-.3rem;transition:color .4s var(--ease)}
.foot__link::after{content:"";position:absolute;left:0;bottom:.2rem;height:1px;width:0;background:var(--copper);transition:width .45s var(--ease)}
.foot__link:hover{color:var(--ink)}
.foot__link:hover::after,.foot__link:focus-visible::after{width:100%}

/* real links, so switching languages works with scripts off */
.langs{display:flex;gap:.45rem}
.langs a{
  font-family:var(--mono);font-size:.6875rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--graphite);text-decoration:none;position:relative;
  padding:.3rem .35rem;margin:-.3rem 0;
  transition:color .4s var(--ease);
}
.langs a::after{content:"";position:absolute;left:.35rem;right:.35rem;bottom:.15rem;height:1px;width:auto;transform:scaleX(0);transform-origin:0 50%;background:var(--copper);transition:transform .45s var(--ease)}
.langs a:hover{color:var(--ink)}
.langs a:hover::after,.langs a:focus-visible::after{transform:scaleX(1)}
.langs a[aria-current="page"]{color:var(--ink)}
.langs a[aria-current="page"]::after{transform:scaleX(1);background:var(--ink);opacity:.35}

/* ───────────────────────────────────────────── motion
   Every hidden-until-revealed state is gated on .js, which the inline script
   in <head> sets. Nothing here can leave content unreadable if the script
   never runs — the page renders fully without it. */
.js .rise{opacity:0;transform:translateY(14px)}
.js .is-in .rise{opacity:1;transform:none;transition:opacity .9s var(--ease),transform .9s var(--ease)}
.js .sec__rule{transform:scaleX(0);transition:transform 1.1s var(--ease)}
.js .is-in .sec__rule{transform:scaleX(1)}
.js .hero__rule{transform:scaleX(0);transition:transform 1.1s var(--ease)}
.js .hero__rule.is-in{transform:scaleX(1)}

/* 01 — each claim's rule draws as the claim is made, in order. */
.js .entry__facts li::before{transform:scaleX(0);transform-origin:0 50%;transition:transform .55s var(--ease)}
.js .is-in .entry__facts li::before{transform:scaleX(1)}
.js .is-in .entry__facts li:nth-child(1)::before{transition-delay:.28s}
.js .is-in .entry__facts li:nth-child(2)::before{transition-delay:.37s}
.js .is-in .entry__facts li:nth-child(3)::before{transition-delay:.46s}
.js .is-in .entry__facts li:nth-child(4)::before{transition-delay:.55s}

/* 02 — the marginalia arrives after the note it annotates, as marginalia does. */
.js .note__mark{opacity:0;transition:opacity .85s var(--ease)}
.js .is-in .note__mark{opacity:1}
.js .is-in .rules > li:nth-child(1) .note__mark{transition-delay:.5s}
.js .is-in .rules > li:nth-child(2) .note__mark{transition-delay:.62s}
.js .is-in .rules > li:nth-child(3) .note__mark{transition-delay:.74s}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
  .js .rise{opacity:1;transform:none}
  .js .sec__rule,.js .hero__rule{transform:scaleX(1)}
  .js .entry__facts li::before{transform:scaleX(1)}
  .js .note__mark{opacity:1}
  .plate__lamp{display:none}
}

/* ───────────────────────────────────────────── chinese
   Instrument Serif has no CJK glyphs and a Chinese webfont is megabytes, so
   the zh page borrows the reader's own system faces — a serif for display,
   a sans for prose. Latin inside Chinese text still comes from Geist. */
:lang(zh) .hero__thesis,
:lang(zh) h2,
:lang(zh) h3,
:lang(zh) .entry__title,
:lang(zh) .plate__cap,
:lang(zh) .contact__lead{
  font-family:"Instrument Serif",Songti SC,STSong,"Noto Serif SC",SimSun,serif;
  letter-spacing:0;
}
:lang(zh) body,
:lang(zh) p,
:lang(zh) li{
  font-family:"Geist",-apple-system,"PingFang SC","Hiragino Sans GB","Noto Sans SC","Microsoft YaHei",sans-serif;
  letter-spacing:0;
}
/* Chinese has no italic; the accent colour has to carry the emphasis alone. */
:lang(zh) .hero__thesis{font-style:normal}
:lang(zh) h3 em,:lang(zh) .entry__title em{font-style:normal}
/* CJK sets tighter than Latin at the same size, so the wordmark line can close up */
:lang(zh) .hero__sub,:lang(zh) .rules p,:lang(zh) .entry__body p{line-height:1.85}

/* ───────────────────────────────────────────── categories
   Not feature cards: no rounding, no shadow, no icon. Three dyed papers
   butted together on hairlines, each carrying an orthographic schematic of
   what the category is — a drawing of a kind of object, never a photograph
   of a product that does not exist yet. */
.cats{
  display:grid;gap:1px;background:var(--rule);
  border-block:1px solid var(--rule);
  margin:2.75rem 0 0;
}
@media (min-width:52rem){.cats{grid-template-columns:repeat(3,1fr)}}

.cat{
  background:var(--tone);
  padding:clamp(1.5rem,3vw,2.25rem);
  display:flex;flex-direction:column;
  position:relative;isolation:isolate;overflow:hidden;
}
/* The real material, sunk far enough that the dyed paper still governs the
   contrast. An <img> rather than a CSS background so it is genuinely lazy. */
.cat__mat{
  position:absolute;inset:0;z-index:-1;
  width:100%;height:100%;object-fit:cover;
  opacity:var(--mat-opacity,.24);
}
/* The three photographs differ in density, so a single opacity would read as
   three different amounts of texture. Terracotta is much the darkest and has
   to sink furthest to leave the body text above 4.5:1. */
.cat--flax { --mat-opacity:.22 }
.cat--slate{ --mat-opacity:.28 }
.cat--clay { --mat-opacity:.13 }
.cat--flax {--tone:var(--flax);  --tone-mark:var(--flax-mark)}
.cat--slate{--tone:var(--slate); --tone-mark:var(--slate-mark)}
.cat--clay {--tone:var(--clay);  --tone-mark:var(--clay-mark)}

.cat__draw{
  display:block;width:100%;max-width:19rem;height:auto;
  margin:0 0 clamp(1.25rem,3vw,2rem);
}
.cat__draw .ln{fill:none;stroke:var(--tone-mark);stroke-width:1.15;stroke-linecap:square}
.cat__draw .ln--soft{stroke:var(--tone-mark);opacity:.42}
.cat__draw .ln--dash{stroke:var(--tone-mark);opacity:.42;stroke-dasharray:2.5 3}
.cat__draw .fill{fill:var(--tone-mark);opacity:.1}

.cat__lbl{color:var(--tone-mark);font-weight:500;margin-bottom:.75rem}
.cat__h{
  font-family:var(--display);font-size:clamp(1.375rem,1.15rem + .9vw,1.75rem);
  line-height:1.08;letter-spacing:-.02em;margin:0 0 .65rem;
}
.cat p{font-size:.9375rem;line-height:1.6;color:var(--graphite);margin:0}

/* The schematics draw themselves card by card; site.js measures each path and
   owns the timing, so nothing here can leave a drawing half-finished. */
@media (prefers-reduced-motion:reduce){
  .cat__draw .ln{stroke-dasharray:none!important;stroke-dashoffset:0!important}
}

/* ───────────────────────────────────────────── the list
   An underlined field and a mono label, so the one place that asks for
   something looks like the rest of the document rather than an ad unit. */
.signup{max-width:38rem;margin:0 0 2.75rem}
.signup__lbl{display:block;margin-bottom:.9rem;color:var(--copper-text)}
.signup__row{
  display:flex;align-items:baseline;gap:1.25rem;
  border-bottom:1px solid var(--ink);padding-bottom:.7rem;
  transition:border-color .4s var(--ease);
}
.signup__row:focus-within{border-bottom-color:var(--copper)}
.signup__input{
  flex:1;min-width:0;background:none;border:0;padding:.15rem 0;border-radius:0;
  font-family:var(--text);font-size:1.0625rem;font-weight:350;color:var(--ink);
  letter-spacing:-.006em;
}
.signup__input::placeholder{color:var(--graphite);opacity:1}
/* No outline:none here. The border-colour shift reads for a mouse, but a
   keyboard user needs to see where they are, and :focus-visible only fires
   for them anyway. */
.signup__input:focus-visible{outline-offset:4px}
.signup__btn{
  background:none;border:0;padding:.4rem 0;margin-block:-.25rem;cursor:pointer;white-space:nowrap;
  min-height:1.6rem;
  font-family:var(--mono);font-size:.6875rem;font-weight:500;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink);
  transition:color .4s var(--ease);
}
.signup__btn:hover{color:var(--copper)}
.signup__btn[disabled]{opacity:.45;cursor:default}
.signup__note{font-size:.875rem;line-height:1.55;color:var(--graphite);margin:.9rem 0 0;max-width:34rem}
.signup__msg{font-size:.9375rem;line-height:1.55;color:var(--copper-text);margin:.75rem 0 0}
.signup__msg:empty{display:none}
/* off-screen rather than display:none — a bot that skips hidden fields still fills this */
.signup__hp{position:absolute!important;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden}

/* ───────────────────────────────────────────── the scripts-off reply
   /api/subscribe answers a native form POST with a page. It borrows this
   sheet so no stylesheet has to travel inline with it. */
.reply{min-height:100svh;display:flex;flex-direction:column;justify-content:center;padding-block:4rem}
.reply__mark{margin-bottom:1.25rem}
.reply__msg{
  font-family:var(--display);font-size:clamp(1.75rem,1.3rem + 2vw,2.75rem);
  line-height:1.15;letter-spacing:-.025em;max-width:22ch;margin:0 0 2rem;
}
.reply__links{max-width:26rem}
.reply__num{color:var(--copper-text);margin-bottom:1.25rem}
.reply__rule{height:1px;background:var(--ink);opacity:.85;margin:0 0 1.5rem;max-width:38rem}
.reply__note{color:var(--graphite);max-width:34rem;margin:0 0 2.5rem}

/* ───────────────────────────────────────────── the standard
   A ledger, not another stack of headings: the number sits out in the margin,
   the criterion is set in display, and the reasoning follows underneath in the
   quieter face. Ruled above each row like a form that expects to be filled in. */
.spec__lede{color:var(--graphite);max-width:var(--measure);margin:1.5rem 0 0}
.spec{
  list-style:none;margin:clamp(3rem,7vh,4.5rem) 0 0;padding:0;
  border-top:1px solid var(--rule);
}
.spec__row{
  display:grid;gap:.55rem 2.5rem;grid-template-columns:1fr;
  padding-block:clamp(1.75rem,4vh,2.5rem);
  border-bottom:1px solid var(--rule);
}
@media (min-width:52rem){
  .spec__row{grid-template-columns:11rem 1fr;gap:0 2.5rem}
  .spec__n{padding-top:.5rem}
}
.spec__n{color:var(--copper-text)}
.spec__body{max-width:var(--measure)}
.spec__t{
  font-family:var(--display);font-size:clamp(1.5rem,1.2rem + 1.4vw,2.125rem);
  line-height:1.06;letter-spacing:-.022em;margin:0 0 .7rem;
}
.spec__d{font-size:.9375rem;line-height:1.6;color:var(--graphite);margin:0}

/* the rule above each criterion draws itself as the row arrives */
.js .spec__row{border-bottom-color:transparent}
.js .is-in .spec__row{border-bottom-color:var(--rule);transition:border-color .9s var(--ease)}
.js .is-in .spec__row:nth-child(2){transition-delay:.08s}
.js .is-in .spec__row:nth-child(3){transition-delay:.16s}
.js .is-in .spec__row:nth-child(4){transition-delay:.24s}
.js .is-in .spec__row:nth-child(5){transition-delay:.32s}
@media (prefers-reduced-motion:reduce){
  .js .spec__row{border-bottom-color:var(--rule)}
}

/* ───────────────────────────────────────────── the colophon
   A sub-page, so it has no spine to track — one column, the same ledger, and
   a way back. */
.doc-page{padding-block:clamp(7rem,16vh,10rem) clamp(4rem,10vh,6rem)}
.doc-page__h{
  font-family:var(--display);font-weight:400;
  font-size:clamp(2.5rem,1.5rem + 4vw,4.5rem);
  line-height:.98;letter-spacing:-.03em;margin:0 0 1.75rem;
}
.doc-page__lede{color:var(--graphite);max-width:var(--measure);margin:0}
.doc-page__back{margin-top:clamp(3rem,7vh,4.5rem);max-width:26rem}
/* the sub-page has no sections to observe, so nothing gates its rules */
.doc-page .spec__row{border-bottom-color:var(--rule)}


/* ───────────────────────────────────────────── swatches
   The four surfaces spend the site at between six and twenty-eight per cent,
   underneath text. This is the one place they are themselves. */
.swatches{margin:clamp(3rem,7vh,4.5rem) 0 0;padding:0}
.swatches__lbl{color:var(--copper-text);margin-bottom:.75rem}
.swatches__note{color:var(--graphite);max-width:var(--measure);font-size:.9375rem;line-height:1.6;margin:0 0 2rem}
.swatches__row{display:grid;gap:1px;background:var(--rule);border:1px solid var(--rule)}
@media (min-width:44rem){.swatches__row{grid-template-columns:repeat(4,1fr)}}
.swatch{background:var(--paper);padding:0 0 1rem}
.swatch img{display:block;width:100%;height:auto;aspect-ratio:5/4;object-fit:cover;margin-bottom:.9rem}
.swatch__name{color:var(--ink);padding-inline:1rem}
.swatch__use{margin-top:.3rem;padding-inline:1rem}

/* ───────────────────────────────────────────── dark
   Paper and ink swap roles; the plate swaps with them, so it stays the
   opposite of whatever the page is. Its internal values are the light
   scheme's, already measured — the rule buys us one palette, not two.
   Every pairing below was computed against the dark ground the same way the
   light one was: the three tints sit at a matched L* about nine points above
   the ground, so a card lifts off the page without any of them strobing. */
@media (prefers-color-scheme: dark) {
  :root{
    --paper:var(--charcoal);
    --ink:var(--cream);
    /* Lighter than the light scheme's counterpart is dark: the category cards
       sit under a material and a grain layer that lift them about seven L*
       points, so this is chosen against the card as rendered, not the tint as
       declared. */
    --graphite:#B2AB9B;

    --copper:#C97B57;
    --copper-text:#DE8F6A;

    --rule:rgba(237,231,218,.18);
    --rule-soft:rgba(237,231,218,.10);

    --flax:#22241C;   --flax-mark:#A2AD72;
    --slate:#1F2429;  --slate-mark:#8DABC9;
    --clay:#29211E;   --clay-mark:#D69A81;

    /* the plate becomes the paper */
    --plate-bg:var(--cream);
    --plate-fg:var(--charcoal);
    --plate-mute:#5A5449;
    --plate-line:rgba(20,17,12,.34);
    --plate-hair:rgba(20,17,12,.18);
    --plate-key:#9C4F2A;
  }

  /* multiply over a dark ground removes the grain instead of adding it */
  body::before, .hero__field::after { mix-blend-mode:screen; opacity:.32 }

  /* the material photographs are light; over a dark card they lift it far more
     than they textured the cream one, so they sink further */
  .cat--flax { --mat-opacity:.07 }
  .cat--slate{ --mat-opacity:.08 }
  .cat--clay { --mat-opacity:.06 }

  /* a cream rectangle at full strength is a lamp in a dark room */
  .plate__lamp{
    background:radial-gradient(26rem 26rem at var(--lx,50%) var(--ly,50%),
      rgba(20,17,12,.10), rgba(20,17,12,.03) 42%, transparent 68%);
  }
  ::selection{background:var(--copper);color:var(--charcoal)}
}

/* ───────────────────────────────────────────── print
   The whole site is arranged as a document, so it ought to behave like one
   when someone prints it or saves a PDF. Screen chrome goes, the dark plate
   inverts rather than laying down a full-bleed black rectangle, link targets
   are spelled out because a printed link cannot be clicked, and no criterion
   is allowed to break across a page. */
@media print {
  @page { margin: 18mm 16mm; }

  html, body { background: #fff; color: #000; }
  body::before { display: none; }              /* grain wastes ink and prints as mud */

  /* fixed chrome, and the affordances that only mean something on a screen */
  .doc, .spine, .progress, .hero__field, .cat__mat, .plate__lamp,
  .signup, .langs, .skip,
  .hero__foot span[aria-hidden="true"] { display: none !important; }

  /* absolute positioning collapses once the hero stops being a screen tall */
  .hero__foot { position: static; margin-top: 6mm; }

  .band { padding-left: 0 !important; padding-right: 0 !important; }
  .wrap { max-width: none; }
  main { z-index: auto; }

  /* one screen per section is a screen idea; on paper it is wasted paper */
  .hero { min-height: 0; padding-block: 0 8mm; }
  .sec { padding-block: 10mm 0; border-top: .3pt solid #999; }
  .doc-page { padding-block: 0; }

  .hero__mark { font-size: 48pt; }
  h2 { font-size: 20pt; }
  h3, .spec__t, .cat__h { font-size: 13pt; }
  .hero__thesis { font-size: 16pt; }
  body, p, li { font-size: 10pt; line-height: 1.5; color: #000; }
  .lbl, .sec__num, .sec__name { color: #444; }

  /* the plate is a black field on screen; on paper it is a drawing */
  .plate { background: none; color: #000; margin-inline: 0; padding: 6mm 0 0; }
  .plate__cap, .plate__sub, .plate__foot .lbl, .plate__head .lbl { color: #000; }
  .diagram text { fill: #000; }
  .diagram text.dim { fill: #444; }
  .diagram .box, .diagram .wire { stroke: #000; }
  .diagram .box--key, .diagram .wire--key { stroke: #000; stroke-width: 1.4; }
  .diagram .pkt, .diagram .node-end { fill: #000; }
  .cat__draw .ln { stroke: #000; }
  /* A4 is narrower than the three-column breakpoint, so stacked cards would
     cost a page each. The drawing comes out of the flow entirely — spanning
     grid rows made it distribute its height between the label and the
     criterion and open a gap in the middle. */
  .cats { background: none; display: block; border: 0; }
  .cat {
    background: none; border: 0; border-top: .3pt solid #999;
    display: block; position: relative;
    padding: 4mm 0 0 41mm; margin-bottom: 4mm;
  }
  .cat__draw { position: absolute; left: 0; top: 4mm; width: 34mm; max-width: 34mm; margin: 0; }
  .cat__lbl { margin-bottom: 2mm; }
  .cat__h { margin: 0 0 2mm; }
  .cat p { margin: 0; }

  /* a printed link is a dead end unless it says where it went */
  a[href^="http"]::after,
  a[href^="mailto"]::after { content: " (" attr(href) ")"; font-size: 8pt; color: #444; }
  a[href^="/"]::after { content: " (meravin.dev" attr(href) ")"; font-size: 8pt; color: #444; }
  a { text-decoration: none; color: #000; }
  .links a::after { border: 0; }

  /* nothing that reads as one unit may be split across a page */
  .spec__row, .cat, .entry, .rules > li, figure { break-inside: avoid; page-break-inside: avoid; }
  h1, h2, h3 { break-after: avoid; page-break-after: avoid; }

  /* every reveal must be in its finished state — none of this is animated on paper */
  .rise { opacity: 1 !important; transform: none !important; }
  .sec__rule, .hero__rule { transform: scaleX(1) !important; background: #999; }
  .cat__draw .ln { stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
}
