/* ============================================================
   PROFOCUS
   Luxury property photography & film
   Design language: black, white and cream. No hue anywhere — the
   "accent" is warmth, carried by cream on the dark grounds and a warm
   neutral on the light ones.
   Cormorant Garamond display over light DM Sans UI. Square edges,
   hairline rules, generous negative space, slow easing.
   ============================================================ */

/* ---------- self-hosted fonts ----------
   No third-party CDN, so the page renders identically on flaky mobile data.
   swap keeps text visible while the woff2 loads. */
@font-face{
  font-family:"Cormorant Garamond";
  src:url("assets/font/CormorantGaramond-400.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap;
}
@font-face{
  font-family:"Cormorant Garamond";
  src:url("assets/font/CormorantGaramond-400-italic.woff2") format("woff2");
  font-weight:400;font-style:italic;font-display:swap;
}
@font-face{
  font-family:"DM Sans";
  src:url("assets/font/DMSans-400.woff2") format("woff2");
  font-weight:100 1000;font-style:normal;font-display:swap;   /* variable */
}

/* ---------- tokens ----------
   Black #111111 primary, cream #DED8CE secondary, off-white #F9F6F1
   highlight. The light grounds sit well below paper white on purpose — they
   should read as cream, not as a lit screen — so every warm neutral that
   goes on them is darker than it would need to be over an ivory. There is no chromatic accent: what used to be an ice teal is
   now warmth alone, pitched per ground — cream where the ground is black,
   a warm neutral where the ground is cream.

   That removes the old ceiling. The teal CTA could only go as light as
   4.5:1 under white type; a black/white/cream CTA has no such limit, so the
   fill is now the ground's opposite — black under white type on the light
   grounds, cream under black type on the dark ones. Both clear 16:1.
   Every value is annotated with the ratio it was chosen for. */
:root{
  /* grounds */
  --ink:        #111111;   /* deep charcoal — the primary ground */
  --ink-deep:   #0A0A0A;   /* deeper, for full-bleed, footer and scrims */
  --ink-2:      #1C1C1C;   /* raised: cards, inputs */
  --cream:      #DED8CE;   /* warm cream — the light ground (L* 87) */
  --paper:      #D4CDBF;   /* cream one step down — secondary light bands (L* 83) */
  --cream-2:    #CBC3B3;   /* light surfaces that must separate from cream */
  --line:       #C2B9A8;   /* dividers and UI hairlines on light */
  --bone:       #F9F6F1;   /* off-white — the highlight, and type on dark.
                              Deliberately NOT #FFFFFF: pure white glares against
                              the black grounds and reads cold beside the cream.
                              Nothing in the interface should be brighter than
                              this, so use var(--bone), never a white literal. */

  /* accents — warmth, not hue, pitched per ground */
  --accent:     #E0D3B8;   /* cream; display italics on black (12.8:1) */
  --accent-lt:  #EFE7D8;   /* pale cream — small text and outline buttons
                              on black grounds (15.4:1) */
  --accent-md:  #6C6351;   /* warm neutral; display italics on light grounds
                              (4.2:1 cream, 3.8:1 paper — display sizes only,
                              where 3:1 is the bar) */
  --accent-dp:  #4F483C;   /* small warm-neutral text on light grounds
                              (6.4:1 cream, 5.7:1 paper) */
  /* muted body copy on light grounds (5.8:1 cream, 5.2:1 paper) */
  --stone:      #564E42;

  /* type */
  --display: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --ui:      "DM Sans", -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;

  /* rhythm */
  --pad:     clamp(1.25rem, 5vw, 4.5rem);
  --sec:     clamp(6rem, 13vw, 12rem);
  --maxw:    82rem;

  /* motion */
  --ease:    cubic-bezier(.22, 1, .36, 1);
  --ease-io: cubic-bezier(.65, .05, .36, 1);
}

/* ---------- reset ---------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
html:not(.lenis){scroll-behavior:smooth}
body{
  margin:0;
  background:var(--ink);
  color:var(--ink);
  font-family:var(--ui);
  font-size:16px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}
img{display:block;max-width:100%;height:auto}
h1,h2,h3,p,figure,blockquote,dl,dd{margin:0}
ul,ol{margin:0;padding:0;list-style:none}
a{color:inherit;text-decoration:none}
button,input,select,textarea{font:inherit;color:inherit}

::selection{background:var(--accent);color:var(--ink)}

.skip{
  position:absolute;left:-9999px;top:0;z-index:200;
  background:var(--accent);color:var(--ink);
  padding:14px 20px;font-size:11px;letter-spacing:.2em;text-transform:uppercase;
}
.skip:focus{left:0}

/* a label a screen reader reads and nobody sees */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}
/* spam honeypot — never shown, never announced, never tabbed into */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

:focus-visible{outline:1px solid var(--mark);outline-offset:4px}

/* ============================================================
   CUSTOM CURSOR
   Only on precise-pointer devices, and only once JS has mounted it —
   if the script never runs, the native cursor is untouched.
   ============================================================ */
.cursor{
  position:fixed;top:0;left:0;z-index:9999;
  width:0;height:0;
  pointer-events:none;
  opacity:0;
  transition:opacity .35s var(--ease);
  will-change:transform;
}
.cursor.is-visible{opacity:1}
.cursor__ring{
  position:absolute;top:0;left:0;
  width:36px;height:36px;
  margin:-18px 0 0 -18px;
  border-radius:50%;
  background:rgba(255,255,255,.14);
  border:1px solid rgba(255,255,255,.55);
  transition:transform .3s var(--ease), background-color .3s var(--ease), border-color .3s var(--ease);
}
/* shrink over anything clickable */
.cursor.is-active .cursor__ring{
  transform:scale(.5);
  background:rgba(var(--tint),.30);
  border-color:var(--accent-lt);
}
.cursor.is-down .cursor__ring{transform:scale(.38)}
/* on cream sections the ring needs a darker edge to stay visible */
.cursor.is-light .cursor__ring{
  background:rgba(17,17,17,.12);
  border-color:rgba(17,17,17,.45);
}
.cursor.is-light.is-active .cursor__ring{
  background:rgba(var(--tint),.22);
  border-color:var(--accent-dp);
}

html.has-cursor,
html.has-cursor a,
html.has-cursor button,
html.has-cursor .svc__row{cursor:none}

@media (hover:none),(pointer:coarse){
  .cursor{display:none}
  html.has-cursor,html.has-cursor a,html.has-cursor button{cursor:auto}
}

/* ---------- the pointer must come back in full screen ----------
   Full screen renders the full-screen element and its descendants and
   nothing else, and .cursor lives in <body> — outside a full-screened
   <video>. So the ring is not drawn, while `cursor:none` above is still
   inherited: no pointer at all, and no way to see the control that gets
   you out. Two independent fixes, because this one is worth over-solving.

   1. :fullscreen gives the element its own `cursor` declaration, which
      beats an inherited one outright. Works with no JS at all. */
:fullscreen,
:fullscreen *,
:-webkit-full-screen,
:-webkit-full-screen *{cursor:auto}

/* 2. …and initCursor() sets .is-fs on <html> while anything is full
      screen, which also covers full-screening a container rather than
      the video itself. */
html.has-cursor.is-fs,
html.has-cursor.is-fs a,
html.has-cursor.is-fs button,
html.has-cursor.is-fs .svc__row,
html.has-cursor.is-fs video{cursor:auto}

/* the ring would be stranded mid-page behind the full-screen layer */
html.is-fs .cursor{display:none}

/* ---------- layout ---------- */
.wrap{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--pad)}

/* ---------- grounds ----------
   Five grounds, and every component reads its colours from the same tokens
   rather than hard-coding a tint. A block dropped on any ground picks up type
   and rules that clear AA there, with no per-section patching:
     --on         primary type          --on-muted  secondary
     --on-faint   tertiary              --mark      accent at text size
     --mark-lg    accent at display size (3:1 is enough)
     --rule       hairlines and dividers
     --cta        filled-button ground   --cta-on    type on that fill
     --tint       rgb triple for the wash behind hovers and highlights

   --cta is the ground's opposite, which is what keeps a black/white/cream
   scheme legible without a hue to lean on: black under white on the light
   grounds, cream under black on the dark ones. --tint follows the same
   logic, so a hover wash darkens on cream and lightens on black.

   .nav is in the dark list because the bar is ALWAYS dark — translucent
   black once scrolled, solid black from the top on the light pages. Without
   it the nav fell back to the light-ground tokens and its "Start a Project"
   button came out black-on-black, instead of matching the cream CTA in the
   hero directly beneath it. */
:root{
  --on:var(--ink);
  --on-muted:var(--stone);
  --on-faint:#61584B;          /* 4.9:1 on cream */
  --mark:var(--accent-dp);
  --mark-lg:var(--accent-md);
  --rule:var(--line);
  --cta:var(--ink);            /* black fill … */
  --cta-on:var(--bone);        /* … under off-white type (17.5:1) */
  --tint:17,17,17;             /* washes darken on a light ground */
}
:is(.section--ink,.section--deep,.foot,.menu,.reel,.shero,.hero,.nav){
  --on:var(--bone);
  --on-muted:rgba(255,255,255,.76);
  --on-faint:rgba(255,255,255,.62);
  --mark:var(--accent-lt);
  --mark-lg:var(--accent);
  --rule:rgba(255,255,255,.18);
  --cta:var(--cream);          /* cream fill … */
  --cta-on:var(--ink);         /* … under black type (13.3:1) */
  --tint:224,211,184;          /* washes lighten on a dark ground */
}
/* Cream one step down: the accent and the tertiary neutral each need a
   little more weight to stay over 4.5:1 on it. */
.section--paper{
  --on-faint:#5A5146;          /* 4.9:1 */
  --mark:var(--accent-dp);     /* 5.7:1 */
}

.section--cream{background:var(--cream);   color:var(--on)}
.section--paper{background:var(--paper);   color:var(--on)}
.section--ink  {background:var(--ink);     color:var(--on)}
.section--deep {background:var(--ink-deep);color:var(--on)}

/* ---------- typography primitives ---------- */
.display{
  font-family:var(--display);
  font-weight:400;
  letter-spacing:-.03em;
  line-height:1.06;
  text-wrap:balance;
}
.display--lg{font-size:clamp(2.6rem, 7.2vw, 5.6rem)}
.display--md{font-size:clamp(2.1rem, 5vw, 3.9rem)}

.accent{color:var(--mark)}
.accent-i{color:var(--mark-lg);font-style:italic}

.eyebrow{
  font-family:var(--ui);
  font-size:10px;
  font-weight:400;
  letter-spacing:.2em;
  text-transform:uppercase;
  color:var(--on-muted);
  margin-bottom:clamp(1.5rem,3vw,2.5rem);
}
.eyebrow--accent{color:var(--mark)}

.lede{
  font-family:var(--display);
  font-size:clamp(1.25rem,2.1vw,1.6rem);
  line-height:1.6;
  letter-spacing:.005em;
}
.body{
  font-family:var(--display);
  font-size:clamp(1.05rem,1.5vw,1.2rem);
  line-height:1.8;
  color:var(--on-faint);
}
.lede{color:var(--on-muted)}

/* ---------- buttons ----------
   Ice teal reads at very different strengths on ivory and on charcoal, so the
   outline button carries --btn-c: the teal the ground it sits on can support.
   Dark grounds re-declare it; light grounds take the base value.

   No button changes colour on any state. Both the outline and the filled
   variant used to sweep a second tone up behind the label on hover, which read
   as a lighter blue appearing from nowhere. That is gone — the only hover
   feedback is a slight shrink, which says "clickable" without touching the
   palette.

   The shrink uses the independent `scale` property, NOT `transform`. Most of
   these buttons also carry .reveal, whose `.reveal.in{transform:none}` has the
   same specificity and sits later in the file, so a transform-based hover is
   silently overridden the moment the button scrolls into view. `scale`
   composes alongside transform instead of competing with it. */
.btn{
  --btn-c:var(--accent-dp);
  --bh:14px;
  display:inline-flex;align-items:center;justify-content:center;
  font-family:var(--ui);font-size:10px;font-weight:400;
  letter-spacing:.2em;text-transform:uppercase;
  padding:var(--bh) 34px;
  border:1px solid var(--btn-c);
  border-radius:0;
  background:transparent;color:var(--btn-c);
  cursor:pointer;
  transition:scale .35s var(--ease);
}
:is(.section--ink,.section--deep) .btn,.reel .btn,.shero .btn,.foot .btn{
  --btn-c:var(--accent-lt);
}
.btn:hover{scale:.97}
.btn:active{scale:.955}

/* CTA: the ground's opposite. Black under white type on the light grounds
   (17.5:1), cream under black type on the dark ones (13.3:1). Both come from
   --cta / --cta-on, so a button never has to know which section it is in. */
.btn--solid{
  background:var(--cta);color:var(--cta-on);
  border-color:var(--cta);
}
.btn--lg{--bh:17px;padding-inline:52px}

/* ============================================================
   NAV
   ============================================================ */
.nav{
  position:fixed;inset:0 0 auto 0;z-index:100;
  transition:transform .6s var(--ease), background-color .5s var(--ease), border-color .5s var(--ease);
  border-bottom:1px solid transparent;
}
.nav__inner{
  max-width:var(--maxw);margin-inline:auto;
  padding:clamp(1rem,1.8vw,1.6rem) var(--pad);
  display:flex;align-items:center;gap:2rem;
}
.nav.is-solid{
  background:rgba(17,17,17,.9);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  border-bottom-color:rgba(255,255,255,.14);
}
.nav.is-hidden{transform:translateY(-101%)}

/* Pages whose first section is light need the bar solid from the top so the
   wordmark and links never sit on bare photography. */
body.page-light .nav{
  background:rgba(17,17,17,.94);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  border-bottom-color:rgba(255,255,255,.14);
}


/* ---------- brand lockup ----------
   Reproduced from the supplied artwork: a six-blade camera iris with an
   open hexagonal centre, set beside PROFOCUS (bold) over REALTY (light),
   all in white. Every dimension below is expressed in em against the
   PROFOCUS size set on .brand, so the whole lockup scales as one piece and
   the proportions of the original never drift.
   Measured off the supplied artwork (cap height 85 / mark 271 / gap 39 /
   line gap 47, all against a 118.5 PROFOCUS size):
      mark diameter  = 2.29em      gap mark→text = .33em
      REALTY size    = 1em         REALTY offset = .114em
      both lines set solid, no tracking  */
.brand{
  font-size:clamp(.85rem,1.15vw,1.05rem);   /* = PROFOCUS size */
  display:inline-flex;align-items:center;
  gap:.33em;
  white-space:nowrap;flex:none;
}
.brand__mark{
  width:2.29em;height:2.29em;
  color:var(--bone);flex:none;
  transition:color .45s var(--ease);
  overflow:visible;
}
/* dark grounds take the artwork's white lockup; light grounds take deep teal */
:is(.section--cream,.section--paper) :is(.brand__mark,.brand__pro,.brand__realty){color:var(--ink)}

.brand__name{display:flex;flex-direction:column;line-height:1}
.brand__pro,.brand__realty{
  display:flex;color:var(--bone);
  font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;
}
.brand__pro{
  font-weight:700;
  font-size:1em;
  letter-spacing:0;
}
.brand__realty{
  font-weight:300;
  font-size:1em;
  letter-spacing:0;
  margin-top:.114em;
}
.brand--lg{font-size:clamp(1.3rem,2.6vw,1.75rem)}

/* ---------- mark animation: the iris racks open ----------
   The blade group (six gaps + the central hexagon) is rotated and scaled
   inside the mask, so the centre opening genuinely winds open and shut like
   a real diaphragm — the outline of the mark itself never changes. */
.ap__blades{
  transform-box:view-box;
  transform-origin:50% 50%;
  animation:apOpen 1.35s var(--ease) .1s backwards;   /* never 'forwards' — hover needs it back */
  transition:transform .6s var(--ease);
}
.ap__disc{
  transform-box:view-box;transform-origin:50% 50%;
  animation:apDisc .9s var(--ease) backwards;
}
@keyframes apOpen{
  0%  {transform:rotate(-62deg) scale(1.75)}   /* wide open: blades swept out */
  55% {transform:rotate(9deg)   scale(.86)}    /* overshoot past the stop */
  78% {transform:rotate(-3deg)  scale(1.05)}
  100%{transform:rotate(0)      scale(1)}
}
@keyframes apDisc{
  0%  {opacity:0;transform:scale(.84) rotate(-14deg)}
  100%{opacity:1;transform:scale(1)   rotate(0)}
}
/* hover: wind the aperture down a stop, release to rack back open */
.brand:hover .ap__blades,
.brand:focus-visible .ap__blades{transform:rotate(-20deg) scale(.62)}

/* wordmark letters rack focus on hover, same as before */
.brand__l{display:inline-block;will-change:transform,filter}
.brand:hover .brand__l{animation:bnRack .6s var(--ease) both}
.brand:hover .brand__pro .brand__l:nth-child(1){animation-delay:0ms}
.brand:hover .brand__pro .brand__l:nth-child(2){animation-delay:28ms}
.brand:hover .brand__pro .brand__l:nth-child(3){animation-delay:56ms}
.brand:hover .brand__pro .brand__l:nth-child(4){animation-delay:84ms}
.brand:hover .brand__pro .brand__l:nth-child(5){animation-delay:112ms}
.brand:hover .brand__pro .brand__l:nth-child(6){animation-delay:140ms}
.brand:hover .brand__pro .brand__l:nth-child(7){animation-delay:168ms}
.brand:hover .brand__pro .brand__l:nth-child(8){animation-delay:196ms}
.brand:hover .brand__realty .brand__l:nth-child(1){animation-delay:112ms}
.brand:hover .brand__realty .brand__l:nth-child(2){animation-delay:140ms}
.brand:hover .brand__realty .brand__l:nth-child(3){animation-delay:168ms}
.brand:hover .brand__realty .brand__l:nth-child(4){animation-delay:196ms}
.brand:hover .brand__realty .brand__l:nth-child(5){animation-delay:224ms}
.brand:hover .brand__realty .brand__l:nth-child(6){animation-delay:252ms}

@keyframes bnRack{
  0%  {filter:blur(0);   transform:translateY(0)      scale(1);    opacity:1}
  38% {filter:blur(3px); transform:translateY(-2.5px) scale(1.04); opacity:.45}
  100%{filter:blur(0);   transform:translateY(0)      scale(1);    opacity:1}
}

/* ---------- loading screen ----------
   The mark's full performance: the iris racks open while PROFOCUS pulls
   into focus letter by letter, then the curtain lifts. main.js owns the
   timing once it has set html.js; without JS the fallback animation below
   clears the curtain on its own so the page can never be trapped. */
.preload{
  position:fixed;inset:0;z-index:400;
  display:grid;place-items:center;
  background:var(--ink-deep);
  animation:plFallback 0s linear 6s forwards;   /* no-JS escape hatch */
}
html.js .preload{animation:none}
.preload.is-done{
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .8s var(--ease), visibility 0s linear .8s;
}
.preload__inner{
  display:flex;flex-direction:column;align-items:center;
  gap:clamp(1.1rem,2.4vw,1.6rem);
}
.preload__mark{
  width:clamp(66px,9vw,104px);height:auto;
  color:var(--bone);overflow:visible;
}
.preload__name{
  display:flex;
  font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;
  font-weight:700;line-height:1;
  font-size:clamp(.95rem,1.8vw,1.3rem);
  letter-spacing:0;color:var(--bone);
}
.preload__l{
  display:inline-block;
  animation:plRack .85s var(--ease) both;
}
.preload__l:nth-child(1){animation-delay:.34s}
.preload__l:nth-child(2){animation-delay:.40s}
.preload__l:nth-child(3){animation-delay:.46s}
.preload__l:nth-child(4){animation-delay:.52s}
.preload__l:nth-child(5){animation-delay:.58s}
.preload__l:nth-child(6){animation-delay:.64s}
.preload__l:nth-child(7){animation-delay:.70s}
.preload__l:nth-child(8){animation-delay:.76s}
@keyframes plRack{
  0%  {opacity:0;filter:blur(7px);transform:translateY(6px)}
  100%{opacity:1;filter:blur(0);  transform:translateY(0)}
}
@keyframes plFallback{
  to{opacity:0;visibility:hidden;pointer-events:none}
}

.nav__links{
  margin-left:auto;
  display:flex;gap:clamp(1.1rem,2.2vw,2.2rem);
  font-family:var(--display);
  font-size:1.02rem;
  letter-spacing:.01em;
  color:var(--bone);
}
.nav__links a{position:relative;padding-block:4px;opacity:.82;transition:opacity .35s var(--ease)}
.nav__links a::after{
  content:"";position:absolute;left:0;bottom:0;width:100%;height:1px;
  background:rgba(255,255,255,.7);
  transform:scaleX(0);transform-origin:right;
  transition:transform .5s var(--ease);
}
.nav__links a:hover{opacity:1}
.nav__links a:hover::after{transform:scaleX(1);transform-origin:left}

.nav__cta{flex:none}

/* burger */
.burger{
  display:none;flex:none;
  width:40px;height:40px;margin-left:auto;
  background:none;border:0;cursor:pointer;padding:0;
  position:relative;
}
.burger span{
  position:absolute;left:9px;width:22px;height:1px;background:var(--bone);
  transition:transform .45s var(--ease), opacity .3s var(--ease);
}
.burger span:nth-child(1){top:18px}
.burger span:nth-child(2){top:24px}
.burger[aria-expanded="true"] span:nth-child(1){transform:translateY(3px) rotate(45deg)}
.burger[aria-expanded="true"] span:nth-child(2){transform:translateY(-3px) rotate(-45deg)}

/* mobile menu */
.menu{
  position:fixed;inset:0;z-index:99;
  background:var(--ink-deep);
  display:flex;flex-direction:column;justify-content:center;
  padding:6rem var(--pad) 3rem;
  opacity:0;transition:opacity .5s var(--ease);
  /* it stays display:flex for 450ms while it fades out; without this it
     goes on swallowing every click across the whole viewport */
  pointer-events:none;
}
.menu.is-open{pointer-events:auto}
/* MUST stay: the class sets display:flex, which beats the UA rule for the
   [hidden] attribute. Without this the closed menu is an invisible
   full-screen overlay that swallows every click on the page. */
.menu[hidden]{display:none}
.menu.is-open{opacity:1}
.menu__links{display:flex;flex-direction:column;gap:.2em}
.menu__links a{
  font-family:var(--display);
  font-size:clamp(2rem,10vw,3rem);
  letter-spacing:-.02em;
  color:var(--bone);
  display:flex;align-items:baseline;gap:.7em;
  padding-block:.16em;
  border-bottom:1px solid rgba(255,255,255,.09);
}
.menu__links em{
  font-family:var(--ui);font-style:normal;
  font-size:10px;letter-spacing:.2em;color:var(--accent-lt);
}
.menu__foot{
  margin-top:auto;padding-top:2.5rem;
  display:flex;flex-direction:column;gap:.35rem;
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:rgba(255,255,255,.62);
}
.menu__foot a{color:var(--accent-lt)}

/* ============================================================
   HERO
   ============================================================ */
.hero{
  position:relative;
  min-height:100svh;
  display:flex;align-items:center;justify-content:center;
  text-align:center;
  /* vertical rhythm tracks viewport height so the scroll cue stays in view
     on short laptop screens without cramping tall displays */
  padding:clamp(4.5rem,10vh,8rem) var(--pad) clamp(4.5rem,10vh,7rem);
  overflow:hidden;
  background:var(--ink-deep);
}
.hero__media{position:absolute;inset:0;z-index:0}

/* shared montage container — hero and showreel both use it */
/* The poster of whatever clip is showing sits behind them all, so the
   section is a photograph from the first paint and stays one if a clip never
   plays. A clip needs BOTH .is-live (it is the current one) and .is-ready
   (it is genuinely playing) before it is shown — that is what stops a black
   rectangle appearing while a file is still arriving. */
.montage{
  position:absolute;inset:0;
  background-image:var(--montage-poster);
  background-size:cover;background-position:center;background-repeat:no-repeat;
  background-color:var(--ink-deep);
}
.montage__vid{
  position:absolute;inset:0;
  width:100%;height:100%;object-fit:cover;
  opacity:0;
  transition:opacity 1.5s var(--ease);
}
.montage__vid.is-live.is-ready{opacity:1}

/* iOS paints a large play button over any video it has not started.
   These are background films with their own controls, so suppress it. */
.montage__vid::-webkit-media-controls,
.montage__vid::-webkit-media-controls-panel,
.montage__vid::-webkit-media-controls-start-playback-button{
  display:none!important;
  -webkit-appearance:none;
  appearance:none;
}

/* The footage itself is left alone — no grade, no colour cast. Everything
   that makes the type read comes from the gradient over it. */
.hero .montage{filter:none}
.hero__wash{
  position:absolute;inset:0;
  background:linear-gradient(200deg, rgba(240,232,216,.20) 0%, transparent 55%);
  mix-blend-mode:overlay;
}
/* Soft dark gradient — black fading to transparent through the middle, so
   the image stays visible while white type clears AA at every band. */
.hero__scrim{
  position:absolute;inset:0;
  background:
    linear-gradient(to bottom, rgba(0,0,0,.62) 0%, rgba(0,0,0,.34) 30%, rgba(0,0,0,.46) 62%, rgba(0,0,0,.78) 100%),
    rgba(10,10,10,.2);
}
.hero__vignette{
  position:absolute;inset:0;
  background:radial-gradient(120% 85% at 50% 45%, transparent 34%, rgba(0,0,0,.6) 100%);
}

.hero__content{position:relative;z-index:2;max-width:60rem;width:100%}

.hero__eyebrow{
  font-family:var(--display);
  font-style:italic;
  font-size:clamp(1rem,1.55vw,1.22rem);
  letter-spacing:.055em;
  color:var(--on-muted);
  margin-bottom:clamp(1rem,3vh,2.2rem);
}

.hero__title{
  font-family:var(--display);
  font-weight:400;
  font-size:clamp(2.9rem, 8.6vw, 7.2rem);
  line-height:1.02;
  letter-spacing:-.032em;
  color:var(--bone);
  margin:0;
}
/* 'that inspire.' takes the ice teal — 7.7:1 on the scrimmed image, well
   over the 3:1 display-type threshold at this size. */
.hero__title .accent{color:var(--accent);font-style:italic}

.hero__rule{
  width:64px;height:1px;
  background:var(--rule);
  margin:clamp(1.25rem,3.6vh,3.2rem) auto;
}

/* stats */
.stats{
  display:flex;justify-content:center;align-items:flex-start;
  gap:clamp(1.5rem,5vw,4.5rem);
  margin-bottom:clamp(1.5rem,4vh,3.4rem);
}
.stats li{
  display:flex;flex-direction:column;align-items:center;gap:.55rem;
  position:relative;
  padding-inline:clamp(.5rem,2vw,1.5rem);
}
.stats li + li::before{
  content:"";position:absolute;left:calc(clamp(1.5rem,5vw,4.5rem) / -2);top:.35rem;
  width:1px;height:calc(100% - .7rem);
  background:var(--rule);
}
.stats__n{
  font-family:var(--display);
  font-size:clamp(1.9rem,4vw,2.9rem);
  line-height:1;
  letter-spacing:.02em;
  color:var(--bone);
  font-variant-numeric:oldstyle-nums;
}
.stats__l{
  font-family:var(--ui);
  font-size:9.5px;font-weight:400;
  letter-spacing:.18em;text-transform:uppercase;
  color:var(--accent-lt);
  line-height:1.6;
}

/* hero pause — WCAG 2.2.2 needs a way to stop autoplaying motion */
.hero__pause{
  position:absolute;z-index:3;
  right:var(--pad);bottom:2.4rem;
  width:34px;height:34px;
  display:flex;align-items:center;justify-content:center;
  background:rgba(10,10,10,.4);
  border:1px solid rgba(255,255,255,.34);
  border-radius:50%;
  cursor:pointer;
  transition:border-color .4s var(--ease), background-color .4s var(--ease);
}
.hero__pause:hover{background:rgba(10,10,10,.62)}
.hero__pause-icon{
  width:8px;height:9px;
  border-left:2px solid rgba(255,255,255,.85);
  border-right:2px solid rgba(255,255,255,.85);
}
.hero__pause.is-paused .hero__pause-icon{
  border:0;width:0;height:0;
  border-left:8px solid rgba(255,255,255,.85);
  border-top:5px solid transparent;
  border-bottom:5px solid transparent;
  margin-left:3px;
}

/* scroll cue */
.hero__cue{
  position:absolute;left:50%;bottom:2.2rem;transform:translateX(-50%);
  z-index:3;
  display:flex;flex-direction:column;align-items:center;gap:.75rem;
  font-size:9px;font-weight:400;letter-spacing:.24em;text-transform:uppercase;
  color:var(--on-muted);
  transition:color .4s var(--ease);
}
.hero__cue:hover{color:var(--on)}
.hero__cue-line{
  width:1px;height:clamp(30px,6vh,52px);
  background:linear-gradient(to bottom, transparent, rgba(255,255,255,.7));
  transform-origin:top;
  animation:cue 2.6s var(--ease-io) infinite;
}
@keyframes cue{
  0%   {transform:scaleY(0);opacity:0}
  35%  {transform:scaleY(1);opacity:1}
  75%  {transform:scaleY(1);opacity:1}
  100% {transform:scaleY(0);opacity:0;transform-origin:bottom}
}

/* ============================================================
   STUDIO
   ============================================================ */
.studio{padding-block:var(--sec)}
.studio__head{margin-bottom:clamp(3rem,7vw,5.5rem);max-width:20ch}
.studio__grid{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:clamp(2.5rem,6vw,6rem);
  align-items:start;
}
.studio__copy{display:flex;flex-direction:column;gap:clamp(1.4rem,2.5vw,2rem);padding-top:.5rem}

.facts{
  display:flex;flex-wrap:wrap;gap:clamp(1.75rem,4vw,3.5rem);
  margin-top:clamp(.75rem,2vw,1.5rem);
  padding-top:clamp(1.5rem,3vw,2.25rem);
  border-top:1px solid var(--rule);
}
.facts dt{
  font-size:9.5px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--stone);margin-bottom:.5rem;
}
.facts dd{font-family:var(--display);font-size:1.4rem;letter-spacing:-.01em}

.studio__figure{position:relative;overflow:hidden}
.studio__figure img{width:100%;aspect-ratio:4/3.2;object-fit:cover}
.studio__figure figcaption{
  margin-top:1rem;
  font-size:9.5px;font-weight:400;letter-spacing:.18em;text-transform:uppercase;
  color:var(--stone);
}

/* ============================================================
   SERVICES
   ============================================================ */
.services{padding-block:var(--sec);position:relative}
.sec-head{margin-bottom:clamp(3.5rem,8vw,6rem)}
.sec-head--split{
  display:flex;justify-content:space-between;align-items:flex-end;
  gap:clamp(2rem,6vw,5rem);flex-wrap:wrap;
}
.sec-head__note{
  font-family:var(--display);
  font-size:1.1rem;line-height:1.75;color:var(--stone);
  max-width:34ch;
}

.svc{border-top:1px solid var(--rule)}
.svc__row{
  position:relative;
  display:grid;
  grid-template-columns:auto 1fr auto;
  align-items:baseline;
  gap:clamp(1.5rem,4vw,3.5rem);
  padding-block:clamp(2rem,4.2vw,3.1rem);
  border-bottom:1px solid var(--rule);
  transition:padding-left .6s var(--ease);
}
.svc__row::before{
  content:"";position:absolute;z-index:0;
  /* the bleed must never exceed the page padding or it widens the document
     past the viewport on small screens */
  inset:0 calc(-1 * min(2rem, var(--pad)));
  background:linear-gradient(90deg, rgba(var(--tint),.09), transparent 65%);
  opacity:0;transition:opacity .6s var(--ease);
  pointer-events:none;
}
.svc__row:hover::before{opacity:1}
.svc__num{
  position:relative;z-index:1;
  font-family:var(--ui);font-size:10px;font-weight:400;
  letter-spacing:.2em;color:var(--mark);
  padding-top:.55rem;
}
.svc__body{position:relative;z-index:1;max-width:52ch}
.svc__title{
  font-family:var(--display);font-weight:400;
  font-size:clamp(1.75rem,4vw,2.9rem);
  line-height:1.12;letter-spacing:-.025em;
  color:var(--on);
  transition:color .5s var(--ease), transform .6s var(--ease);
}
.svc__row:hover .svc__title{color:var(--mark)}
.svc__desc{
  font-family:var(--display);
  font-size:clamp(1rem,1.35vw,1.13rem);
  line-height:1.75;
  color:var(--on-faint);
  margin-top:.85rem;
  max-width:44ch;
}
.svc__meta{
  position:relative;z-index:1;
  font-size:9.5px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--on-faint);
  white-space:nowrap;padding-top:.6rem;
}
.svc__thumb{display:none}

/* ============================================================
   AERIAL REEL
   Full-bleed autoplaying montage. Muted + playsinline so browsers
   allow autoplay; a visible control satisfies WCAG 2.2.2.
   ============================================================ */
.reel{
  position:relative;
  min-height:min(88svh, 800px);
  display:flex;align-items:center;
  padding:clamp(6rem,12vh,9rem) 0 clamp(7rem,14vh,10rem);
  background:var(--ink-deep);
  overflow:hidden;
}
.reel__media{position:absolute;inset:0;z-index:0}
/* weighted toward the text side so the overlaid type always has a dark bed,
   while the right of the frame stays open enough to actually see the footage */
.reel__scrim{
  position:absolute;inset:0;
  background:
    linear-gradient(to right, rgba(10,10,10,.8) 0%, rgba(10,10,10,.55) 42%, rgba(10,10,10,.2) 100%),
    linear-gradient(to bottom, rgba(10,10,10,.55) 0%, rgba(10,10,10,.3) 42%, rgba(10,10,10,.8) 100%);
}
@media (max-width:860px){
  .reel__scrim{
    background:linear-gradient(to bottom, rgba(10,10,10,.72) 0%, rgba(10,10,10,.66) 45%, rgba(10,10,10,.86) 100%);
  }
}
.reel__inner{position:relative;z-index:2}
.reel__head{color:var(--on);max-width:16ch;margin-bottom:clamp(1.5rem,3vw,2.25rem)}
.reel__lede{max-width:44ch;color:var(--on-muted)}

/* controls */
.reel__ui{
  position:absolute;z-index:3;
  left:0;right:0;bottom:clamp(2rem,4vw,3.25rem);
  padding-inline:var(--pad);
  max-width:var(--maxw);margin-inline:auto;
  display:flex;justify-content:space-between;align-items:flex-end;
  gap:1.5rem;flex-wrap:wrap;
}
.reel__caption{
  font-size:9.5px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--on-muted);
}
.reel__controls{display:flex;align-items:center;gap:clamp(1rem,2vw,1.75rem)}
.reel__dots{display:flex;gap:.6rem}
.reel__dots button{
  position:relative;
  width:26px;height:2px;padding:0;border:0;border-radius:0;
  background:rgba(255,255,255,.28);
  cursor:pointer;
  transition:background-color .5s var(--ease);
}
/* the dash stays 2px; the thing you can actually hit is 24px tall */
.reel__dots button::after{
  content:"";position:absolute;left:0;right:0;top:50%;
  transform:translateY(-50%);height:24px;
}
.reel__dots button[aria-current="true"]{background:var(--mark)}
.reel__dots button:hover{background:var(--on-faint)}

.reel__toggle{
  display:inline-flex;align-items:center;gap:.6rem;
  background:none;border:0;padding:6px 2px;cursor:pointer;
  font-size:9.5px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--on-muted);
  transition:color .4s var(--ease);
}
.reel__toggle:hover{color:var(--mark)}
.reel__toggle-icon{
  width:9px;height:10px;flex:none;
  border-left:2px solid currentColor;border-right:2px solid currentColor;
}
.reel__toggle.is-paused .reel__toggle-icon{
  border:0;
  width:0;height:0;
  border-left:8px solid currentColor;
  border-top:5px solid transparent;
  border-bottom:5px solid transparent;
}

@media (max-width:600px){
  .reel{min-height:auto;padding-block:clamp(5rem,12vh,7rem) 7rem}
  .reel__ui{flex-direction:column;align-items:flex-start;gap:1rem}
}


/* ============================================================
   LEGAL PAGE
   Long-form prose: narrow measure, clear hierarchy, hairline rules.
   ============================================================ */
.legal{padding-block:clamp(8rem,16vh,11rem) var(--sec)}
.legal__head{max-width:52rem;margin-bottom:clamp(2.5rem,5vw,4rem)}
.legal__title{margin-bottom:clamp(1.25rem,2.5vw,1.9rem)}
.legal__lede{max-width:46ch;color:var(--ink)}
.legal__meta{
  margin-top:clamp(1.25rem,2.5vw,1.75rem);
  font-size:10px;font-weight:400;letter-spacing:.18em;text-transform:uppercase;
  color:var(--stone);
}
.legal__sec{
  max-width:52rem;
  padding-top:clamp(2rem,4vw,2.75rem);
  margin-top:clamp(2rem,4vw,2.75rem);
  border-top:1px solid var(--rule);
}
.legal__sec:first-of-type{border-top:0;margin-top:0;padding-top:0}
.legal__h{
  font-family:var(--display);font-weight:400;
  font-size:clamp(1.45rem,2.4vw,1.95rem);
  line-height:1.2;letter-spacing:-.02em;
  color:var(--ink);
  margin-bottom:clamp(1rem,2vw,1.4rem);
}
.legal__body{
  font-family:var(--display);
  font-size:clamp(1.02rem,1.4vw,1.14rem);
  line-height:1.8;color:var(--stone);
}
.legal__body p + p{margin-top:1.1em}
.legal__body strong{color:var(--ink);font-weight:500}
.legal__body a{
  color:var(--mark);
  text-decoration:underline;text-underline-offset:3px;
  text-decoration-thickness:1px;
}
.legal__list{
  margin:1.1em 0 0;
  display:flex;flex-direction:column;gap:.7em;
}
.legal__list li{padding-left:1.2rem;position:relative}
.legal__list li::before{
  content:"";position:absolute;left:0;top:.75em;
  width:6px;height:1px;background:var(--mark);
}
.foot__nav a[aria-current="page"]{color:var(--mark)}

/* ============================================================
   PRICING
   ============================================================ */
.pricing{padding-block:var(--sec)}
.sec-head__note--light{color:var(--on-faint)}
.price__grid{
  display:grid;grid-template-columns:repeat(3,1fr);
  gap:0;
  border-top:1px solid var(--rule);
}
.price__card{
  display:flex;flex-direction:column;
  padding:clamp(2rem,3.4vw,2.9rem) clamp(1.25rem,2.2vw,2rem);
  border-right:1px solid var(--rule);
  border-bottom:1px solid var(--rule);
  position:relative;
  transition:background-color .6s var(--ease);
}
.price__card:first-child{padding-left:0}
.price__card:last-child{border-right:0;padding-right:0}
.price__card:hover{background:rgba(var(--tint),.04)}
.price__card--feature{background:rgba(var(--tint),.06)}

.price__label{
  font-size:10px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--mark);
  margin-bottom:clamp(1.25rem,2.4vw,1.9rem);
}
.price__fig{
  font-family:var(--display);
  font-size:clamp(2.4rem,4.2vw,3.3rem);
  line-height:1;letter-spacing:-.03em;
  color:var(--on);
  margin-bottom:clamp(1.5rem,3vw,2.2rem);
}
.price__list{
  display:flex;flex-direction:column;gap:.85rem;
  font-family:var(--display);
  font-size:1.02rem;line-height:1.5;
  color:var(--on-muted);
}
.price__list li{padding-left:1.1rem;position:relative}
.price__list li::before{
  content:"";position:absolute;left:0;top:.62em;
  width:5px;height:1px;background:var(--mark);
}
.price__foot{
  margin-top:clamp(2rem,4vw,3rem);
  font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--on-faint);
}

/* ---------- extras: the à la carte list ----------
   A two-column rule sheet rather than more cards — the packages are the offer,
   these are the parts. Same hairline vocabulary as the grid above it. */
.extras{margin-top:clamp(3.5rem,7vw,5.5rem)}
.extras__head{
  font-family:var(--display);font-weight:400;
  font-size:clamp(1.6rem,3vw,2.2rem);
  line-height:1.1;letter-spacing:-.02em;
  color:var(--on);
}
.extras__lede{
  margin-top:.7rem;
  font-family:var(--display);
  font-size:1.02rem;line-height:1.7;
  color:var(--on-faint);
  max-width:46ch;
}
.extras__list{
  margin-top:clamp(1.75rem,3.5vw,2.6rem);
  border-top:1px solid var(--rule);
}
.extras__row{
  display:grid;grid-template-columns:1fr auto;
  gap:clamp(1.25rem,4vw,3rem);
  align-items:baseline;
  padding-block:clamp(.95rem,1.8vw,1.3rem);
  border-bottom:1px solid var(--rule);
}
.extras__name{
  font-family:var(--display);
  font-size:clamp(1.05rem,1.5vw,1.2rem);line-height:1.4;
  color:var(--on);
}
.extras__price{
  font-family:var(--display);
  font-size:clamp(1.05rem,1.5vw,1.2rem);line-height:1.4;
  color:var(--on);
  text-align:right;
}
.extras__note{
  display:block;margin-top:.3rem;
  font-family:var(--ui);
  font-size:9.5px;font-weight:400;
  letter-spacing:.14em;text-transform:uppercase;line-height:1.7;
  color:var(--on-faint);
}

@media (max-width:600px){
  /* the qualifiers are long; give each row the full width and stack it */
  .extras__row{grid-template-columns:1fr;gap:.35rem}
  .extras__price{text-align:left}
}

@media (max-width:1080px){
  .price__grid{grid-template-columns:repeat(2,1fr)}
  .price__card:nth-child(2n){border-right:0;padding-right:0}
  .price__card:nth-child(2n+1){padding-left:0}
}
@media (max-width:600px){
  .price__grid{grid-template-columns:1fr}
  .price__card{border-right:0;padding-inline:0}
}

/* ============================================================
   CONTACT
   ============================================================ */
.contact{position:relative;padding-block:var(--sec);overflow:hidden}
.contact__media{position:absolute;inset:0;z-index:0}
.contact__media img{width:100%;height:100%;object-fit:cover;opacity:.26}
.contact__media::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(to right, var(--ink) 4%, rgba(17,17,17,.88) 42%, rgba(17,17,17,.6));
}
.contact__inner{
  position:relative;z-index:1;
  display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(3rem,7vw,7rem);
  align-items:start;
}
.contact__lead .display{margin-bottom:clamp(1.75rem,3.5vw,2.5rem);max-width:16ch}
.contact__details{
  display:flex;flex-direction:column;gap:1.5rem;
  margin-top:clamp(2.25rem,4.5vw,3.25rem);
  padding-top:clamp(2rem,4vw,2.75rem);
  border-top:1px solid var(--rule);
}
.contact__details dt{
  font-size:9.5px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--on-faint);margin-bottom:.45rem;
}
.contact__details dd{font-family:var(--display);font-size:clamp(1.15rem,1.7vw,1.38rem)}
.contact__details a{
  position:relative;
  color:var(--mark);
  background-image:linear-gradient(var(--mark),var(--mark));
  background-size:0 1px;background-repeat:no-repeat;background-position:left 92%;
  transition:background-size .5s var(--ease);
}
.contact__details a:hover{background-size:100% 1px}
.contact__details a::after{
  content:"";position:absolute;left:0;right:0;top:50%;
  transform:translateY(-50%);height:24px;
}

/* form */
.form{
  display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(1.4rem,2.4vw,1.9rem) clamp(1.2rem,2vw,1.6rem);
  align-content:start;
  padding-top:.5rem;
}
.field{position:relative;display:flex;flex-direction:column}
.field--full{grid-column:1/-1}
.field input,.field textarea,.field select{
  width:100%;
  background:transparent;border:0;border-bottom:1px solid rgba(255,255,255,.2);
  border-radius:0;
  padding:.85rem 0 .7rem;
  font-family:var(--display);font-size:1.1rem;
  color:var(--on);
  transition:border-color .5s var(--ease);
  -webkit-appearance:none;appearance:none;
}
.field textarea{resize:vertical;min-height:3.5rem}
.field select{color:rgba(255,255,255,.55);cursor:pointer}
.field select option{background:var(--ink);color:var(--on)}
.field input:focus,.field textarea:focus,.field select:focus{
  outline:0;border-bottom-color:var(--mark);
}
/* A pointer user gets the hairline recolour above, which is enough on its own.
   A keyboard user gets a thicker rule as well — the underline is the only
   focus indicator these fields have, and one pixel of colour change is a thin
   thing to navigate a form by. */
.field input:focus-visible,.field textarea:focus-visible,.field select:focus-visible{
  border-bottom-width:2px;
  padding-bottom:calc(.7rem - 1px);   /* keep the field from shifting */
}
.field label{
  position:absolute;left:0;top:.85rem;
  font-family:var(--display);font-size:1.1rem;
  color:var(--on-faint);
  pointer-events:none;
  transition:transform .45s var(--ease), font-size .45s var(--ease), color .45s var(--ease), letter-spacing .45s var(--ease);
  transform-origin:left top;
}
.field input:focus + label,
.field input:not(:placeholder-shown) + label,
.field textarea:focus + label,
.field textarea:not(:placeholder-shown) + label{
  transform:translateY(-1.35rem);
  font-family:var(--ui);font-size:9.5px;letter-spacing:.2em;
  color:var(--mark);
  text-transform:uppercase;
}
.field.is-invalid input,.field.is-invalid textarea{border-bottom-color:#E08C84}

.form__privacy{
  grid-column:1/-1;
  font-size:11px;line-height:1.7;letter-spacing:.02em;
  color:var(--on-faint);
  margin-top:.25rem;
}
.form__privacy a{color:var(--mark);text-decoration:underline;text-underline-offset:3px}
.form .btn{grid-column:1/-1;justify-self:start;margin-top:.5rem}
.form__status{
  grid-column:1/-1;
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--mark);min-height:1.2em;
  line-height:1.6;
}
/* a failure has to look different from a success, not just read differently —
   the contact section is a dark ground, so both are checked against it */
.form__status.is-ok{color:var(--accent-lt)}      /* 15.4:1 on ink */
.form__status.is-error{
  color:#FF9B8A;                                  /* 7.4:1 on ink */
  text-transform:none;letter-spacing:.04em;font-size:12px;
}

/* ============================================================
   FOOTER
   ============================================================ */
.foot{
  background:var(--ink-deep);color:var(--on);
  padding-block:clamp(3.5rem,7vw,6rem) clamp(2rem,4vw,3rem);
  border-top:1px solid var(--rule);
}
.foot__inner{
  display:grid;grid-template-columns:auto 1fr auto;
  gap:clamp(2rem,5vw,4rem);align-items:center;
}
.foot__nav{display:flex;flex-wrap:wrap;gap:clamp(.7rem,1.5vw,1.45rem);justify-content:center}
.foot__nav a{
  display:inline-block;
  padding-block:5px;               /* 16px of text -> a 26px target */
  font-size:10px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--on-faint);transition:color .4s var(--ease);
}
.foot__nav a:hover{color:var(--mark)}
.foot__meta{text-align:right;font-size:10px;letter-spacing:.12em;color:var(--on-faint);line-height:1.9}

/* ============================================================
   REVEAL ANIMATIONS
   ============================================================ */
.reveal{
  opacity:0;transform:translateY(26px);
  transition:opacity 1s var(--ease), transform 1s var(--ease);
  transition-delay:var(--d, 0ms);
}
.reveal.in{opacity:1;transform:none}

.reveal-img{
  opacity:0;
  transition:opacity 1.1s var(--ease);
}
.reveal-img img{
  clip-path:inset(0 0 100% 0);
  transform:scale(1.12);
  transition:clip-path 1.4s var(--ease), transform 1.6s var(--ease);
}
.reveal-img.in{opacity:1}
.reveal-img.in img{clip-path:inset(0 0 0 0);transform:scale(1.01)}

/* line-by-line display reveal */
.display .line,.hero__title .line{display:block;overflow:hidden;padding-bottom:.06em}
.display .line > span,.hero__title .line > span{
  display:block;
  transform:translateY(110%);
  transition:transform 1.15s var(--ease);
  transition-delay:var(--d,0ms);
}
.display.in .line > span,.hero__title.in .line > span{transform:translateY(0)}

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width:1180px){
  .nextsvc__grid{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:1080px){
  .nav__links{display:none}
  .nav__cta{display:none}
  .burger{display:block}

}

@media (max-width:860px){
  .studio__grid{grid-template-columns:1fr}
  .studio__figure{order:-1}
  .studio__head{max-width:none}

  .contact__inner{grid-template-columns:1fr}
  .contact__lead .display{max-width:none}
  .contact__media::after{background:linear-gradient(to bottom, rgba(17,17,17,.92), rgba(17,17,17,.86))}

  .foot__inner{grid-template-columns:1fr;justify-items:center;text-align:center;gap:2.5rem}
  .foot__meta{text-align:center}

  /* services: stack, show inline thumb, no cursor preview */
  .svc__row{grid-template-columns:auto 1fr;gap:1.25rem 1.5rem}
  .svc__meta{display:none}
  .svc__thumb{
    display:block;grid-column:1/-1;
    width:100%;aspect-ratio:16/9;object-fit:cover;
    margin-top:1.5rem;
  }
}

@media (max-width:600px){
  .hero{padding-top:7rem;padding-bottom:6rem}
  .hero__title{font-size:clamp(2.6rem,12.5vw,4rem)}

  /* keep the three figures on one line — stacking made the hero too tall */
  .stats{
    display:grid;grid-template-columns:repeat(3,1fr);
    gap:0;width:100%;
  }
  .stats li{padding-inline:.35rem;gap:.45rem}
  .stats li + li::before{left:0;top:.25rem;height:calc(100% - .5rem)}
  .stats__n{font-size:1.7rem}
  .stats__l{font-size:8px;letter-spacing:.12em;text-align:center}

  .form{grid-template-columns:1fr}
}

/* ============================================================
   REDUCED MOTION
   ============================================================ */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms!important;
    animation-iteration-count:1!important;
    transition-duration:.01ms!important;
    scroll-behavior:auto!important;
  }
  .reveal,.reveal-img{opacity:1;transform:none}
  .reveal-img img{clip-path:none;transform:none}
  .display .line > span,.hero__title .line > span{transform:none}
  .hero__cue-line{animation:none;opacity:.7}

  /* the iris holds fully open — no opening animation, no hover shift */
  .ap__blades,.ap__disc{animation:none!important;transform:none!important;opacity:1}
  .brand:hover .ap__blades{transform:none!important}

  /* wordmark stays put; letters never blur */
  .brand:hover .brand__l{animation:none!important}
  /* buttons hold still — an instant snap is worse than no movement at all */
  .btn:hover,.btn:active{scale:1}
  .preload__l{opacity:1;filter:none;transform:none;animation:none!important}
  /* clear the curtain immediately rather than animating it away */
  .preload{animation:none!important;opacity:0;visibility:hidden;pointer-events:none}
}

/* the service rows are links now */
.svc__item{border-bottom:1px solid var(--rule)}
.svc__row{align-items:start}
.svc__body{display:flex;flex-direction:column}
.svc__title{display:block}
.svc__desc{display:block}
.svc__more{
  display:inline-flex;align-items:center;gap:.5rem;
  margin-top:1.25rem;
  font-family:var(--ui);font-size:9.5px;font-weight:400;
  letter-spacing:.2em;text-transform:uppercase;
  color:var(--mark);
}
.svc__more i{font-style:normal;transition:transform .5s var(--ease)}
.svc__row:hover .svc__more i{transform:translateX(5px)}

/* ============================================================
   SERVICE PAGE
   ============================================================ */
.shero{
  position:relative;
  min-height:min(72svh,640px);
  display:flex;align-items:flex-end;
  padding:clamp(8rem,18vh,12rem) 0 clamp(3.5rem,7vh,5rem);
  background:var(--ink-deep);
  overflow:hidden;
}
.shero__media{position:absolute;inset:0;z-index:0}
.shero__media img{width:100%;height:100%;object-fit:cover}
/* Hero images range from very dark (film) to very bright (aerial), so the
   scrim has to be heavy enough for the brightest of them. Text sits bottom-left,
   which is where it is darkest. */
.shero__scrim{
  position:absolute;inset:0;
  background:
    linear-gradient(to right, rgba(10,10,10,.92) 0%, rgba(10,10,10,.74) 46%, rgba(10,10,10,.46) 100%),
    linear-gradient(to bottom, rgba(10,10,10,.72) 0%, rgba(10,10,10,.5) 34%, rgba(10,10,10,.9) 100%);
}
.shero__inner{position:relative;z-index:2}
.shero__eyebrow{
  font-size:10px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--on-faint);
  margin-bottom:clamp(1rem,2.4vw,1.6rem);
}
.shero__eyebrow span{color:var(--mark);margin-right:.6rem}
.shero__title{
  font-family:var(--display);font-weight:400;
  font-size:clamp(2.4rem,6.4vw,4.8rem);
  line-height:1.04;letter-spacing:-.03em;
  color:var(--on);margin:0;
}
.shero__title .accent{color:var(--mark);font-style:italic}
.shero__lede{max-width:48ch;margin-top:clamp(1.25rem,2.5vw,1.9rem);color:var(--on-muted)}

.sintro{padding-block:clamp(4.5rem,10vw,8rem) clamp(3rem,6vw,5rem)}
.sintro__grid{
  display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(2rem,5vw,5rem);align-items:start;
}
.sintro__head{max-width:16ch}
.sintro__body{padding-top:.4rem}

.sgal{padding-block:clamp(3rem,6vw,5rem) var(--sec)}
.sgal__grid{
  display:grid;grid-template-columns:repeat(4,1fr);
  gap:clamp(1rem,2vw,1.75rem);
}
.sgal__frame{
  position:relative;overflow:hidden;
  aspect-ratio:4/3;background:var(--cream-2);
}
.sgal__frame img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform 1.1s var(--ease);
}
.sgal__item:hover .sgal__frame img{transform:scale(1.05)}

.inc{padding-block:var(--sec)}
.inc__grid{
  display:grid;grid-template-columns:repeat(2,1fr);
  gap:0;border-top:1px solid var(--rule);
}
.inc__item{
  padding:clamp(1.75rem,3vw,2.5rem) clamp(1.25rem,2.4vw,2.25rem);
  border-bottom:1px solid var(--rule);
  border-right:1px solid var(--rule);
}
.inc__item:nth-child(2n){border-right:0;padding-right:0}
.inc__item:nth-child(2n+1){padding-left:0}
.inc__t{
  font-family:var(--display);font-weight:400;
  font-size:clamp(1.3rem,2vw,1.6rem);
  line-height:1.2;letter-spacing:-.02em;
  color:var(--on);margin-bottom:.7rem;
}
.inc__d{
  font-family:var(--display);font-size:1.02rem;line-height:1.75;
  color:var(--on-faint);
}
.inc__price{
  margin-top:clamp(3rem,6vw,4.5rem);
  display:flex;flex-direction:column;align-items:flex-start;
}
.inc__from{
  font-size:9.5px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--on-faint);margin-bottom:.6rem;
}
.inc__fig{
  font-family:var(--display);
  font-size:clamp(2.6rem,5vw,3.8rem);line-height:1;letter-spacing:-.03em;
  color:var(--on);
}
.inc__note{
  margin-top:1rem;
  font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--on-faint);
}
.inc__price .btn{margin-top:clamp(1.75rem,3vw,2.5rem)}

.nextsvc{padding-block:clamp(4rem,8vw,7rem)}
/* three cards now that there are four services — two left an odd gap */
.nextsvc__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(1rem,2vw,1.75rem)}
.nextsvc__card{
  display:flex;flex-direction:column;gap:.9rem;
  padding:clamp(1.75rem,3vw,2.5rem);
  border:1px solid var(--rule);
  transition:background-color .6s var(--ease), border-color .6s var(--ease);
}
.nextsvc__card:hover{background:rgba(var(--tint),.08);border-color:rgba(var(--tint),.5)}
.nextsvc__num{
  font-size:9.5px;font-weight:400;letter-spacing:.2em;color:var(--mark);
}
.nextsvc__t{
  font-family:var(--display);
  font-size:clamp(1.4rem,2.4vw,1.9rem);
  line-height:1.15;letter-spacing:-.02em;color:var(--on);
}
.nextsvc__go{
  margin-top:auto;
  display:inline-flex;align-items:center;gap:.5rem;
  font-size:9.5px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--mark);
}
.nextsvc__go i{font-style:normal;transition:transform .5s var(--ease)}
.nextsvc__card:hover .nextsvc__go i{transform:translateX(5px)}

@media (max-width:1080px){
  .sgal__grid{grid-template-columns:repeat(3,1fr)}
}
@media (max-width:860px){
  .sintro__grid{grid-template-columns:1fr}
  .sintro__head{max-width:none}
  .sgal__grid{grid-template-columns:repeat(2,1fr)}
  .inc__grid{grid-template-columns:1fr}
  .inc__item{border-right:0;padding-inline:0}
  .nextsvc__grid{grid-template-columns:1fr}
  .shero__scrim{
    background:linear-gradient(to bottom, rgba(10,10,10,.66) 0%, rgba(10,10,10,.78) 45%, rgba(10,10,10,.94) 100%);
  }
}
@media (max-width:560px){
  .sgal__grid{grid-template-columns:1fr}
}

/* ============================================================
   LIGHTBOX
   Opened from any [data-lightbox] anchor in a gallery. The anchor
   points at the full-size file, so without JS the photograph still
   opens — this is the enhancement, not the mechanism.
   ============================================================ */

/* .lb sets display, so it MUST opt out when [hidden] is set — the same
   trap that left an invisible full-screen .menu swallowing every click. */
.lb[hidden]{display:none}

.lb{
  position:fixed;inset:0;z-index:200;
  display:flex;align-items:center;justify-content:center;
  padding:clamp(3.25rem,7vh,5rem) clamp(1rem,4vw,4rem);
  background:rgba(10,10,10,.96);
  overscroll-behavior:contain;
  opacity:0;
  transition:opacity .32s var(--ease);
}
@supports (backdrop-filter:blur(6px)){
  .lb{background:rgba(10,10,10,.9);backdrop-filter:blur(8px)}
}
.lb.is-open{opacity:1}

.lb__stage{
  position:relative;margin:0;
  max-width:100%;max-height:100%;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:clamp(.9rem,2vh,1.4rem);
}
.lb__img{
  display:block;
  max-width:100%;
  /* leave room for the caption under the frame. svh, not vh: on a phone
     with the toolbars showing, vh is the TALLER measurement, so a vh-sized
     photograph is cut off at the bottom exactly when the caption is too. */
  max-height:calc(100vh - clamp(9rem,20vh,13rem));
  max-height:calc(100svh - clamp(9rem,20vh,13rem));
  width:auto;height:auto;
  object-fit:contain;
  opacity:0;
  transition:opacity .4s var(--ease);
}
.lb__img.is-ready{opacity:1}

.lb__cap{
  display:flex;align-items:baseline;gap:1.25rem;
  max-width:60rem;
  font-family:var(--ui);
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:rgba(255,255,255,.62);
  text-align:left;
}
.lb__count{flex:none;color:var(--accent-lt);font-variant-numeric:tabular-nums}
.lb__text{text-transform:none;letter-spacing:.04em;font-size:12px;line-height:1.5}

/* controls — square edges and hairlines, like every other button here */
.lb__btn{
  position:absolute;z-index:2;
  display:flex;align-items:center;justify-content:center;
  width:44px;height:44px;
  padding:0;
  background:rgba(10,10,10,.55);
  border:1px solid rgba(255,255,255,.22);
  color:var(--bone);
  cursor:pointer;
  transition:background .35s var(--ease),border-color .35s var(--ease);
}
.lb__btn:hover{background:rgba(var(--tint),.22);border-color:var(--accent)}
.lb__btn:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.lb__btn svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.4}

.lb__close{top:clamp(.85rem,2.5vh,1.6rem);right:clamp(.85rem,3vw,1.6rem)}
.lb__prev{left:clamp(.85rem,3vw,1.6rem);top:50%;transform:translateY(-50%)}
.lb__next{right:clamp(.85rem,3vw,1.6rem);top:50%;transform:translateY(-50%)}

/* a photograph mid-download shouldn't look like a broken one */
.lb__wait{
  position:absolute;top:50%;left:50%;
  width:26px;height:26px;margin:-13px 0 0 -13px;
  border:1px solid rgba(255,255,255,.25);
  border-top-color:var(--accent);
  border-radius:50%;
  opacity:0;pointer-events:none;
  animation:lb-spin 900ms linear infinite;
  transition:opacity .2s linear;
}
.lb.is-waiting .lb__wait{opacity:1}
@keyframes lb-spin{to{transform:rotate(360deg)}}

/* the grid cell announces itself as a control — but only on the pages whose
   frames are actually anchors. Film and aerial still use plain divs, and a
   pointer cursor over one of those promises something that isn't there. */
a.sgal__frame{display:block;cursor:pointer}
a.sgal__frame:focus-visible{outline:2px solid var(--accent-md);outline-offset:3px}

@media (max-width:700px){
  .lb{padding:4.25rem .75rem 1rem}
  .lb__prev{left:.6rem}
  .lb__next{right:.6rem}
  .lb__img{max-height:calc(100vh - 11rem);max-height:calc(100svh - 11rem)}
  .lb__cap{flex-direction:column;gap:.4rem}
}

@media (prefers-reduced-motion:reduce){
  .lb,.lb__img{transition:none}
  .lb__wait{animation:none}
}

/* ============================================================
   FILM PORTFOLIO
   Ten full-length films. Nothing is downloaded until a visitor
   presses one — see initFilms() in main.js — so the page costs a
   poster image per card and no more.
   ============================================================ */
.films{padding-block:clamp(3rem,6vw,5rem) var(--sec)}
.films__grid{
  display:grid;grid-template-columns:repeat(2,1fr);
  gap:clamp(2rem,3.5vw,3.25rem) clamp(1.25rem,2.5vw,2.25rem);
}

.film{margin:0;display:flex;flex-direction:column;gap:1rem}

.film__frame{
  position:relative;
  aspect-ratio:16/9;
  overflow:hidden;
  background:var(--ink-deep);   /* the ground a film sits on, before and during */
}
.film__poster{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform 1.1s var(--ease),opacity .4s var(--ease);
}
.film:hover .film__poster{transform:scale(1.03)}

/* the whole frame is the target — a 640px card with a 48px button is a
   needlessly small thing to ask someone to hit */
.film__play{
  position:absolute;inset:0;z-index:2;
  display:flex;align-items:center;justify-content:center;
  width:100%;height:100%;
  padding:0;border:0;background:transparent;
  cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}
.film__play-mark{
  display:flex;align-items:center;justify-content:center;
  width:clamp(56px,6vw,72px);aspect-ratio:1;
  background:rgba(10,10,10,.52);
  border:1px solid rgba(255,255,255,.34);
  border-radius:50%;
  color:var(--bone);
  transition:background .4s var(--ease),border-color .4s var(--ease),transform .4s var(--ease);
}
.film__play-mark svg{width:26px;height:26px;fill:currentColor;margin-left:3px}
.film__play:hover .film__play-mark{
  background:rgba(224,211,184,.92);color:var(--ink);border-color:var(--accent);transform:scale(1.06);
}
.film__play:focus-visible{outline:2px solid var(--accent);outline-offset:-4px}

.film__dur{
  /* bottom-LEFT on purpose: the films carry the commissioning agency's
     watermark in the bottom-right corner, and the badge sat on top of it */
  position:absolute;left:.75rem;bottom:.75rem;z-index:3;
  padding:.3rem .55rem;
  background:rgba(10,10,10,.7);
  color:rgba(255,255,255,.9);
  font-family:var(--ui);font-size:10px;letter-spacing:.14em;
  font-variant-numeric:tabular-nums;
  pointer-events:none;
}

/* the <video> swapped in on press */
.film__vid{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:contain;                /* never crop a film */
  background:var(--ink-deep);
  z-index:4;
}

.film__cap{display:flex;flex-direction:column;gap:.3rem}
.film__title{
  font-family:var(--display);font-size:clamp(1.15rem,1.6vw,1.4rem);
  letter-spacing:-.01em;color:var(--on);
}
.film__place{
  font-family:var(--ui);font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--on-muted);
}

/* a film that will not load says so, rather than sitting black */
.film__err{
  position:absolute;inset:0;z-index:5;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:.75rem;padding:1.5rem;text-align:center;
  background:rgba(10,10,10,.92);
  font-family:var(--ui);font-size:12px;line-height:1.6;
  color:rgba(255,255,255,.8);
}
.film__err a{color:var(--accent-lt);text-decoration:underline}

@media (max-width:860px){
  .films__grid{grid-template-columns:1fr;gap:clamp(1.75rem,5vw,2.5rem)}
}

@media (prefers-reduced-motion:reduce){
  .film__poster,.film__play-mark{transition:none}
  .film:hover .film__poster{transform:none}
}

/* ---------- 404 ---------- */
.nf__actions{margin-top:clamp(2rem,4vw,3rem);display:flex;flex-wrap:wrap;gap:.9rem}
.nf__nav{margin-top:1.25rem;justify-content:flex-start}

/* ---------- films hosted off-site ----------
   A card whose film comes from YouTube says so on its face, and the section
   note above says what pressing it does. Nothing is requested from Google
   until the press, so there is no PECR consent owed before that point — but
   the visitor still has to be able to see it coming. */
.film__host{
  position:absolute;left:.75rem;bottom:2.6rem;z-index:3;
  padding:.3rem .55rem;
  background:rgba(10,10,10,.7);
  border:1px solid rgba(255,255,255,.28);
  color:rgba(255,255,255,.82);
  font-family:var(--ui);font-size:9px;letter-spacing:.16em;text-transform:uppercase;
  pointer-events:none;
}
/* the YouTube player replaces the poster in the same 16:9 box — but only
   once it is actually there. Until then it is transparent and the poster
   underneath keeps showing, so a slow player looks like a photograph that is
   loading rather than a black hole. */
.film__embed{
  border:0;display:block;
  opacity:0;
  transition:opacity .3s var(--ease);
}
.film__embed.is-ready{opacity:1}

/* the frame dims and shows a spinner while the player boots */
.film__frame.is-loading .film__poster{filter:brightness(.55)}
.film__frame.is-loading::after{
  content:"";
  position:absolute;top:50%;left:50%;z-index:5;
  width:34px;height:34px;margin:-17px 0 0 -17px;
  border:2px solid rgba(255,255,255,.28);
  border-top-color:var(--accent);
  border-radius:50%;
  animation:film-spin 800ms linear infinite;
  pointer-events:none;
}
@keyframes film-spin{to{transform:rotate(360deg)}}

@media (prefers-reduced-motion:reduce){
  .film__embed{transition:none}
  .film__frame.is-loading::after{animation:none}
}
.legal__mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.92em}

/* ============================================================
   COOKIE CONSENT
   Decline is the same size, weight and prominence as Allow, sits
   beside it, and is reachable in the same number of actions. That
   is an ICO requirement, not a style choice — don't "improve" the
   Allow button on its own.
   ============================================================ */
.cc[hidden]{display:none}
.cc{
  position:fixed;left:0;right:0;bottom:0;z-index:150;
  background:var(--ink-deep);
  border-top:1px solid rgba(255,255,255,.14);
  padding:clamp(1.1rem,2.4vw,1.6rem) var(--pad);
  transform:translateY(100%);
  transition:transform .45s var(--ease);
  /* On a short window this bar can be taller than the viewport, and it used
     to overflow off the TOP — leaving the two buttons visible and the
     explanation unreachable. Consent has to be informed, so the copy scrolls
     inside the bar instead and the buttons stay put. */
  max-height:85vh;
  max-height:85svh;
  display:flex;flex-direction:column;
}
@supports (backdrop-filter:blur(6px)){
  .cc{background:rgba(10,10,10,.94);backdrop-filter:blur(10px)}
}
.cc.is-up{transform:translateY(0)}

.cc__inner{
  max-width:var(--maxw);width:100%;margin-inline:auto;
  display:flex;align-items:center;gap:clamp(1.25rem,3vw,3rem);
  flex-wrap:wrap;
  min-height:0;                 /* let the copy actually shrink and scroll */
}
.cc__copy{flex:1 1 30rem;min-width:0;min-height:0;overflow-y:auto}
.cc__eyebrow{
  font-family:var(--ui);font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--accent-lt);margin-bottom:.5rem;
}
.cc__text{
  font-family:var(--ui);font-size:12.5px;line-height:1.65;
  color:rgba(255,255,255,.8);max-width:68ch;
}
.cc__text a{color:var(--accent-lt);text-decoration:underline;text-underline-offset:3px}

/* A grid at every width, so Decline and Allow are exactly the same size.
   Content-sizing made "Decline" wider than "Allow" purely because the word is
   longer, and unequal prominence is the thing PECR/ICO guidance objects to. */
.cc__actions{display:grid;grid-template-columns:1fr 1fr;gap:.75rem;flex:0 0 auto}
.cc__btn{text-align:center}
.cc__btn{
  font-family:var(--ui);font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  padding:.95rem 1.75rem;
  border:1px solid rgba(255,255,255,.4);
  background:transparent;color:var(--bone);
  cursor:pointer;white-space:nowrap;
  transition:background .35s var(--ease),border-color .35s var(--ease),color .35s var(--ease);
}
.cc__btn:hover{background:rgba(255,255,255,.1);border-color:var(--bone)}
.cc__btn:focus-visible{outline:2px solid var(--accent);outline-offset:3px}

@media (max-width:640px){
  .cc__inner{flex-direction:column;align-items:stretch;gap:1.1rem}
  .cc__copy{flex:1 1 auto}
  .cc__actions{display:grid;grid-template-columns:1fr 1fr;gap:.6rem;flex:0 0 auto}
  .cc__btn{padding:.95rem .75rem;text-align:center}
}
/* landscape phones and small windows: give the copy the room, not the padding */
@media (max-height:560px){
  .cc{padding-block:.9rem}
  .cc__inner{gap:.9rem}
  .cc__text{font-size:12px}
}
@media (prefers-reduced-motion:reduce){
  .cc{transition:none}
}

/* the in-card prompt shown when media cookies are not allowed */
.film__gate{
  position:absolute;inset:0;z-index:6;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:.6rem;padding:clamp(1.25rem,4vw,2rem);text-align:center;
  background:rgba(10,10,10,.93);
}
.film__gate-t{
  font-family:var(--display);font-size:clamp(1.05rem,1.7vw,1.3rem);
  color:var(--bone);
}
.film__gate-d{
  font-family:var(--ui);font-size:11.5px;line-height:1.6;
  color:rgba(255,255,255,.72);max-width:38ch;
}
.film__gate-row{display:flex;flex-wrap:wrap;gap:.6rem;justify-content:center;margin-top:.6rem}
.film__gate-row .btn{font-size:9.5px;padding:.8rem 1.25rem}
.film__gate-x{
  margin-top:.35rem;padding:.35rem .5rem;
  background:none;border:0;cursor:pointer;
  font-family:var(--ui);font-size:9.5px;letter-spacing:.18em;text-transform:uppercase;
  color:rgba(255,255,255,.55);
}
.film__gate-x:hover{color:var(--bone)}
.film__gate-x:focus-visible,.film__gate-row .btn:focus-visible{outline:2px solid var(--accent);outline-offset:3px}

/* ---------- legal: sub-headings and the cookie table ---------- */
.legal__h3{
  margin-top:clamp(1.75rem,3.5vw,2.5rem);margin-bottom:.85rem;
  font-family:var(--ui);font-size:10px;font-weight:500;
  letter-spacing:.2em;text-transform:uppercase;
  color:var(--on);
}
/* a table is the honest shape for "what is stored, by whom, for how long",
   and it has to be able to scroll on a phone without taking the page with it */
.legal__tablewrap{
  overflow-x:auto;
  margin:1rem 0 .5rem;
  border:1px solid var(--rule);
  -webkit-overflow-scrolling:touch;
}
.legal__table{
  width:100%;min-width:34rem;
  border-collapse:collapse;
  font-family:var(--ui);font-size:12px;line-height:1.6;
  color:var(--on-muted);
}
.legal__caption{
  caption-side:top;text-align:left;
  padding:.85rem 1rem;
  font-size:9.5px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--on-faint);
  border-bottom:1px solid var(--rule);
}
.legal__table th,.legal__table td{
  padding:.85rem 1rem;
  border-bottom:1px solid var(--rule);
  text-align:left;vertical-align:top;
}
.legal__table thead th{
  font-size:9.5px;font-weight:500;letter-spacing:.18em;text-transform:uppercase;
  color:var(--on);white-space:nowrap;
}
.legal__table tbody tr:last-child th,.legal__table tbody tr:last-child td{border-bottom:0}
.legal__table td:first-child{color:var(--on)}

/* ============================================================
   HERO BACKGROUND FILM

   Centring the rectangle is not the same as centring what is in
   it. In the opening shot the man on the balcony sits at about
   54.5% across and 52% down, so a perfectly centred 16:9 frame
   still reads low and right. initHeroFilm() therefore sizes and
   positions the film in pixels so that POINT lands in the middle
   of the hero, at every viewport — see `frame()` there. Both the
   still and the video get identical treatment, so they occupy the
   same place and the hand-off is invisible.

   Nothing here should set width/height/left/top on .herofilm__v or
   .herofilm__still — JS owns those.
   ============================================================ */
.herofilm{
  position:absolute;inset:0;
  overflow:hidden;
  background-color:var(--ink-deep);
  isolation:isolate;
}
/* ambient fill behind everything, so no edge can ever show through */
.herofilm::before{
  content:"";
  position:absolute;inset:0;z-index:0;
  background-image:var(--hero-poster);
  background-size:cover;background-position:center;
  filter:blur(30px) brightness(.5) saturate(.85);
  transform:scale(1.12);
}
.herofilm__still,
.herofilm__v{
  position:absolute;
  will-change:transform;
}
.herofilm__still{
  z-index:1;
  background-image:var(--hero-poster);
  background-size:100% 100%;
  background-repeat:no-repeat;
}
.herofilm__v{
  z-index:2;
  object-fit:fill;          /* the box is already the exact frame aspect */
  opacity:0;
  transition:opacity 1.1s var(--ease);
  pointer-events:none;
}
.herofilm__v.is-live{opacity:1}

/* iOS draws a play button over any video it has not started, and this one
   has no controls of its own — suppress it so a blocked autoplay looks like
   a photograph rather than a broken player */
.herofilm__v::-webkit-media-controls,
.herofilm__v::-webkit-media-controls-start-playback-button,
.herofilm__v::-webkit-media-controls-panel{display:none!important;-webkit-appearance:none}

.hero__pause[hidden]{display:none}

@media (prefers-reduced-motion:reduce){
  .herofilm__v{transition:none}
}

/* ============================================================
   LOOPING CLIP GRID — the virtual-effects work
   Every tile is a real <img> poster with a video laid over it,
   and the video is only ever revealed once it is genuinely
   playing — so a tile is a photograph from first paint and never
   a black rectangle. How many tiles hold a decoder at once is
   decided in JS (see createLoopGrid); nothing here assumes a
   number.
   ============================================================ */
.lg{padding-block:clamp(3rem,6vw,5rem) var(--sec)}


.lg__feature{margin-bottom:clamp(2rem,4vw,3rem)}
.lg__grid{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:clamp(1.25rem,2.4vw,2.25rem) clamp(1rem,2vw,1.75rem);
}

.lg__item{margin:0}
.lg__media{
  position:relative;
  aspect-ratio:16/9;
  overflow:hidden;
  background:var(--ink-deep);
}
/* Overshot by a pixel on every side, and clipped back by the overflow:hidden
   on .lg__media. Grid tracks land on fractional widths (measured 540.8px), so
   a media box sized to exactly 100% rasterises with a half-covered edge
   column — which blends the picture into the near-black behind it and reads
   as a light hairline down the right-hand side. Overshooting means the
   anti-aliased edge is cut off rather than composited. */
.lg__poster,.lg__vid{
  position:absolute;inset:-1px;
  width:calc(100% + 2px);height:calc(100% + 2px);
  /* the reset's img{max-width:100%} clamps the poster back to exactly the
     container width while the <video> keeps its overshoot — which reinstates
     the very 1px gap this is here to close */
  max-width:none;
  object-fit:cover;
}
.lg__vid{
  opacity:0;
  transition:opacity .9s var(--ease);
  pointer-events:none;      /* the tile is not a control — there is nothing to press */
}
.lg__media.is-ready .lg__vid{opacity:1}

/* iOS paints a play button over any video it has not started. These loops
   carry no controls of their own, so a blocked autoplay has to look like a
   photograph rather than a broken player. */
.lg__vid::-webkit-media-controls,
.lg__vid::-webkit-media-controls-panel,
.lg__vid::-webkit-media-controls-start-playback-button{
  display:none!important;-webkit-appearance:none;appearance:none;
}

.lg__cap{margin-top:1.1rem;padding-top:1.1rem;border-top:1px solid var(--rule)}
.lg__num{
  font-size:9.5px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--mark);
}
.lg__t{
  font-family:var(--display);font-weight:400;
  font-size:clamp(1.15rem,1.7vw,1.4rem);line-height:1.25;
  margin-top:.4rem;
}
.lg__feature .lg__t{font-size:clamp(1.6rem,3vw,2.3rem)}
.lg__d{
  margin-top:.55rem;
  font-size:13.5px;line-height:1.75;color:var(--on-muted);
  max-width:44ch;
}
.lg__feature .lg__d{font-size:15px;max-width:52ch}

@media (max-width:1000px){
  .lg__grid{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:620px){
  .lg__grid{grid-template-columns:1fr}
}
@media (prefers-reduced-motion:reduce){
  .lg__vid{transition:none}
}

/* An odd number of items leaves the last one alone in its row, where the
   column divider has nothing to divide. */
.inc__item:last-child:nth-child(odd){border-right:0}

/* ============================================================
   BEFORE / AFTER PAIRS
   The photograph as taken, beside the same frame furnishing
   itself. Both panes are the identical 16:9 crop of the same
   locked-off camera, so the eye can compare them directly
   without having to re-find anything between the two.

   The right-hand pane is also a .lg__media, which means the
   looping engine (createLoopGrid) drives it exactly as it
   drives the gallery above — same decoder budget, same poster
   underneath, same no-play-button contract.
   ============================================================ */
.basec{padding-block:clamp(3rem,6vw,5rem) var(--sec)}

.ba__list{
  display:flex;flex-direction:column;
  gap:clamp(3rem,6vw,5rem);
}
.ba{margin:0}
.ba__pair{
  display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(.75rem,1.4vw,1.25rem);
}
.ba__pane{
  position:relative;
  aspect-ratio:16/9;
  overflow:hidden;
  background:var(--ink-deep);
}
/* overshot and clipped, so a fractional column width cannot leave a
   half-covered edge blending into the ground — see .lg__poster */
.ba__still{
  position:absolute;inset:-1px;
  width:calc(100% + 2px);height:calc(100% + 2px);
  max-width:none;object-fit:cover;
  user-select:none;-webkit-user-drag:none;
}

.ba__tag{
  position:absolute;top:.75rem;left:.75rem;z-index:3;
  padding:.3rem .6rem;
  background:rgba(10,10,10,.72);
  color:#F9F6F1;
  font-family:var(--ui);font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;
  pointer-events:none;
}
/* the moving pane earns a mark that says so */
.ba__tag--live{display:inline-flex;align-items:center;gap:.4rem}
.ba__tag--live::before{
  content:"";width:5px;height:5px;border-radius:50%;
  background:var(--accent);
}

.ba__cap{margin-top:1.1rem;padding-top:1.1rem;border-top:1px solid var(--rule)}
.ba__t{
  font-family:var(--display);font-weight:400;
  font-size:clamp(1.15rem,1.7vw,1.45rem);line-height:1.25;
}
.ba__d{margin-top:.5rem;font-size:13.5px;line-height:1.75;color:var(--on-muted);max-width:62ch}

@media (max-width:900px){
  /* stacked, so each frame keeps a usable width rather than two narrow ones */
  .ba__pair{grid-template-columns:1fr;gap:.6rem}
}

/* ============================================================
   VIRTUAL EFFECTS BAND  (home, between studio and services)
   Copy on one side, a looping clip on the other. The clip runs
   through the same budgeted engine as the grid on the service
   page, so it is a poster until frames are genuinely playing.
   ============================================================ */
.vfxband{padding-block:var(--sec)}
/* the heading spans the full width above the two columns, as .studio does */
.vfxband__head{margin-bottom:clamp(3rem,7vw,5.5rem);max-width:20ch}
.vfxband__grid{
  display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(2.5rem,6vw,6rem);
  align-items:start;
}
.vfxband__copy{
  display:flex;flex-direction:column;
  gap:clamp(1.4rem,2.5vw,2rem);
  padding-top:.5rem;
}
.vfxband__copy .btn{align-self:start;margin-top:.4rem}
.vfxband__media{margin:0}
.vfxband__cap{
  margin-top:1rem;
  font-family:var(--ui);font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--on-faint);
}

@media (max-width:900px){
  .vfxband__grid{grid-template-columns:1fr;gap:clamp(2rem,6vw,3rem)}
  /* MOBILE ONLY. Once the two columns stack, source order would drop the film
     below the copy — so it sits under the heading instead, where it introduces
     the paragraphs rather than trailing them. Desktop is untouched: there the
     grid still runs copy-left, film-right, exactly as .studio does. */
  .vfxband__media{order:-1}
}

/* ---------- Instagram, in the footer nav ---------- */
.foot__social{
  display:inline-flex;align-items:center;gap:.45rem;
}
.foot__social svg{
  width:13px;height:13px;flex:none;
  fill:currentColor;
  /* nudged to sit on the cap-height of the uppercase label beside it */
  transform:translateY(-.5px);
}

/* ---------- build credit ----------
   Sits below the footer's own row, quiet enough not to compete with the
   studio's copyright line but legible rather than hidden. The mark is the
   real TFM vector, so it stays crisp at any size and on any background. */
.foot__credit{
  margin-top:clamp(1.75rem,3.5vw,2.5rem);
  padding-top:clamp(1.25rem,2.5vw,1.75rem);
  border-top:1px solid var(--rule);
  text-align:center;
}
.foot__credit a{
  display:inline-flex;align-items:center;gap:.6rem;
  padding-block:5px;                 /* a 24px target, as the footer links have */
  font-family:var(--ui);
  font-size:9.5px;font-weight:400;letter-spacing:.2em;text-transform:uppercase;
  color:var(--on-faint);
  transition:color .4s var(--ease),opacity .4s var(--ease);
}
.foot__credit img{
  /* 22px was too small for the lettering inside the ring to read; at 32 the
     TFM is legible while the credit still sits quietly under the copyright */
  height:32px;width:auto;
  opacity:.9;
  transition:opacity .4s var(--ease);
}
.foot__credit a:hover{color:var(--mark)}
.foot__credit a:hover img{opacity:1}

@media (prefers-reduced-motion:reduce){
  .foot__credit a,.foot__credit img{transition:none}
}
