/* ==========================================================================
   VAELO — brand guideline inherited from vaelo-agency.html
   Palette, type pairing and motion language are locked. Layout is not.
   ========================================================================== */
:root{
  --black:#0a0a0a; --deep:#030303; --off:#f4f2ec; --dim:#8c887e;
  --accent:#d6ff3f; --line:rgba(244,242,236,0.14); --soft:rgba(244,242,236,0.06);
  /* ── TWO FONTS. Nothing else is used anywhere on the site. ──────────────
     --display  Bricolage Grotesque — every heading, the wordmark, figures,
                and the "We're not a department store" statement.
     --text     Archivo — body copy, labels, captions, buttons.
     Adding a third face here (or a Google Fonts link on any page) breaks
     the pairing; use a weight or a size instead. */
  --display:'Bricolage Grotesque',ui-sans-serif,system-ui,sans-serif;
  --text:'Archivo',ui-sans-serif,system-ui,-apple-system,sans-serif;
  /* the wordmark only; see .word */
  --mark:'Montserrat',ui-sans-serif,system-ui,sans-serif;
  --pad:5vw;
}
*{margin:0;padding:0;box-sizing:border-box}
/* the script eases scrolling on pointer devices and turns this off; it stays
   for touch, keyboard-only and reduced-motion users */
html{scroll-behavior:smooth}
body{background:var(--black);color:var(--off);font-family:var(--text);font-weight:400;line-height:1.5;
  overflow-x:clip;-webkit-font-smoothing:antialiased}
::selection{background:var(--accent);color:var(--black)}
a{color:inherit;text-decoration:none}
:focus-visible{outline:2px solid var(--accent);outline-offset:4px}
img{max-width:100%;display:block}
h1,h2,h3,.disp{font-family:var(--display);font-weight:700;letter-spacing:-.02em;text-transform:uppercase;text-wrap:balance}
/* The emphasised line in a headline. It used to be drawn as transparent
   text with a stroke, but -webkit-text-stroke centres the stroke on the
   glyph edge, which eats into the counters and makes the word read as a
   narrower, different typeface sitting next to the solid lines. Same
   family, same weight — it just did not look it. It is now solid and
   carries the accent instead, so the page holds one face throughout. */
.out{color:var(--accent)}
.lab{font-size:11px;text-transform:uppercase;letter-spacing:.1em;color:var(--dim)}
.lab.ac{color:var(--accent)}
.tab{font-variant-numeric:tabular-nums}

/* ---------- image slots (stand in for real assets) ---------- */
.slot{position:relative;overflow:hidden;background:#111110;isolation:isolate}
.slot::before{content:'';position:absolute;inset:-14% -4%;
  background:
    radial-gradient(ellipse 60% 50% at 30% 30%,rgba(214,255,63,.10),transparent 60%),
    radial-gradient(ellipse 70% 60% at 75% 70%,rgba(150,150,140,.16),transparent 62%),
    repeating-linear-gradient(135deg,rgba(244,242,236,.035) 0 1px,transparent 1px 11px),
    #121211;
  will-change:transform}
.slot::after{content:attr(data-spec);position:absolute;left:14px;bottom:12px;z-index:2;
  font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--dim)}

/* ---------- page transition wipe ---------- */
.wipe{position:fixed;inset:0;z-index:500;background:var(--accent);transform:scaleY(0);transform-origin:bottom;pointer-events:none}
.wipe.in{transform:scaleY(1);transform-origin:bottom;transition:transform .55s cubic-bezier(.72,0,.16,1)}
.wipe.out{transform:scaleY(0);transform-origin:top;transition:transform .55s cubic-bezier(.72,0,.16,1)}

/* ---------- cursor ---------- */
.cursor{position:fixed;top:0;left:0;width:10px;height:10px;border-radius:50%;background:var(--accent);
  pointer-events:none;z-index:450;mix-blend-mode:difference;transform:translate(-50%,-50%);
  transition:width .28s cubic-bezier(.2,.7,.2,1),height .28s cubic-bezier(.2,.7,.2,1)}
.cursor.big{width:76px;height:76px}
@media(hover:none),(pointer:coarse){.cursor{display:none}}

/* ---------- nav ---------- */
nav.top{position:fixed;top:0;left:0;right:0;z-index:200;display:flex;justify-content:space-between;align-items:center;
  padding:22px var(--pad);mix-blend-mode:difference;transition:background .35s ease,padding .35s ease,backdrop-filter .35s ease}
/* once past the hero the bar takes a ground of its own, so the wordmark
   never has to compete with whatever is scrolling underneath it */
body.scrolled nav.top{mix-blend-mode:normal;background:rgba(6,6,5,.82);backdrop-filter:blur(12px);
  padding-top:15px;padding-bottom:15px;border-bottom:1px solid var(--line)}
/* The wordmark is the one place a third face is used: Montserrat, in
   pure white, so the logo reads as a mark rather than as another heading
   set in the display face. Everything else still holds to the two. */
.word{font-family:var(--mark);font-weight:700;font-size:20px;letter-spacing:-.01em;color:#fff}
.nav-links{display:flex;gap:28px;font-size:12px;text-transform:uppercase;letter-spacing:.05em}
.nav-links a{position:relative;padding-bottom:3px}
.nav-links a::after{content:'';position:absolute;left:0;bottom:0;width:100%;height:1px;background:currentColor;
  transform:scaleX(0);transform-origin:right;transition:transform .4s cubic-bezier(.2,.7,.2,1)}
.nav-links a:hover::after{transform:scaleX(1);transform-origin:left}
.burger{display:none;flex-direction:column;gap:5px;background:none;border:0;cursor:pointer;padding:6px;z-index:210;font:inherit}
.burger i{display:block;width:24px;height:1.5px;background:var(--off);transition:transform .3s,opacity .3s}
body.menu .burger i:nth-child(1){transform:translateY(6.5px) rotate(45deg)}
body.menu .burger i:nth-child(2){opacity:0}
body.menu .burger i:nth-child(3){transform:translateY(-6.5px) rotate(-45deg)}
@media(max-width:820px){
  nav.top{mix-blend-mode:normal}
  .burger{display:flex}
  .nav-links{position:fixed;inset:0;background:var(--deep);flex-direction:column;justify-content:center;gap:22px;
    padding:0 var(--pad);font-family:var(--display);font-weight:700;font-size:clamp(30px,10vw,58px);letter-spacing:-.02em;
    clip-path:inset(0 0 100% 0);transition:clip-path .6s cubic-bezier(.72,0,.16,1);z-index:190}
  body.menu .nav-links{clip-path:inset(0 0 0 0)}
}

/* ---------- hero ---------- */
.hero{position:relative;min-height:100svh;display:flex;flex-direction:column;justify-content:flex-end;
  padding:110px var(--pad) 56px;overflow:hidden;background:var(--deep)}
.hero-media{position:absolute;inset:0;z-index:0}
/* The showreel is a 16:9 film, shown whole (contain) rather than cropped to
   the taller hero; the deep hero background fills the letterbox margins. */
.hero-media video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  filter:saturate(.72) contrast(1.14) brightness(.66)}
/* Generative backdrop: runs whenever no video file is present, so the hero
   is never a flat black box. Drawn small and blurred up — cheap on mobile. */
#heroCanvas{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:blur(38px) saturate(1.15) contrast(1.06) brightness(.82);transform:scale(1.12)}
.hero-scan{position:absolute;inset:0;z-index:1;pointer-events:none;opacity:.5;
  background:linear-gradient(180deg,transparent 0%,rgba(214,255,63,.05) 46%,transparent 60%);
  animation:scan 13s cubic-bezier(.45,0,.55,1) infinite}
@keyframes scan{0%{transform:translateY(-62%)}100%{transform:translateY(62%)}}
.hero-bars{position:absolute;inset:0;z-index:1;pointer-events:none;opacity:.35;
  background:repeating-linear-gradient(180deg,rgba(0,0,0,.22) 0 1px,transparent 1px 3px)}
.hero-tint{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(150deg,rgba(6,6,4,.74),rgba(6,6,4,.18) 46%,rgba(6,6,4,.86))}
.hero-vig{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(ellipse 76% 66% at 50% 54%,transparent 38%,var(--deep) 97%)}
.hero-grain{position:absolute;inset:0;z-index:1;pointer-events:none;opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
.hero-in{position:relative;z-index:2}
.hero-line{font-size:clamp(13px,1.6vw,17px);color:var(--dim);text-transform:uppercase;letter-spacing:.06em;margin-bottom:20px}
.hero h1{font-size:clamp(38px,9vw,138px);line-height:1.1;max-width:15ch}
.mask{display:block;overflow:hidden}
.mask > i{display:block;font-style:normal;will-change:transform}
.hero-foot{display:flex;justify-content:space-between;align-items:flex-end;gap:24px;flex-wrap:wrap;margin-top:46px}
.hero-sub{font-size:15.5px;color:var(--dim);max-width:38ch;line-height:1.55}
.scroll-cue{display:flex;align-items:center;gap:10px;font-size:11px;text-transform:uppercase;letter-spacing:.09em;color:var(--dim)}
.scroll-cue i{width:1px;height:40px;background:linear-gradient(var(--accent),transparent);display:block;animation:drop 1.9s infinite}
@keyframes drop{0%{transform:scaleY(0);transform-origin:top}48%{transform:scaleY(1);transform-origin:top}
  52%{transform:scaleY(1);transform-origin:bottom}100%{transform:scaleY(0);transform-origin:bottom}}

/* ---------- marquee ---------- */
.marquee{border-top:1px solid var(--line);border-bottom:1px solid var(--line);overflow:hidden;padding:15px 0;background:var(--black)}
.track{display:flex;gap:42px;width:max-content}
.track span{font-family:var(--display);font-weight:800;text-transform:uppercase;font-size:clamp(18px,2.5vw,31px);
  letter-spacing:-.01em;color:var(--dim);display:flex;align-items:center;gap:42px;white-space:nowrap}
.track span::after{content:'';width:7px;height:7px;border-radius:50%;background:var(--accent);flex:none}

/* ---------- section shell ---------- */
.sec{padding:clamp(80px,11vw,150px) var(--pad);border-top:1px solid var(--line);position:relative}
.sec-hd{display:flex;justify-content:space-between;align-items:flex-end;gap:20px;flex-wrap:wrap;margin-bottom:48px}
.sec-hd h2{font-size:clamp(28px,5vw,64px);line-height:.94}

/* ---------- work: horizontal rail ----------
   Wide viewports pin the section and drive the strip with scroll. Narrow
   ones get a native horizontal scroller with snap points — swipeable, and
   still unmistakably sideways. The work never stacks into a column. */
.rail-head{display:flex;justify-content:space-between;align-items:flex-end;gap:20px;flex-wrap:wrap;
  padding:clamp(80px,11vw,150px) var(--pad) 0}
.rail-head h2{font-size:clamp(28px,5vw,64px);line-height:.94}
/* The progress line is now a real scrubber: a grab handle you can drag to
   move through the work, not just a read-out of where you are. The hit area
   is 22px tall while the rule itself stays hairline. */
/* The scrubber lives inside the pinned area, not above it — otherwise it
   scrolls out of view the moment you start using it. */
.prog{position:absolute;left:var(--pad);right:var(--pad);bottom:clamp(22px,4vh,44px);z-index:6;
  height:22px;display:flex;align-items:center;
  cursor:grab;touch-action:none;-webkit-tap-highlight-color:transparent}
.rail-stick{position:sticky}
@media(max-width:720px){
  .prog{position:relative;left:auto;right:auto;bottom:auto;margin:14px var(--pad) 0}
}
.prog::before{content:'';position:absolute;left:0;right:0;height:1px;background:var(--line)}
.prog:hover::before,.prog.dragging::before{background:rgba(244,242,236,.26)}
.prog.dragging{cursor:grabbing}
.prog i{position:absolute;left:0;height:3px;background:var(--accent);width:5%;display:block;
  border-radius:2px;transition:height .2s}
.prog:hover i,.prog.dragging i{height:5px}
.prog .knob{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;background:var(--accent);
  transform:translate(-50%,-50%);box-shadow:0 0 0 4px rgba(214,255,63,.16);transition:transform .18s}
.prog:hover .knob,.prog.dragging .knob{transform:translate(-50%,-50%) scale(1.25)}
.prog:focus-visible{outline:2px solid var(--accent);outline-offset:4px}
.rail-wrap{position:relative}
.rail-stick{position:sticky;top:0;height:100svh;display:flex;align-items:center;overflow:hidden}
.rail{display:flex;gap:clamp(14px,2vw,28px);padding:0 var(--pad);will-change:transform}
/* Every brand cover is one size. The rail used to alternate a wide 4:3 with
   a narrow 3:4, which made some clients' work read as bigger than others'.
   One width, one ratio, matching the archive cards. */
/* Every brand cover is one size and one shape: 4:5 portrait, a static frame.
   The rail used to alternate a wide 4:3 with a narrow 3:4, which made some
   clients' work read as bigger than others'. */
.tile,.tile.tall{flex:none;display:block;width:min(34vw,420px)}
.tile .frame,.tile.tall .frame{position:relative;overflow:hidden;aspect-ratio:4/5;border-radius:18px}
/* Every card in a row needs to be the same height to read as organized -
   that matters more here than showing a creative uncropped, so this stays
   a fixed box with object-fit:cover (biased toward the top, where a face
   or headline usually sits, rather than dead centre). The per-project case
   page is where the full, uncropped creative gets shown. */
.tile .slot{position:absolute;inset:0}
.tile .slot::before{transition:transform .9s cubic-bezier(.2,.7,.2,1)}
.tile:hover .slot::before{transform:scale(1.07)}
.tile .veil{position:absolute;inset:0;z-index:1;background:var(--black);opacity:.42;transition:opacity .5s}
.tile:hover .veil{opacity:.14}
.tile .go{position:absolute;right:16px;top:16px;z-index:2;width:44px;height:44px;border:1px solid var(--off);
  border-radius:50%;display:flex;align-items:center;justify-content:center;background:rgba(10,10,10,.3);
  transition:background .35s,color .35s,border-color .35s,transform .35s}
.tile:hover .go{background:var(--accent);color:var(--black);border-color:var(--accent);transform:rotate(45deg)}
.tile .meta{display:flex;justify-content:space-between;align-items:flex-end;gap:16px;padding:15px 2px 0}
.tile .meta h3{font-size:clamp(17px,2vw,28px);transition:color .3s;margin-bottom:10px}
.tile:hover .meta h3{color:var(--accent)}
.tile .idx{font-family:var(--display);font-weight:800;font-size:12px;color:var(--dim);font-variant-numeric:tabular-nums}
.tags{display:flex;flex-wrap:wrap;gap:7px}
.pill{font-size:10px;text-transform:uppercase;letter-spacing:.07em;color:var(--dim);
  border:1px solid var(--line);border-radius:999px;padding:4px 11px;white-space:nowrap;
  transition:color .3s,border-color .3s}
.tile:hover .pill,.arch-item:hover .pill{color:var(--off);border-color:rgba(244,242,236,.3)}

/* narrow: swipeable strip, no pinning */
@media(max-width:720px){
  .rail-wrap{height:auto!important}
  .rail-stick{position:static;height:auto;overflow-x:auto;overflow-y:hidden;padding:36px 0 10px;
    scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none}
  .rail-stick::-webkit-scrollbar{display:none}
  .rail{transform:none!important;padding-right:calc(var(--pad) + 40px)}
  .tile,.tile.tall{width:72vw;scroll-snap-align:center}
  .tile .frame,.tile.tall .frame{aspect-ratio:4/5}
}
.swipe-hint{display:none;padding:12px var(--pad) 0;font-size:10.5px;text-transform:uppercase;
  letter-spacing:.1em;color:var(--dim)}
@media(max-width:720px){.swipe-hint{display:block}}

/* ---------- services: cards ---------- */
.svc-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--line);border:1px solid var(--line)}
@media(max-width:900px){.svc-grid{grid-template-columns:repeat(2,1fr)}}
@media(max-width:600px){.svc-grid{grid-template-columns:1fr}}
.svc-card{display:flex;flex-direction:column;background:var(--black);padding:clamp(24px,2.6vw,34px);
  transition:background .3s}
.svc-card:hover{background:#0f0f0e}
.svc-card .no{font-size:11px;color:var(--dim);letter-spacing:.06em;font-variant-numeric:tabular-nums}
.svc-card .name{font-family:var(--display);font-weight:600;text-transform:uppercase;letter-spacing:-.01em;
  font-size:clamp(19px,2.2vw,25px);margin:14px 0 12px;transition:color .3s}
.svc-card:hover .name{color:var(--accent)}
.svc-card p{font-size:14px;color:var(--dim);line-height:1.6;margin-bottom:16px}
.svc-card ul{list-style:none;display:flex;flex-direction:column;gap:8px;font-size:13px;color:var(--dim);
  margin-bottom:24px}
.svc-card li{padding-left:16px;position:relative}
.svc-card li::before{content:'';position:absolute;left:0;top:9px;width:6px;height:1px;background:var(--accent)}
.svc-card .more{margin-top:auto;display:inline-flex;align-items:center;gap:8px;font-size:12.5px;
  text-transform:uppercase;letter-spacing:.07em;color:var(--off);transition:gap .3s,color .3s}
.svc-card:hover .more{gap:12px;color:var(--accent)}
.svc-card .more .arrow{font-style:normal;transition:transform .35s cubic-bezier(.2,.7,.2,1)}
.svc-card:hover .more .arrow{transform:translate(3px,-3px)}

/* ---------- process ---------- */
.steps{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--soft);border:1px solid var(--line)}
@media(max-width:800px){.steps{grid-template-columns:repeat(2,1fr)}}
@media(max-width:480px){.steps{grid-template-columns:1fr}}
.steps > div{background:var(--black);padding:26px 22px;display:flex;flex-direction:column;gap:9px;min-height:195px}
.steps .n{font-family:var(--display);font-weight:800;font-size:13px;color:var(--accent);font-variant-numeric:tabular-nums}
.steps h3{font-size:16px}
.steps p{font-size:13px;color:var(--dim)}

/* ---------- statement ---------- */
.statement h2{font-size:clamp(26px,5vw,66px);line-height:1.08;text-transform:none;max-width:19ch}
.statement .w{color:#3a3934;transition:color .5s ease}
.statement .w.on{color:var(--off)}
.statement .em{color:var(--accent)}

/* ---------- capabilities ---------- */
.grid6{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--soft);border:1px solid var(--line)}
@media(max-width:900px){.grid6{grid-template-columns:repeat(2,1fr)}}
@media(max-width:560px){.grid6{grid-template-columns:1fr}}
.cell{background:var(--black);padding:26px 22px;display:flex;flex-direction:column;gap:10px;min-height:215px;transition:background .35s}
.cell:hover{background:#131312}
.cell h3{font-size:16px}
.cell p{font-size:13px;color:var(--dim)}
.cell ul{list-style:none;display:flex;flex-direction:column;gap:6px;margin-top:auto;font-size:11.5px;color:var(--dim)}
.cell li{padding-left:14px;position:relative}
.cell li::before{content:'';position:absolute;left:0;top:8px;width:5px;height:1px;background:var(--accent)}

/* ---------- counters ---------- */
.strip{display:flex;flex-wrap:wrap;gap:1px;background:var(--soft);border-block:1px solid var(--line)}
.strip div{background:var(--black);padding:24px clamp(20px,3vw,40px);flex:1 1 180px}
.strip .n{font-family:var(--display);font-weight:800;font-size:clamp(26px,3.4vw,40px);font-variant-numeric:tabular-nums}
.strip .n em{font-style:normal;color:var(--accent)}
.strip .l{font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--dim);margin-top:6px}

/* ---------- contact ---------- */
.end{text-align:center;border-top:1px solid var(--line);padding:clamp(80px,12vw,160px) var(--pad)}
.end h2{font-size:clamp(38px,9vw,138px);line-height:.88}
.mail{display:inline-flex;align-items:center;gap:12px;margin-top:36px;font-family:var(--display);font-weight:700;
  font-size:clamp(17px,2.6vw,30px);border-bottom:1px solid var(--line);padding-bottom:8px;transition:color .3s,border-color .3s}
.mail:hover{color:var(--accent);border-color:var(--accent)}
.cbits{display:flex;justify-content:center;gap:clamp(20px,5vw,60px);flex-wrap:wrap;margin-top:46px}
.cbits div{display:flex;flex-direction:column;gap:5px}
.cbits b{font-weight:500;font-size:14px}
footer{border-top:1px solid var(--line);padding:26px var(--pad);display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;
  font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--dim)}

/* ---------- converge: scattered work drifts to centre, then washes out ---
   Pinned like the rail, but reads scroll as a single 0-1 progress value
   (set as --p by script) rather than a horizontal position. Each card
   starts wherever --tx/--ty/--rot place it and eases to dead centre as
   --p approaches 1; the wash behind it fades in on the same progress. */
.converge{position:relative;height:150vh;background:var(--black)}
.converge-stick{position:sticky;top:0;height:100svh;overflow:hidden}
.conv-item{position:absolute;top:50%;left:50%;width:min(20vw,210px);aspect-ratio:4/5;
  border-radius:20px;overflow:hidden;box-shadow:0 40px 80px rgba(0,0,0,.55);
  transform:translate(-50%,-50%) translate(calc(var(--tx) * 1vw),calc(var(--ty) * 1vh))
    scale(1) rotate(calc(var(--rot) * 1deg))}
.conv-item img{width:100%;height:100%;object-fit:cover;display:block;filter:grayscale(.3) contrast(1.04)}
/* The wash used to end on navy and then white — two colours that appear
   nowhere else in the brand, and it left a tall empty pale screen once the
   cards had converged. It now closes on the page's own ground with a single
   accent bloom, so the section hands off to the footer instead of blanking. */
.conv-wash{position:absolute;inset:0;z-index:2;pointer-events:none;opacity:0;
  background:
    radial-gradient(ellipse 70% 55% at 50% 62%,rgba(214,255,63,.16),transparent 66%),
    linear-gradient(180deg,rgba(10,10,10,0) 0%,rgba(10,10,10,.55) 55%,var(--black) 100%)}
@media(max-width:720px){.conv-item{width:34vw}}
@media(prefers-reduced-motion:reduce){.converge{display:none}}

/* ==========================================================================
   CASE STUDY PAGE
   ========================================================================== */
.case-hero{position:relative;min-height:82svh;display:flex;align-items:flex-end;padding:130px var(--pad) 52px;overflow:hidden;background:var(--deep)}
.case-hero .slot{position:absolute;inset:0;z-index:0}
.case-hero .tint{position:absolute;inset:0;z-index:1;background:linear-gradient(180deg,rgba(4,4,4,.6),rgba(4,4,4,.2) 40%,rgba(4,4,4,.9))}
.case-hero .in{position:relative;z-index:2;width:100%}
.case-hero h1{font-size:clamp(34px,7.4vw,116px);line-height:.88;max-width:16ch}
.crumb{display:flex;gap:10px;align-items:center;font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--dim);margin-bottom:18px}
.crumb a:hover{color:var(--accent)}
.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--soft);border-block:1px solid var(--line)}
@media(max-width:760px){.facts{grid-template-columns:repeat(2,1fr)}}
.facts div{background:var(--black);padding:22px clamp(18px,2.6vw,32px)}
.facts b{display:block;font-size:15px;font-weight:500;margin-top:7px}
/* These bands used to open with 130px of air and close with another 130px,
   leaving one small grey paragraph stranded in the middle of a dark screen
   with the work pushed far below it. Tighter above, much tighter below, so
   the words read as the lead-in to the images rather than an interruption. */
.case-body{padding:clamp(54px,7vw,92px) var(--pad) clamp(26px,3.4vw,44px);
  display:grid;grid-template-columns:minmax(180px,26%) 1fr;
  gap:clamp(22px,5vw,70px);align-items:start}
@media(max-width:860px){.case-body{grid-template-columns:1fr;gap:20px}}
.case-body .stick{position:sticky;top:100px}
@media(max-width:860px){.case-body .stick{position:static}}
.case-body h2{font-size:clamp(20px,2.5vw,30px);line-height:1.08;margin-top:10px}
/* Lead copy carried --dim at 16px, which sat too faint and too small beside
   full-bleed imagery. Larger, looser, and lifted off the grey. */
.prose{display:flex;flex-direction:column;gap:18px;font-size:clamp(16.5px,1.25vw,18.5px);
  line-height:1.68;color:rgba(244,242,236,.76);max-width:60ch}
.prose p:first-child{color:rgba(244,242,236,.92)}
.prose b{color:var(--off);font-weight:500}
.gal{padding:0 var(--pad) clamp(44px,6vw,86px);display:grid;grid-template-columns:repeat(12,1fr);gap:clamp(12px,2vw,26px)}
.gal .slot{width:100%}
/* These cells used to force 16:9, 4:5 and 1:1 boxes onto whatever was inside
   them. Nearly every asset here is a 4:5 or 9:16 social creative, so
   object-fit:cover was slicing the top and bottom off the work, headlines
   included. A cell now takes the shape of its own media — --ar is set from
   the file's natural size once it loads — so nothing is cropped. */
.g-full,.g-half{grid-column:span 6;aspect-ratio:var(--ar,4/5)}
.g-third{grid-column:span 4;aspect-ratio:var(--ar,4/5)}
@media(max-width:900px){.g-full,.g-half,.g-third{grid-column:span 6}}
@media(max-width:600px){.g-full,.g-half,.g-third{grid-column:1/13}}
.kpis{display:flex;flex-wrap:wrap;gap:1px;background:var(--soft);border-block:1px solid var(--line)}
.kpis div{background:var(--black);padding:28px clamp(20px,3vw,40px);flex:1 1 200px}
.kpis .v{font-family:var(--display);font-weight:800;font-size:clamp(28px,4.2vw,52px);color:var(--accent);font-variant-numeric:tabular-nums}
.kpis .l{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--dim);margin-top:8px}
/* The next-project link sat on the same flat black as the case body with
   only a hairline above it, so it read as more copy rather than as the
   way out of the page. It now has its own ground, the next project's own
   colour along the top, and a picture of what it leads to. */
.next{position:relative;overflow:hidden;display:grid;
  grid-template-columns:1fr auto;align-items:center;gap:clamp(20px,4vw,60px);
  padding:clamp(48px,7vw,96px) var(--pad);
  background:linear-gradient(180deg,#121211,#0d0d0c);
  border-top:3px solid var(--tone,var(--accent))}
/* a wash of the next project's colour, so the panel is tinted by where
   it is going rather than being another grey box */
.next::before{content:'';position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(120% 140% at 0% 0%,var(--tone,var(--accent)),transparent 62%);
  opacity:.10;transition:opacity .5s}
.next:hover::before{opacity:.2}
.next-txt{position:relative;z-index:1;min-width:0}
.next .lab{margin-bottom:14px}
.next h2{font-size:clamp(28px,5.6vw,80px);line-height:.92;transition:color .35s}
.next:hover h2{color:var(--tone,var(--accent))}
.next-shot{position:relative;z-index:1;flex:none;width:clamp(88px,11vw,150px);
  aspect-ratio:4/5;border-radius:14px;overflow:hidden;background:#111110}
.next-shot img{width:100%;height:100%;object-fit:cover;transition:transform .8s cubic-bezier(.2,.7,.2,1)}
.next:hover .next-shot img{transform:scale(1.07)}
.next .arrow{position:absolute;z-index:1;right:var(--pad);top:clamp(26px,4vw,44px);
  font-size:clamp(22px,2.6vw,34px);color:var(--tone,var(--accent));
  transition:transform .45s cubic-bezier(.2,.7,.2,1)}
.next:hover .arrow{transform:translate(10px,-10px)}
@media(max-width:620px){
  .next{gap:18px}
  .next .arrow{display:none}
}

/* ---------- reveal system ----------
   Gated on html.js: with scripting off nothing is ever hidden. The motion
   itself is native — IntersectionObserver adds .in, CSS does the rest. */
.js [data-rev]{opacity:0;transform:translateY(26px);
  transition:opacity .85s cubic-bezier(.2,.75,.2,1),transform .85s cubic-bezier(.2,.75,.2,1)}
.js [data-rev].in{opacity:1;transform:none}
.js [data-rev][data-stagger] > *{opacity:0;transform:translateY(22px);
  transition:opacity .7s cubic-bezier(.2,.75,.2,1),transform .7s cubic-bezier(.2,.75,.2,1)}
.js [data-rev][data-stagger] > *.in{opacity:1;transform:none}
.js [data-rev="left"]{transform:translateX(-30px)}
.js [data-rev="scale"]{transform:scale(.95);transform-origin:left bottom}
.js [data-rev="rise"]{transform:translateY(46px)}

/* parallax: JS sets --py, CSS moves it */
[data-par]{--py:0%}
[data-par] .slot::before,.slot[data-par]::before{transform:translateY(var(--py))}

/* hero masked lines run on a class, not a library */
.js .mask > i{transform:translateY(108%)}
.js body.lit .mask > i,.js.no-motion .mask > i{transform:none;
  transition:transform 1.05s cubic-bezier(.2,.75,.2,1)}
.js .mask:nth-of-type(2) > i{transition-delay:.09s}
.js .mask:nth-of-type(3) > i{transition-delay:.18s}
.js .hero-line,.js .hero-foot,.js .crumb,.js .case-hero .facts{opacity:0;transition:opacity .9s ease}
.js body.lit .hero-line,.js body.lit .crumb{opacity:1;transition-delay:.35s}
.js body.lit .hero-foot,.js body.lit .case-hero .facts{opacity:1;transition-delay:.9s}
@media(prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
  .rev{transform:none}.tile .frame{clip-path:none!important}.mask > i{transform:none!important}
}

/* ==========================================================================
   WORK ARCHIVE (/work/)
   ========================================================================== */
.arch-hd{padding:130px var(--pad) 0}
.arch-hd h1{font-size:clamp(36px,8vw,120px);line-height:.88}
.tabs{display:flex;gap:8px;flex-wrap:wrap;padding:34px var(--pad) 0;border-bottom:1px solid var(--line);
  margin-bottom:clamp(30px,5vw,60px);padding-bottom:22px}
.tab-btn{font:inherit;font-size:11.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--dim);
  background:none;border:1px solid var(--line);border-radius:999px;padding:8px 16px;cursor:pointer;
  transition:color .25s,border-color .25s,background .25s}
.tab-btn:hover{color:var(--off);border-color:var(--off)}
.tab-btn.on{background:var(--accent);border-color:var(--accent);color:var(--black);font-weight:600}
.tab-btn .c{font-variant-numeric:tabular-nums;opacity:.6;margin-left:6px}
.arch{padding:0 var(--pad) clamp(70px,10vw,130px);display:grid;grid-template-columns:repeat(2,1fr);
  gap:clamp(20px,3vw,44px)}
@media(max-width:760px){.arch{grid-template-columns:1fr}}
.arch-item{display:block}
.arch-item .frame{position:relative;overflow:hidden;aspect-ratio:4/5;border-radius:18px}
.arch-item .slot{position:absolute;inset:0}
.arch-item .slot::before{transition:transform .9s cubic-bezier(.2,.7,.2,1)}
.arch-item:hover .slot::before{transform:scale(1.06)}
.arch-item .veil{position:absolute;inset:0;z-index:1;background:var(--black);opacity:.4;transition:opacity .45s}
.arch-item:hover .veil{opacity:.14}
.arch-item .go{position:absolute;right:14px;top:14px;z-index:2;width:40px;height:40px;border:1px solid var(--off);
  border-radius:50%;display:flex;align-items:center;justify-content:center;background:rgba(10,10,10,.3);
  transition:background .3s,color .3s,border-color .3s,transform .3s}
.arch-item:hover .go{background:var(--accent);color:var(--black);border-color:var(--accent);transform:rotate(45deg)}
.arch-item .meta{display:flex;justify-content:space-between;align-items:flex-end;gap:14px;padding:14px 2px 0}
.arch-item h3{font-size:clamp(18px,2.2vw,30px);transition:color .3s;margin-bottom:10px}
.arch-item:hover h3{color:var(--accent)}
.arch-item .sum{font-size:13px;color:var(--dim);margin-top:8px;max-width:46ch}

/* ---------- blog (/blog/) ---------- */
.post-list{padding:0 var(--pad) clamp(70px,10vw,130px);display:grid;
  grid-template-columns:repeat(2,1fr);gap:clamp(20px,3vw,44px)}
@media(max-width:760px){.post-list{grid-template-columns:1fr}}
.post-card{display:block;border:1px solid var(--line);border-radius:18px;overflow:hidden;
  padding:clamp(24px,2.6vw,34px);transition:border-color .3s,background .3s}
.post-card:hover{border-color:rgba(244,242,236,.3);background:#0f0f0e}
/* a card with a cover carries the image flush to its top edge, then pads the
   text below; a card without one keeps the plain padded text layout */
.post-card.has-cover{padding:0}
.post-card.has-cover .post-body{padding:clamp(24px,2.6vw,34px)}
.post-card-cover{display:block;width:100%;aspect-ratio:16/9;object-fit:cover;
  border-bottom:1px solid var(--line)}
.post-card .post-body{display:block}
.post-meta{display:flex;justify-content:space-between;font-size:11px;text-transform:uppercase;
  letter-spacing:.07em;color:var(--dim);margin-bottom:14px}
.post-meta .tag{color:var(--accent)}
.post-card h2{font-size:clamp(20px,2.4vw,28px);margin-bottom:12px;transition:color .3s}
.post-card:hover h2{color:var(--accent)}
.post-card p{font-size:14px;color:var(--dim);line-height:1.6;margin-bottom:20px}
.post-card .more{display:inline-flex;align-items:center;gap:8px;font-size:12.5px;
  text-transform:uppercase;letter-spacing:.07em;color:var(--off);transition:gap .3s,color .3s}
.post-card:hover .more{gap:12px;color:var(--accent)}
.post-card .more .arrow{font-style:normal;transition:transform .35s cubic-bezier(.2,.7,.2,1)}
.post-card:hover .more .arrow{transform:translate(3px,-3px)}
.arch-item .yr{font-family:var(--display);font-weight:800;font-size:12px;color:var(--dim);font-variant-numeric:tabular-nums}


/* ---------- reduced motion: everything resolves, nothing moves ---------- */
@media(prefers-reduced-motion:reduce){
  .js [data-rev],.js [data-rev][data-stagger] > *{opacity:1!important;transform:none!important}
  .js .mask > i{transform:none!important}
  .js .hero-line,.js .hero-foot,.js .crumb,.js .case-hero .facts{opacity:1!important}
}

/* ==========================================================================
   ORNAMENT — the layer that makes it feel made, not assembled
   ========================================================================== */

/* scroll progress, hairline across the top of the page */
.sprog{position:fixed;top:0;left:0;height:2px;width:0;background:var(--accent);z-index:250;
  box-shadow:0 0 14px rgba(214,255,63,.5);pointer-events:none}

/* the cursor speaks when it is over something openable */
.cursor{display:flex;align-items:center;justify-content:center}
.cursor .cur-label{font-family:var(--display);font-weight:800;font-size:10.5px;letter-spacing:.06em;
  color:var(--black);opacity:0;transform:scale(.6);transition:opacity .2s,transform .25s;white-space:nowrap}
.cursor.view .cur-label{opacity:1;transform:scale(1)}
.cursor.view{width:82px;height:82px;mix-blend-mode:normal}

/* rail tiles gain depth as they pass the middle of the screen */
.tile{--depth:1;--lift:0px}
.tile .frame{transform:scale(var(--depth)) translateY(var(--lift));
  transition:transform .5s cubic-bezier(.2,.7,.2,1)}

/* eyebrow labels decode themselves on reveal */
.lab.ac{font-variant-ligatures:none}

/* the wordmark, set enormous, filling with accent as the page ends */
/* The big wordmark that closes the page. It used to be an outline that
   filled with lime as you scrolled; that animation is gone, so this is
   simply the mark set large, in the same white Montserrat as the one in
   the nav, cropped tight to its own baseline. */
.endmark{position:relative;border-top:1px solid var(--line);
  padding:clamp(34px,5vw,64px) var(--pad) clamp(22px,3.4vw,46px);text-align:center;line-height:1;
  overflow:hidden}
.endmark span{font-family:var(--mark);font-weight:700;
  font-size:clamp(64px,20vw,300px);line-height:.92;letter-spacing:-.03em;display:block;
  padding-bottom:.06em;                      /* room for the baseline, never clipped */
  color:#fff}

/* buttons lean toward the pointer */
.magnet{transition:transform .35s cubic-bezier(.2,.7,.2,1)}

/* a hairline that draws itself under every section heading */
.sec-hd,.rail-head{position:relative}
.sec-hd::after,.rail-head::after{content:'';position:absolute;left:0;bottom:-18px;height:1px;width:100%;
  background:var(--line);transform:scaleX(0);transform-origin:left;transition:transform 1.1s cubic-bezier(.2,.75,.2,1)}
.sec-hd.in::after,.rail-head.in::after{transform:scaleX(1)}

@media(prefers-reduced-motion:reduce){
  .sec-hd::after,.rail-head::after{transform:scaleX(1)}
  .tile .frame{transform:none!important}
  .cursor{display:none}
}

/* ==========================================================================
   SECOND MOTION PASS — the parts whose markup exists today
   ========================================================================== */

/* gallery images wipe open on case pages */
.js .gal .slot{clip-path:inset(0 0 100% 0);transition:clip-path 1.1s cubic-bezier(.72,0,.16,1)}
.js .gal.in .slot{clip-path:inset(0 0 0 0)}
.js .gal .slot:nth-child(2){transition-delay:.1s}
.js .gal .slot:nth-child(3){transition-delay:.2s}
.js .gal .slot:nth-child(4){transition-delay:.3s}

/* the mail link sweeps rather than simply changing colour */
.mail{position:relative;overflow:hidden}
.mail::after{content:'';position:absolute;left:0;bottom:0;height:1px;width:100%;background:var(--accent);
  transform:scaleX(0);transform-origin:right;transition:transform .5s cubic-bezier(.2,.7,.2,1)}
.mail:hover::after{transform:scaleX(1);transform-origin:left}

@media(prefers-reduced-motion:reduce){
  .js .gal .slot{clip-path:none!important}
}

/* ==========================================================================
   OPENING CURTAIN + RAIL LEAN
   ========================================================================== */

/* The curtain is built by script, so a page without JS never sees one and is
   never left sitting behind a cover that cannot lift. */
.curtain{position:fixed;inset:0;z-index:600;background:var(--deep);overflow:hidden;
  display:flex;flex-direction:column;justify-content:flex-end;padding:var(--pad);
  transition:clip-path 1.05s cubic-bezier(.72,0,.16,1)}
.curtain.up{clip-path:inset(0 0 100% 0)}
.curtain::after{content:'';position:absolute;inset:0;pointer-events:none;opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
.curtain .c-bar{height:1px;background:var(--line);margin-bottom:26px;position:relative}
.curtain .c-bar i{position:absolute;left:0;top:-1px;display:block;height:3px;width:0;background:var(--accent);
  transition:width .25s linear}
.curtain .c-row{display:flex;align-items:flex-end;justify-content:space-between;gap:20px;flex-wrap:wrap}
.curtain .c-word{font-family:var(--display);font-weight:800;text-transform:uppercase;
  font-size:clamp(44px,11vw,150px);letter-spacing:-.03em;line-height:.78;overflow:hidden}
.curtain .c-word i{display:block;font-style:normal;transform:translateY(106%);
  animation:c-rise .95s .05s cubic-bezier(.2,.75,.2,1) forwards}
@keyframes c-rise{to{transform:translateY(0)}}
.curtain .c-num{font-family:var(--display);font-weight:800;font-size:clamp(30px,5vw,68px);
  color:var(--accent);font-variant-numeric:tabular-nums;line-height:1}
.curtain .c-sub{font-size:11px;text-transform:uppercase;letter-spacing:.12em;color:var(--dim);
  margin-bottom:14px}

/* The rail leans into the distance it still has to travel — the lag itself
   drives the lean, so it flexes on a flick and stands up as it settles. */
.rail{transform-origin:center center}

@media(prefers-reduced-motion:reduce){.curtain{display:none}}

/* ==========================================================================
   THIRD MOTION PASS
   ========================================================================== */

/* hero headline arrives letter by letter, each on its own delay */
.js .mask > i .wgrp{display:inline-block}
.js .mask > i b{display:inline-block;font-weight:inherit;transform:translateY(106%);
  transition:transform .85s cubic-bezier(.2,.75,.2,1);transition-delay:calc(var(--i) * 26ms)}
.js body.lit .mask > i b{transform:none}
.js .mask > i b.sp{width:.28em}

/* the hero block drifts and dims as it leaves */
.hero-in{will-change:transform,opacity}

.rail{position:relative;z-index:1}

/* tile titles shuffle their letters on approach */
.tile .meta h3{font-variant-ligatures:none}

@media(prefers-reduced-motion:reduce){
  .js .mask > i b{transform:none!important}
  .hero-in{transform:none!important;opacity:1!important}
}

/* ==========================================================================
   REAL MEDIA — takes over the placeholder frames once images are imported
   ========================================================================== */
.shot{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;
  background:#111110;transform:translateY(var(--py,0))}
.tile .shot,.arch-item .shot{transition:transform .9s cubic-bezier(.2,.7,.2,1),filter .6s ease;
  filter:grayscale(.45) contrast(1.04);object-position:center 22%}
.tile:hover .shot,.arch-item:hover .shot{transform:scale(1.06);filter:grayscale(0) contrast(1.08)}
.case-hero .shot{filter:saturate(.85) contrast(1.06) brightness(.7)}
/* fill the cell — the cell matches the media's ratio, so this never crops */
.gal .shot{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
/* Real media keeps the template's column widths but sizes to its own height
   instead of the template's fixed ratio - a figure with overflow:hidden and
   an aspect-ratio still crops an auto-height image to that ratio, so the
   ratio has to go, not just the image's own sizing. */
.gal figure{position:relative;margin:0;overflow:hidden;background:#111110;border-radius:14px}

.js .gal figure{clip-path:inset(0 0 100% 0);transition:clip-path 1.1s cubic-bezier(.72,0,.16,1)}
.js .gal.in figure{clip-path:inset(0 0 0 0)}

/* ==========================================================================
   FOURTH MOTION PASS — tactility
   ========================================================================== */

/* tiles tilt toward the pointer, on a real 3D plane */
.rail,.work,.arch{perspective:1400px}
.tile .frame,.arch-item .frame{transform-style:preserve-3d;
  transition:transform .5s cubic-bezier(.2,.7,.2,1)}
.tile.tilt .frame,.arch-item.tilt .frame{transition:transform .12s linear}

/* the rail can be grabbed and thrown */
.rail-stick{cursor:grab}
.rail-stick.dragging{cursor:grabbing}
.rail-stick.dragging .tile .frame{transition:none}

/* scrambling titles keep their box while the glyphs churn */
.tile .meta h3,.arch-item h3{font-variant-numeric:tabular-nums}

@media(prefers-reduced-motion:reduce){
  .tile .frame,.arch-item .frame{transform:none!important}
}


/* the one monospace use — the generated-code box in the editor — set in
   Archivo with tabular figures rather than a third typeface */
.mono-box{font-family:var(--text);font-variant-numeric:tabular-nums;letter-spacing:.01em}

/* Column span follows the shape of the media, so a tall 9:16 reel sits in a
   narrow column instead of becoming a 2,000px-high slab, and a landscape
   still gets the width it needs. Set by script from the file's own size. */
.gal figure.is-portrait{grid-column:span 4}
.gal figure.is-square{grid-column:span 5}
.gal figure.is-landscape{grid-column:span 8}
@media(max-width:900px){
  .gal figure.is-portrait{grid-column:span 6}
  .gal figure.is-square,.gal figure.is-landscape{grid-column:span 12}
}
@media(max-width:600px){.gal figure{grid-column:1/13!important}}


/* a client's live site, linked from the case study's facts bar */
.live-link{color:var(--accent);position:relative}
.live-link::after{content:'';position:absolute;left:0;bottom:-3px;width:100%;height:1px;background:var(--accent);
  transform:scaleX(0);transform-origin:right;transition:transform .4s cubic-bezier(.2,.7,.2,1)}
.live-link:hover::after{transform:scaleX(1);transform-origin:left}

/* ==========================================================================
   MOBILE PASS
   A phone is the first screen this site is judged on, so the small-screen
   rules live together here rather than scattered through the file. Three
   things are being fixed: touch targets that were too small to hit
   reliably, headers that ran into the content underneath them, and copy
   set at desktop sizes that got cramped once the column narrowed.
   ========================================================================== */

/* ---------- touch targets ----------
   A finger needs roughly 44px. Several controls were drawn smaller than
   that, so the hit area is grown with padding and pulled back with a
   negative margin — the target gets bigger, the layout does not move. */
@media(pointer:coarse),(max-width:720px){
  .word{padding:8px 2px;margin:-8px -2px}
  .burger{padding:15px;margin:-15px;gap:6px}
  .burger i{width:26px}

  /* inline links that sat on a single line of text */
.live-link,.crumb a,footer a,.more,.rail-head .tab a,.nav-links a{
    display:inline-block;padding-block:14px;margin-block:-14px}

  /* .mail keeps its own display and top margin — it is a block-level
     control already, so it only needs a taller strike area */
  .mail{padding-top:10px;padding-bottom:12px}

  /* filter pills and tabs */
  .tab-btn{padding:11px 18px;font-size:12px}
  .pill{font-size:11px;padding:6px 12px}

  /* the rail scrubber is a drag handle — give it a real grab area */
  /* a two-word breadcrumb is too narrow to hit on its own */
  .crumb a{padding-inline:6px;margin-inline:-6px}

  .prog{height:34px}
  .prog .knob{width:16px;height:16px}
}

/* ---------- page headers ----------
   .arch-hd carries no bottom padding because the work archive puts its
   filter tabs directly beneath it. The blog has no tabs, so its first
   card was landing against the headline. */
.arch-hd + .post-list{padding-top:clamp(28px,6vw,56px)}

@media(max-width:720px){
  .arch-hd{padding-top:104px}
  .arch-hd h1{line-height:.94}

  /* ---------- hero ----------
     Bottom-anchored over a full viewport left the standfirst below the
     fold on a phone. Shortening the box and tightening the padding brings
     the whole statement into the first screen. */
  .hero{min-height:92svh;padding:96px var(--pad) 40px}
  .hero-foot{margin-top:22px}
  /* On a portrait phone the 16:9 film letterboxes into tall black bars, so it
     fills the hero here instead; desktop keeps the whole 16:9 frame visible. */
  .hero-media video{object-fit:cover}

  /* ---------- copy ----------
     Uppercase text with wide tracking is hard work at small sizes over
     several lines, so the tracking comes in as the column narrows. */
  /* the section standfirsts are set in the small uppercase label style;
     over four lines that needs looser leading and tighter tracking */
  .lab{letter-spacing:.06em}
  .sec-hd .lab,.rail-head .tab{font-size:12px;line-height:1.75}

  /* section headings were breaking to four and five lines */
  .sec h2{line-height:.96}

  /* contact details stack into one readable column */
  .cbits{gap:22px}

  /* the footer's two halves were colliding on the narrowest phones */
  footer{flex-direction:column;gap:10px}
}

/* ---------- very narrow (360px and below) ---------- */
@media(max-width:380px){
  :root{--pad:18px}
  .tile,.tile.tall{width:78vw}
}

/* ---------- landscape phones ----------
   100svh sections become unreadable when the viewport is 380px tall. */
@media(max-height:520px) and (orientation:landscape){
  .hero{min-height:auto;padding-top:88px;padding-bottom:36px}
  .rail-stick{height:auto}
}

/* ==========================================================================
   WORK ARCHIVE — staggered grid with coloured caption bars
   Each project is an image over a bar carrying that brand's own colour, so
   the page reads as a set of brands rather than a wall of thumbnails.
   The covers stay a uniform 4:5 and every column starts on the same line,
   so the cards read as one grid rather than a staggered mosaic.
   ========================================================================== */
.arch-hd.centred,.tabs.centred{text-align:center}
.tabs.centred{justify-content:center}

.arch.mason{grid-template-columns:repeat(3,1fr);gap:clamp(18px,2.4vw,34px);align-items:stretch}

.arch.mason .arch-item{display:flex;flex-direction:column;gap:14px}
/* the category filter hides cards with the hidden attribute; a class-level
   display rule outranks the browser's own [hidden] styling, so it has to be
   restated here or filtering silently stops hiding anything */
.arch.mason .arch-item[hidden]{display:none}
.arch.mason .frame{border-radius:20px}
/* the covers carry the page here, so they sit almost undimmed; the veil is
   only there to keep a bright image from fighting the caption under it */
.arch.mason .veil{opacity:.12}
.arch.mason .arch-item:hover .veil{opacity:0}

.arch.mason .bar{flex:1;min-height:136px;display:flex;flex-direction:column;align-items:stretch;gap:14px;
  background:var(--tone);color:var(--ink);border-radius:18px;
  padding:16px clamp(16px,1.5vw,22px);transition:transform .4s cubic-bezier(.2,.7,.2,1)}
.arch.mason .arch-item:hover .bar{transform:translateY(-4px)}
.arch.mason .bar h3{font-size:clamp(15px,1.35vw,21px);color:inherit;margin:0;line-height:1.1}
.arch.mason .arch-item:hover .bar h3{color:inherit}
.arch.mason .bar .tags{margin-top:9px}
/* the pills sit on a coloured ground here, so they take their contrast from
   the bar's ink rather than the page's dim grey */
.arch.mason .bar .pill{color:inherit;border-color:currentColor;opacity:.85;font-size:11px}
.arch.mason .arch-item:hover .bar .pill{color:inherit;border-color:currentColor}

/* One solid, full-width button pinned to the bottom of the bar, the same on
   every screen — margin-top:auto keeps buttons aligned across a row even when
   titles wrap to different heights. */
.arch.mason .see{margin-top:auto;align-self:stretch;display:inline-flex;align-items:center;justify-content:center;
  font-size:11.5px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;
  background:var(--ink);color:var(--tone);border:1px solid transparent;border-radius:999px;
  padding:13px 16px;white-space:nowrap;transition:opacity .3s}
.arch.mason .arch-item:hover .see{opacity:.88}

@media(max-width:900px){
  .arch.mason{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:620px){
  .arch.mason{grid-template-columns:1fr}
  /* single column: no need to force uniform bar heights */
  .arch.mason .bar{min-height:0;gap:12px}
  .arch.mason .see{padding:14px 18px;font-size:12px}
}

/* every caption bar is the same height: a floor tall enough for a two-line title
   plus a row of tags, and each row stretches to its tallest card */

/* ---------- homepage work section ----------
   Same staggered grid as the archive. The section needs its own padding
   because it used to be a full-bleed pinned rail rather than a normal
   band, and the head centres to match the archive's. */
.work-sec{padding:clamp(80px,11vw,150px) 0 clamp(60px,8vw,110px);border-top:1px solid var(--line)}
.work-sec .rail-head.centred{display:block;text-align:center;padding:0 var(--pad) clamp(34px,5vw,60px)}
.work-sec .rail-head.centred .tab{margin-top:18px}
.work-sec .arch.mason{padding-left:var(--pad);padding-right:var(--pad)}

/* ---------- case page header, without the hero image ----------
   The full-bleed hero cropped a 4:5 cover into a letterbox band, which
   cut heads and product off. The header is now type on the page ground,
   so nothing is cropped and the title lands immediately. */
.case-hero.bare{min-height:0;padding:clamp(140px,16vh,190px) var(--pad) clamp(30px,4vw,48px);
  border-bottom:1px solid var(--line)}
.case-hero.bare h1{max-width:20ch}

/* ==========================================================================
   SERVICES (/services/)
   Three columns per discipline: the statement and its copy on the left,
   the capability chips down the middle, the image on the right. Each row
   is divided from the next by a rule, so the page reads as a list of
   six rather than a grid of cards.
   ========================================================================== */
.svc-hd{padding:clamp(130px,17vh,180px) var(--pad) clamp(40px,6vw,72px);text-align:center;
  border-bottom:1px solid var(--line)}
.svc-hd h1{font-size:clamp(46px,10vw,132px);line-height:.9}
.svc-intro{margin:clamp(22px,3vw,34px) auto 0;max-width:52ch;color:rgba(244,242,236,.66);
  font-size:clamp(15px,1.2vw,18px);line-height:1.6}

.svc-row{display:grid;grid-template-columns:minmax(0,1.05fr) auto minmax(0,.95fr);
  gap:clamp(24px,4vw,64px);align-items:center;
  padding:clamp(56px,8vw,110px) var(--pad);border-bottom:1px solid var(--line)}
.svc-no{font-family:var(--display);font-weight:800;font-size:12px;color:var(--accent);
  font-variant-numeric:tabular-nums;letter-spacing:.08em;margin-bottom:16px}
.svc-row h2{font-size:clamp(32px,4.6vw,68px);line-height:.95;max-width:11ch}
.svc-copy{margin-top:clamp(18px,2vw,28px);max-width:44ch;color:rgba(244,242,236,.66);
  font-size:clamp(15px,1.15vw,17.5px);line-height:1.65}
.svc-cta{display:inline-block;margin-top:clamp(22px,2.4vw,32px);font-size:12px;
  text-transform:uppercase;letter-spacing:.08em;color:var(--accent);
  border-bottom:1px solid transparent;padding-bottom:3px;transition:border-color .3s}
.svc-cta:hover{border-color:var(--accent)}

.svc-chips{display:flex;flex-direction:column;align-items:stretch;gap:clamp(9px,1vw,14px)}
.chip{border:1px solid var(--line);border-radius:999px;padding:11px 20px;white-space:nowrap;
  text-align:center;
  font-size:clamp(12px,1vw,14px);color:rgba(244,242,236,.86);background:rgba(244,242,236,.03);
  transition:border-color .3s,background .3s,transform .3s}
.svc-row:hover .chip{border-color:rgba(244,242,236,.34)}

/* the image is the client's work, so it links to that case study and
   names the client on it: an unlabelled picture gives a reader no reason
   to think there is anything behind it */
.svc-shot{position:relative;display:block;overflow:hidden;border-radius:22px;aspect-ratio:4/5;
  background:#111110;transition:box-shadow .35s}
.svc-shot:hover{box-shadow:0 0 0 2px var(--accent)}
.svc-shot-tag{position:absolute;left:12px;right:12px;bottom:12px;z-index:2;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:10px 14px;border-radius:12px;
  background:rgba(10,10,10,.68);backdrop-filter:blur(8px);
  font-size:clamp(11.5px,.95vw,13px);text-transform:uppercase;letter-spacing:.07em;
  color:var(--off);transition:background .3s,color .3s}
.svc-shot:hover .svc-shot-tag{background:var(--accent);color:var(--black)}
.svc-shot img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform .9s cubic-bezier(.2,.7,.2,1)}
.svc-row:hover .svc-shot img{transform:scale(1.05)}

@media(max-width:980px){
  .svc-row{grid-template-columns:1fr 1fr;gap:clamp(20px,3vw,40px)}
  .svc-chips{grid-column:1;align-items:stretch;margin-top:8px}
  .svc-shot{grid-column:2;grid-row:1 / span 2}
}
@media(max-width:680px){
  .svc-row{grid-template-columns:1fr}
  .svc-shot{grid-column:1;grid-row:auto;aspect-ratio:4/3}
  .svc-chips{flex-direction:row;flex-wrap:wrap}
}

/* The archive used to carry a filter pill per category. With roughly one
   project in each, every pill read "1" and narrowed nothing, so the row
   was noise. A plain count says the same thing in one line. */
.arch-count{text-align:center;padding:clamp(20px,3vw,34px) var(--pad) 0;
  font-size:12px;text-transform:uppercase;letter-spacing:.1em;color:var(--dim)}
.arch-hd + .arch-count{padding-top:clamp(18px,2.6vw,30px)}
.arch-count + .arch.mason{padding-top:clamp(30px,5vw,58px)}
