/* ============================================================
   SHARED PROJECT-PAGE TEMPLATE STYLES
   This is the real project.html design (hero parallax mask, the
   "What I Did" horizontal card scroller + progress bar, "The
   Situation" issues list + device shot, "The Results" gallery
   blocks + parallax stat banner) extracted so every /projects/
   page can reuse the exact same look, driven by data instead of
   being hand-written per project. Dead/unused blocks from earlier
   project.html iterations (the old ring-based What I Did, the old
   sit-flow circles, issue hotspot shots) were intentionally left
   out — only the CSS that's actually live on project.html today
   is reproduced here.
   ============================================================ */

:root{
  --ink:#1a1a1a;--ink-60:rgba(26,26,26,.55);--bg:#fff;--bg-off:#f5f5f5;
  --accent:#4caf50;
  --d:"Sora",-apple-system,BlinkMacSystemFont,"SF Pro Display","Segoe UI",sans-serif;
  --b:"Sora",-apple-system,BlinkMacSystemFont,sans-serif;
  --nav-h:72px;--ease:cubic-bezier(.22,1,.36,1);
}
*{margin:0;padding:0;box-sizing:border-box}
/* overflow-x:clip, NOT hidden. `overflow-x:hidden` forces the paired
   overflow-y to compute as `auto`, which turns html/body into scroll
   containers — and that silently breaks every position:sticky descendant,
   including the What I Did pin stage and the sticky subnav. `clip` stops
   horizontal scrolling without creating a scroll container. `hidden` is kept
   first purely as a fallback for engines with no `clip` support. */
html{max-width:100vw;overflow-x:hidden;overflow-x:clip;scroll-behavior:auto!important}
body{background:var(--bg);color:var(--ink);font-family:var(--b);font-size:16px;line-height:1.7;max-width:100vw;overflow-x:hidden;overflow-x:clip;-webkit-font-smoothing:antialiased}
.title{overflow-wrap:break-word}
img{display:block;max-width:100%}a{color:inherit;text-decoration:none}
button{font:inherit;background:none;border:0;cursor:pointer;color:inherit}

/* === NAV === */
.nav{position:fixed;inset:0 0 auto 0;height:var(--nav-h);display:flex;align-items:center;gap:32px;padding:0 48px;z-index:100;background:#c983c4;transition:background .4s var(--ease),backdrop-filter .4s var(--ease),box-shadow .4s var(--ease)}
.nav__logo{width:40px;height:40px;flex:none;color:#fff;transition:color .4s var(--ease)}
.nav__logo svg{width:100%;height:100%;display:block;animation:badgeHue 12s linear infinite}
.nav__spacer{flex:1}
.nav__link{font-size:14px;color:#fff;opacity:.7;transition:opacity .3s,color .4s}.nav__link:hover{opacity:1}
.nav__link.is-active{opacity:1}
.nav__cta{position:relative;display:inline-flex;align-items:center;justify-content:center;height:42px;padding:0 22px;border:1px solid #fff;border-radius:100px;font-size:14px;color:#fff;overflow:hidden;isolation:isolate;transition:color .35s var(--ease),border-color .4s}
.nav__cta::before{content:"";position:absolute;inset:0;background:#fff;transform:translateY(100%);transition:transform .35s var(--ease);z-index:-1;border-radius:inherit}
.nav__cta:hover{color:#111}.nav__cta:hover::before{transform:translateY(0)}
.nav__burger{display:none;width:40px;height:40px;color:#fff;align-items:center;justify-content:center;transition:color .4s;position:relative}
/* Bars morph into an X (rather than swapping to a separate close icon
   elsewhere on screen) driven purely by the aria-expanded attribute
   project-engine.js already sets on click — no extra class needed. */
.nav__burger-bar{position:absolute;left:50%;width:20px;height:2px;background:currentColor;border-radius:2px;transform:translateX(-50%);transition:top .32s var(--ease),transform .32s var(--ease),opacity .2s var(--ease)}
.nav__burger-bar:nth-child(1){top:14px}
.nav__burger-bar:nth-child(2){top:19px}
.nav__burger-bar:nth-child(3){top:24px}
.nav__burger[aria-expanded="true"] .nav__burger-bar:nth-child(1){top:19px;transform:translateX(-50%) rotate(45deg)}
.nav__burger[aria-expanded="true"] .nav__burger-bar:nth-child(2){opacity:0}
.nav__burger[aria-expanded="true"] .nav__burger-bar:nth-child(3){top:19px;transform:translateX(-50%) rotate(-45deg)}
.nav.is-light{background:rgba(255,255,255,.72);backdrop-filter:blur(18px) saturate(1.4);-webkit-backdrop-filter:blur(18px) saturate(1.4);box-shadow:0 1px 0 rgba(0,0,0,.06)}
.nav.is-light .nav__logo,.nav.is-light .nav__burger{color:var(--ink)}
.nav.is-light .nav__link{color:var(--ink);opacity:.7}
.nav.is-light .nav__cta{color:var(--ink);border-color:rgba(0,0,0,.25)}
.nav.is-light .nav__cta::before{background:var(--ink)}
.nav.is-light .nav__cta:hover{color:#fff}
/* === FULL-SCREEN MENU — deveb-style two-column layout ===
   Left column: contact email + a short social list. Right column:
   the site's real nav links, set large like a "menu of pages"
   rather than a small centred list. Nav bar (z-index:100) stays
   visible above this panel (z-index:99) exactly as before. */
/* overflow-y:auto + padding (instead of flex align-items:center) is the
   actual fix for "not responsive": the old 4-link menu always fit, but
   this two-column layout has enough content (email, 3 social links, 4
   big nav links) to be taller than 100vh on a short mobile viewport.
   align-items:center on its own doesn't create a scroll container, and
   worse, centring a flex item taller than its container can push the
   top of the content above scrollTop:0 where it's unreachable — using
   padding to position it instead avoids that trap entirely. */
/* Panel now enters with a slight scale + upward slide alongside the fade
   (rather than a flat opacity swap), and the nav links themselves stagger
   in a beat after that — reads far more considered on the small, single-
   column mobile layout where the flat instant-fade was most noticeable. */
.menu{position:fixed;inset:0;z-index:99;background:#0a0a0a;overflow-y:auto;padding:calc(var(--nav-h) + 56px) 24px 56px;opacity:0;pointer-events:none;transform:translateY(-10px) scale(.99);transition:opacity .4s var(--ease),transform .45s var(--ease)}
.menu.is-open{opacity:1;pointer-events:auto;transform:translateY(0) scale(1)}
.menu__close{position:absolute;top:24px;right:28px;width:44px;height:44px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:#fff;transition:opacity .25s,background .25s}
.menu__close:hover{opacity:.6}
@media(hover:hover){ .menu__close:hover{background:rgba(255,255,255,.10);opacity:1} }
.menu__close:active{background:rgba(255,255,255,.16)}
.menu__close svg{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round}
.menu__inner{width:min(1100px,90vw);margin:0 auto;display:grid;grid-template-columns:1fr minmax(160px,260px);gap:clamp(48px,8vw,140px)}
.menu__label{font-size:13px;letter-spacing:.04em;color:#fff;font-weight:600;margin-bottom:14px}
.menu__label--social{margin-top:36px}
.menu__email{display:block;font-size:15px;color:rgba(255,255,255,.6);font-weight:500;transition:color .25s,opacity .5s var(--ease),transform .5s var(--ease);opacity:0;transform:translateY(10px)}
.menu__email:hover{color:#fff}
.menu__social{display:flex;flex-direction:column;gap:10px;margin-top:2px}
.menu__contact{display:flex;flex-direction:column;align-items:flex-start;gap:8px}
.menu__social a{font-size:15px;color:rgba(255,255,255,.6);font-weight:500;transition:color .25s,opacity .5s var(--ease),transform .5s var(--ease);opacity:0;transform:translateY(10px)}
.menu__social a:hover{color:#fff}
.menu__links{display:flex;flex-direction:column}
.menu__links a{font-family:var(--d);font-weight:500;font-size:clamp(32px,5vw,58px);line-height:1.35;color:#8a8a8a;transition:color .3s,opacity .55s var(--ease),transform .55s var(--ease);opacity:0;transform:translateY(16px)}
.menu__links a:hover{color:#fff}
/* Legacy flat menu markup (about.html / contact.html still put bare <a>
   children straight inside .menu with no .menu__inner wrapper). Give those
   the same treatment as .menu__links a so they stay readable now that the
   panel is black instead of white. */
.menu > a{display:block;font-family:var(--d,var(--font-display,sans-serif));font-weight:500;font-size:clamp(32px,5vw,58px);line-height:1.35;color:#8a8a8a;text-decoration:none;transition:color .3s}
.menu > a:hover{color:#fff}
/* Staggered reveal, nav links leading the eye first (they're the primary
   content), the contact column following a touch behind. Only runs while
   the panel is actually open — closed state stays instant so there's no
   delay/flash the next time it opens. */
.menu.is-open .menu__email,.menu.is-open .menu__social a,.menu.is-open .menu__links a{opacity:1;transform:translateY(0)}
.menu.is-open .menu__links a:nth-child(1){transition-delay:.1s}
.menu.is-open .menu__links a:nth-child(2){transition-delay:.16s}
.menu.is-open .menu__links a:nth-child(3){transition-delay:.22s}
.menu.is-open .menu__links a:nth-child(4){transition-delay:.28s}
.menu.is-open .menu__email{transition-delay:.05s}
.menu.is-open .menu__social a:nth-child(1){transition-delay:.12s}
.menu.is-open .menu__social a:nth-child(2){transition-delay:.17s}
.menu.is-open .menu__social a:nth-child(3){transition-delay:.22s}
@media(max-width:700px){
  .menu__inner{grid-template-columns:1fr;gap:40px}
  .menu__links a{font-size:clamp(28px,9vw,40px)}
  .menu__close{top:18px;right:18px}
}
@media(prefers-reduced-motion:reduce){
  .menu,.menu__email,.menu__social a,.menu__links a{transition:opacity .2s ease!important;transform:none!important}
}

/* === SCROLL PROGRESS BAR === */
.progress-bar{position:fixed;top:0;left:0;height:3px;width:0%;background:var(--accent);z-index:200;transition:width .1s linear}

/* === SHARED === */
.wrap{width:min(1400px,90vw);margin:0 auto}
.wrap--narrow{width:min(920px,88vw);margin:0 auto}
.label{font-size:11px;letter-spacing:.25em;text-transform:uppercase;color:var(--accent);font-weight:600;margin-bottom:16px}
.title{font-family:var(--d);font-weight:700;font-size:clamp(30px,3.8vw,56px);line-height:1.08;letter-spacing:-.035em}
h2.title.fi{position:relative;padding-bottom:.3em}
h2.title.fi::after{content:"";position:absolute;left:50%;bottom:0;width:64px;height:3px;border-radius:2px;background:var(--accent);transform:translateX(-50%) scaleX(0);transform-origin:left center;opacity:0;transition:transform .8s var(--ease) .15s, opacity .4s var(--ease) .15s}
h2.title.fi.is-visible::after{transform:translateX(-50%) scaleX(1);opacity:1}
.body{color:var(--ink-60);font-size:18px;line-height:1.75;max-width:480px}
.body p+p{margin-top:14px}

/* === FADE-IN === */
/* Safety net: if the IntersectionObserver in project-engine.js never
   fires for some reason, this plain CSS animation still forces the
   element visible after 2s so content can never be stuck invisible. */
.fi{opacity:0;transform:translateY(40px);transition:opacity .8s var(--ease),transform .8s var(--ease);animation:fiFallback 0s linear 2s forwards}
@keyframes fiFallback{to{opacity:1;transform:none}}
.fi.is-visible{opacity:1;transform:translateY(0)}
.fi[data-delay="1"]{transition-delay:.12s}
.fi[data-delay="2"]{transition-delay:.24s}
.fi[data-delay="3"]{transition-delay:.36s}
.fi[data-delay="4"]{transition-delay:.48s}
.slide-up{opacity:0;transform:translateY(70px);transition:opacity .9s var(--ease),transform .9s var(--ease)}
.slide-up.is-visible{opacity:1;transform:translateY(0)}

/* === PLACEHOLDERS === */
.ph{background:#d4d4d4;border-radius:16px;overflow:hidden;position:relative}
.ph::after{content:"";position:absolute;inset:0;background:linear-gradient(135deg,rgba(0,0,0,.04),rgba(0,0,0,.08))}
.ph--169{aspect-ratio:16/9;border-radius:20px;box-shadow:0 20px 50px rgba(0,0,0,.12)}
.ph--square{aspect-ratio:1/1;border-radius:16px;box-shadow:0 16px 40px rgba(0,0,0,.12)}
.three-up{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(16px,2.5vw,32px)}
.img-pair{display:grid;grid-template-columns:1fr 1fr;gap:clamp(40px,6vw,96px);align-items:start;margin-top:clamp(56px,8vw,110px)}

/* === iPad-style device mockup — static frame, screenshot pans inside === */
.ipad-hero{position:relative;width:min(900px,88vw);aspect-ratio:4/3;margin:0 auto;border-radius:clamp(12px,1.8vw,20px);background:#0a0a0a;padding:clamp(10px,1.8vw,20px);box-shadow:0 40px 90px rgba(0,0,0,.22)}
/* Camera dot removed along with the rest of the notch treatment. */
.ipad-hero__screen{position:relative;width:100%;height:100%;border-radius:clamp(6px,1vw,10px);overflow:hidden;background:#111}
.ipad-hero__screen img{position:absolute;top:0;left:0;width:100%;height:220%;object-fit:cover;object-position:top center;will-change:transform}

/* Mobile mockup panels — corner radius intentionally tighter than the
   old 30/20px values (less "toy-like", reads more like a real modern
   phone/notch bezel) per a direct ask to make these less rounded. */
.mobile-panel{position:relative;aspect-ratio:1/1.05;border-radius:10px;overflow:hidden}
.mobile-panel--blue{background:#0d3b66}
.mobile-panel--green{background:#1e8449}
.mobile-panel__phone{position:absolute;left:50%;top:10%;transform:translateX(-50%);width:min(360px,82%);height:140%;background:#0a0a0a;border-radius:8px 8px 0 0;padding:9px 9px 0;box-shadow:0 30px 60px rgba(0,0,0,.3)}
.mobile-panel__screen{position:relative;width:100%;height:100%;border-radius:5px 5px 0 0;overflow:hidden;background:#111}
.mobile-panel__screen img{position:absolute;top:0;left:0;width:100%;height:200%;object-fit:cover;object-position:top center;will-change:transform}

/* White sections */
.sec-white{background:#fff;padding:clamp(100px,14vh,180px) 0;position:relative;overflow:hidden}
.sec-white .title{color:var(--ink)}
/* Same top padding The Results uses, so What I Did -> The Situation and
   The Situation -> The Results are the identical gap. */
.sit-section{padding-top:clamp(40px,6vh,64px)}

/* What I Did — horizontal scrollable card row + scroll progress bar */
/* These values only apply in the NON-pinned fallback (reduced motion, or
   fewer than two cards) — .wid-pinned .wid-scroll zeroes them. Kept at the
   site's standard rhythm so the fallback matches every other section. */
.wid-scroll{display:flex;gap:22px;margin-top:clamp(48px,7vh,80px);overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;padding:28px 0 40px max(24px,calc((100vw - min(1400px,90vw))/2))}
.wid-scroll::-webkit-scrollbar{display:none}
.wid-card{flex:0 0 clamp(230px,22vw,280px);background:#fff;border-radius:20px;padding:30px 26px 32px;display:flex;flex-direction:column;align-items:flex-start;text-align:left;box-shadow:0 24px 48px -14px rgba(20,20,20,.16),0 6px 18px rgba(20,20,20,.06);opacity:0;transform:translateX(-30px);transition:opacity .6s var(--ease),transform .6s var(--ease)}
.wid-card.is-visible{opacity:1;transform:translateX(0)}
.wid-card h3{font-family:var(--d);font-weight:700;font-size:18px;margin-top:18px;color:var(--ink);letter-spacing:-.01em}
.wid-card p{font-size:14px;line-height:1.6;color:var(--ink-60);margin-top:8px}
.wid-icon-wrap{width:44px;height:44px;border-radius:12px;background:rgba(76,175,80,.12);display:flex;align-items:center;justify-content:center}
.wid-icon-wrap svg{width:24px;height:24px;stroke:var(--accent);fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.wid-progress-track{width:min(1400px,90vw);margin:4px auto 0;height:4px;border-radius:4px;background:rgba(0,0,0,.08);overflow:hidden}
.wid-progress-track span{display:block;height:100%;width:0%;background:var(--accent);border-radius:4px}

/* The Situation — issues list */
.issues{list-style:none;padding:0;margin-top:8px}
.issue{display:flex;align-items:center;gap:18px;padding:18px 0;border-bottom:1px solid rgba(255,255,255,.12);font-family:var(--d);font-weight:600;font-size:clamp(17px,1.7vw,22px);color:#fff;opacity:0;transform:translateX(-24px);transition:opacity .6s var(--ease),transform .6s var(--ease)}
.issue.is-visible{opacity:1;transform:translateX(0)}
.issues--light .issue{color:var(--ink);border-bottom-color:rgba(0,0,0,.1)}
.issue__x{width:34px;height:34px;flex:none;border-radius:50%;background:rgba(220,60,60,.1);display:flex;align-items:center;justify-content:center}
.issue__x--bang{color:#dc3c3c;font-family:var(--d);font-weight:800;font-size:18px}

/* === HERO — full-viewport parallax banner + device mask === */
.hero{position:relative;min-height:100svh;display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff}
.hero__bg{position:absolute;inset:-25% 0;background-size:cover;background-position:center;will-change:transform}
/* Hero background video, matching the homepage banners. Sits between
   .hero__bg (the still, which stays as the fallback and as the poster
   while the clip loads) and .hero__scrim, so the tint applies to it the
   same way. pointer-events:none keeps it from swallowing clicks meant
   for the hero copy or CTA.
   The iframe sizing is the standard 16:9 cover trick — 177.78vh wide by
   56.25vw tall, centred — because a YouTube embed can't use object-fit.
   A self-hosted <video> can, so it just covers. */
.hero__bgvideo{position:absolute;inset:0;overflow:hidden;pointer-events:none;background:#000;z-index:0}
.hero__bgvideo iframe{position:absolute;top:0;left:50%;width:177.78vh;height:56.25vw;min-width:100%;min-height:100%;transform:translateX(-50%) scale(1.3);transform-origin:top center;border:0}
.hero__bgvideo video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.hero__bgvideo video::-webkit-media-controls{display:none!important}
.hero__bgvideo video::-webkit-media-controls-start-playback-button{display:none!important;-webkit-appearance:none}
/* Flat tint rather than the old three-stop gradient — matches the
   homepage banners. With footage behind it the bright part of the frame
   lands anywhere, so a consistent tint is the only thing that keeps the
   headline legible for a whole clip. */
.hero__scrim{position:absolute;inset:0;background:rgba(0,0,0,.68);z-index:0}
.hero__inner{position:relative;z-index:1;width:min(1400px,90vw);margin:0 auto;padding:calc(var(--nav-h) + 32px) 0 56px;display:grid;grid-template-columns:minmax(0,1fr);align-items:center;gap:36px}
.hero__eyebrow{font-family:var(--d);font-size:13px;letter-spacing:.18em;text-transform:uppercase;color:rgba(255,255,255,.7);margin-bottom:18px;display:flex;gap:12px;align-items:center;flex-wrap:wrap}
.hero__eyebrow span{padding:5px 12px;border:1px solid rgba(255,255,255,.3);border-radius:100px;font-size:11px;letter-spacing:.12em}
/* Client logo in the hero eyebrow, in place of the plain client-name
   text — the source art is already white (see assets/logos/), so no
   filter is needed on the dark hero background. Going-forward
   convention: every new project page's hero__eyebrow should lead with
   <img class="hero__logo" src="../assets/logos/{realfilename}.png" alt="{Client}"
     onerror="this.onerror=null;this.src='../assets/logos/{realfilename}.svg'">
   instead of <strong>{Client}</strong>.
   IMPORTANT: {realfilename} is NOT derived from the project's slug —
   the actual uploaded filenames in assets/logos/ don't follow the
   slug pattern (they use underscores + a "_logo" suffix, e.g.
   "pilkington_logo", and some don't match the company name at all —
   Haçienda's file is "fac51_logo"). Always copy the exact base
   filename from that project's "logo" field in projects-data.json
   rather than assuming a convention; guessing from the slug is what
   caused every logo to 404 across the whole site previously.
   PNG is loaded first, not the SVG, purely so every browser renders
   an identical plain raster with no engine-specific SVG quirks to
   worry about; the .svg is kept only as a last-resort fallback if the
   .png is ever missing.
   The SVGs themselves were re-cropped to a tight viewBox around their
   visible mark (they used to ship with a lot of blank canvas padding,
   which is what made them look oversized and knocked their left edge
   out of line with the H1 below). With that padding gone, height+
   max-width (rather than a plain fixed height) keeps every logo's
   rendered size consistent regardless of how wide or tall its mark is. */
.hero__logo{height:34px;width:auto;max-width:220px;display:block}
.hero .title{color:#fff;font-size:clamp(26px,5.2vw,54px);overflow-wrap:anywhere;hyphens:auto}
.hero .body{color:rgba(255,255,255,.75);margin-top:18px;font-size:clamp(14px,1.6vw,16px);max-width:100%}
.hero__mask{position:relative;width:min(560px,94vw);aspect-ratio:4/3;margin:32px auto 0;border-radius:8px 8px 0 0;overflow:hidden;background:#0a0a0a;padding:14px 14px 0;box-shadow:0 -30px 70px rgba(0,0,0,.35)}
.hero__mask__screen{position:relative;width:100%;height:100%;border-radius:5px 5px 0 0;overflow:hidden;background:#111}
.hero__mask img{position:absolute;top:0;left:0;width:100%;height:230%;object-fit:cover;onjest-position:top center;will-change:transform;transform:translateY(0)}
@media(min-width:901px){
  .hero__inner{grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);gap:clamp(40px,6vw,100px);padding:calc(var(--nav-h) + 40px) 0 60px}
  /* The desktop gradient that used to live here (75% on the left fading
     to 35% on the right) is gone — it sat inside a min-width media query
     and so beat the flat tint set above, meaning the right-hand side of
     every hero stayed pale. With video behind these now, the bright part
     of the frame moves, so the tint has to be even across the whole
     banner. Kept as a comment rather than deleted so it's obvious this
     was removed on purpose. */
  .hero .title{font-size:clamp(32px,3.4vw,56px)}
  .hero__copy{margin-left:clamp(-40px,-3vw,0px);max-width:640px}
  /* Right offset keyed to the wrap's actual edge (like .wid-scroll's
     padding trick below) rather than the full-width .hero, so the
     mask can't grow past the content column and crowd the title on
     wide screens — same balanced text/image split as the homepage
     banners (.banner__inner's grid keeps its image column contained). */
  .hero__mask{position:absolute;right:max(24px,calc((100vw - min(1400px,90vw))/2));bottom:0;width:min(600px,40vw);aspect-ratio:10/9.5;margin:0}
  /* Full-width variant (no right-hand device mock-up) — set by
     project-media-render.js when a project's config has
     hero.layout:"full". Lets the copy column use the full width
     instead of the split 1.25fr/1fr grid. */
  .hero--full .hero__inner{grid-template-columns:minmax(0,1fr)}
  .hero--full .hero__copy{margin-left:0;max-width:820px}
}
.hero__mask--portrait{aspect-ratio:3/4;width:min(420px,80vw)}
.hero__mask--square{aspect-ratio:1/1;width:min(460px,80vw)}
@media(min-width:901px){
  .hero__mask--portrait{width:min(340px,24vw)}
  .hero__mask--square{width:min(380px,26vw)}
}

/* === Two-phone hero variant ("mobile-pair") ===
   Built by project-media-render.js: replaces the single #heroMask
   with a flex row of two .hero__mask elements. Combined-class
   selector (.hero__mask.hero__mask--in-pair) outranks the base
   .hero__mask position/width rules above without needing !important,
   since source order + specificity both favour the more specific
   two-class selector. */
.hero__mask-pair{display:flex;gap:16px;align-items:flex-end;width:min(600px,94vw);margin:32px auto 0}
.hero__mask.hero__mask--in-pair{position:static;margin:0;width:calc(50% - 8px);aspect-ratio:9/14;box-shadow:0 -20px 50px rgba(0,0,0,.3)}
@media(min-width:901px){
  .hero__mask-pair{position:absolute;right:max(24px,calc((100vw - min(1400px,90vw))/2));bottom:0;width:min(560px,38vw);gap:20px;margin:0}
  .hero__mask.hero__mask--in-pair{position:static;width:calc(50% - 10px);aspect-ratio:9/15}
}

/* === RESULTS — configurable media blocks ===
   Built at runtime by assets/project-media-render.js from each
   project's entry in assets/project-media-config.js. Every block
   type below reuses the existing device/image primitives (ph--169,
   ph--square, img-pair, three-up, ipad-hero, mobile-panel) so a
   project's Results section can mix and order them freely instead
   of every page hard-coding the same fixed set of sections. */
.results-block{padding-top:clamp(48px,7vh,80px)}
.ipad-hero--portrait{aspect-ratio:3/4;width:min(520px,80vw)}
.ipad-grid{display:grid;gap:clamp(28px,4vw,56px);grid-template-columns:repeat(var(--cols,2),1fr);align-items:start}
.ipad-grid .ipad-hero{width:100%;margin:0}
.media-grid{display:grid;gap:clamp(16px,2.5vw,32px);grid-template-columns:repeat(var(--cols,3),1fr)}
.results-parallax{position:relative;width:100%;overflow:hidden;aspect-ratio:21/8;margin-top:clamp(48px,7vh,80px)}
.results-parallax img{position:absolute;inset:-15% 0;width:100%;height:130%;object-fit:cover;will-change:transform}
.video-tile{cursor:default}
.video-tile__play{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none}
.video-tile__play svg{width:clamp(40px,5vw,56px);height:clamp(40px,5vw,56px);filter:drop-shadow(0 6px 18px rgba(0,0,0,.35))}
/* Instagram-portrait (4:5) images — a middle ground between the
   standard 16:9 landscape frame and the 1:1 square frame. */
.ph--45{aspect-ratio:4/5;border-radius:18px;box-shadow:0 18px 45px rgba(0,0,0,.12)}

/* === RESULTS — parallax stat banner === */
.pxbanner{position:relative;overflow:hidden;color:#fff}
.pxbanner__bg{position:absolute;inset:-25% 0;background-size:cover;background-position:center;will-change:transform}
.pxbanner__scrim{position:absolute;inset:0;background:rgba(0,0,0,.68)}
.pxbanner .label{color:var(--accent)}
.stat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:clamp(32px,4vw,64px);margin-top:40px}
.stat{text-align:center}
.stat__number{font-family:var(--d);font-weight:700;font-size:clamp(56px,7vw,110px);line-height:1;letter-spacing:-.03em}
.stat__unit{font-size:clamp(24px,3vw,42px);font-weight:400}
.stat__label{margin-top:12px;font-size:15px;color:rgba(255,255,255,.6);max-width:240px;margin-left:auto;margin-right:auto}
.stat--quote{display:flex;flex-direction:column;justify-content:center;align-items:center}
.stat__avatar{width:56px;height:56px;border-radius:50%;background:rgba(255,255,255,.12);display:flex;align-items:center;justify-content:center;margin-bottom:18px;overflow:hidden}
.stat__avatar svg{width:46%;height:46%;stroke:#fff;fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.stat__quote{font-family:var(--d);font-weight:600;font-style:italic;font-size:clamp(17px,1.9vw,21px);line-height:1.5;max-width:280px;margin:0 auto}
.stat__quote-name{margin-top:16px;font-size:14px;color:rgba(255,255,255,.55)}

/* === STICKY RESULTS CTA === */
.results-cta{position:fixed;left:50%;bottom:24px;transform:translate(-50%,120%);z-index:90;display:inline-flex;align-items:center;gap:10px;height:54px;padding:0 30px;background:var(--ink);color:#fff;border-radius:100px;font-family:var(--d);font-weight:600;font-size:14px;box-shadow:0 12px 32px rgba(0,0,0,.35);opacity:0;pointer-events:none;transition:transform .5s var(--ease),opacity .4s var(--ease),background .3s}
.results-cta.is-visible{transform:translate(-50%,0);opacity:1;pointer-events:auto}
.results-cta:hover{background:#000}
.results-cta svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

/* === STICKY SUB-NAV === */
.subnav{position:sticky;top:var(--nav-h);z-index:50;background:rgba(255,255,255,.85);backdrop-filter:blur(14px) saturate(1.3);-webkit-backdrop-filter:blur(14px) saturate(1.3);border-bottom:1px solid rgba(0,0,0,.08)}
.subnav__row{display:flex;gap:28px;overflow-x:auto;padding:16px 0;scrollbar-width:none}
.subnav__row::-webkit-scrollbar{display:none}
.subnav a{flex:none;font-size:13px;color:var(--ink-60);white-space:nowrap;padding:6px 2px;border-bottom:2px solid transparent;transition:color .25s,border-color .25s}
.subnav a:hover{color:var(--ink)}
.subnav a.is-active{color:var(--ink);border-color:var(--accent);font-weight:600}

/* === RELATED PROJECTS === */
.related{padding:clamp(80px,10vw,140px) 0;background:var(--bg-off)}
.related__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:28px;margin-top:40px}
.related__card{--overhang:75px;display:block;border-radius:18px;overflow:hidden;background:#fff;box-shadow:0 16px 40px rgba(0,0,0,.08);transition:transform .4s var(--ease),box-shadow .4s var(--ease)}
.related__card:hover{transform:translateY(-6px);box-shadow:0 24px 56px rgba(0,0,0,.14)}
.related__thumb{position:relative;aspect-ratio:4/3;overflow:hidden}
.related__thumb img{width:100%;height:100%;object-fit:cover}
/* Device mockups on the "More work" cards — same construction as the drawer
   (see drawer.css). .related__thumb is aspect-ratio:4/3 and overflow:hidden, so
   its height scales with card width; a fixed device height drifted and a
   negative bottom offset cut roughly a third off each device. Percentages fix
   both at once. */
.related__thumb-inset{position:absolute;left:50%;bottom:calc(-1 * var(--overhang));transform:translateX(-50%);height:116%;z-index:0;width:auto;box-sizing:border-box;background:#0a0a0a;border:1px solid rgba(255,255,255,.12);box-shadow:0 18px 40px rgba(0,0,0,.55);line-height:0;font-size:0}
.related__thumb-inset img{display:block;height:100%;width:auto;object-fit:cover;object-position:top center}
.related__thumb-inset--phone{border-radius:20px;padding:5px}
/* Phone apertures are 141px shorter than the export (1170x2760 -> 1170x2619).
   The exports have the iOS status bar baked in — 47pt at 3x = 141px — and
   anchoring to the bottom pushes exactly that band above the visible screen,
   so the app content starts flush at the top. Tablet exports have no device
   status bar (what looks like one is the site's own nav), so they keep the
   full 1536x2458 aperture and stay top-anchored.
   A project can override --screen-ratio when its shot isn't a standard export;
   where the override equals the image's own ratio there is no overflow, so the
   bottom anchor has nothing to crop and the whole shot shows. */
.related__thumb-inset--phone img{aspect-ratio:var(--screen-ratio,1170/2619);object-position:center bottom;border-radius:15px}
.related__thumb-inset--tablet{border-radius:13px;padding:5px}
.related__thumb-inset--tablet img{aspect-ratio:var(--screen-ratio,1536/2458);border-radius:9px}
/* Poster variant — printed/flat artwork rather than a screen, so no bezel:
   just the artwork with rounded corners and the same shadow. */
.related__thumb-inset--poster{border-radius:14px;padding:0;background:transparent;border:0}
.related__thumb-inset--poster img{aspect-ratio:var(--screen-ratio,3/4);border-radius:14px;object-position:top center}

/* Right-hand hero image (device mockup/poster) as a floating inset card,
   same treatment as the Projects-drawer tiles (.pdrawer__thumb-inset) —
   only rendered when the project has one (projects-data.json "heroImg"). */
.related__body{padding:20px 22px 24px}
.related__company{font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--accent);font-weight:600}
.related__title{font-family:var(--d);font-weight:600;font-size:19px;margin-top:6px}

/* === PREV / NEXT FOOTER NAV === */
.pn{display:grid;grid-template-columns:1fr 1fr;border-top:1px solid rgba(0,0,0,.08)}
.pn__link{display:flex;flex-direction:column;padding:44px 48px;gap:8px;transition:background .3s}
.pn__link:hover{background:var(--bg-off)}
.pn__link--next{text-align:right;align-items:flex-end;border-left:1px solid rgba(0,0,0,.08)}
.pn__eyebrow{font-size:11px;letter-spacing:.15em;text-transform:uppercase;color:var(--ink-60)}
.pn__name{font-family:var(--d);font-weight:600;font-size:22px}

/* === FOOTER (shared, fetched from footer.html) === */
@keyframes badgeHue{0%{filter:sepia(.45) saturate(1.8) hue-rotate(0deg)}50%{filter:sepia(.45) saturate(1.8) hue-rotate(180deg)}100%{filter:sepia(.45) saturate(1.8) hue-rotate(360deg)}}
/* Pink "let's work together" bar above the black footer. Copy sits
   left, the three contact actions sit right, all on a single row.
   .footer-signup__inner repeats the black footer's exact container
   (max-width:1400px, centred, inside the same 24px section padding)
   so the copy starts on the same vertical line as the footer blurb
   below it and the WhatsApp button ends on the same line as the
   social links — without it the bar ran full-bleed to the section
   padding while the footer stayed boxed, so the two never lined up
   on anything wider than 1400px. */
.footer-signup{background:#c983c4;color:#fff;padding:clamp(48px,8vh,80px) 24px}
.footer-signup__inner{max-width:1400px;margin:0 auto;width:100%;display:flex;flex-direction:column;align-items:center;text-align:center;gap:clamp(20px,3vw,30px)}
.footer-signup__copy{font-family:var(--d);font-size:clamp(21px,2.9vw,38px);font-weight:600;letter-spacing:-.02em;line-height:1.15;margin:0}
.footer-signup__actions{display:flex;align-items:center;gap:20px;flex:none}
.footer-signup__btn{display:inline-flex;align-items:center;height:60px;padding:0 36px;border-radius:100px;border:1px solid rgba(255,255,255,.65);background:transparent;color:#fff;font-size:15px;font-weight:600;white-space:nowrap;cursor:pointer;transition:background .3s,color .3s;font-family:inherit;text-decoration:none}
.footer-signup__btn:hover{background:#fff;color:#c983c4}
.footer-signup__phone{color:#fff;font-size:16px;font-weight:600;white-space:nowrap;text-decoration:none;opacity:.9;transition:opacity .3s}
.footer-signup__phone:hover{opacity:1;text-decoration:underline}
.footer-signup__whatsapp{display:inline-flex;align-items:center;justify-content:center;width:56px;height:56px;border-radius:50%;border:1px solid rgba(255,255,255,.65);color:#fff;flex:none;transition:background .3s,color .3s}
.footer-signup__whatsapp:hover{background:#fff;color:#c983c4}
.footer-signup__whatsapp svg{width:27px;height:27px}
/* Below ~1100px the one-line row would force the copy to shrink past
   the point it reads as a headline, so it breaks to two stacked rows
   (still left-aligned, still on the same container edges) before the
   full centred mobile treatment kicks in at 800px. */
.footer{background:#000;color:#fff;padding:clamp(56px,9vh,96px) 24px 32px;display:flex;flex-direction:column;gap:48px}
.footer__top{display:flex;flex-direction:column;align-items:center;text-align:center;gap:clamp(28px,4vw,44px);max-width:1400px;margin:0 auto;width:100%}
.footer__col{display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px}
.footer__col--links{align-items:center;text-align:center}
.footer__blurb{max-width:420px;font-size:14px;line-height:1.6;color:rgba(255,255,255,.65);margin:0 0 6px}
.footer__link{font-size:14px;color:rgba(255,255,255,.85);text-decoration:underline;text-underline-offset:3px;width:fit-content}
.footer__link:hover{color:#fff}
.footer__wordmark{color:#fff;justify-self:center}
.footer__wordmark svg{width:clamp(220px,26vw,420px);height:auto;display:block}
.footer__social{display:flex;flex-direction:row;justify-content:center;gap:20px}
.footer__social a{font-size:14px;color:rgba(255,255,255,.85);text-decoration:underline;text-underline-offset:3px}
.footer__social a:hover{color:#fff}
/* Icon variant of the footer socials. The underline and font-size from the
   text version would otherwise apply to the anchors wrapping the SVGs. */
.footer__social--icons{gap:16px}
.footer__social--icons a{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:50%;text-decoration:none;color:rgba(255,255,255,.85);background:rgba(255,255,255,.08);transition:background .25s,color .25s,transform .25s}
.footer__social--icons a:hover{background:#fff;color:#111;transform:translateY(-2px)}
.footer__social--icons svg{width:18px;height:18px;display:block}

.footer__meta{max-width:1400px;margin:0 auto;width:100%;display:flex;flex-direction:column;align-items:center;text-align:center;gap:6px;justify-content:center;font-size:11px;letter-spacing:.02em;color:rgba(255,255,255,.4)}
@media(max-width:800px){
  .footer-signup__actions{justify-content:center;width:100%;flex-wrap:wrap;gap:16px}
  .footer-signup__btn{height:54px;padding:0 30px}
  .footer-signup__whatsapp{width:50px;height:50px}
}
.back-to-top{position:fixed;right:32px;bottom:32px;width:52px;height:52px;border-radius:50%;background:var(--ink);color:#fff;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transform:translateY(10px);transition:opacity .3s,transform .3s;z-index:80}
.back-to-top.is-visible{opacity:1;pointer-events:auto;transform:translateY(0)}
.back-to-top svg{width:20px;height:20px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

/* === FILTER GRID (projects.html) === */
.filters{position:sticky;top:var(--nav-h);z-index:50;background:rgba(255,255,255,.9);backdrop-filter:blur(14px) saturate(1.3);-webkit-backdrop-filter:blur(14px) saturate(1.3);border-bottom:1px solid rgba(0,0,0,.08);padding:20px 0}
.filters__row{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
.chip{padding:9px 18px;border-radius:100px;border:1px solid rgba(0,0,0,.15);font-size:13.5px;color:var(--ink-60);transition:all .25s var(--ease)}
.chip:hover{border-color:var(--ink)}
.chip.is-active{background:var(--ink);color:#fff;border-color:var(--ink)}
.select-wrap{position:relative;display:inline-flex;align-items:center}
.filter-select{appearance:none;-webkit-appearance:none;-moz-appearance:none;padding:11px 42px 11px 20px;border-radius:100px;border:1px solid rgba(0,0,0,.15);font-size:13.5px;font-family:var(--b);color:var(--ink);background:#fff;cursor:pointer;transition:border-color .25s var(--ease)}
.filter-select:hover{border-color:var(--ink)}
.filter-select:focus{outline:none;border-color:var(--ink)}
.select-arrow{position:absolute;right:16px;top:50%;transform:translateY(-50%);width:14px;height:14px;stroke:var(--ink-60);pointer-events:none}
.search{margin-left:auto;position:relative}
.search input{width:min(260px,50vw);padding:9px 16px 9px 38px;border-radius:100px;border:1px solid rgba(0,0,0,.15);font-size:13.5px;font-family:var(--b);background:#fff}
.search input:focus{outline:none;border-color:var(--ink)}
.search svg{position:absolute;left:13px;top:50%;transform:translateY(-50%);width:15px;height:15px;stroke:var(--ink-60);fill:none;stroke-width:2}
.pgrid{padding:60px 0 140px}
.pgrid__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:32px}
.pgrid__card{display:block;border-radius:20px;overflow:hidden;background:#fff;box-shadow:0 16px 40px rgba(0,0,0,.08);transition:transform .45s var(--ease),box-shadow .45s var(--ease)}
.pgrid__card:hover{transform:translateY(-8px);box-shadow:0 30px 64px rgba(0,0,0,.16)}
.pgrid__thumb{aspect-ratio:4/3;overflow:hidden}
.pgrid__thumb img{width:100%;height:100%;object-fit:cover;transition:transform .6s var(--ease)}
.pgrid__card:hover .pgrid__thumb img{transform:scale(1.06)}
.pgrid__body{padding:22px 24px 26px}
.pgrid__tags{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px}
.pgrid__tags span{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--accent);background:rgba(76,175,80,.1);padding:4px 10px;border-radius:100px}
.pgrid__company{font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-60);font-weight:600}
.pgrid__title{font-family:var(--d);font-weight:600;font-size:21px;margin-top:6px}
.pgrid__empty{text-align:center;padding:100px 0;color:var(--ink-60);display:none}
.pgrid__empty.is-visible{display:block}
.page-hero{padding:calc(var(--nav-h) + 80px) 0 60px}
.page-hero .title{color:var(--ink)}

/* === BACK BUTTON (project detail pages) === */
/* position:absolute (not fixed) so it scrolls away with the hero
   instead of staying pinned over the sticky subnav further down the
   page — back-btn has no positioned ancestor, so its containing
   block is the document itself, giving "sits near the top, scrolls
   with the page" rather than "stuck to the viewport forever". */
.back-btn{position:absolute;top:calc(var(--nav-h) + 20px);left:24px;z-index:90;display:inline-flex;align-items:center;gap:8px;padding:10px 18px 10px 14px;border-radius:100px;background:rgba(255,255,255,.92);backdrop-filter:blur(10px) saturate(1.3);-webkit-backdrop-filter:blur(10px) saturate(1.3);box-shadow:0 8px 24px rgba(0,0,0,.14);color:var(--ink);font-family:var(--d);font-size:13.5px;font-weight:600;transition:transform .25s var(--ease),box-shadow .25s}
.back-btn:hover{transform:translateX(-3px);box-shadow:0 12px 30px rgba(0,0,0,.2)}
.back-btn svg{width:16px;height:16px;flex:none}
@media(max-width:600px){
  .back-btn{top:calc(var(--nav-h) + 14px);left:16px;padding:8px 14px 8px 10px;font-size:12.5px}
  .back-btn svg{width:14px;height:14px}
}

/* === CONTACT PAGE === */
.contact-main{padding:60px 0 160px}
.contact-main__inner{text-align:center}
.contact-email{display:inline-block;font-family:var(--d);font-weight:700;font-size:clamp(30px,6vw,60px);letter-spacing:-.03em;color:var(--ink);border-bottom:2px solid rgba(0,0,0,.12);padding-bottom:10px;transition:border-color .3s var(--ease),opacity .3s;word-break:break-word}
.contact-email:hover{border-color:var(--ink);opacity:.75}
.contact-meta{margin-top:44px;display:flex;flex-direction:column;align-items:center;gap:22px;color:var(--ink-60);font-size:14px}
.contact-social{display:flex;gap:26px}
.contact-social a{opacity:.75;transition:opacity .3s}
.contact-social a:hover{opacity:1}
.contact-social svg{width:18px;height:18px;fill:var(--ink)}

/* === PAGE TRANSITION OVERLAY (GSAP-driven) === */
.pt-overlay{position:fixed;inset:0;background:var(--ink);z-index:300;transform:translateY(101%);pointer-events:none}

@media(max-width:900px){
  .nav{padding:0 20px;gap:14px}.nav__link,.nav__cta{display:none}.nav__burger{display:flex}
  .nav__link[data-drawer-tab]{display:inline-flex;font-size:13px}
  .title{font-size:clamp(24px,6vw,34px)}
  .hero__copy{margin-left:0}
  .hero__inner{padding-top:calc(var(--nav-h) + 74px)}
  .sit-section{padding-top:18px}
  .issues{margin-top:4px}
  .issue{font-size:15px;gap:12px;padding:13px 0}
  .issue__x{width:28px;height:28px}
  .img-pair{grid-template-columns:1fr!important}
  .img-pair>div{margin-top:0!important}
  .stat-grid{grid-template-columns:1fr;gap:36px}
  .stat__number{font-size:clamp(48px,14vw,72px)}
  .three-up{grid-template-columns:1fr!important}
  .media-grid{grid-template-columns:repeat(2,1fr)!important}
  .results-parallax{aspect-ratio:4/5;margin-top:clamp(32px,6vw,48px)}
  .ipad-hero--portrait{width:80vw}
  .ipad-grid{grid-template-columns:1fr!important;gap:clamp(48px,10vw,72px)}
  .related__grid{grid-template-columns:1fr}
  .pgrid__grid{grid-template-columns:1fr 1fr}
  .pn{grid-template-columns:1fr}
  .pn__link--next{border-left:0;border-top:1px solid rgba(0,0,0,.08);text-align:left;align-items:flex-start}
  .back-to-top{right:16px;bottom:16px;width:44px;height:44px}
  .subnav__row{gap:18px}
  .search input{width:44vw}
}
@media(max-width:480px){ .hero__inner{width:88vw} }
@media(max-width:600px){
  .pgrid__grid{grid-template-columns:1fr}
  .search{width:100%;margin-left:0;margin-top:12px;order:10}
  .filters__row{gap:8px}
  .select-wrap{width:100%}
  .filter-select{width:100%}
  .media-grid{grid-template-columns:1fr!important}
}
@media(prefers-reduced-motion:reduce){
  .fi,.slide-up{opacity:1!important;transform:none!important;transition:none!important}
  .hero__bg,.pxbanner__bg{inset:0!important}
  .nav__logo svg{animation:none;filter:none}
  .issue{opacity:1!important;transform:none!important;transition:none!important}
  .wid-card{opacity:1!important;transform:none!important;transition:none!important}
}

/* ---- Mobile hero backgrounds ----------------------------------------------
   Portrait 393x852 exports, one per project, set as --hero-bg-mobile on the
   hero element itself so there's one rule here rather than a media query in
   every page.

   inset is reset to 0 on mobile. The desktop .hero__bg is inset:-25% 0, i.e.
   150% tall, to give the parallax somewhere to travel — but that makes the box
   ~0.31 wide/tall, and a 0.461 portrait image dropped into it loses about a
   third of its width to cover(). Removing the overscan makes the box match the
   artwork, so these land exactly as composed. Parallax is off on mobile as a
   consequence, which is the right trade for a full-bleed phone hero.

   The bg video is hidden only where a mobile still exists, so pages without
   one (Bill Brewster, Hidden) keep their video. */
@media(max-width:700px){
  .hero--mobile-img .hero__bg{inset:0;background-image:var(--hero-bg-mobile);background-size:cover;background-position:center;background-repeat:no-repeat;transform:none!important;will-change:auto}
  .hero--mobile-img .hero__bgvideo{display:none}
}

/* Bill Brewster's hero clip is framed low, so it's nudged up 200px. Only `top`
   is touched — the iframe's width/height pair must stay exactly 16:9 or
   YouTube letterboxes the clip and black bars appear at the seams. */
.hero__bgvideo--up200 iframe{top:-200px}

/* ABB's hero clip has words burnt into the top-left of the frame. The shared
   rule scales from top center, so it only ever crops the bottom and those
   words survived. Re-anchoring to the centre and zooming harder pushes them
   outside the visible frame on all four sides. The width/height pair is still
   exactly 16:9 — only the transform changes, so YouTube won't letterbox. */
.hero__bgvideo--zoom iframe{top:50%;transform:translate(-50%,-50%) scale(2.3);transform-origin:center center}
/* 2.3x, up from 1.75 — at 1.75 the burnt-in caption in the top-left of the
   ABB clip was still inside the visible frame. The width/height pair stays
   exactly 16:9 so YouTube still will not letterbox it. */

/* Glass pill nav buttons + social icons (matches index.html). */
.nav__cta{height:46px;padding:0 26px;border:1px solid rgba(255,255,255,.35);border-radius:100px;font-size:16px;font-weight:500;letter-spacing:-.01em;color:#fff;background:rgba(255,255,255,.12);backdrop-filter:blur(14px) saturate(1.4);-webkit-backdrop-filter:blur(14px) saturate(1.4);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 6px 18px rgba(0,0,0,.14);display:inline-flex;align-items:center;justify-content:center;transition:color .35s,background .35s,border-color .4s}
.nav__cta--book{background:#0a0a0a;border-color:rgba(255,255,255,.18);color:#fff;box-shadow:inset 0 1px 0 rgba(255,255,255,.12),0 6px 18px rgba(0,0,0,.3)}
.nav__social{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%;color:#fff;background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.28);backdrop-filter:blur(14px) saturate(1.4);-webkit-backdrop-filter:blur(14px) saturate(1.4);transition:background .25s,color .25s,transform .25s}
.nav__social:hover{background:#fff;color:#111;transform:translateY(-2px)}
.nav__social svg{width:18px;height:18px;display:block}
.nav__link{font-size:16px;font-weight:500;letter-spacing:-.01em}
@media(max-width:900px){.nav__social,.nav__cta--book{display:none}}

/* Light frosted nav (matches index.html). */
.nav{background:rgba(255,255,255,.72);backdrop-filter:blur(20px) saturate(1.6);-webkit-backdrop-filter:blur(20px) saturate(1.6);border-bottom:1px solid rgba(0,0,0,.06)}
.nav__logo,.nav__burger{color:var(--ink,#111)}
.nav__link{color:var(--ink,#111);opacity:.85}
.nav__cta{height:44px;padding:0 24px;border:1px solid rgba(0,0,0,.14);border-radius:100px;font-size:16px;font-weight:500;color:var(--ink,#111);background:rgba(255,255,255,.5);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px)}
.nav__cta--book{background:#0a0a0a;border-color:#0a0a0a;color:#fff;box-shadow:0 6px 18px rgba(0,0,0,.22)}
.nav__cta--book:hover{background:#000;color:#fff}
.nav__social{color:var(--ink,#111);background:rgba(0,0,0,.05);border:1px solid rgba(0,0,0,.10)}
.nav__social:hover{background:#0a0a0a;color:#fff}

/* Proportional overshoot so baked-in edge pixels never show (see index.html). */
/* Videos can keep the scale overshoot; still images can NOT, because the
   parallax script writes an inline transform on .js-parallax-img that wipes
   it. Those get a left/width overshoot in each page instead. Several exports
   have a pure-white 3-4px edge baked in (both Palmers phones, the Palmers and
   Pilkington iPads), which showed as a white line down the mockup. */
.iphone-flat__screen video,.poster-card video{transform:scale(1.04);transform-origin:center center}

/* Floating rounded nav bar (matches index.html) — inset from the edges, not
   full-bleed, with larger type. The --book rules are written with extra
   specificity because .nav.is-light .nav__cta would otherwise win and make the
   black pill's label dark-on-dark. */
.nav{position:fixed;inset:0 0 auto 0;transform:none;width:auto;height:var(--nav-h,72px);display:flex;align-items:center;gap:28px;padding:0 48px;z-index:100;background:rgba(255,255,255,.74);backdrop-filter:blur(22px) saturate(1.7);-webkit-backdrop-filter:blur(22px) saturate(1.7);border:0;border-bottom:1px solid rgba(0,0,0,.07);border-radius:0;box-shadow:0 4px 24px rgba(0,0,0,.06)}
.nav__link{font-size:18px;font-weight:500;letter-spacing:-.015em;color:var(--ink,#111);opacity:.9}
.nav__cta{height:46px;padding:0 26px;font-size:18px;letter-spacing:-.015em}
.nav .nav__cta--book,.nav.is-light .nav__cta--book{background:#0a0a0a;border-color:#0a0a0a;color:#fff}
.nav .nav__cta--book:hover,.nav.is-light .nav__cta--book:hover{background:#000;color:#fff}
@media(max-width:900px){.nav{padding:0 16px;gap:12px}}

@media(max-width:900px){
  /* Mobile nav carries only Projects and Clients plus the burger. */
  .nav__link,.nav__cta,.nav__social{display:none}
  .nav__link[data-drawer-tab]{display:inline-flex;font-size:15px;font-weight:500;opacity:1}
  .nav__burger{display:flex}
}

/* ---- Footer CTA band + footer -------------------------------------------
   Full-bleed orange band with centred copy and one black pill, then a black
   footer whose links are pills grouped into FOLLOW / CONTACT / LEGAL, with the
   Satch wordmark set large across the bottom. */
.cta-band{background:#FF4A17;color:#0a0a0a;padding:clamp(72px,12vh,140px) 24px;text-align:center}
.cta-band__pill{display:inline-flex;align-items:center;padding:8px 20px;margin-bottom:clamp(20px,3vh,32px);border:1px solid #0a0a0a;border-radius:100px;font-size:12px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:#0a0a0a}
.cta-band__inner{width:min(1100px,92vw);margin:0 auto}
.cta-band__copy{font-family:var(--font-display,var(--d,sans-serif));font-weight:500;letter-spacing:-.03em;line-height:1.15;font-size:clamp(28px,4.4vw,56px);margin:0 0 clamp(28px,4vh,44px);color:#0a0a0a}
.cta-band__btn{display:inline-flex;align-items:center;justify-content:center;height:52px;padding:0 34px;border-radius:100px;background:#0a0a0a;color:#fff;font-size:17px;font-weight:500;letter-spacing:-.01em;text-decoration:none;transition:transform .25s var(--ease,ease),box-shadow .25s}
.cta-band__btn:hover{transform:translateY(-2px);box-shadow:0 12px 28px rgba(0,0,0,.28)}

.footer{background:#000;color:#fff;padding:clamp(48px,7vh,72px) 0 0;overflow:hidden}
.footer__grid{width:min(1560px,92vw);margin:0 auto;display:grid;grid-template-columns:1.4fr 1.2fr 1fr;gap:clamp(24px,3vw,48px);padding-top:clamp(24px,4vh,40px);border-top:1px solid rgba(255,255,255,.28)}
.footer__col{display:flex;flex-direction:column;align-items:flex-start;gap:10px;min-width:0}
.footer__col--copyright{font-size:13px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:rgba(255,255,255,.85)}
.footer__label{font-size:13px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:rgba(255,255,255,.55);margin-bottom:4px}
.footer__pill{display:inline-flex;align-items:center;max-width:100%;padding:9px 18px;border-radius:100px;background:#c9c9c9;color:#0a0a0a;font-size:15px;line-height:1.2;text-decoration:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:background .25s,color .25s,transform .25s}
.footer__pill:hover{background:#fff;transform:translateY(-2px)}
.footer__wordmark{margin-top:clamp(40px,7vh,80px);padding:0 2vw clamp(10px,2vh,24px);color:#fff;line-height:0;text-align:center}
.footer__wordmark svg{width:clamp(220px,26vw,420px);height:auto;display:inline-block}
@media(max-width:900px){
  .footer__grid{grid-template-columns:1fr 1fr;gap:28px 20px}
  .footer__col--copyright{grid-column:1 / -1;order:3;padding-top:8px}
  .footer__pill{font-size:14px;padding:8px 15px}
}
@media(max-width:520px){
  .footer__grid{grid-template-columns:1fr}
  .cta-band__copy br{display:none}
}

/* ==========================================================================
   PROJECT HERO BANNER — identical to the homepage banner scroller
   --------------------------------------------------------------------------
   Lifted verbatim from index.html's .banner block so a case-study hero and
   its counterpart on the homepage are the same component: same two-column
   grid, same scrim, same device frames, same 200px/125px drop, same mobile
   behaviour (device on top, black copy panel sat on the bottom edge).

   The ONE difference is position: on the homepage each banner is
   position:sticky inside a taller .banner-slot so it pins while the next one
   slides over it. A project page has a single hero and no stack, so
   .banner--static makes it position:relative instead. Nothing else changes —
   which is the point: restyle the homepage banner and this follows.
   ========================================================================== */
.banner{position:relative;height:100vh;height:100svh;overflow:hidden;background:#000}
.banner--static{position:relative}
.banner__bg{position:absolute;inset:0;background-size:cover;background-position:center}
.banner__bg--mobile{display:none}
.banner__bgvideo{position:absolute;inset:0;overflow:hidden;pointer-events:none;background:#000}
.banner__bgvideo video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.banner__bgvideo iframe{position:absolute;top:50%;left:50%;width:177.78vh;height:56.25vw;min-width:100%;min-height:100%;transform:translate(-50%,-50%) scale(1.02);border:0;pointer-events:none}
.banner__scrim{position:absolute;inset:0;background:rgba(0,0,0,.68)}
.banner__inner{
  position:relative;height:100%;
  width:min(1500px,94vw);margin:0 auto;
  display:grid;grid-template-columns:minmax(0,460px) minmax(0,1fr);
  align-items:center;gap:clamp(24px,4vw,80px);
  padding-top:var(--nav-h,72px);
}
.banner__text{color:#fff}
.banner__logo{height:clamp(32px,3.6vw,50px);width:auto;max-width:230px;object-fit:contain;object-position:left center;margin-bottom:20px;display:block}
.banner__title{font-family:var(--font-display,var(--d,sans-serif));font-weight:700;font-size:clamp(22px,2.4vw,38px);line-height:1.12;letter-spacing:-.025em;color:#fff;margin:0}
.banner__copy{margin-top:18px;max-width:400px;color:rgba(255,255,255,.85);font-size:16px;line-height:1.75}
.banner__actions{margin-top:32px;display:flex;align-items:center;gap:16px}
.banner__cta{display:inline-flex;align-items:center;justify-content:center;height:52px;padding:0 40px;border:1px solid rgba(255,255,255,.7);border-radius:100px;color:#fff;font-size:14px;text-decoration:none;position:relative;overflow:hidden;isolation:isolate;transition:color .35s var(--ease,ease)}
.banner__cta::before{content:"";position:absolute;inset:0;z-index:-1;background:#fff;transform:translateY(100%);transition:transform .35s var(--ease,ease);border-radius:inherit}
.banner__cta:hover{color:var(--ink,#111)}
.banner__cta:hover::before{transform:translateY(0)}

/* Device imagery — desktop. .banner__device is align-self:stretch, so an
   absolutely positioned frame inside it measures from the top of the text
   column (i.e. the client logo's line) and is then dropped by top:. */
.banner__device{position:relative;align-self:stretch;display:flex;align-items:flex-end;justify-content:center}
.banner__phone{position:absolute;top:200px;left:50%;transform:translateX(-50%);width:min(470px,35vw);background:#0a0a0a;border-radius:44px;padding:11px;box-shadow:0 40px 90px rgba(0,0,0,.5);border:1px solid rgba(255,255,255,.10);margin:0}
.banner__phone-screen{position:relative;width:100%;aspect-ratio:var(--shot-ratio,1170/2300);border-radius:34px;overflow:hidden;background:#0a0a0a}
.banner__phone-screen::before{content:"";position:absolute;top:0;left:50%;transform:translateX(-50%);width:40%;height:30px;background:#0a0a0a;border-radius:0 0 16px 16px;z-index:2}
.banner__tablet{position:absolute;top:125px;left:50%;transform:translateX(-50%);width:min(960px,62vw,calc(92svh - 115px));background:#0a0a0a;border-radius:22px;padding:13px;box-shadow:0 40px 90px rgba(0,0,0,.5);border:1px solid rgba(255,255,255,.10);margin:0}
.banner__tablet .banner__phone-screen{aspect-ratio:3/4;border-radius:8px}
.banner__tablet.banner__phone--video .banner__phone-screen{aspect-ratio:var(--shot-ratio,1586/1950)}
.banner__tablet .banner__phone-screen::before{display:none}
.banner__phone-screen img.banner__capture{width:calc(100% + 2px);height:auto;object-fit:unset;top:-1px;left:-1px;bottom:auto}
.banner__mockup{max-height:100%;width:auto;max-width:100%;object-fit:contain;object-position:bottom center;align-self:flex-end;display:block}
/* scale(1.04) crops ~2% a side at any render size, so dirty baked-in edge
   pixels in the source clips never show as a hairline inside the bezel. */
.banner__phone-screen img,.banner__phone-screen video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:top center;display:block;transform:scale(1.04);transform-origin:center center}
.banner__phone .banner__phone-screen{aspect-ratio:var(--shot-ratio,888/1920)}
.banner__phone-screen video::-webkit-media-controls{display:none!important}
.banner__phone-screen video::-webkit-media-controls-start-playback-button{display:none!important;-webkit-appearance:none}
.banner__phone-screen::after{content:"";position:absolute;bottom:7px;left:50%;transform:translateX(-50%);width:32%;height:4px;border-radius:3px;background:rgba(0,0,0,.2);z-index:2}

@media(max-width:900px){
  /* MOBILE HERO BANNER — device sizing lifted straight from the homepage
     banner scroller (index.html), so a project's hero mockup and that same
     project's homepage banner are identical:
       phone   width:min(62vw,244px)   radius 34px   bezel 9px
       tablet  width:min(84vw,330px)   radius 22px   bezel 13px
     Order stays copy-first / mockup-underneath (the project-page convention),
     unlike the homepage's device-first stack.
     The drawn body — dark shell, hairline border, deep shadow — is restated
     explicitly here because an earlier revision stripped it back to a
     frameless 100vw screen; the mockup has to read as a device. */
  .banner__bg--desktop{display:none}
  .banner__bg--mobile{display:block}
  /* min-height, so the section grows to fit the whole framed device rather
     than slicing it; the small negative margin below still lets the base
     bleed off the bottom edge the way the homepage banners do. */
  .banner{height:auto;min-height:100vh;min-height:100svh}
  .banner__inner{grid-template-columns:1fr;grid-template-rows:auto auto;align-content:space-between;gap:0;padding:calc(var(--nav-h,72px) + 74px) 6vw 0}
  .banner__text{order:1;align-self:start;background:none;margin:0;width:auto;padding:0 0 clamp(24px,4vh,40px)}
  .banner__text .banner__logo{margin-bottom:16px}
  .banner__title{font-size:clamp(24px,6.4vw,34px)}
  .banner__copy{margin-top:14px;max-width:none}
  .banner__actions{margin-top:22px}
  .banner__cta{height:46px;padding:0 30px}
  /* Stays inside the 6vw gutter — NOT the old 100vw full bleed — so the
     frame is visible down both sides. */
  .banner__device{order:2;align-self:end;width:auto;max-width:100%;margin:0 auto calc(-1 * clamp(18px,3vh,34px));height:auto;min-height:0;padding:0;overflow:visible;display:flex;align-items:flex-end;justify-content:center}
  .banner__phone{position:static;transform:none;width:min(62vw,244px);max-width:none;height:auto;margin:0 auto;background:#0a0a0a;border:1px solid rgba(255,255,255,.10);box-shadow:0 40px 90px rgba(0,0,0,.5);border-radius:34px;padding:9px}
  .banner__phone .banner__phone-screen{height:auto;width:100%;max-height:none;border-radius:26px}
  .banner__tablet{position:static;transform:none;width:min(84vw,330px);max-width:none;height:auto;margin:0 auto;background:#0a0a0a;border:1px solid rgba(255,255,255,.10);box-shadow:0 40px 90px rgba(0,0,0,.5);border-radius:22px;padding:13px}
  .banner__tablet .banner__phone-screen{height:auto;width:100%;max-height:none;border-radius:8px}
  /* Per-project widths, matched one-for-one to the homepage banner overrides. */
  .banner--hacienda .banner__tablet,.banner--the-hacienda .banner__tablet{width:min(90vw,352px)}
  .banner--ig-galaxy .banner__phone{width:min(66vw,258px)}
  .banner__mockup{width:auto;max-width:78vw;max-height:none;margin:0 auto}
}

/* ==============================================================
   "WHAT I DID" — SCROLL-PINNED HORIZONTAL TRACK  (live rules)
   ============================================================== */
.wid-pinned #whatidid{overflow:clip}
.wid-pin{position:relative}
.wid-pin__stage{position:sticky;top:0;height:100vh;height:100svh;display:flex;flex-direction:column;justify-content:center;overflow:hidden}
.wid-pinned .wid-scroll{overflow:visible;margin-top:0;padding-top:0;padding-bottom:clamp(20px,4vh,36px);will-change:transform}
.wid-pinned .wid-card{opacity:1;transform:none;transition:none}
.wid-pinned .wid-progress-track{flex:none}

/* Dark "What I Did" cards — carried over from the deployed stylesheet so this
   file is a superset of it and can't regress the card styling. */
.wid-card{background:#0a0a0a;box-shadow:0 24px 48px -14px rgba(0,0,0,.45),0 6px 18px rgba(0,0,0,.25)}
.wid-card h3{color:#fff}
.wid-card p{color:rgba(255,255,255,.72)}
.wid-icon-wrap{background:rgba(255,255,255,.10)}
.wid-icon-wrap svg{stroke:#fff}
