  /* ================================================================
     Instrument Serif — self-hosted (SIL Open Font License 1.1) so the
     page has no third-party requests at all and never flashes an
     unstyled fallback. Used only for display moments: the ethos
     statement, project names, quotes and big figures.
     ================================================================ */
  @font-face{
    font-family:"Instrument Serif";
    /* relative to THIS stylesheet (assets/site.css), not to the page */
    src:url("fonts/instrument-serif-latin.woff2") format("woff2");
    font-weight:400; font-style:normal; font-display:swap;
    unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
  }

  :root{
    --bg:#ffffff;
    --fg:#0a0a0a;
    --fg-muted:#6e6e73;
    --fg-faint:#a1a1a6;
    --hairline:rgba(10,10,10,.14);
    --hairline-soft:rgba(10,10,10,.07);
    --glass:rgba(255,255,255,.72);
    --surface:#f5f5f7;
    --container:1180px;
    --serif:"Instrument Serif",Georgia,"Times New Roman",serif;
    --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
    --sans:-apple-system,BlinkMacSystemFont,"SF Pro Display","SF Pro Text","Segoe UI",Roboto,Helvetica,Arial,sans-serif;
    --nav-h:76px;
    /* distance from the window edge to the inside of .wrap — refined to
       the exact pixel by script once the page is measured */
    --gutter:clamp(1.5rem,5vw,3.25rem);
    --ease:cubic-bezier(.16,1,.3,1);
    color-scheme:light dark;
  }
  @media (prefers-color-scheme:dark){
    :root{
      --bg:#000000;
      --fg:#f5f5f7;
      --fg-muted:#98989d;
      --fg-faint:#6c6c70;
      --hairline:rgba(245,245,247,.18);
      --hairline-soft:rgba(245,245,247,.09);
      --glass:rgba(0,0,0,.6);
      --surface:#121214;
    }
  }

  *{box-sizing:border-box;}
  html{-webkit-text-size-adjust:100%;}
  @media (prefers-reduced-motion:no-preference){ html{scroll-behavior:smooth;} }
  body{
    margin:0; background:var(--bg); color:var(--fg);
    font-family:var(--sans);
    -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
    overflow-x:hidden;
  }
  body.is-locked{overflow:hidden;}
  svg,img,video{display:block;max-width:100%;}
  a{color:inherit;text-decoration:none;}
  p,figure,blockquote{margin:0;}
  h1,h2,h3,h4{margin:0;font-weight:inherit;}
  button{font:inherit;color:inherit;background:none;border:none;padding:0;cursor:pointer;}
  ::selection{background:var(--fg);color:var(--bg);}
  :focus-visible{outline:2px solid currentColor;outline-offset:3px;border-radius:2px;}

  #top,#ethos,#approach,#work,#craft,#clients,#contact{scroll-margin-top:var(--nav-h);}

  /* ---------- shared bits ---------- */
  .wrap{max-width:var(--container);margin:0 auto;padding:0 clamp(1.5rem,5vw,3.25rem);}
  .eyebrow{
    font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.18em;
    color:var(--fg-muted);margin:0 0 1.15rem;display:flex;align-items:center;gap:.7rem;
  }
  .eyebrow::before{content:"";width:1.6rem;height:1px;background:currentColor;opacity:.55;flex:none;}
  .h-section{
    font-size:clamp(1.85rem,4.4vw,3.05rem);font-weight:800;letter-spacing:-0.02em;
    text-transform:uppercase;line-height:1.1;margin:0 0 1.25rem;max-width:19ch;
  }
  .lede{color:var(--fg-muted);font-size:clamp(1rem,1.5vw,1.12rem);line-height:1.65;max-width:56ch;}
  .num{font-family:var(--mono);font-variant-numeric:tabular-nums;}
  .rule{height:1px;background:var(--hairline);border:0;margin:0;}

  .btn{
    display:inline-flex;align-items:center;gap:.6rem;padding:.9rem 1.75rem;border-radius:2px;
    font-size:.92rem;font-weight:700;letter-spacing:.01em;
    transition:box-shadow .3s var(--ease),transform .3s var(--ease),background-color .3s ease,color .3s ease;
  }
  .btn-primary{background:var(--fg);color:var(--bg);box-shadow:5px 5px 0 0 var(--fg-muted);}
  .btn-primary:hover{box-shadow:2px 2px 0 0 var(--fg-muted);transform:translate(2px,2px);}
  .btn-light{background:#fff;color:#0a0a0a;box-shadow:5px 5px 0 0 rgba(255,255,255,.35);}
  .btn-light:hover{box-shadow:2px 2px 0 0 rgba(255,255,255,.35);transform:translate(2px,2px);}
  .btn .arw{transition:transform .3s var(--ease);}
  .btn:hover .arw{transform:translateX(3px);}

  /* Scroll-in reveal. Was .9s over 22px, which is long enough that on a
     normal scroll you overtake your own content — you arrive at a heading
     that is still arriving. Same gesture, roughly a third quicker and a
     shorter throw: it now lands before you get there rather than after. */
  .rv{opacity:0;transform:translateY(15px);transition:opacity .58s var(--ease),transform .58s var(--ease);}
  .rv.in{opacity:1;transform:none;}
  .rv-d1{transition-delay:.06s;} .rv-d2{transition-delay:.12s;} .rv-d3{transition-delay:.18s;}

  /* photos that fade up once decoded, so nothing ever pops in raw */
  .ph{width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity 1s ease;background:var(--surface);}
  .ph.loaded{opacity:1;}

  @media (prefers-reduced-motion:reduce){
    .rv{opacity:1!important;transform:none!important;transition:none!important;}
    .ph{opacity:1!important;transition:none!important;}
    .btn{transition:none!important;}
  }

  /* ================================================================
     NAV — transparent and white while it sits over the hero, then
     glass with normal page colours once you're past it.
     ================================================================ */
  .nav{
    position:fixed;top:0;left:0;right:0;z-index:70;border-bottom:1px solid transparent;
    transition:background-color .45s ease,border-color .45s ease,color .45s ease,backdrop-filter .45s ease;
    color:var(--fg);
  }
  .nav.over-hero{color:#fff;}
  .nav.scrolled{
    background:var(--glass);border-bottom-color:var(--hairline);
    backdrop-filter:blur(22px) saturate(1.7);-webkit-backdrop-filter:blur(22px) saturate(1.7);
  }
  .nav-inner{
    max-width:var(--container);margin:0 auto;height:var(--nav-h);
    padding:0 clamp(1.5rem,5vw,3.25rem);
    display:flex;align-items:center;justify-content:space-between;gap:1.5rem;
  }
  .nav-mark{font-size:1.1rem;font-weight:900;letter-spacing:-0.02em;flex:none;}
  .nav-mark em{font-family:var(--serif);font-style:normal;font-weight:400;letter-spacing:0;}
  .nav-links{display:flex;align-items:center;gap:1.9rem;font-size:.875rem;font-weight:600;}
  .nav-links a{opacity:.62;transition:opacity .25s ease;position:relative;padding:.25rem 0;}
  .nav-links a:hover{opacity:1;}
  .nav-links a::after{
    content:"";position:absolute;left:0;right:0;bottom:0;height:1px;background:currentColor;
    transform:scaleX(0);transform-origin:left;transition:transform .35s var(--ease);
  }
  .nav-links a:hover::after{transform:scaleX(1);}
  .nav-actions{display:flex;align-items:center;gap:1.1rem;flex:none;}
  .nav-cta{
    padding:.5rem 1.05rem;border-radius:2px;border:1.5px solid currentColor;
    font-size:.85rem;font-weight:700;transition:background-color .25s ease,color .25s ease;
  }
  .nav.over-hero .nav-cta:hover{background:#fff;color:#0a0a0a;}
  .nav:not(.over-hero) .nav-cta:hover{background:var(--fg);color:var(--bg);}
  .nav-toggle{display:none;flex-direction:column;justify-content:center;gap:5px;width:2.1rem;height:2.1rem;}
  .nav-toggle span{display:block;width:100%;height:1.5px;background:currentColor;transition:transform .35s var(--ease),opacity .25s ease;}
  .nav-toggle[aria-expanded="true"] span:nth-child(1){transform:translateY(6.5px) rotate(45deg);}
  .nav-toggle[aria-expanded="true"] span:nth-child(2){opacity:0;}
  .nav-toggle[aria-expanded="true"] span:nth-child(3){transform:translateY(-6.5px) rotate(-45deg);}

  .nav-menu{
    position:fixed;inset:0;z-index:65;background:var(--bg);
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1.4rem;
    opacity:0;pointer-events:none;transition:opacity .35s ease;
  }
  .nav-menu.open{opacity:1;pointer-events:auto;}
  .nav-menu a{font-size:1.6rem;font-weight:800;letter-spacing:-0.01em;text-transform:uppercase;}
  .nav-menu .btn{margin-top:1rem;font-size:1rem;}
  @media (max-width:840px){
    .nav-links,.nav-cta{display:none;}
    .nav-toggle{display:flex;}
  }

  /* ================================================================
     HERO — one screen, full bleed, three photographs cross-fading
     behind the statement. No wasted scroll before the message.
     ================================================================ */
  .hero{
    position:relative;min-height:100vh;min-height:100svh;
    display:flex;flex-direction:column;justify-content:flex-end;
    padding:calc(var(--nav-h) + 3rem) clamp(1.5rem,5vw,3.25rem) clamp(3.5rem,7vw,5rem);
    background:#0a0a0a;overflow:hidden;isolation:isolate;
  }
  .hero-media{position:absolute;inset:0;z-index:0;background:#0a0a0a;}
  /* Every slide — photo or clip — is stacked full-bleed and shown purely
     by opacity, so crossfading between an <img> and a <video> is free:
     same class, same transition, the browser doesn't care what's under
     it. JS (below) owns which one has .active; there is no CSS rule
     that hard-codes the first slide visible, so nothing fights it once
     the cycle takes over — see the JS comment for why that matters. */
  .hero-slide{
    position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
    opacity:0;transition:opacity .9s ease;
  }
  .hero-slide.active{opacity:1;}
  /* the subtle zoom — photos only. A film clip already has its own
     motion; stacking a zoom on top of that would just look busy. */
  @keyframes heroZoom{ from{transform:scale(1);} to{transform:scale(1.015);} }
  img.hero-slide.zooming{animation:heroZoom 5.8s linear forwards;}
  .hero-scrim{
    position:absolute;inset:0;z-index:1;
    background:
      linear-gradient(180deg,rgba(0,0,0,.62) 0%,rgba(0,0,0,.18) 34%,rgba(0,0,0,.28) 60%,rgba(0,0,0,.86) 100%),
      radial-gradient(120% 80% at 20% 100%,rgba(0,0,0,.5),transparent 60%);
  }
  .hero-inner{position:relative;z-index:2;color:#fff;max-width:var(--container);margin:0 auto;width:100%;}
  .hero-eyebrow{
    font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.2em;
    color:rgba(255,255,255,.72);display:flex;align-items:center;gap:.7rem;margin:0 0 1.5rem;
  }
  .hero-eyebrow::before{content:"";width:2.2rem;height:1px;background:currentColor;flex:none;}
  .hero h1{
    font-size:clamp(2.7rem,8.4vw,6.4rem);font-weight:900;letter-spacing:-0.035em;
    text-transform:uppercase;line-height:.96;margin:0;
  }
  /* overflow:hidden masks the line as it rises in — but a serif descender
     (the g in "design") hangs below the line box, so the mask edge is
     pushed down by a padding the negative margin then takes back out of
     the layout. Clips the entrance, not the letterform. */
  .hero h1 .line{display:block;overflow:hidden;padding-bottom:.16em;margin-bottom:-.16em;}
  .hero h1 .line > span{display:block;}
  .hero h1 .serif{
    font-family:var(--serif);font-weight:400;text-transform:none;letter-spacing:-0.01em;
    font-size:1.06em;line-height:1.04;
  }
  .hero-sub{
    color:rgba(255,255,255,.8);font-size:clamp(1rem,1.7vw,1.2rem);line-height:1.6;
    max-width:48ch;margin:1.9rem 0 0;
  }
  .hero-actions{display:flex;flex-wrap:wrap;align-items:center;gap:1.5rem;margin-top:2.6rem;}
  .hero-actions .ghost{
    font-size:.9rem;font-weight:600;color:rgba(255,255,255,.78);
    border-bottom:1px solid rgba(255,255,255,.3);padding-bottom:.2rem;transition:color .25s,border-color .25s;
  }
  .hero-actions .ghost:hover{color:#fff;border-color:#fff;}

  /* animated entrance */
  .hero h1 .line > span,.hero-eyebrow,.hero-sub,.hero-actions,.hero-cue{
    opacity:0;transform:translateY(clamp(14px,2vw,26px));
    transition:opacity 1s var(--ease),transform 1s var(--ease);
  }
  .hero.ready .hero-eyebrow{opacity:1;transform:none;transition-delay:.15s;}
  .hero.ready h1 .line:nth-child(1) > span{opacity:1;transform:none;transition-delay:.3s;}
  .hero.ready h1 .line:nth-child(2) > span{opacity:1;transform:none;transition-delay:.42s;}
  .hero.ready .hero-sub{opacity:1;transform:none;transition-delay:.6s;}
  .hero.ready .hero-actions{opacity:1;transform:none;transition-delay:.72s;}
  .hero.ready .hero-cue{opacity:1;transform:none;transition-delay:.95s;}

  .hero-cue{
    position:absolute;z-index:2;right:clamp(1.5rem,5vw,3.25rem);bottom:clamp(3.5rem,7vw,5rem);
    display:flex;align-items:center;gap:.75rem;color:rgba(255,255,255,.6);
    font-size:.65rem;font-weight:700;text-transform:uppercase;letter-spacing:.2em;
  }
  .hero-cue .track{position:relative;width:1px;height:3rem;background:rgba(255,255,255,.25);overflow:hidden;}
  .hero-cue .drip{position:absolute;top:-100%;left:0;width:100%;height:100%;background:#fff;animation:drip 2.1s ease-in-out infinite;}
  @keyframes drip{0%{top:-100%;}55%{top:100%;}100%{top:100%;}}
  @media (max-width:640px){ .hero-cue{display:none;} }
  @media (max-width:480px){ .hero-eyebrow{font-size:.63rem;letter-spacing:.14em;gap:.55rem;} }

  @media (prefers-reduced-motion:reduce){
    .hero h1 .line > span,.hero-eyebrow,.hero-sub,.hero-actions,.hero-cue{opacity:1!important;transform:none!important;transition:none!important;}
    /* JS never starts the cycle under reduced motion (see below), so
       this is what actually makes the one eager slide visible */
    .hero-slide{opacity:1!important;transition:none!important;}
    img.hero-slide.zooming{animation:none!important;}
    .hero-cue .drip{display:none;}
  }

  /* ================================================================
     PROOF STRIP — three facts, straight after the hero.
     ================================================================ */
  .proof{border-bottom:1px solid var(--hairline);}
  .proof-grid{display:grid;grid-template-columns:repeat(3,1fr);}
  .proof-item{padding:clamp(2.25rem,4.5vw,3.25rem) 0;padding-right:2rem;}
  .proof-item + .proof-item{border-left:1px solid var(--hairline);padding-left:clamp(1.25rem,3vw,2.5rem);}
  .proof-fig{
    font-family:var(--serif);font-size:clamp(2.1rem,4.6vw,3.4rem);line-height:1;
    letter-spacing:-0.01em;font-variant-numeric:tabular-nums;margin-bottom:.6rem;
  }
  .proof-label{color:var(--fg-muted);font-size:.9rem;line-height:1.5;max-width:24ch;}
  @media (max-width:760px){
    .proof-grid{grid-template-columns:1fr;}
    .proof-item{padding:1.6rem 0;padding-right:0;}
    .proof-item + .proof-item{border-left:0;border-top:1px solid var(--hairline);padding-left:0;}
    .proof-fig{font-size:2rem;}
  }

  /* ================================================================
     ETHOS — scroll-scrubbed, without the jank.

     The clip is a slow crane down the Villa Vittoria gallery, and
     scrubbing it is the whole point: scrolling the page becomes
     descending through the room. v1 did that by setting a <video>'s
     currentTime from the scroll wheel, which makes the browser seek
     and decode on every single frame — the reason it dragged.

     So the film is no longer a film here. It is 60 still frames
     pulled out of it, preloaded, and painted to a canvas: a lookup and
     a blit instead of a seek and a decode. Coarse frames load first so
     the scrub works within a few hundred KB, and the gaps fill in
     behind it. 80vh of travel rather than v1's 180vh — the section is
     180vh tall (100vh sticky viewport + 80vh of actual scroll), since
     the section's own height is what sets how far the wheel has to
     move, not the sticky element pinned inside it.

     The words are a separate job — see THE STATEMENTS below for how
     they are timed, and why that changed in v3.
     ================================================================ */
  .ethos{position:relative;height:180vh;background:#08080a;}
  .ethos-stage{
    position:sticky;top:0;height:100vh;height:100svh;
    display:flex;flex-direction:column;overflow:hidden;
  }
  .ethos-media{position:absolute;inset:0;z-index:0;background:#08080a;}
  .ethos-canvas{
    width:100%;height:100%;object-fit:cover;
    opacity:0;transition:opacity 1s ease;
  }
  .ethos-canvas.ready{opacity:1;}
  /* The gallery is a bright, busy interior, so a flat wash would either
     lose the type or kill the room. A pool of shadow anchored bottom-left
     holds the statements; the far side stays open so the perspective down
     the hall still reads.

     Tuned against the hero rather than by eye. The home hero is the
     reference for how dark a scrim on this site is allowed to feel, and
     measured the same way — mean scrim alpha over the area the type
     occupies — it sits at 0.57. This block was at 0.96, then 0.84, and
     still read as murky next to it. It is now 0.57 too.

     The bigger change is shape. The old pool was enormous (125% x 105%)
     so it washed the entire frame; this one is 82% x 92% and falls to
     nothing well before the far side, which drops the right of frame
     from 0.42 to 0.06. That is what actually reads as "bright" — the
     room is open where there are no words, dense only where there are,
     which is exactly how the hero does it.

     The black is tinted rgba(6,9,16) rather than neutral: a fractionally
     cool cast reads as the room being graded, where flat black just
     reads as the picture being turned down. */
  .ethos-scrim{
    position:absolute;inset:0;z-index:1;
    background:
      radial-gradient(82% 92% at 5% 54%,rgba(6,9,16,.74) 0%,rgba(6,9,16,.56) 32%,rgba(6,9,16,.20) 66%,rgba(6,9,16,0) 100%),
      linear-gradient(180deg,rgba(6,9,16,.40) 0%,rgba(6,9,16,.05) 30%,rgba(6,9,16,.08) 62%,rgba(6,9,16,.46) 100%);
  }
  /* a whisper of grain keeps the upscaled film from looking soft */
  .ethos-grain{
    position:absolute;inset:0;z-index:2;pointer-events:none;opacity:.18;mix-blend-mode:overlay;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  }
  /* the statements sit optically centred in the frame; the footnote is
     anchored to the bottom edge so it can fade in late without
     shunting the statements off-centre while it waits */
  .ethos-copy{
    position:relative;z-index:3;flex:1;min-height:0;
    display:flex;flex-direction:column;justify-content:center;
    padding-top:var(--nav-h);
  }
  .ethos-foot{position:relative;z-index:3;padding-bottom:clamp(1.5rem,4vh,2.75rem);}
  .ethos-copy .eyebrow{color:rgba(255,255,255,.74);text-shadow:0 1px 10px rgba(0,0,0,.6);}

  /* ----------------------------------------------------------------
     THE STATEMENTS.

     v2 painted these on left-to-right with a roller wipe, gated on
     scroll. Two readers independently said it "dragged" / felt like a
     forced read, and they were right: tying LEGIBILITY to scroll
     position means the reader can never go at their own pace. Reading
     is faster than scrolling, so you end up stuck mid-sentence waiting
     for the rest of your own thought to arrive.

     So legibility is no longer scroll-driven. Each statement fades to
     fully readable within the first ~15% of its window and stays that
     way. What scroll drives now is COMPOSITION: the line drifts
     steadily upward across its whole window, so descending the page
     feels like descending past the words — which is the same motion the
     film behind it is making. The statements are stacked in one grid
     cell rather than listed, so each is a discrete beat in the same
     optical spot instead of a block of text to work through.
     ---------------------------------------------------------------- */
  .coats{
    display:grid;                      /* every line in the same cell */
    font-size:clamp(1.55rem,3.7vw,3rem);font-weight:700;letter-spacing:-0.025em;
    line-height:1.2;
  }
  .coat{
    grid-area:1/1;                     /* stacked, so the box is as tall as the tallest line */
    align-self:center;
    max-width:22ch;
    color:#fff;
    /* Three ranges, because the scrim behind is now much lighter: a tight
       shadow for edge contrast, a mid halo that kills detail immediately
       around each letter, and a wide one that separates the block from
       the room. Cheaper than making the whole frame darker. */
    text-shadow:0 1px 2px rgba(0,0,0,.7),0 2px 10px rgba(0,0,0,.65),0 6px 30px rgba(0,0,0,.8),0 4px 60px rgba(0,0,0,.9);
    /* --q is this line's own 0→1 progress, set from script.
       --drift: a slow, continuous rise across the entire window — this
       is the part tied to scroll, and the part that reads as descent.
       --vis: a fast in/out envelope, and the ONLY thing controlling
       whether the words can be read. */
    opacity:var(--vis,0);
    transform:translate3d(0,calc((0.5 - var(--q,0)) * 2.4rem),0);
    filter:blur(calc((1 - var(--vis,0)) * 7px));
    will-change:opacity,transform;
  }
  /* a phone has no room for three stacked lines at this size, and the
     drift reads as jitter on a short viewport — hold them still there */
  @media (max-width:640px){
    .coat{max-width:none;transform:none;filter:none;}
  }

  /* Three ticks under the eyebrow: at a glance this section is clearly
     three short beats, not an indefinite scroll. Most of the "it drags"
     feeling is not knowing how much is left. */
  .coat-ticks{display:flex;gap:.4rem;margin:0 0 1.6rem;}
  .coat-tick{
    width:2.1rem;height:2px;background:rgba(255,255,255,.3);overflow:hidden;
  }
  .coat-tick i{
    display:block;height:100%;background:rgba(255,255,255,.9);
    transform:scaleX(var(--t,0));transform-origin:left;
  }

  .ethos-rule{
    height:1px;background:rgba(255,255,255,.38);margin:0 0 1.05rem;
    max-width:20rem;transform:scaleX(var(--rule,0));transform-origin:left;
  }
  .ethos-note{
    font-family:var(--mono);font-size:.72rem;line-height:1.7;letter-spacing:.01em;
    color:rgba(255,255,255,.62);text-shadow:0 1px 12px rgba(0,0,0,.7);max-width:52ch;
    opacity:clamp(0,calc((var(--all,0) - .58) * 3.4),1);
  }
  .ethos-note b{color:rgba(255,255,255,.92);font-weight:400;}

  /* static, readable fallback when the scroll effect is switched off */
  .ethos.plain{height:auto;}
  .ethos.plain .ethos-stage{position:static;height:auto;padding:clamp(5rem,11vw,8rem) 0;}
  .ethos.plain .ethos-copy{padding-top:0;}
  .ethos.plain .ethos-foot{padding-bottom:0;padding-top:clamp(2rem,4vw,3rem);}
  /* with no scroll to drive them, show every statement at rest */
  .ethos.plain .coats{display:block;}
  .ethos.plain .coat{opacity:1;transform:none;filter:none;max-width:none;}
  .ethos.plain .coat + .coat{margin-top:.5em;}
  .ethos.plain .coat-ticks{display:none;}
  .ethos.plain .ethos-rule{transform:none;}
  .ethos.plain .ethos-note{opacity:1;}
  @media (max-height:620px){ .ethos-foot{display:none;} }
  /* on a phone the statements run the full width, so the scrim has to
     work top-to-bottom rather than left-to-right */
  @media (max-width:760px){
    .ethos-scrim{
      background:
          radial-gradient(115% 64% at 39% 50%,rgba(6,9,16,.55) 0%,rgba(6,9,16,.36) 55%,rgba(6,9,16,.10) 100%),
        linear-gradient(180deg,rgba(6,9,16,.30) 0%,rgba(6,9,16,.04) 30%,rgba(6,9,16,.06) 66%,rgba(6,9,16,.36) 100%);
    }
  }

  /* ================================================================
     APPROACH
     ================================================================ */
  .approach{padding:clamp(4.5rem,9vw,7.5rem) 0;}
  .approach-head{display:grid;grid-template-columns:1fr 1fr;gap:2rem 4rem;align-items:end;margin-bottom:clamp(3rem,6vw,4.5rem);}
  .approach-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:0 clamp(2rem,5vw,4.5rem);}
  .ap-item{border-top:1px solid var(--hairline);padding:1.6rem 0 1.9rem;display:grid;grid-template-columns:auto 1fr;gap:0 1.4rem;}
  .ap-no{font-family:var(--mono);font-size:.72rem;color:var(--fg-faint);padding-top:.35rem;letter-spacing:.05em;}
  .ap-name{font-size:1.12rem;font-weight:700;letter-spacing:-0.01em;margin-bottom:.5rem;}
  .ap-desc{color:var(--fg-muted);line-height:1.65;font-size:.95rem;}
  @media (max-width:820px){
    .approach-head{grid-template-columns:1fr;}
    .approach-grid{grid-template-columns:1fr;}
  }

  /* ================================================================
     WORK — full-bleed bands, each one a button into the viewer
     ================================================================ */
  .work{padding:clamp(3.5rem,7vw,5.5rem) 0 clamp(4.5rem,9vw,7rem);}
  .work-head{margin-bottom:clamp(2.25rem,5vw,3.25rem);}
  .work-region{
    display:flex;align-items:center;gap:1rem;
    margin:clamp(2.25rem,4vw,3rem) auto 1.1rem;
    max-width:var(--container);padding:0 clamp(1.5rem,5vw,3.25rem);
    font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.18em;color:var(--fg-muted);
  }
  .work-region::after{content:"";flex:1;height:1px;background:var(--hairline);}
  .work-region:first-of-type{margin-top:0;}

  .band{
    position:relative;width:100%;text-align:left;cursor:pointer;
    min-height:clamp(300px,40vw,480px);overflow:hidden;background:#101012;
    display:flex;align-items:flex-end;
  }
  .band + .band{margin-top:2px;}
  .band-media{position:absolute;inset:-9% 0;z-index:0;}
  .band-media .ph{transition:opacity 1s ease,transform 1.1s var(--ease);}
  .band:hover .band-media .ph,.band:focus-visible .band-media .ph{transform:scale(1.04);}
  .band-scrim{
    position:absolute;inset:0;z-index:1;
    background:linear-gradient(180deg,rgba(0,0,0,.16) 0%,rgba(0,0,0,.1) 38%,rgba(0,0,0,.82) 100%);
    transition:background .5s ease;
  }
  .band:hover .band-scrim{background:linear-gradient(180deg,rgba(0,0,0,.24) 0%,rgba(0,0,0,.2) 38%,rgba(0,0,0,.88) 100%);}
  /* the caption sits on the same grid as every section heading, so a
     full-bleed photograph never breaks the column the page is built on */
  .band-body{position:relative;z-index:2;width:100%;color:#fff;padding:clamp(1.6rem,4.5vw,3rem) 0;}
  .band-inner{
    max-width:var(--container);margin:0 auto;padding:0 clamp(1.5rem,5vw,3.25rem);
    display:flex;align-items:flex-end;justify-content:space-between;gap:2rem;
  }
  .band-name{
    font-family:var(--serif);font-weight:400;letter-spacing:-0.01em;
    font-size:clamp(1.75rem,4.2vw,3.1rem);line-height:1.05;
  }
  .band-meta{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem .9rem;margin-top:.85rem;}
  .band-loc{font-size:.7rem;text-transform:uppercase;letter-spacing:.16em;color:rgba(255,255,255,.66);}
  .band-tag{
    font-family:var(--mono);font-size:.72rem;letter-spacing:.02em;color:rgba(255,255,255,.9);
    border:1px solid rgba(255,255,255,.4);border-radius:2px;padding:.28rem .6rem;
  }
  .band.hero-job .band-tag{border-color:#fff;background:rgba(255,255,255,.1);}
  /* Clicking anywhere on the band opens it; the button inside is the
     focusable control that carries that action for keyboard and screen
     readers, which leaves the project name free to be a real heading
     instead of text trapped inside a <button>. */
  .band-open{
    flex:none;display:flex;align-items:center;gap:.6rem;font-size:.78rem;font-weight:700;
    text-transform:uppercase;letter-spacing:.14em;color:rgba(255,255,255,.85);
    padding-bottom:.35rem;border-bottom:1px solid rgba(255,255,255,.35);
    transition:color .3s ease,border-color .3s ease,gap .3s var(--ease);
  }
  .band:hover .band-open,.band-open:focus-visible{color:#fff;border-color:#fff;gap:.95rem;}
  .band-count{font-family:var(--mono);opacity:.7;}
  @media (max-width:760px){
    .band-inner{flex-direction:column;align-items:flex-start;gap:1.15rem;}
    .band-open{font-size:.72rem;}
    .band-tag{font-size:.66rem;padding:.25rem .5rem;}
    .band-meta{gap:.45rem .7rem;}
  }
  @media (prefers-reduced-motion:reduce){ .band-media .ph{transition:opacity 1s ease;} }

  .work-also{
    margin-top:clamp(2.5rem,5vw,3.5rem);display:grid;grid-template-columns:repeat(2,1fr);
    gap:0 clamp(2rem,5vw,4.5rem);
  }
  .also-item{border-top:1px solid var(--hairline);padding:1.35rem 0;display:flex;justify-content:space-between;align-items:baseline;gap:1.5rem;}
  .also-name{font-weight:700;font-size:1rem;}
  .also-meta{font-size:.82rem;color:var(--fg-muted);font-family:var(--mono);text-align:right;}
  @media (max-width:760px){ .work-also{grid-template-columns:1fr;} }

  /* ================================================================
     CRAFT — the process pictures, laid out as an editorial spread
     ================================================================ */
  .craft{padding:clamp(4.5rem,9vw,7.5rem) 0;background:var(--surface);}
  .craft-head{display:grid;grid-template-columns:1fr 1fr;gap:2rem 4rem;align-items:end;margin-bottom:clamp(2.75rem,5vw,4rem);}
  .craft-grid{display:grid;grid-template-columns:5fr 7fr;gap:clamp(.9rem,1.6vw,1.35rem);align-items:start;}
  .craft-right{display:grid;grid-template-columns:1fr 1fr;gap:clamp(.9rem,1.6vw,1.35rem);}
  .frame{position:relative;overflow:hidden;background:#111;}
  .frame.tall{aspect-ratio:3/4;}
  .frame.film{aspect-ratio:9/16;}
  .frame video{width:100%;height:100%;object-fit:cover;}
  .frame-cap{
    position:absolute;left:0;right:0;bottom:0;z-index:2;padding:1.5rem 1.25rem .95rem;
    background:linear-gradient(180deg,transparent,rgba(0,0,0,.72));
    color:rgba(255,255,255,.88);font-size:.72rem;font-weight:600;
    text-transform:uppercase;letter-spacing:.13em;
  }
  .craft-foot{
    margin-top:clamp(2.25rem,4vw,3rem);padding-top:1.6rem;border-top:1px solid var(--hairline);
    display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:1.25rem clamp(1.5rem,3vw,2.5rem);
    align-items:center;
  }
  .crew-shot{width:clamp(140px,17vw,215px);aspect-ratio:3/2;overflow:hidden;background:#111;flex:none;}
  .crew{font-family:var(--serif);font-size:clamp(1.35rem,3vw,2rem);letter-spacing:-0.01em;}
  .crew-note{color:var(--fg-muted);font-size:.92rem;max-width:38ch;line-height:1.6;}
  @media (max-width:860px){
    .craft-foot{grid-template-columns:1fr;align-items:start;}
    .crew-shot{width:100%;max-width:320px;}
  }
  @media (max-width:860px){
    .craft-head{grid-template-columns:1fr;}
    .craft-grid{grid-template-columns:1fr;}
    .frame.film{aspect-ratio:4/5;}
  }

  /* ================================================================
     CLIENTS
     ================================================================ */
  .clients{padding:clamp(4.5rem,9vw,7.5rem) 0;}
  /* --gutter matches the inside edge of .wrap so the first card lines up
     with the heading above it; scroll-padding stops the snap from
     swallowing that inset the moment the rail is scrolled. */
  .testi-rail{
    display:flex;gap:clamp(1rem,2vw,1.5rem);overflow-x:auto;scroll-snap-type:x mandatory;
    padding:0 var(--gutter) 1rem;scroll-padding-left:var(--gutter);
    -webkit-overflow-scrolling:touch;scrollbar-width:none;
  }
  .testi-rail::-webkit-scrollbar{display:none;}
  .testi{
    scroll-snap-align:start;flex:0 0 auto;width:min(85vw,380px);
    border:1px solid var(--hairline);border-radius:2px;padding:clamp(1.5rem,3vw,2rem);
    display:flex;flex-direction:column;gap:1.5rem;background:var(--bg);
  }
  .testi-mark{font-family:var(--serif);font-size:2.6rem;line-height:.6;color:var(--fg-faint);height:1.1rem;}
  .testi q{
    quotes:none;font-family:var(--serif);font-size:clamp(1.05rem,1.9vw,1.24rem);
    line-height:1.5;letter-spacing:-0.005em;flex-grow:1;
  }
  .testi figcaption{border-top:1px solid var(--hairline);padding-top:1rem;display:flex;flex-direction:column;gap:.2rem;}
  .testi-name{font-weight:700;font-size:.9rem;}
  .testi-role{font-size:.78rem;color:var(--fg-muted);}
  .rail-nav{display:flex;gap:.6rem;margin-top:1.25rem;}
  .rail-btn{
    width:2.6rem;height:2.6rem;border:1px solid var(--hairline);border-radius:50%;
    display:grid;place-items:center;transition:background-color .25s ease,color .25s ease,border-color .25s ease;
  }
  .rail-btn:hover:not(:disabled){background:var(--fg);color:var(--bg);border-color:var(--fg);}
  .rail-btn:disabled{opacity:.3;cursor:default;}
  @media (max-width:640px){ .rail-nav{display:none;} }

  /* ================================================================
     CREDENTIALS + CONTACT + FOOTER
     ================================================================ */
  /* Light, not inverted. This was a black band — but it sits directly
     above the black CTA that closes the page, and two inverted sections
     butted together read as one 500px slab with the join invisible.
     Keeping the credentials light gives the CTA back its job as the one
     dark moment at the end, and puts these three facts into the same
     hairline-over-column vocabulary as .svc and .ap-item. */
  .creds{padding:clamp(4rem,8vw,6rem) 0;}
  .creds-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:0 clamp(2rem,4vw,3.5rem);margin-top:clamp(2rem,4vw,3rem);}
  .cred{border-top:1px solid var(--hairline);padding:1.4rem 0 0;}
  .cred-name{font-weight:700;font-size:1rem;letter-spacing:-0.01em;line-height:1.35;margin-bottom:.45rem;}
  .cred-meta{font-size:.84rem;line-height:1.5;color:var(--fg-muted);}
  @media (max-width:820px){ .creds-grid{grid-template-columns:1fr;} }

  .contact{padding:clamp(4.5rem,9vw,7.5rem) 0;}
  .contact-sub{display:block;font-size:1.08rem;color:var(--fg-muted);margin:0 0 clamp(2.5rem,5vw,3.5rem);max-width:46ch;line-height:1.6;}
  .contact-links{border-top:1px solid var(--hairline);}
  .clink{
    position:relative;display:flex;justify-content:space-between;align-items:center;gap:1.5rem;
    padding:1.85rem clamp(.25rem,2vw,1rem);border-bottom:1px solid var(--hairline);overflow:hidden;
  }
  .clink::before{
    content:"";position:absolute;inset:0 auto 0 0;width:0;background:var(--surface);
    transition:width .5s var(--ease);z-index:0;
  }
  .clink:hover::before,.clink:focus-visible::before{width:100%;}
  .clink > *{position:relative;z-index:1;}
  .clink-text{display:flex;flex-direction:column;gap:.35rem;}
  .clink-label{font-size:.7rem;text-transform:uppercase;letter-spacing:.16em;color:var(--fg-muted);}
  .clink-value{font-size:clamp(1.2rem,2.8vw,1.7rem);font-weight:700;letter-spacing:-0.015em;}
  .clink-arw{font-size:1.3rem;color:var(--fg-muted);transition:transform .45s var(--ease),color .3s ease;}
  .clink:hover .clink-arw,.clink:focus-visible .clink-arw{transform:translateX(7px);color:var(--fg);}
  @media (max-width:600px){ .clink-arw{display:none;} }

  /* Two columns once there's room: the two big call/email tap-targets
     stay exactly as they were, and the enquiry form sits alongside as
     the option for someone who'd rather write the job down than call —
     a common preference at the estate-work end of this business. On a
     narrow screen the form drops below, after the direct links, since
     a call or a tap-to-email is still the faster first move there. */
  .contact-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(2.75rem,6vw,5rem);align-items:start;}
  @media (max-width:860px){ .contact-grid{grid-template-columns:1fr;gap:3.5rem;} }

  .enquiry-form{display:flex;flex-direction:column;gap:1.5rem;}
  /* [hidden] is normally display:none via the UA stylesheet, but that's
     equal specificity to the class rule above and author styles win
     ties — so without this, JS setting .hidden on a successful submit
     would do nothing and the filled-in form would just sit there under
     the confirmation message. */
  .enquiry-form[hidden]{display:none;}
  .field-row{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem;}
  @media (max-width:480px){ .field-row{grid-template-columns:1fr;} }
  .field{display:flex;flex-direction:column;gap:.55rem;}
  .field label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:var(--fg-muted);}
  .field label .opt{text-transform:none;letter-spacing:normal;font-weight:400;opacity:.75;}
  /* underlined, not boxed — matches the hairline language used
     everywhere else on the page instead of introducing a new input
     style the rest of the site doesn't have */
  .field input,.field textarea{
    font:inherit;font-size:1rem;color:var(--fg);background:transparent;
    border:0;border-bottom:1.5px solid var(--hairline);border-radius:0;
    padding:.5rem .05rem;transition:border-color .25s ease;resize:vertical;
  }
  .field textarea{min-height:5rem;line-height:1.55;}
  .field input:focus,.field textarea:focus{outline:none;border-bottom-color:var(--fg);}
  /* No custom :invalid styling: the browser's own validation runs before
     the submit handler below ever sees the event, so an invalid field
     already gets a native tooltip pointing right at it. A CSS :invalid
     rule here would just paint every empty required field red the
     instant the page loads — :not(:placeholder-shown) only guards
     against that on fields that carry a placeholder, and these
     deliberately don't (a persistent label above already says what
     each field is, so there's nothing useful to put in one). */

  /* honeypot — present for bots, invisible and unreachable for real
     visitors: off-screen rather than display:none, since some spam
     bots specifically skip fields hidden that way */
  .hp-field{position:absolute;width:1px;height:1px;left:-9999px;overflow:hidden;}

  .form-submit{align-self:flex-start;margin-top:.25rem;}
  .form-submit .label-sending{display:none;}
  .enquiry-form.is-sending .form-submit{opacity:.7;pointer-events:none;}
  .enquiry-form.is-sending .label-idle{display:none;}
  .enquiry-form.is-sending .label-sending{display:inline;}
  .form-status{font-size:.85rem;color:var(--fg-muted);margin:.9rem 0 0;min-height:1.3em;}
  .form-status.is-error{color:#b3432f;}

  .form-success{border-top:1px solid var(--hairline);padding-top:1.5rem;}
  .form-success-title{font-family:var(--serif);font-size:clamp(1.7rem,3.4vw,2.1rem);letter-spacing:-0.01em;margin:0 0 .6rem;}
  .form-success-note{color:var(--fg-muted);line-height:1.6;max-width:38ch;}

  /* A one-line footer was fine for a single page. With four pages it has
     to do real work: secondary navigation, and the name/phone/area block
     that local search wants to find repeated consistently sitewide. */
  .footer{padding:clamp(3rem,6vw,4.5rem) 0 2rem;border-top:1px solid var(--hairline);}
  .footer-top{
    display:grid;grid-template-columns:1.6fr 1fr 1fr;gap:2.5rem 3rem;
    padding-bottom:clamp(2rem,4vw,3rem);
  }
  .footer-mark{font-weight:900;font-size:1.1rem;letter-spacing:-0.02em;margin-bottom:.9rem;}
  .footer-mark em{font-family:var(--serif);font-style:normal;font-weight:400;letter-spacing:0;}
  .footer-line{color:var(--fg-muted);font-size:.9rem;line-height:1.6;}
  .footer-head{
    font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.16em;
    color:var(--fg-faint);margin-bottom:1rem;
  }
  .footer-nav{display:flex;flex-direction:column;align-items:flex-start;gap:.6rem;}
  /* "Selected work" was wrapping to two lines in the narrow two-column
     mobile footer. Scoped off the email, which is the one link long
     enough that holding it on one line would push the row out. */
  .footer-nav a{font-size:.92rem;color:var(--fg-muted);transition:color .25s ease;}
  .footer-nav a:not([href^="mailto"]){white-space:nowrap;}
  .footer-nav a:hover{color:var(--fg);}
  .footer-note{font-size:.82rem;color:var(--fg-faint);margin-top:.2rem;}
  .footer-bottom{
    border-top:1px solid var(--hairline-soft);padding-top:1.5rem;
    display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:.75rem 1.5rem;
  }
  .footer-legal{display:flex;flex-wrap:wrap;gap:.4rem 1.5rem;}
  .footer-meta{font-size:.78rem;color:var(--fg-muted);}

  /* ----------------------------------------------------------------
     ALTER studio signature — supplied by Kory as a self-contained
     component. Kept visually as designed; three things changed to make
     it a citizen of this stylesheet rather than a guest:

     1. The mark's base64 is declared ONCE as a custom property and
        referenced by both mask properties. Shipped as written it was
        the same 2.7KB string twice, for -webkit- and standard.
     2. It asked for Inter, which this site does not load, so it would
        have fallen through to Helvetica Neue while everything around
        it renders in the system stack. It now falls through to --sans
        instead; if ALTER ever wants their own face here, load it and
        the first entry picks it up.
     3. currentColor + opacity is theirs and is left alone — it is why
        this reads correctly on both the light and dark palette without
        a second rule.
     ---------------------------------------------------------------- */
  .alter-credit{
    --alter-mark:url("data:image/png;base64,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");
    display:inline-flex;align-items:center;gap:.42rem;
    color:var(--alter-credit-color,inherit);
    font-family:Inter,var(--sans);
    font-size:.75rem;line-height:1;text-decoration:none;
    opacity:.72;transition:opacity .18s ease;
  }
  .alter-credit:hover,.alter-credit:focus-visible{opacity:1;}
  .alter-credit:focus-visible{outline:1px solid currentColor;outline-offset:5px;border-radius:2px;}
  .alter-credit__mark{
    width:.92rem;height:.86rem;flex:0 0 auto;
    -webkit-mask-image:var(--alter-mark);mask-image:var(--alter-mark);
    -webkit-mask-position:center;mask-position:center;
    -webkit-mask-size:contain;mask-size:contain;
    -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  }
  /* without mask support the span would paint as a solid block, which is
     worse than no mark at all — so it only gets its colour where it can
     actually be cut to the logo */
  @supports ((-webkit-mask-image:url("")) or (mask-image:url(""))){
    .alter-credit__mark{background:currentColor;}
  }
  .alter-credit__built{letter-spacing:.045em;}
  .alter-credit__name{margin-left:.06rem;font-size:.75rem;font-weight:700;letter-spacing:.2em;}
  .alter-credit__arrow{
    width:.7rem;height:.7rem;margin-left:-.08rem;
    fill:none;stroke:currentColor;stroke-width:1.25;
    stroke-linecap:round;stroke-linejoin:round;
    transition:transform .18s ease;
  }
  .alter-credit:hover .alter-credit__arrow{transform:translate(1px,-1px);}
  @media (prefers-reduced-motion:reduce){
    .alter-credit,.alter-credit__arrow{transition:none;}
    .alter-credit:hover .alter-credit__arrow{transform:none;}
  }
  @media (max-width:760px){
    .footer-top{grid-template-columns:1fr 1fr;gap:2.25rem;}
    .footer-brand{grid-column:1/-1;}
  }

  /* keyboard users get a way past the nav without tabbing the whole menu */
  .skip-link{
    position:absolute;left:-9999px;top:0;z-index:200;
    background:var(--fg);color:var(--bg);padding:.85rem 1.4rem;font-size:.9rem;font-weight:700;
  }
  .skip-link:focus{left:0;}

  /* current page in the nav — same underline the hover state uses, held on */
  .nav-links a[aria-current="page"]{opacity:1;}
  .nav-links a[aria-current="page"]::after{transform:scaleX(1);}
  .nav-menu a[aria-current="page"]{text-decoration:underline;text-underline-offset:.3em;}

  /* ================================================================
     PAGE HEAD — the opener on every page that isn't the home page.
     Home earns a full-bleed hero; the others get something quieter that
     still states the h1 plainly for search.
     ================================================================ */
  .page-head{padding:calc(var(--nav-h) + clamp(3.5rem,8vw,6.5rem)) 0 clamp(2.5rem,5vw,4rem);}
  .page-head h1{
    font-size:clamp(2.3rem,6vw,4.2rem);font-weight:900;letter-spacing:-0.03em;
    text-transform:uppercase;line-height:1;margin:0 0 1.4rem;max-width:22ch;
    text-wrap:balance;
  }
  /* The serif half gets its OWN line, the way the home hero sets it.
     Inline beside 900-weight uppercase it just read as smaller and
     weaker — lowercase x-height against full caps, 400 against 900 —
     and the old 16ch measure was also snapping the phrase in half
     ("turn / up."). On its own line the contrast becomes a deliberate
     two-part composition instead of a mismatch, and 1.24em lifts the
     lowercase up to meet the caps above it. */
  .page-head h1 .serif{
    display:block;margin-top:.06em;
    font-family:var(--serif);font-weight:400;text-transform:none;
    letter-spacing:-0.015em;font-size:1.24em;line-height:1;
  }
  .page-head .lede{max-width:52ch;}
  .page-head-rule{margin-top:clamp(2.5rem,5vw,3.5rem);}

  /* ================================================================
     SERVICES — plain, scannable capability list. Exists as much for
     search (these are the phrases people actually type) as for readers.
     ================================================================ */
  .services{padding:clamp(4rem,8vw,6.5rem) 0;border-top:1px solid var(--hairline);}
  .svc-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:0 clamp(2rem,4vw,3.5rem);}
  .svc{border-top:1px solid var(--hairline);padding:1.5rem 0 1.9rem;}
  .svc-name{font-size:1.05rem;font-weight:700;letter-spacing:-0.01em;margin-bottom:.55rem;}
  .svc-desc{color:var(--fg-muted);font-size:.94rem;line-height:1.65;}
  @media (max-width:860px){ .svc-grid{grid-template-columns:1fr 1fr;} }
  @media (max-width:560px){ .svc-grid{grid-template-columns:1fr;} }

  /* ================================================================
     CTA BAND — closes every page that isn't the contact page.
     ================================================================ */
  .cta{background:var(--fg);color:var(--bg);padding:clamp(3.5rem,7vw,5.5rem) 0;}
  .cta-inner{display:flex;align-items:center;justify-content:space-between;gap:2rem 3rem;flex-wrap:wrap;}
  .cta h2{
    font-family:var(--serif);font-weight:400;letter-spacing:-0.01em;
    font-size:clamp(1.9rem,4.2vw,3rem);line-height:1.1;max-width:16ch;
  }
  .cta-side{display:flex;flex-direction:column;gap:1.1rem;align-items:flex-start;}
  .cta-phone{font-size:1.05rem;opacity:.72;}
  .cta-phone a{border-bottom:1px solid currentColor;padding-bottom:.15rem;}
  .btn-invert{background:var(--bg);color:var(--fg);box-shadow:5px 5px 0 0 rgba(128,128,128,.45);}
  .btn-invert:hover{box-shadow:2px 2px 0 0 rgba(128,128,128,.45);transform:translate(2px,2px);}

  /* ================================================================
     PROJECT VIEWER — a full-screen gallery, opened from a band.
     Keeps everything on one page: no second load, no back button.
     ================================================================ */
  .viewer{
    position:fixed;inset:0;z-index:100;background:#08080a;color:#fff;
    display:flex;flex-direction:column;
    opacity:0;pointer-events:none;transition:opacity .4s ease;
  }
  .viewer.open{opacity:1;pointer-events:auto;}
  /* Title, blurb and close all live in the top bar so the bottom is
     nothing but thumbnails — which leaves the photograph the tallest
     thing on screen, as it should be. */
  .viewer-top{
    display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:.75rem 2.5rem;align-items:start;
    padding:clamp(1.1rem,2.5vw,1.5rem) clamp(1.25rem,4vw,2.5rem);
    border-bottom:1px solid rgba(255,255,255,.12);flex:none;
  }
  .viewer-title{font-family:var(--serif);font-size:clamp(1.35rem,3vw,2.1rem);line-height:1.05;letter-spacing:-0.01em;}
  .viewer-sub{
    margin-top:.5rem;display:flex;flex-wrap:wrap;gap:.4rem .9rem;align-items:center;
    font-size:.7rem;text-transform:uppercase;letter-spacing:.15em;color:rgba(255,255,255,.6);
  }
  .viewer-sub .dot{opacity:.4;}
  .viewer-close{
    flex:none;width:2.9rem;height:2.9rem;border:1px solid rgba(255,255,255,.28);border-radius:50%;
    display:grid;place-items:center;transition:background-color .25s,color .25s,border-color .25s;
  }
  .viewer-close:hover{background:#fff;color:#08080a;border-color:#fff;}

  .viewer-stage{position:relative;flex:1;min-height:0;display:flex;align-items:center;justify-content:center;overflow:hidden;}
  .viewer-slide{
    position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
    padding:clamp(.75rem,2vw,1.75rem);
    opacity:0;transition:opacity .45s ease;pointer-events:none;
  }
  .viewer-slide.active{opacity:1;}
  .viewer-slide img,.viewer-slide video{
    max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;
  }
  .viewer-arrow{
    position:absolute;top:50%;transform:translateY(-50%);z-index:5;
    width:3rem;height:3rem;border-radius:50%;display:grid;place-items:center;
    background:rgba(0,0,0,.45);border:1px solid rgba(255,255,255,.22);color:#fff;
    backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
    transition:background-color .25s,border-color .25s,opacity .25s;
  }
  .viewer-arrow:hover{background:rgba(255,255,255,.92);color:#08080a;border-color:transparent;}
  .viewer-arrow.prev{left:clamp(.6rem,2vw,1.5rem);}
  .viewer-arrow.next{right:clamp(.6rem,2vw,1.5rem);}

  .viewer-bottom{
    flex:none;padding:clamp(.75rem,1.6vw,1rem) clamp(1.25rem,4vw,2.5rem) clamp(.9rem,2vw,1.25rem);
    border-top:1px solid rgba(255,255,255,.12);
    display:flex;align-items:center;justify-content:space-between;gap:1.5rem;
  }
  .viewer-desc{font-size:.85rem;line-height:1.55;color:rgba(255,255,255,.68);max-width:74ch;padding-top:.3rem;}
  .viewer-count{font-family:var(--mono);font-size:.78rem;color:rgba(255,255,255,.6);white-space:nowrap;flex:none;}
  .viewer-next{
    flex:none;display:flex;align-items:center;gap:.55rem;white-space:nowrap;
    font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.14em;
    color:rgba(255,255,255,.8);padding-bottom:.3rem;
    border-bottom:1px solid rgba(255,255,255,.32);
    transition:color .3s ease,border-color .3s ease,gap .3s var(--ease);
  }
  .viewer-next:hover{color:#fff;border-color:#fff;gap:.9rem;}
  .viewer-thumbs{display:flex;gap:.5rem;overflow-x:auto;flex:1;min-width:0;scrollbar-width:none;padding-bottom:.15rem;}
  .viewer-thumbs::-webkit-scrollbar{display:none;}
  .thumb{
    flex:none;width:4.5rem;height:3.1rem;border-radius:2px;overflow:hidden;position:relative;
    opacity:.42;transition:opacity .25s ease,outline-color .25s ease;
    outline:1.5px solid transparent;outline-offset:2px;
  }
  .thumb img{width:100%;height:100%;object-fit:cover;}
  .thumb.on{opacity:1;outline-color:#fff;}
  .thumb:hover{opacity:.8;}
  .thumb .vid-dot{
    position:absolute;inset:auto .3rem .3rem auto;width:1.05rem;height:1.05rem;border-radius:50%;
    background:rgba(0,0,0,.72);display:grid;place-items:center;font-size:.5rem;line-height:1;
    color:#fff;padding-left:1px;
  }
  @media (max-width:1024px){
    .viewer-top{grid-template-columns:minmax(0,1fr) auto;}
    .viewer-desc{grid-column:1/-1;padding-top:0;}
  }
  @media (max-width:640px){
    .viewer-desc{
      font-size:.8rem;
      display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;
    }
    .thumb{width:3.6rem;height:2.5rem;}
    .viewer-count{display:none;}
  }
  /* a project name would crowd out the thumbnails on a phone; the button
     keeps the full name in its aria-label either way */
  @media (max-width:700px){
    #viewerNextLabel{display:none;}
    .viewer-next::before{content:"Next";}
    .viewer-next{font-size:.68rem;letter-spacing:.1em;}
  }
  @media (prefers-reduced-motion:reduce){
    .viewer,.viewer-slide{transition:none!important;}
  }

  .ghost-link{
    font-size:.92rem;font-weight:600;color:var(--fg-muted);
    border-bottom:1px solid var(--hairline);padding-bottom:.2rem;
    transition:color .25s ease,border-color .25s ease;
  }
  .ghost-link:hover{color:var(--fg);border-color:var(--fg);}
