/* ============================================================
   AUGMENT — case-study pages (shared by all four)

   SPACING CONTRACT: every gap on the page derives from ONE
   value, --cs-gap. The image grid is CSS multi-column, so the
   horizontal gap (column-gap) and the vertical gap (the items'
   margin-bottom) are literally the same variable — they cannot
   drift apart. Change --cs-gap and the whole page re-spaces in
   lockstep. Column count changes at breakpoints; the gap never
   does anything but follow its clamp.
   ============================================================ */
body.work{
  /* THE gap. Nothing else sets spacing between images. Deliberately an integer
     at every breakpoint: a fluid clamp() lands on fractional pixels, and the
     browser quantises margins to 1/64px while column-gap keeps full precision,
     so the vertical and horizontal gaps would differ by ~0.007px. Integers make
     them byte-identical and render crisper. */
  --cs-gap:22px;
  --cs-pad:clamp(1.1rem,3.3vw,50px);         /* page side padding */
  --cs-maxw:1512px;
  background:var(--c-ink) url('../img/work/pf-pattern.webp');
  background-size:clamp(360px,50vw,756px);
  background-repeat:repeat;
  color:#8f8f8f;min-height:100vh;overflow-x:hidden;}

.cs{position:relative;z-index:1;padding-bottom:clamp(4rem,10vw,9.5rem);}
.cs-titlewrap,.cs-intro,.cs-grid,.cs-foot{
  max-width:var(--cs-maxw);margin-inline:auto;padding-inline:var(--cs-pad);}

/* ---------- edge-to-edge title ---------- */
.cs-titlewrap{width:100%;max-width:none;padding-inline:0;overflow:hidden;text-align:center;padding-top:clamp(.2rem,1vw,1rem);}
.cs-title{display:inline-block;margin:0;white-space:nowrap;
  font-family:var(--font-display);font-weight:700;line-height:.88;letter-spacing:-.01em;
  text-transform:uppercase;color:#727272;font-size:16vw;}  /* JS fits this to the viewport width */

/* ---------- intro: lede + meta ---------- */
.cs-intro{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;
  gap:clamp(1.4rem,3vw,3rem);margin-top:clamp(1.2rem,3vw,2.6rem);margin-bottom:clamp(2rem,4.5vw,3.4rem);}
.cs-lede{flex:1 1 30ch;max-width:56ch;margin:0;
  font-family:var(--font-sans);font-weight:400;
  font-size:clamp(.95rem,1.35vw,1.35rem);line-height:1.45;color:#9a9a9a;}
.cs-meta{display:flex;flex-wrap:wrap;gap:clamp(1.2rem,2.6vw,3rem);margin:0;}
.cs-meta dt{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.16em;
  text-transform:uppercase;color:#6e6e6e;margin-bottom:.5em;}
.cs-meta dd{margin:0;font-family:var(--font-sans);font-weight:500;
  font-size:clamp(.85rem,1.05vw,1.02rem);line-height:1.4;color:var(--c-white);max-width:30ch;}

/* ---------- the image grid ----------
   Multi-column masonry: the browser balances column heights on its
   own and reflows at each breakpoint, so no per-page column maths
   is baked into the HTML — every page is the same flat list. */
.cs-grid{columns:3;column-gap:var(--cs-gap);margin-bottom:calc(-1 * var(--cs-gap));}
.cs-item{break-inside:avoid;-webkit-column-break-inside:avoid;page-break-inside:avoid;
  margin:0 0 var(--cs-gap);overflow:hidden;border-radius:0;background:var(--c-ink-2);}
/* width/height attributes on the img carry the intrinsic ratio, so the box
   is reserved before the image loads — no layout shift, no CLS */
.cs-item img{display:block;width:100%;height:auto;
  transition:transform .8s var(--ease),filter .5s var(--ease);}
.cs-item:hover img{transform:scale(1.05);filter:brightness(.85);}

/* ---------- stat tile ----------
   Sits in the masonry as an ordinary .cs-item, so it inherits --cs-gap and the
   column flow exactly like an image — no second spacing value anywhere.
   No fixed aspect-ratio: the box HUGS the numeral (tight line-height + small
   padding), which is what makes the number appear to touch the top and sit on
   the bottom of the cell. */
.cs-stat{display:flex;align-items:flex-end;gap:clamp(.5rem,2.2cqw,1.1rem);
  /* vertical padding stays tiny on purpose: the numeral should almost graze the
     top of the cell and sit on its floor */
  padding:clamp(.2rem,.8cqw,.5rem) clamp(.9rem,3.4cqw,1.7rem) clamp(.25rem,1cqw,.6rem);
  /* no plate — the stat sits straight on the page pattern like type, not a card */
  background:none;border:0;
  container-type:inline-size;}
.cs-stat__inner{display:flex;align-items:flex-end;gap:clamp(.5rem,2.2cqw,1.1rem);width:100%;}
.cs-stat__num{font-family:var(--font-display);font-weight:700;
  /* .74 crops the line box tight to the glyphs so the numeral fills the cell */
  line-height:.74;letter-spacing:-.035em;color:var(--c-g3);
  font-size:clamp(2.2rem,25cqw,7.5rem);}
.cs-stat__label{font-family:var(--font-mono);font-size:clamp(.56rem,2.1cqw,.82rem);
  letter-spacing:.14em;text-transform:uppercase;line-height:1.35;
  color:#8f8f8f;max-width:10em;padding-bottom:.15em;}

/* ---------- footer / nav ---------- */
.cs-foot{display:flex;align-items:center;justify-content:space-between;gap:1.5rem;
  margin-top:clamp(3.5rem,8vw,7rem);padding-top:clamp(2rem,4vw,3rem);
  border-top:1px solid color-mix(in srgb,var(--c-g1) 40%,transparent);}
.cs-back{font-family:var(--font-mono);font-size:var(--fs-label);letter-spacing:.16em;
  text-transform:uppercase;color:#8f8f8f;transition:color .25s var(--ease);}
.cs-back span{margin-right:.4em;}
.cs-back:hover{color:var(--c-cyan);}
.cs-home img{height:clamp(30px,3vw,42px);width:auto;display:block;opacity:.7;transition:opacity .25s var(--ease);}
.cs-home:hover img{opacity:1;}
.cs-next{text-align:right;transition:color .3s var(--ease);}
.cs-next__label{display:block;font-family:var(--font-mono);font-size:var(--fs-label);
  letter-spacing:.16em;text-transform:uppercase;color:#6e6e6e;margin-bottom:.45em;}
.cs-next__name{display:block;font-family:var(--font-display);font-weight:600;
  font-size:clamp(1.1rem,2vw,1.85rem);letter-spacing:-.01em;color:var(--c-white);
  transition:color .3s var(--ease);}
.cs-next__name span{display:inline-block;transition:transform .3s var(--ease);}
.cs-next:hover .cs-next__name{color:var(--c-cyan);}
.cs-next:hover .cs-next__name span{transform:translateX(6px);}

/* ---------- entrance: title, intro and cells fade + rise in ---------- */
html.cs-anim .cs-title,
html.cs-anim .cs-lede,
html.cs-anim .cs-meta,
html.cs-anim .cs-item{opacity:0;transform:translateY(38px);will-change:opacity,transform;
  transition:opacity .9s var(--ease),transform 1s var(--ease);}
html.cs-anim.cs-in .cs-title,
html.cs-anim.cs-in .cs-lede,
html.cs-anim.cs-in .cs-meta,
html.cs-anim.cs-in .cs-item{opacity:1;transform:none;}

/* ---------- responsive: column count changes, the gap does not ---------- */
@media (max-width:1000px){ body.work{--cs-gap:16px;} .cs-grid{columns:2;} }
@media (max-width:620px){
  body.work{--cs-gap:12px;}
  .cs-grid{columns:1;}
  /* stacked: reset the lede's flex — in a column container `flex:1 1 30ch`
     applies to HEIGHT, inflating it to ~240px, and space-between then shoved
     the meta far down the page. Size both by content instead. */
  .cs-intro{flex-direction:column;justify-content:flex-start;gap:clamp(1.6rem,5vw,2.2rem);}
  .cs-lede{flex:0 0 auto;max-width:none;}
  .cs-meta{gap:1.4rem 2.4rem;}
  /* case-study.js stops auto-fitting below this width (one line would shrink a
     long name to ~20px). Wrap it at a proper display size, inset to the page
     padding rather than bleeding to the very edge. */
  .cs-titlewrap{padding-inline:var(--cs-pad);text-align:left;}
  .cs-title{white-space:normal;font-size:clamp(2rem,10vw,3.4rem);line-height:.94;}
}
/* ultrawide: match the wider frame the rest of the site uses */
@media (min-width:1600px){
  body.work{--cs-maxw:min(92vw,2400px);--cs-gap:24px;}
  .cs-grid{columns:4;}
}

@media (prefers-reduced-motion:reduce){
  html.cs-anim .cs-title,html.cs-anim .cs-lede,html.cs-anim .cs-meta,
  html.cs-anim .cs-item{opacity:1!important;transform:none!important;}
}

/* ============================================================
   shared cursor + ghost trail (same as the main site)
   ============================================================ */
@media (hover:hover) and (pointer:fine){
  html.has-cursor, html.has-cursor *{ cursor:none !important; }
}
/* Flat brand-cyan dot — no ring, no glow. Two full-viewport layers clipped to
   mutually exclusive regions (see cursor.js): cyan everywhere EXCEPT the image
   under the pointer, and an invert+grayscale lens exactly ON it, so the cursor
   splits on the photo edge. These pages are almost entirely imagery, so this is
   where the effect does most of its work. */
.cur{position:fixed;inset:0;pointer-events:none;opacity:0;}
.cur-base{z-index:9000;}
.cur-base__in{position:absolute;inset:0;clip-path:circle(0);background:var(--c-cyan);}

/* The lens is a DIRECT CHILD OF <body> and deliberately does not carry the
   .cur class. backdrop-filter is killed by a "backdrop root": any ancestor
   with clip-path, opacity < 1, filter, mask or a transform makes the element
   filter an empty backdrop and vanish. JS positions and sizes it and gives it
   a single polygon() for circle-intersect-image. */
.cur-lens{position:fixed;z-index:9001;pointer-events:none;display:none;
  backdrop-filter:invert(1) grayscale(1);
  -webkit-backdrop-filter:invert(1) grayscale(1);}
#fxTrail{position:fixed;inset:0;z-index:8000;pointer-events:none;}
@media (prefers-reduced-motion:reduce){ .cur,#fxTrail{display:none;} }
