/* ============================================================
   shutter kif. — black & white, gritty, minimal
   Composed sections sit on a 16:9 stage carrying the exact PSD
   coordinates in percent.
   ============================================================ */

@font-face{font-family:'Helv';src:url('../assets/fonts/Helvetica.woff') format('woff'),url('../assets/fonts/Helvetica.ttf') format('truetype');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'Helv';src:url('../assets/fonts/Helvetica-Oblique.woff') format('woff'),url('../assets/fonts/Helvetica-Oblique.ttf') format('truetype');font-weight:400;font-style:italic;font-display:swap}
@font-face{font-family:'Helv';src:url('../assets/fonts/Helvetica-Bold.woff') format('woff'),url('../assets/fonts/Helvetica-Bold.ttf') format('truetype');font-weight:700;font-style:normal;font-display:swap}
@font-face{font-family:'VCR';src:url('../assets/fonts/VCR.woff') format('woff'),url('../assets/fonts/VCR.ttf') format('truetype');font-weight:400;font-display:swap}

:root{
  --light:#ffffff;
  --dark:#000000;
  --on-light:#000000;
  --on-dark:#ffffff;

  /* paper = the tone actually painted behind the cut-outs.
     --el-inv / --el-blend are derived from it, never from a section name. */
  --paper:var(--dark);
  --el-inv:1;
  --el-blend:screen;

  --f:'Helv','Helvetica Neue',Helvetica,Arial,sans-serif;
  --f-vcr:'VCR','Helv',monospace;
  --ease:cubic-bezier(.16,1,.3,1);
  --gutter:clamp(1rem,3.5vw,3rem);
  --fade-t:7svh;        /* seam bleed, per side — 0 where there is no seam */
  --fade-b:7svh;
}

/* the angle is its own animatable property so the parallax translate on the
   same element stays live instead of being frozen into the keyframes */
@property --spin{syntax:'<angle>';inherits:false;initial-value:0deg}
@property --hands-lift{syntax:'<length>';inherits:false;initial-value:0px}
@property --hands-turn{syntax:'<angle>';inherits:false;initial-value:0deg}
@property --hands-scale{syntax:'<number>';inherits:false;initial-value:1}
@property --hands-pointer-lift{syntax:'<length>';inherits:false;initial-value:0px}
@property --hands-pointer-turn{syntax:'<angle>';inherits:false;initial-value:0deg}
@property --word-slide{syntax:'<length>';inherits:false;initial-value:0px}
@property --glass-shift{syntax:'<length>';inherits:false;initial-value:0px}
@property --glass-pointer{syntax:'<length>';inherits:false;initial-value:0px}
@property --signal-lift{syntax:'<length>';inherits:false;initial-value:0px}
@property --signal-turn{syntax:'<angle>';inherits:false;initial-value:0deg}
@property --signal-scale{syntax:'<number>';inherits:false;initial-value:1}

/* invert — every surface and every cut-out flips together */
body.is-invert{
  --light:#000000;
  --dark:#ffffff;
  --on-light:#ffffff;
  --on-dark:#000000;
}

*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth;scroll-padding-top:5rem;-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--dark);color:var(--on-dark);
  font-family:var(--f);line-height:1.5;
  overflow-x:hidden;-webkit-font-smoothing:antialiased;
}
body.is-booting{overflow:hidden}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
::selection{background:currentColor;color:var(--light)}
:focus-visible{outline:2px solid currentColor;outline-offset:4px}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* A single fixed backdrop behind everything has its tone interpolated on
   scroll, so where two sections differ the tones bleed instead of meeting at a
   hard seam. Each stage paints its own opaque paper over it and fades that
   paper out at the viewport edges, which is where the bleed shows through. */
.backdrop{position:fixed;inset:0;z-index:-1;background:var(--dark)}
.sec{position:relative;overflow:hidden}

/* ---- paper, and everything derived from it -------------------------------
   The cut-outs are dark artwork printed on an opaque white rectangle (star-a,
   star-b, hands, cards) or dark artwork on transparency (cd-a, cd-b, ic-mail).
   Either way the rule is the same: the artwork must end up LIGHTER than the
   paper and screen onto it, or DARKER than the paper and multiply into it.
   Anything else leaves the source rectangle sitting on top of the type — that
   was the black-box bug on the first and last pages.                        */
.sec--light{--paper:var(--light);color:var(--on-light);--el-blend:multiply;--el-inv:0}
.sec--dark {--paper:var(--dark); color:var(--on-dark); --el-blend:screen;  --el-inv:1}
body.is-invert .sec--light{--el-blend:screen;  --el-inv:1}
body.is-invert .sec--dark {--el-blend:multiply;--el-inv:0}

/* Tracking-overlay ink. The overlay composites with `difference` (see .trk),
   so one neutral grey reads the same faint grey over black paper, over white
   paper and over the cut-outs themselves — no per-paper theming, and it can
   never disappear against the white artwork the way a plain white hairline did.
   Same trick the controls use. */
:root{--trk:rgba(146,146,146,.42);--trk-hi:rgba(190,190,190,.52)}

.el,.boot__img,.lay--icons img{filter:invert(var(--el-inv));user-select:none;-webkit-user-drag:none}
/* max-width:none is load-bearing. The base `img{max-width:100%}` clamps any
   cut-out authored wider than its stage — and when only ONE axis is clamped
   while the other is an explicit length, the aspect ratio breaks and the
   artwork renders stretched. These are art-directed cut-outs that are meant to
   bleed past the frame; let them. */
.el{position:absolute;pointer-events:none;z-index:1;max-width:none;
    mix-blend-mode:var(--el-blend);transform:translateY(var(--ty,0))}

/* ============ LOADER ============ */
.boot{
  position:fixed;inset:0;z-index:200;background:var(--light);color:var(--on-light);
  --el-inv:0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1.6rem;
  transition:opacity .5s var(--ease),visibility .5s;
}
body.is-invert .boot{--el-inv:1}
.boot.is-done{opacity:0;visibility:hidden}
.boot__img{width:min(230px,44vw);image-rendering:pixelated}
.boot__bar{width:min(230px,44vw);height:2px;background:currentColor;opacity:.18;position:relative;overflow:hidden}
.boot__bar span{position:absolute;inset:0 100% 0 0;background:var(--on-light);transition:right .16s linear}
.boot__pct{font-family:var(--f-vcr);font-size:.95rem;letter-spacing:.14em;color:var(--on-light);opacity:.55}

/* ============ FIXED CONTROLS ============ */
.ctl{
  position:fixed;right:calc(var(--gutter) + env(safe-area-inset-right));bottom:calc(var(--gutter) - .3rem + env(safe-area-inset-bottom));z-index:95;
  display:flex;flex-direction:column;align-items:flex-end;gap:.25rem;
  mix-blend-mode:difference;
  opacity:0;transition:opacity .8s var(--ease) .2s;
}
.is-lit .ctl{opacity:1}
.ctl__b{
  background:none;border:0;padding:.18rem 0;cursor:pointer;
  font-family:var(--f);font-size:clamp(.72rem,1vw,.86rem);color:#fff;
  line-height:1.35;position:relative;
}
.ctl__b::after{content:'';position:absolute;left:0;right:100%;bottom:.1rem;height:1px;background:currentColor;transition:right .35s var(--ease)}
.ctl__b:hover::after,.ctl__b[aria-pressed="true"]::after{right:0}

/* ============ PAGE NAVIGATION ============
   Sparse enough to stay out of the composition. These are real page routes,
   so About and Catalog can arrive later without reworking the masthead. */
.site-header{
  position:fixed;left:calc(var(--gutter) + env(safe-area-inset-left));right:calc(var(--gutter) + env(safe-area-inset-right));top:env(safe-area-inset-top);z-index:110;
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  padding:1.35rem 0;color:#fff;mix-blend-mode:difference;pointer-events:none;
  opacity:0;transform:translateY(-.5rem);transition:opacity .7s var(--ease) .24s,transform .7s var(--ease) .24s;
}
.is-lit .site-header{opacity:1;transform:none}
.site-header a{color:inherit;pointer-events:auto}
.site-header__home{display:block;line-height:1}
.site-header__mark{font:700 italic clamp(1.25rem,1.7vw,1.75rem)/.9 var(--f);letter-spacing:-.095em}
.site-nav{grid-column:2;display:flex;align-items:center;gap:clamp(1.5rem,3.4vw,3.8rem);font:400 clamp(.84rem,.98vw,1.04rem)/1 var(--f);letter-spacing:-.015em}
.site-nav a{position:relative;padding:.38rem .12rem .52rem;opacity:.76;transition:opacity .3s var(--ease)}
.site-nav a::after{content:'';position:absolute;left:0;right:100%;bottom:0;height:2px;background:currentColor;transition:right .32s var(--ease)}
.site-nav a:hover,.site-nav a:focus-visible,.site-nav a.is-active{opacity:1}
.site-nav a:hover::after,.site-nav a:focus-visible::after,.site-nav a.is-active::after{right:0}

/* ============ COMP STAGE ============
   COVER, not contain: the comps are full-bleed, so on a window wider than 16:9
   the stage grows past the viewport and the section crops it. Contain left bare
   backdrop down both sides — that was the "zoomed out" bug.
   The stage also carries the paper the cut-outs blend against, because
   container-type creates a stacking context and isolates the blend from
   anything painted outside it. The mask is anchored to the VIEWPORT, not to the
   stage box, so the seam fade stays on screen no matter how much of the stage
   is cropped away — --vtop/--vbot are where the viewport edges land inside the
   stage, and they change with how the stage is aligned in its section. */
/* Absolutely placed, not grid-aligned: once the stage overflows its section,
   Chrome falls back to `start` for align-self and the crop anchor silently
   moves to the top — which is what cropped the contact marks off the bottom. */
.stage{
  position:absolute;inset:0;margin:auto;   /* centred WITHOUT transform — the
     data-rise reveal owns `transform` on this element and would cancel it */
  width:max(100vw, calc(100svh * 16 / 9));
  height:max(100svh, calc(100vw * 9 / 16));
  container-type:size;
  background:var(--paper);
  --vtop:calc(50% - 50svh);
  --vbot:calc(50% + 50svh);
  -webkit-mask-image:linear-gradient(to bottom,
      transparent var(--vtop),
      #000 calc(var(--vtop) + var(--fade-t)),
      #000 calc(var(--vbot) - var(--fade-b)),
      transparent var(--vbot));
          mask-image:linear-gradient(to bottom,
      transparent var(--vtop),
      #000 calc(var(--vtop) + var(--fade-t)),
      #000 calc(var(--vbot) - var(--fade-b)),
      transparent var(--vbot));
}
/* First and last pages have no seam above / below them, so they get the full
   frame instead of fading into nothing. */
.hero .stage{--fade-t:0;overflow:hidden}
.hero .stage::after{
  content:'';position:absolute;left:0;right:0;bottom:0;height:31%;z-index:9;pointer-events:none;
  background:linear-gradient(to bottom,transparent 0%,var(--dark) 94%);
}
.contact .stage{--fade-b:0}
.lay{position:absolute;margin:0;z-index:5;line-height:1;letter-spacing:-.02em;font-weight:400;transform:translateY(var(--ty,0))}

/* tracking overlay — above the cut-outs, under the type, never interactive */
.trk{
  position:absolute;inset:0;width:100%;height:100%;z-index:3;
  pointer-events:none;mix-blend-mode:difference;
  opacity:0;transition:opacity 1.6s var(--ease) .25s;
}
.trk.is-on{opacity:.52}
.hero .trk.is-on{opacity:.42}
.machine .trk.is-on{opacity:.18}
.contact .trk{display:none}

/* ---- 01 front ---- */
.hero{height:100svh;display:grid;place-items:center;overflow:visible;z-index:2}
.el--star-a{left:87%;top:-3%;width:15%}
.el--star-b{left:-13%;top:55%;width:34%}
.hero .el--star-b{z-index:10}
/* the stars turn, very slowly and against each other — one revolution is over
   two minutes, so it reads as drift rather than as an animation */
.el--star-a,.el--star-b{transform:translateY(var(--ty,0)) rotate(var(--spin))}
.el--star-a{animation:spin-cw 128s linear infinite}
.el--star-b{animation:spin-ccw 173s linear infinite}
@keyframes spin-cw {to{--spin:360deg}}
@keyframes spin-ccw{to{--spin:-360deg}}
.el--hands{
  left:30%;top:35%;width:40%;z-index:4;opacity:.64;
  --hands-lift:0px;--hands-turn:0deg;--hands-scale:1;--hands-pointer-lift:0px;--hands-pointer-turn:0deg;
  filter:invert(1) grayscale(1) contrast(1.55) brightness(1.14);mix-blend-mode:screen;
  transform:translate3d(0,calc(var(--ty,0px) + var(--hands-lift) + var(--hands-pointer-lift)),0) rotate(calc(var(--hands-turn) + var(--hands-pointer-turn))) scale(var(--hands-scale));
  transform-origin:50% 48%;will-change:transform,opacity;
}
body.is-invert .el--hands{filter:grayscale(1) contrast(1.55) brightness(.64);mix-blend-mode:multiply}
.el--glass-portrait{
  left:17%;width:62%;opacity:.68;z-index:2;
  filter:grayscale(1) contrast(2) brightness(.88);mix-blend-mode:screen;
  clip-path:polygon(18% 0,100% 0,100% 100%,0 100%,0 36%);
  -webkit-mask-image:linear-gradient(90deg,transparent 0 12%,#000 22%,#000 100%);
  mask-image:linear-gradient(90deg,transparent 0 12%,#000 22%,#000 100%);
  transform:translate3d(calc(var(--glass-shift,0px) + var(--glass-pointer,0px)),var(--ty,0px),0) rotate(4deg);
}
.el--glass-portrait{top:-28%}
body.is-invert .el--glass-portrait{filter:grayscale(1) contrast(2) brightness(.88) invert(1);mix-blend-mode:multiply}
.brand-stamp{
  position:absolute;left:7.2%;top:18%;z-index:5;display:grid;gap:.23rem;
  font-family:var(--f-vcr);font-size:clamp(.58rem,.73cqw,.8rem);letter-spacing:.16em;
  line-height:1.15;opacity:.78;transform:translateY(var(--ty,0));
}
.brand-stamp span:nth-child(2){opacity:.66}
.brand-stamp span:nth-child(3){opacity:.42}
.lay--shutter,.lay--kif{
  z-index:7;padding:.03em .12em .09em;background:color-mix(in srgb,var(--dark) 91%,transparent);color:var(--on-dark);
  box-shadow:0 0 0 1px color-mix(in srgb,var(--on-dark) 17%,transparent);font-family:var(--f);
  font-weight:400;letter-spacing:-.105em;line-height:.76;text-shadow:0 1px 0 rgba(255,255,255,.12);
}
.lay--shutter{left:6%;top:54%;font-size:clamp(4.2rem,6.4cqw,9rem);font-style:italic;transform:translate(var(--word-slide,0px),var(--ty,0px))}
.lay--kif    {left:auto;right:6%;top:54%;font-size:clamp(4.2rem,6.4cqw,9rem);font-style:italic;transform:translate(var(--word-slide,0px),var(--ty,0px))}
.hero-deck{position:absolute;left:6.2%;top:65%;z-index:7;margin:0;font:clamp(.56rem,.65cqw,.72rem)/1.2 var(--f-vcr);letter-spacing:.15em;opacity:.68}
.hero-signal{
  position:absolute;left:50%;top:50%;width:53%;aspect-ratio:1;z-index:3;
  pointer-events:none;isolation:isolate;opacity:.9;
  --signal-lift:0px;--signal-turn:0deg;--signal-scale:1;
  transform:translate(-50%,calc(-50% + var(--signal-lift))) rotate(var(--signal-turn)) scale(var(--signal-scale));
}
.signal__field{
  position:absolute;inset:3%;border-radius:50%;opacity:.62;
  background-image:radial-gradient(circle,rgba(233,244,243,.92) 0 1.15px,transparent 1.65px);
  background-size:11px 11px;
  -webkit-mask-image:radial-gradient(ellipse at 50% 52%,transparent 0 15%,#000 31%,rgba(0,0,0,.86) 43%,transparent 71%);
  mask-image:radial-gradient(ellipse at 50% 52%,transparent 0 15%,#000 31%,rgba(0,0,0,.86) 43%,transparent 71%);
  transform:rotate(-12deg) scaleX(1.2);
}
.signal__core{
  position:absolute;inset:17%;border-radius:48% 52% 45% 55% / 56% 43% 57% 44%;opacity:.78;
  background:
    radial-gradient(ellipse at 50% 48%,rgba(239,255,253,.22) 0 4%,rgba(196,219,217,.1) 22%,transparent 58%),
    conic-gradient(from 215deg at 50% 50%,transparent 0 19%,rgba(213,231,229,.18) 28%,transparent 36% 58%,rgba(255,255,255,.14) 69%,transparent 78%);
  filter:blur(2px);mix-blend-mode:screen;
}
.signal__scan{
  position:absolute;left:18%;top:28%;width:64%;height:1px;opacity:.72;
  background:linear-gradient(90deg,transparent,rgba(240,255,253,.08) 8%,rgba(240,255,253,.96) 50%,rgba(240,255,253,.08) 92%,transparent);
  box-shadow:0 0 11px rgba(225,255,251,.35);mix-blend-mode:screen;transform:rotate(-10deg);
}
.signal__tag,.signal__serial{
  position:absolute;font-family:var(--f-vcr);font-size:.68cqw;letter-spacing:.16em;line-height:1.1;
  color:rgba(236,247,245,.78);white-space:nowrap;text-shadow:0 0 10px rgba(236,247,245,.13);
}
.signal__tag{left:68%;top:29%;transform:rotate(-10deg)}
.signal__serial{right:18%;bottom:24%;opacity:.46;transform:rotate(-10deg)}

.cue{position:absolute;bottom:1.5rem;left:50%;transform:translateX(-50%);z-index:6;padding:.6rem}
.cue i{display:block;width:1px;height:34px;background:currentColor;opacity:.3;position:relative;overflow:hidden}
.cue i::after{content:'';position:absolute;inset:0;background:currentColor;animation:sd 2s cubic-bezier(.65,0,.35,1) infinite}
@keyframes sd{0%{transform:translateY(-100%)}60%,100%{transform:translateY(100%)}}

/* ---- 02 work ---- */
.machine{height:100svh;display:flex;flex-direction:column;position:relative;z-index:1}
/* The flower sits in its own stage BEHIND the WebGL canvas, which is now
   genuinely transparent. Being an ordinary cut-out is the whole point: it keys
   off the paper like every other one — dark on white paper, light on black,
   never a white box on black — and it takes the rotation and the tracker for
   free. It replaced a leopard photograph that could do none of that. */
.machine .stage{z-index:1}
/* Sized and centred in container units, never with a centring transform or the
   independent `translate` property — the tracker reads offsetLeft/offsetTop
   plus the computed `transform`, and either of those would desync the contour
   from the artwork. Source is 1248x1152, so height = width / 1.0833. */
/* Sized against the VIEWPORT, not the stage: the stage overflows on a cover
   crop, so a stage-relative size would bleed the petals off screen. Source is
   1248x1152, so width = height * 1.0833 and half of that is 0.5417.
   Never centred with a transform or the independent `translate` property — the
   tracker reads offsetLeft/offsetTop plus the computed `transform`, and either
   would desync the contour from the artwork. */
.el--flower{
  height:104svh;width:auto;
  left:calc(50cqw - 56.3svh);
  top:calc(50cqh - 52svh);
  transform:translateY(var(--ty,0)) rotate(var(--spin));
  animation:spin-cw 214s linear infinite;
}
.el--cards-index{
  left:-3%;top:33%;width:21%;opacity:.48;
  transform:translateY(var(--ty,0)) rotate(-11deg);
  animation:card-drift 11s var(--ease) infinite alternate;
}
@keyframes card-drift{
  from{transform:translateY(var(--ty,0)) rotate(-14deg) translate3d(0,0,0)}
  to{transform:translateY(var(--ty,0)) rotate(-5deg) translate3d(2cqw,-1cqh,0)}
}
.machine__stage{position:relative;flex:1;min-height:0;z-index:2;isolation:isolate}
.machine__stage::before{
  content:'';position:absolute;left:50%;top:48%;z-index:0;width:65%;aspect-ratio:1.75;
  transform:translate(-50%,-50%) rotate(-7deg);pointer-events:none;
  background:radial-gradient(ellipse,rgba(154,203,207,.13) 0%,rgba(105,155,165,.055) 33%,transparent 71%);
  filter:blur(26px);mix-blend-mode:screen;
}
#pspCanvas{position:absolute;inset:0;z-index:1;width:100%;height:100%;display:block;touch-action:pan-y;filter:drop-shadow(0 1.8rem 1.5rem rgba(0,0,0,.74))}
/* deliberately NOT inverted: the bloom and the screen are emitted light,
   and inverting turns the highlights into black smears */
.machine__loading{position:absolute;inset:auto 0 50% 0;text-align:center;z-index:3;transition:opacity .5s}
.machine__loading.is-off{opacity:0;pointer-events:none}
.spin{display:inline-block;width:11px;height:11px;border:1px solid currentColor;border-top-color:transparent;border-radius:50%;opacity:.5;animation:spin .9s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

.rail{
  position:absolute;left:calc(var(--gutter) + env(safe-area-inset-left));bottom:calc(clamp(1.6rem,5vh,3.2rem) + env(safe-area-inset-bottom));z-index:6;
  display:flex;align-items:baseline;gap:.45rem;font-family:var(--f-vcr);color:var(--on-dark);
}
.rail b{font-size:clamp(1.8rem,4vw,3rem);font-weight:400;line-height:1;font-variant-numeric:tabular-nums}
.rail i{font-style:normal;font-size:.9rem;opacity:.45}
.rail--index{display:grid;grid-template-columns:auto auto;gap:.08rem .7rem;align-items:baseline}
.rail--index .rail__eyebrow{grid-column:1/-1;font-size:.55rem;letter-spacing:.18em;opacity:.47}
.rail--index b{grid-column:1;font-size:clamp(2.1rem,4.7vw,3.8rem);letter-spacing:-.08em}
.rail--index i{grid-column:2;font-size:.68rem;letter-spacing:.15em;opacity:.78}
.rail__open{
  margin-left:.7rem;align-self:center;width:36px;height:36px;display:grid;place-items:center;
  border:1px solid currentColor;font-size:1rem;line-height:1;
  transition:background .25s,color .25s,transform .4s var(--ease);
}
.rail__open:hover{background:var(--on-dark);color:var(--dark);transform:translate(2px,-2px)}
.rail.is-swap b{animation:flick .3s steps(2) both}
@keyframes flick{0%{opacity:0}50%,100%{opacity:1}}

.keys{position:absolute;right:calc(var(--gutter) + env(safe-area-inset-right));bottom:calc(clamp(1.6rem,5vh,3.2rem) + env(safe-area-inset-bottom));z-index:6;display:flex;gap:.3rem;color:var(--on-dark)}
kbd{font-family:var(--f-vcr);font-size:.8rem;border:1px solid currentColor;opacity:.45;padding:.1rem .35rem;min-width:24px;text-align:center}

/* ---- 03 about ---- */
.about{height:100svh;display:grid;place-items:center}
.el--vinyl{
  left:8%;top:69%;width:18%;opacity:.5;
  transform:translateY(var(--ty,0)) rotate(-10deg);animation:vinyl-float 19s var(--ease) infinite alternate;
}
@keyframes vinyl-float{from{transform:translateY(var(--ty,0)) rotate(-13deg)}to{transform:translateY(calc(var(--ty,0) - 1.4cqh)) rotate(-5deg)}}
.el--linotype{
  left:76%;top:17%;width:26%;opacity:.58;
  transform:translateY(var(--ty,0)) rotate(-13deg);
}
.lay--abouth{left:50%;top:26%;transform:translate(-50%,var(--ty,0));font-family:var(--f-vcr);font-size:3.3cqw;letter-spacing:.06em}
.lay--bio{
  left:50%;top:38%;width:44%;margin-left:-22%;
  font-size:1.78cqw;line-height:1.3;letter-spacing:0;
  text-align:justify;text-justify:inter-word;hyphens:auto;
}
.lay--bio p{margin:0}
.lay--bio p+p{margin-top:.15em}

/* ---- 04 mailing list ----
   The sign-up belongs to the same visual world as the rest of the home page:
   a single object composition, not an isolated marketing footer. */
.contact{height:100svh;display:grid;place-items:center;--paper:#030303;--contact-ink:#f1f0ec;--contact-faint:rgba(241,240,236,.52)}
body.is-invert .contact{--paper:#eeece5;--contact-ink:#090909;--contact-faint:rgba(9,9,9,.54)}
.contact .stage{--fade-b:0;color:var(--contact-ink);overflow:hidden}
.contact .stage::before{
  content:'';position:absolute;inset:0;z-index:0;pointer-events:none;
  background:radial-gradient(ellipse at 71% 42%,color-mix(in srgb,var(--contact-ink) 8%,transparent),transparent 39%),linear-gradient(120deg,transparent 40%,color-mix(in srgb,var(--contact-ink) 3%,transparent) 55%,transparent 68%);
}
.register__field{position:absolute;left:27%;top:13%;width:64%;height:71%;z-index:0;opacity:.3;transform:rotate(-8deg);background-image:radial-gradient(circle,rgba(238,246,245,.8) 0 1px,transparent 1.65px);background-size:12px 12px;-webkit-mask-image:radial-gradient(ellipse at 55% 48%,#000 0 21%,rgba(0,0,0,.7) 50%,transparent 74%);mask-image:radial-gradient(ellipse at 55% 48%,#000 0 21%,rgba(0,0,0,.7) 50%,transparent 74%)}
.el--cd-register{left:59%;top:9%;width:42%;z-index:1;opacity:.56;filter:grayscale(1) contrast(1.14) brightness(1.14);mix-blend-mode:screen;transform:translateY(var(--ty,0)) rotate(-18deg);animation:cd-register-orbit 38s linear infinite}
.el--glass-register{left:-17%;top:-28%;width:72%;z-index:1;opacity:.29;filter:grayscale(1) contrast(1.9) brightness(.95);mix-blend-mode:screen;transform:translateY(var(--ty,0)) rotate(-6deg)}
@keyframes cd-register-orbit{to{transform:translateY(var(--ty,0)) rotate(342deg)}}
.contact__folio{position:absolute;left:calc(7.2% + env(safe-area-inset-left));top:calc(12% + env(safe-area-inset-top));z-index:2;margin:0;font:clamp(.55rem,.68cqw,.76rem)/1 var(--f-vcr);letter-spacing:.13em;color:var(--contact-faint)}
.contact__core{position:absolute;left:14%;top:50%;z-index:2;width:min(36%,31rem);transform:translateY(-50%)}
.contact__kicker{margin:0 0 1.3rem;font:clamp(.55rem,.68cqw,.76rem)/1 var(--f-vcr);letter-spacing:.14em;color:var(--contact-faint)}
.contact__core h2{margin:0;font:400 clamp(3.4rem,6.1cqw,8.2rem)/.82 var(--f);letter-spacing:-.09em}
.contact__caption{margin:1.7rem 0 0;max-width:26rem;font:clamp(.78rem,1.1cqw,1.15rem)/1.38 var(--f);letter-spacing:-.015em;color:var(--contact-faint)}
.register{margin:2.8rem 0 0}
.register label{display:block;margin:0 0 .78rem;font:clamp(.55rem,.68cqw,.76rem)/1 var(--f-vcr);letter-spacing:.14em;color:var(--contact-faint)}
.register__line{display:grid;grid-template-columns:minmax(0,1fr) auto;border-bottom:1px solid color-mix(in srgb,var(--contact-ink) 54%,transparent)}
.register__line input{min-width:0;border:0;outline:0;background:transparent;padding:.82rem 0;color:var(--contact-ink);font:400 clamp(.9rem,1.15cqw,1.2rem)/1 var(--f);letter-spacing:-.025em}
.register__line input::placeholder{color:var(--contact-faint);opacity:1}
.register__line button{border:0;background:transparent;padding:.82rem 0 .82rem 1.3rem;color:var(--contact-ink);font:clamp(.55rem,.66cqw,.72rem)/1 var(--f-vcr);letter-spacing:.12em;cursor:pointer;white-space:nowrap}
.register__line button i,.contact__ig i{display:inline-block;margin-left:.35rem;font-style:normal;transition:transform .35s var(--ease)}
.register__line button:hover i,.contact__ig:hover i{transform:translate(3px,-3px)}
.register__fine{margin:.75rem 0 0;font:clamp(.5rem,.57cqw,.65rem)/1.4 var(--f-vcr);letter-spacing:.12em;color:var(--contact-faint)}
.register.is-submitted .register__line{border-color:var(--contact-ink)}
.register.is-submitted button{opacity:.42;pointer-events:none}
.contact__ig{position:absolute;right:calc(var(--gutter) + 8rem + env(safe-area-inset-right));bottom:calc(7% + env(safe-area-inset-bottom));z-index:2;font:clamp(.52rem,.62cqw,.7rem)/1 var(--f-vcr);letter-spacing:.12em;color:var(--contact-faint);transition:color .3s var(--ease)}
.contact__ig span{margin-left:.45rem;color:var(--contact-ink)}
.contact__ig:hover{color:var(--contact-ink)}
.contact__edition{position:absolute;left:calc(7.2% + env(safe-area-inset-left));bottom:calc(7% + env(safe-area-inset-bottom));z-index:2;margin:0;font:clamp(.52rem,.62cqw,.7rem)/1 var(--f-vcr);letter-spacing:.12em;color:var(--contact-faint)}

/* ============ MOTION ============
   Nothing here is a page transition — each piece drifts at its own rate as you
   scroll, so a section reads as a moving composition rather than a flat still. */
.el,.lay{will-change:transform}
.rev{opacity:0;filter:blur(6px)}
.rev.is-shown{opacity:1;filter:none;visibility:visible;
  transition:opacity 1.1s var(--ease),filter 1.1s var(--ease)}
/* cut-outs keep their invert while revealing — a bare `filter:none` here would
   drop the polarity and bring the black boxes straight back */
.el.rev{filter:invert(var(--el-inv)) blur(9px)}
.el.rev.is-shown{filter:invert(var(--el-inv));
  transition:opacity 1.1s var(--ease),filter 1.1s var(--ease)}
.rev.is-shown.d1{transition-delay:.08s}
.rev.is-shown.d2{transition-delay:.16s}

/* ============ REVEAL ============ */
[data-rise]{opacity:0;transform:translateY(18px);filter:blur(6px)}
.is-lit [data-rise]{opacity:1;transform:none;filter:none;transition:opacity .9s var(--ease) .1s,transform 1s var(--ease) .1s,filter .9s var(--ease) .1s}

/* ============ NARROW SCREENS ============
   The 16:9 stage would shrink the type past legibility, so let it fill the
   width and grow taller instead. The section grows with it, and the
   viewport-anchored mask no longer makes sense, so it comes off. */
@media (max-width:820px){
  .site-header{display:flex;justify-content:space-between;padding:1rem 0;align-items:center}
  .site-header__mark{font-size:1.35rem}
  .site-nav{gap:1.15rem;font-size:.78rem;letter-spacing:-.01em}
  .site-header a{min-height:44px;display:flex;align-items:center}
  .site-nav a{padding:.35rem .04rem .48rem}
  .ctl{right:calc(1rem + env(safe-area-inset-right));bottom:calc(.8rem + env(safe-area-inset-bottom))}
  .ctl__b{min-height:44px;font-size:.8rem}
  .keys{display:none}

  /* ---- ONE coordinate system, same as desktop, only the aspect changes ----
     The desktop composition is rigid because there is a stage of definite
     size, every element is placed in percent OF THAT STAGE, and every type
     size is in `cqw` — so the whole thing scales as a single piece.

     The old mobile block threw all of that away. It made the stage
     variable-height and `container-type:normal`, then placed elements in
     percent against that moving box while sizing type in `vw` against the
     *viewport*. Two coordinate systems that disagree the moment a phone's
     aspect ratio differs from whatever it was eyeballed at — which is exactly
     what "everything is all over the place" looks like.

     So: keep the machinery, drop the second system. The stage is the viewport,
     with a definite size so container units resolve, and every position and
     type size below is authored against it.

     It also stays ABSOLUTE. Making it a flow item turned it into a flex item
     inside .machine, where it claimed the full 100svh, collapsed
     .machine__stage to zero height, and the PSP never rendered at all —
     resize() bails on a zero-size canvas. */
  .hero,.about,.contact{height:100svh;min-height:0}
  .stage{
    position:absolute;inset:0;margin:0;
    width:100%;height:100%;
    container-type:size;
    -webkit-mask-image:none;mask-image:none;
  }
  .hero .stage::after{height:36%}
  /* No cut-out may inherit a height from the desktop rules. This is what
     stretched the flower: the desktop rule sets `height:104svh; width:auto`
     and the mobile rule only overrode the width, so it rendered at the phone's
     width by the desktop's height — squashed into a completely wrong aspect. */
  .el{height:auto}

  /* Every value below is percent of the stage, or cqw — one system.
     `cqw` and not `vw`: if the stage ever stops being exactly the viewport,
     the type still scales with the composition instead of drifting out of it. */

  /* 01 front — the wordmark sits under the hands.
     The two halves are separate elements and always will be (the copy is
     frozen), so they are butted against the stage's centre line instead:
     `shutter` ends exactly at 50%, `kif.` starts exactly at 50%. They meet
     perfectly as one centred word without anything needing to know how wide
     the text renders — no font metrics, no magic numbers, no drift when the
     webfont swaps in. */
  .el--star-a{left:82%;top:-1%;width:23%;height:auto}
  .el--star-b{left:-15%;top:55cqh;width:39%;height:auto}
  /* The hand cut-out is sized by height so it keeps the same framing gesture
     across phone aspect ratios, rather than swallowing the type on tall screens. */
  .el--hands{width:auto;height:23cqh;left:calc(50cqw - 21.7cqh);top:35cqh}
  .el--glass-portrait{left:-7%;top:-18%;width:108%;opacity:.58}
  .hero-signal{width:90%;top:48%}
  .signal__tag,.signal__serial{font-size:2cqw}
  .signal__tag{left:65%;top:26%}
  .signal__serial{right:14%;bottom:22%}
  .brand-stamp{left:8%;top:13%;font-size:2.55cqw}
  .lay--shutter,.lay--kif{top:61cqh;font-size:13cqw;white-space:nowrap}
  .lay--shutter{left:auto;right:50%;text-align:right}
  .lay--kif    {left:50%;right:auto;text-align:left}
  .hero-deck{left:8%;top:70cqh;font-size:2.4cqw}

  /* 03 about */
  .lay--abouth{left:50%;top:14%;transform:translate(-50%,var(--ty,0));font-size:7.5cqw}
  .lay--bio{left:7%;top:24%;width:86%;margin-left:0;font-size:4.4cqw;text-align:left;hyphens:none;overflow-wrap:normal}
  .el--vinyl{left:-7%;top:73%;width:40%;opacity:.42}
  .el--linotype{left:66%;top:8%;width:39%;height:auto;opacity:.55}

  /* 04 mailing list */
  .register__field{left:0;top:8%;width:100%;height:62%;background-size:8px 8px}
  .el--cd-register{left:23%;top:8%;width:80%;opacity:.45}
  .el--glass-register{left:-30%;top:-12%;width:112%;opacity:.22}
  .contact__folio{left:calc(8% + env(safe-area-inset-left));top:calc(13% + env(safe-area-inset-top));font-size:max(10px,2.05cqw)}
  .contact__core{left:calc(8% + env(safe-area-inset-left));top:61%;width:84%;transform:translateY(-50%)}
  .contact__kicker{font-size:max(10px,2.1cqw);margin-bottom:1rem}
  .contact__core h2{font-size:12.4cqw;line-height:.85}
  .contact__caption{max-width:18rem;margin-top:1.2rem;font-size:3.25cqw}
  .register{margin-top:2.2rem}
  .register label{font-size:max(10px,2.1cqw)}
  .register__line input{min-height:48px;font-size:max(16px,4cqw)}
  .register__line button{min-height:48px;padding-left:.9rem;font-size:max(10px,2cqw)}
  .register__fine{font-size:max(9px,1.8cqw)}
  .contact__edition{left:calc(8% + env(safe-area-inset-left));bottom:calc(8% + env(safe-area-inset-bottom));font-size:max(9px,1.85cqw)}
  .contact__ig{right:calc(8% + env(safe-area-inset-right));bottom:calc(8% + env(safe-area-inset-bottom));min-height:44px;display:flex;align-items:center;font-size:max(9px,1.85cqw)}

  /* 02 work — behind the machine, aspect preserved, centred in container units
     so it stays centred at any phone aspect. Source is 1248x1152, so
     width = height * 1.0833 and half of that is 0.5417. */
  .el--flower{width:auto;height:74cqh;left:calc(50cqw - 40.1cqh);top:13cqh}
  .el--cards-index{width:auto;height:40cqh;left:-14%;top:17cqh}
}

/* Short phone viewports need room for both the browser chrome and the form.
   These values prevent the subscription copy from colliding with the bottom rail. */
@media (max-width:820px) and (max-height:680px){
  .contact{height:max(100svh,38rem)}
  .contact__core{top:60%}
  .contact__core h2{font-size:11cqw}
  .contact__caption{margin-top:.8rem;font-size:2.95cqw}
  .register{margin-top:1.5rem}
}

@media (max-width:390px){
  .site-header__mark{font-size:1.18rem}
  .site-nav{gap:.72rem;font-size:.69rem}
  .hero-deck{font-size:2.1cqw}
  .rail--index b{font-size:2rem}
  .rail--index i{font-size:.58rem}
}

/* Phone landscape uses a shallow desktop-like viewport, but it still needs
   thumb-sized navigation and controls. Keep the composition compact without
   making the interface miniature. */
@media (pointer:coarse) and (orientation:landscape) and (max-height:500px){
  .site-header{padding:.2rem 0}
  .site-header a,.ctl__b{min-height:44px}
  .site-nav{gap:1rem;font-size:.78rem}
  .ctl{bottom:calc(.25rem + env(safe-area-inset-bottom))}
}

/* ============ REDUCED MOTION ============ */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .cue i::after,.rail.is-swap b{animation:none}
  .el--star-a,.el--star-b,.el--flower,.el--cards-index,.el--vinyl{animation:none;transform:translateY(var(--ty,0))}
  .rev{opacity:1;filter:none;visibility:visible;transition:none}
  .el.rev,.el.rev.is-shown{opacity:1;filter:invert(var(--el-inv));transition:none}
  .el,.lay{--ty:0 !important}
  [data-rise]{opacity:1;transform:none;filter:none;transition:none}
  .lay--icons img,.rail__open,.ctl__b::after{transition:none}
}
