/* Self-hosted so no visitor request reaches Google. Only weight 400 is used
   on this site — 500 was being downloaded and never referenced. */
@font-face{
  font-family:"IBM Plex Mono";
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url("fonts/ibm-plex-mono-400-latin.woff2") format("woff2");
}

/* PColombara — three colours, two typefaces, hairline rules. Nothing else. */
:root{
  --ink:   #111111;
  --cream: #F6F3EC;
  --red:   #D62828;

  --sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --gutter: clamp(24px, 4.4vw, 84px);
  --hair:   rgba(246,243,236,.22);

  /* Static film grain. Flat digital darkness is what made this look cheap. */
  --grain: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
}

*,*::before,*::after{ box-sizing:border-box; }

html{ background:var(--ink); }
body{
  margin:0;
  background:var(--ink);
  color:var(--cream);
  font-family:var(--sans);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
img,canvas,picture{ display:block; }

/* One mono rule for every label on the site. */
.cue,.enter,.email,.eyebrow,.venture__meta{
  font-family:var(--mono);
  font-weight:400;
  text-transform:uppercase;
  letter-spacing:.26em;          /* ≈2.4px at 11px — top of the brand range */
  font-size:clamp(10px,.78vw,12px);
  line-height:1;
  margin:0;
}
.lockup__line{
  font-family:var(--mono); font-weight:400; text-transform:uppercase;
  letter-spacing:.26em; font-size:clamp(10px,.78vw,12px); line-height:1; margin:0;
}

:focus-visible{ outline:1px solid var(--cream); outline-offset:8px; }

/* NOTE: any element holding .grain MUST establish a stacking context.
   mix-blend-mode blends with the nearest stacking context's backdrop, and a
   position:relative/z-index:auto parent is NOT one — the blend escapes to the
   root and wipes the section to flat ink. isolation:isolate contains it. */
.grain{
  position:absolute; inset:0; pointer-events:none; z-index:3;
  background-image:var(--grain);
  /* screen, not overlay: overlay is near-inert over black. */
  opacity:.055;
  mix-blend-mode:screen;
}

.rule{ height:1px; width:100%; background:var(--hair); }

/* ══ HOME ═══════════════════════════════════════════════════════════════ */
/* The tall track supplies scroll distance; the sticky child is all you ever
   see, so the geometry never moves. */
.hero{ position:relative; height:340vh; }
.hero__stick{
  position:sticky; top:0;     /* sticky already isolates, but be explicit */
  isolation:isolate;
  height:100vh; height:100svh;
  overflow:hidden;
  background:var(--ink);
}
.hero__canvas,.hero__fallback{ position:absolute; inset:0; width:100%; height:100%; }
.hero__fallback{ object-fit:cover; object-position:40% 50%; filter:brightness(.62); }
.hero__fallback[hidden]{ display:none; }

.hero__scrim{
  position:absolute; inset:0; pointer-events:none; z-index:2;
  background:
    radial-gradient(76% 56% at 2% 0%, rgba(17,17,17,.78), rgba(17,17,17,0) 62%),
    linear-gradient(to top, rgba(17,17,17,.62), rgba(17,17,17,0) 26%),
    radial-gradient(130% 110% at 50% 45%, rgba(17,17,17,0) 52%, rgba(17,17,17,.55) 100%);
}

.lockup{
  position:absolute; z-index:4;
  top:calc(var(--gutter) + env(safe-area-inset-top));
  left:var(--gutter);
}
.lockup__mark{ width:clamp(74px,6.6vw,118px); height:auto; overflow:visible; }
.lockup__line{
  margin-top:clamp(18px,1.5vw,26px);
  padding-top:clamp(14px,1.2vw,20px);
  border-top:1px solid var(--hair);
  color:var(--cream);
}

/* SCROLL and the way through share one anchor and cross-fade. */
.cue,.enter{
  position:absolute; z-index:4;
  left:var(--gutter);
  bottom:calc(var(--gutter) + env(safe-area-inset-bottom));
  padding-left:clamp(16px,1.3vw,22px);
  color:var(--cream);
  transition:opacity .5s ease;
}
.cue::before,.enter::before{
  content:""; position:absolute; left:0; top:50%;
  width:1px; height:clamp(26px,2.6vw,40px);
  transform:translateY(-50%);
  background:linear-gradient(to bottom, rgba(246,243,236,0), rgba(246,243,236,.55));
}
.cue{ opacity:.72; }
.enter{
  display:flex; align-items:center; gap:14px;
  text-decoration:none;
  /* opacity 0 rather than visibility:hidden — the link stays keyboard
     reachable, and :focus-visible below brings it into view. */
  opacity:0; pointer-events:none;
}
.enter svg{ width:16px; height:16px; transition:transform .25s ease; }
.enter:hover svg{ transform:translateX(3px); }

html.is-lit .cue{ opacity:0; }
html.is-lit .enter,
.enter:focus-visible{ opacity:1; pointer-events:auto; }

/* ══ THE CUT ════════════════════════════════════════════════════════════ */
/* The horn. It covers the navigation between the two pages — never a section
   you scroll past, only the frame between two places. It is rendered on a
   canvas and lit by the strike; the CSS image below is the no-WebGL fallback. */
.cut{
  position:fixed; inset:0; z-index:90;
  opacity:0; visibility:hidden;
  background:var(--ink);
  transition:opacity .30s cubic-bezier(.33,0,.2,1), visibility 0s linear .30s;
}
.cut__plate{
  position:absolute; inset:0;
  transform:scale(1.045);
}
/* Held back until its texture is uploaded, so an empty canvas never covers
   the CSS fallback. No transition: the swap with the fallback must happen in
   one frame or the page flashes through the gap. */
.cut__canvas{ position:absolute; inset:0; width:100%; height:100%; opacity:0; }
.cut__canvas.is-ready{ opacity:1; }
/* once the canvas has the horn, the fallback image must go — it is opaque and
   would sit behind the smoke, blocking the reveal */
.cut.is-plated .cut__horn{ display:none; }

/* When the shader owns the reveal it composites straight alpha over the page,
   so the cover itself cannot carry an ink background. */
.cut.is-gl{ background:transparent; }
html.is-entering .cut.is-gl .cut__plate{
  transform:scale(1);
  transition:transform 1.5s cubic-bezier(.16,1,.3,1);
}
.cut__horn{
  position:absolute; inset:0;
  background-size:cover; background-position:42% 58%;
  filter:brightness(.42);          /* match the canvas's resting exposure */
}
/* The image is attached ONLY when there is no WebGL plate to draw the horn.
   Unconditionally, the browser fetched it on every visit and then the canvas
   covered it immediately — ~131 KB nobody ever saw. enter.js sets .no-gl. */
html.no-gl .cut__horn{
  background-image:image-set(url("img/horn-1920.webp") type("image/webp"),
                             url("img/horn-1920.jpg")  type("image/jpeg"));
}
/* leaving home: the massif has gone dark by now, so this dissolves between
   two near-black frames — soft, without turning muddy */
.cut.is-on{ opacity:1; visibility:visible; transition:opacity .30s cubic-bezier(.33,0,.2,1); }
/* arriving on work: already covering, then breathes out */
html.is-entering .cut{ opacity:1; visibility:visible; transition:none; }
html.is-entering .cut.is-clearing{
  opacity:0;
  transition:opacity .92s cubic-bezier(.16,1,.3,1);
}
/* the settle runs on past the fade, so the frame keeps easing after the horn
   itself has gone — that is most of what makes the exit feel smooth */
html.is-entering .cut.is-clearing .cut__plate{
  transform:scale(1);
  transition:transform 1.15s cubic-bezier(.16,1,.3,1);
}
/* the page underneath must not paint before the horn has it covered */
html.is-entering .sheet__inner{ opacity:0; }
html.is-revealed .sheet__inner{ opacity:1; }

/* ══ WORK — the fleece sheet ════════════════════════════════════════════ */
/* Fleece is the surface the words sit on: the photographic page is landscape,
   this one is textile — the material you actually work in. */
.sheet{
  position:relative;
  isolation:isolate;
  min-height:100vh; min-height:100svh;
  display:grid;
  padding:calc(var(--gutter) * .9) var(--gutter);
  background:var(--ink);
  overflow:hidden;
}
.sheet__fleece{
  position:absolute; inset:0; pointer-events:none;
  opacity:.34;
  background-image:image-set(url("img/fleece-1920.webp") type("image/webp"),
                             url("img/fleece-1920.jpg")  type("image/jpeg"));
  background-size:cover; background-position:center;
}
/* Ink wash so the texture stays felt but never fights the type. */
.sheet__wash{
  position:absolute; inset:0; pointer-events:none;
  background:
    linear-gradient(to right, rgba(17,17,17,.94), rgba(17,17,17,.74) 62%, rgba(17,17,17,.88)),
    radial-gradient(120% 100% at 50% 50%, rgba(17,17,17,0) 38%, rgba(17,17,17,.7) 100%);
}
.sheet__inner{
  position:relative; z-index:4;
  width:min(100%,1080px); margin:0 auto;
  display:flex; flex-direction:column; justify-content:space-between;
  gap:clamp(40px,6vh,90px);
  transition:opacity .78s cubic-bezier(.16,1,.3,1) .12s;
}

.home{ display:inline-flex; align-items:center; gap:14px; text-decoration:none; color:var(--cream); }
.home__mark{ width:clamp(30px,2.4vw,40px); height:auto; overflow:visible; }
.home__word{
  font-family:var(--sans); font-weight:900;
  font-size:clamp(17px,1.5vw,22px); letter-spacing:-.8px;
}
.wordmark__dot{ color:var(--red); }

.sheet__body{ display:flex; flex-direction:column; }

/* The declaration. Centred against the ledger below it, which stays left —
   the statement is the claim, the rows underneath are the record. */
.statement{
  margin:0 auto;
  text-align:center;
  text-wrap:balance;
  font-family:var(--sans); font-weight:400;
  font-size:clamp(31px,4.6vw,70px);
  line-height:1.1; letter-spacing:-1.2px;
  max-width:13em;
  color:var(--cream);
}
/* the three pillars, carried by weight instead of repeated as labels */
.statement b{ font-weight:900; letter-spacing:-1.8px; }
.sheet__body .rule{ margin:clamp(32px,3.4vw,52px) 0; }

.eyebrow{ color:var(--cream); opacity:.45; margin-bottom:clamp(18px,1.8vw,26px); }

/* One venture, stated plainly. The registry says one; padding it out with
   invented rows would read as a holding company with nothing shipped. */
.venture{
  display:grid; grid-template-columns:1fr auto auto 16px;
  align-items:baseline; gap:clamp(14px,2.4vw,40px);
  text-decoration:none; color:var(--cream); padding:4px 0;
}
.venture__name{ font-family:var(--sans); font-weight:600; font-size:clamp(21px,2.3vw,34px); letter-spacing:-.6px; }
.venture__meta{ opacity:.52; letter-spacing:.2em; }
.venture__go{ width:16px; height:16px; align-self:center; opacity:.5; transition:opacity .2s ease, transform .2s ease; }
.venture:hover .venture__go,
.venture:focus-visible .venture__go{ opacity:1; transform:translate(2px,-2px); }
.venture:hover .venture__meta{ opacity:.8; }

.sheet__foot .rule{ margin-bottom:clamp(16px,1.6vw,24px); }
.sheet__foot .eyebrow{ margin-bottom:clamp(12px,1.2vw,16px); }
/* the only way to reach him now the legal line is gone — so give it size */
.email{
  display:inline-block;
  font-size:clamp(13px,1.15vw,17px); letter-spacing:.14em;
  color:var(--cream); opacity:.9; text-decoration:none;
  padding-bottom:4px; border-bottom:1px solid rgba(246,243,236,.3);
  transition:opacity .2s ease, border-color .2s ease;
}
.email:hover,.email:focus-visible{ opacity:1; border-color:var(--cream); }

@media (max-width:620px){
  .venture{ grid-template-columns:1fr 16px; row-gap:10px; }
  .venture__name{ grid-column:1 / 2; }
  .venture__go{ grid-column:2 / 3; grid-row:1; }
  .venture__meta{ grid-column:1 / 3; }
  .venture__meta + .venture__meta{ margin-top:-4px; }
}

/* ══ Reduced motion ═════════════════════════════════════════════════════ */
/* Hero holds one static mid-transition frame and binds no scroll listener;
   the cut degrades to an ordinary link. */
@media (prefers-reduced-motion: reduce){
  .hero{ height:100vh; height:100svh; }
  .cue,.enter,.email,.venture__go,.enter svg,.sheet__inner,.cut,.cut__plate{ transition:none; }
}
