/* =========================================================
   Digitech Animated Videos — Video Editor Portfolio
   ========================================================= */

:root{
  /* Blue-violet identity. The ground is a deep blue-violet carrying a visible
     undertone; --accent is the pale periwinkle used for light-on-dark
     accents, --accent-2 the violet CTA. Contrast noted per token. */
  --bg:        #0a0d1c;
  --bg-soft:   #121835;
  --surface:   #1a2049;
  --line:      rgba(150,170,255,.20);
  --line-soft: rgba(150,170,255,.12);
  --fg:        #f2f2f8;   /* 17.3:1 on --bg */
  --fg-dim:    #b3b2c8;   /* 9.3:1 on --bg */
  --fg-faint:  #8d8ca8;   /* 5.9:1 on --bg, 4.8:1 on --surface */
  --accent:    #cfd4f5;   /* 13.2:1 on --bg */
  --accent-2:  #6d3ce8;   /* violet CTA — white on it is 6.1:1 */
  --accent-2-hi: #7c4dff;  /* hover tint; white on it is 4.8:1 */

  /* Blue end of the range, for gradients and glows that need a second hue. */
  --accent-3:  #3d7bff;
  --ink:       #0a0c16;   /* dark text on light/accent grounds */

  /* Channel triplets, so rgba() tints stay in the palette. */
  --bg-rgb:      10,13,28;
  --accent-rgb:  207,212,245;
  --violet-rgb:  109,60,232;
  --blue-rgb:    61,123,255;

  --serif: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif;   /* display face — geometric, was Instrument Serif */
  --sans:  "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --pad: clamp(1.25rem, 5vw, 6rem);
  --maxw: 1440px;
  --ease: cubic-bezier(.22,1,.36,1);
}

*,*::before,*::after{ box-sizing:border-box; }

html{
  /* 109% * 0.95 — the site-wide 5% type reduction. Every rem/em size follows
     this automatically; the clamp() sizes below carry a matching 0.95 on both
     their rem bounds and their vw term so headings shrink by the same 5%
     rather than staying put at viewport-driven widths. */
  font-size:103.55%;   /* ~16.6px root; every rem-based size scales with it */
  scroll-behavior:smooth;
  -webkit-text-size-adjust:100%;
}

body{
  margin:0;
  background:var(--bg);
  color:var(--fg);
  font-family:var(--sans);
  font-size:1rem;
  line-height:1.6;
  /* 300 rendered thin and washed out on the dark ground; 400 holds its
     colour at the small sizes used for body copy and meta text. */
  font-weight:400;
  letter-spacing:.005em;
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
}

body.is-loading{ overflow:hidden; height:100vh; }

img,video{ display:block; max-width:100%; height:auto; }
a{ color:inherit; text-decoration:none; }
ul,ol{ list-style:none; margin:0; padding:0; }
h1,h2,h3,h4{ margin:0; font-weight:400; letter-spacing:-.02em; line-height:1.05; }
p{ margin:0; }

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

/* --- focus visibility --- */
:focus-visible{
  outline:2px solid var(--accent);
  outline-offset:3px;
  border-radius:2px;
}

/* =========================================================
   Preloader
   ========================================================= */
/* A film strip spooling up: sprocket rails, four frames that expose one by
   one, a playhead scrubbing across, and a timecode. On exit two shutter
   blades split apart instead of the panel sliding away. */
.loader{
  position:fixed; inset:0; z-index:9999;
  display:grid; place-items:center;
  background:transparent;   /* the blades carry the ground */
  overflow:hidden;
}

/* --- shutter blades --- */
.loader__blade{
  position:absolute; left:0; right:0; height:50.5%;   /* .5 overlap: no seam */
  background:var(--bg);
  z-index:0;
}
.loader__blade--t{ top:0; }
.loader__blade--b{ bottom:0; }

.loader__inner{
  position:relative; z-index:1;
  display:flex; flex-direction:column; align-items:center; gap:1.1rem;
}

/* --- the strip --- */
.loader__strip{
  position:relative;
  width:min(72vw,340px);
  padding:5px 0;
  background:#05070f;
  border:1px solid var(--line-soft);
  border-radius:3px;
}

/* Sprocket holes, drawn as a repeating gradient so there is no extra markup. */
.loader__perfs{
  display:block; height:5px;
  background-image:repeating-linear-gradient(
    to right,
    rgba(var(--accent-rgb),.34) 0 6px,
    transparent 6px 14px
  );
  background-size:14px 100%;
}
.loader__perfs--t{ margin-bottom:5px; }
.loader__perfs--b{ margin-top:5px; }

.loader__frames{
  display:grid; grid-template-columns:repeat(4,1fr); gap:4px;
  padding:0 5px;
}
.loader__frame{
  position:relative;
  aspect-ratio:16/10;
  background:rgba(var(--accent-rgb),.06);
  border-radius:1px;
  overflow:hidden;
}
/* The exposing wipe — JS scales this from 0 to 1 per frame. */
.loader__frame::after{
  content:"";
  position:absolute; inset:0;
  background:linear-gradient(135deg,
    var(--accent-2) 0%,
    var(--accent-3) 55%,
    var(--accent) 100%);
  /* --exposed (0→1) is written per frame by the preloader in main.js. */
  transform:scaleY(var(--exposed,0));
  transform-origin:bottom;
}

/* --- playhead --- */
.loader__playhead{
  position:absolute; top:-3px; bottom:-3px; left:0;
  width:1px;
  background:var(--accent);
  box-shadow:0 0 10px 1px rgba(var(--accent-rgb),.65);
  opacity:0;
}

/* --- caption row --- */
.loader__meta{
  display:flex; align-items:baseline; justify-content:space-between;
  width:min(72vw,340px);
  font-size:.62rem; text-transform:uppercase; letter-spacing:.22em;
  color:var(--fg-faint);
}
.loader__tc{
  font-variant-numeric:tabular-nums; letter-spacing:.12em;
  color:var(--accent);
}

/* Reduced motion: no scrub, no shutter — show a finished strip and a
   static caption, and let the JS path remove the panel outright. */
@media (prefers-reduced-motion: reduce){
  .loader__frame{ --exposed:1; }
  .loader__playhead{ display:none; }
}

/* =========================================================
   Background canvas
   ========================================================= */
/* Graded film-plate layer (assets/js/three-bg.js) — the page's only
   background canvas. Fixed, non-interactive, and painted before .bg-scrim
   so it can never sit over content or affect a hover target. */
#bg-canvas{
  position:fixed; inset:0;
  width:100%; height:100%;
  z-index:0;
  pointer-events:none;
  opacity:.85;
}

@media (max-width:760px){
  /* Slightly dimmer on small screens: stacked mobile text leaves less
     clear ground between the plate and the copy sitting on it. */
  #bg-canvas{ opacity:.7; }
}

@media (prefers-reduced-motion:reduce){
  #bg-canvas{ display:none; }
}

/* Readability scrim: a fixed veil between the animated canvas and the page
   content, guaranteeing a contrast floor no matter where the plate's bright
   passages land. Deliberately light through the middle so the grade still
   reads as colour rather than mud, and weighted at the very top and bottom
   where the header and footer sit directly on it.
   The radial pass darkens the centre a touch further — that is where the
   halation and the streak are brightest, and where the headline sits. */
.bg-scrim{
  position:fixed; inset:0;
  z-index:1;
  pointer-events:none;
  background:
    /* Ambient violet and blue pools, so the page reads as colour rather
       than as a neutral dark. Kept low-alpha to protect text contrast. */
    radial-gradient(
      70% 50% at 15% 10%,
      rgba(var(--violet-rgb),.22) 0%,
      rgba(var(--violet-rgb),0) 70%
    ),
    radial-gradient(
      65% 55% at 90% 80%,
      rgba(var(--blue-rgb),.18) 0%,
      rgba(var(--blue-rgb),0) 70%
    ),
    radial-gradient(
      120% 85% at 50% 45%,
      rgba(var(--bg-rgb),.34) 0%,
      rgba(var(--bg-rgb),.18) 55%,
      rgba(var(--bg-rgb),0) 100%
    ),
    linear-gradient(
      to bottom,
      rgba(var(--bg-rgb),.62) 0%,
      rgba(var(--bg-rgb),.34) 18%,
      rgba(var(--bg-rgb),.34) 80%,
      rgba(var(--bg-rgb),.72) 100%
    );
}

main, .site-header, .site-footer, .mobile-menu{ position:relative; z-index:2; }

/* =========================================================
   Cursor
   ========================================================= */
.cursor{
  position:fixed; top:0; left:0; z-index:9998;
  width:28px; height:28px; margin:-14px 0 0 -14px;
  border:1px solid rgba(178,190,255,.35);
  border-radius:50%;
  pointer-events:none;
  transition:width .3s var(--ease), height .3s var(--ease),
             margin .3s var(--ease), background-color .3s var(--ease),
             border-color .3s var(--ease);
  mix-blend-mode:difference;
}
.cursor.is-hover{
  width:56px; height:56px; margin:-28px 0 0 -28px;
  background:rgba(255,255,255,.9);
  border-color:transparent;
}
@media (hover:none),(pointer:coarse){ .cursor{ display:none; } }

/* =========================================================
   Header
   ========================================================= */
.site-header{
  position:fixed; top:0; left:0; right:0; z-index:100;
  display:flex; align-items:center; gap:2rem;
  padding:1.35rem var(--pad);
  transition:background-color .4s var(--ease), padding .4s var(--ease),
             border-color .4s var(--ease), backdrop-filter .4s var(--ease);
  border-bottom:1px solid transparent;
}
.site-header.is-stuck{
  padding-block:.9rem;
  background:rgba(var(--bg-rgb),.72);
  backdrop-filter:blur(18px) saturate(140%);
  border-bottom-color:var(--line-soft);
}

.brand{ display:flex; align-items:center; gap:.6rem; margin-right:auto; }
.brand__mark{
  width:11px; height:11px; border-radius:50%;
  background:var(--accent-2);
  box-shadow:0 0 0 4px rgba(var(--violet-rgb),.32);
  animation:rec 2.4s ease-in-out infinite;
}
@keyframes rec{ 0%,100%{opacity:1} 50%{opacity:.25} }

.brand__text {
    font-family: var(--serif);
    font-weight: 500;
    font-size: 1.3rem;
    letter-spacing: -.01em;
}
.brand__text em{ font-style:italic; font-weight:600; color:var(--fg-dim); }

.nav ul{ display:flex; gap:1.9rem; }
.nav a{
  position:relative;
  font-size:.85rem; font-weight:600; letter-spacing:.04em; color:var(--fg-dim);
  transition:color .3s var(--ease);
}
.nav a::after{
  content:""; position:absolute; left:0; bottom:-6px;
  width:100%; height:1px; background:var(--accent);
  transform:scaleX(0); transform-origin:right;
  transition:transform .45s var(--ease);
}
.nav a:hover{ color:var(--fg); }
.nav a:hover::after{ transform:scaleX(1); transform-origin:left; }

/* Buttons */
.btn{
  --btn-h:2.9rem;          /* one control height keeps mixed rows aligned */
  --btn-pad:1.6rem;
  --btn-size:.82rem;
  display:inline-flex; align-items:center; justify-content:center; gap:.6rem;
  min-height:var(--btn-h); padding:0 var(--btn-pad);
  font-family:var(--sans);  /* <button> does not inherit the body font */
  font-size:var(--btn-size); line-height:1; letter-spacing:.04em; font-weight:400;
  border-radius:100px;
  border:1px solid var(--line);
  background:transparent; color:var(--fg);
  transition:background-color .35s var(--ease), color .35s var(--ease),
             border-color .35s var(--ease), transform .35s var(--ease),
             opacity .35s var(--ease);
  cursor:pointer; white-space:nowrap;
  -webkit-tap-highlight-color:transparent;
}
/* Every variant shares the same lift on hover and the same press. */
.btn:hover{ transform:translateY(-2px); }
.btn:active{ transform:translateY(0) scale(.98); }

/* CTA colour strategy
   ------------------------------------------------------------------
   Anything that sends the visitor into the enquiry/questionnaire is
   VIOLET with WHITE text (.btn--solid, .btn--pill) — a blue-to-violet
   gradient, lifting to the brighter violet on hover.
   Anything that only views or previews content is WHITE with DARK
   text (.btn--ghost). Keeping the two families apart means a "watch"
   never competes with a "get in touch". */

.btn--pill,
.btn--solid{
  background:linear-gradient(135deg, var(--accent-3) 0%, var(--accent-2) 55%);
  color:#fff; border-color:transparent;
  box-shadow:0 6px 20px -6px rgba(var(--violet-rgb),.55);
}
.btn--pill:hover,
.btn--solid:hover{
  background:linear-gradient(135deg, #5b93ff 0%, var(--accent-2-hi) 55%);
  color:#fff; border-color:transparent;
  box-shadow:0 10px 26px -6px rgba(var(--violet-rgb),.7);
}

/* View / preview actions — white surface, black label. */
.btn--ghost{ background:#fff; color:var(--ink); border-color:#fff; }
.btn--ghost:hover{ background:var(--fg); color:var(--ink); border-color:var(--fg); }

.btn--lg{ --btn-h:3.6rem; --btn-pad:2.4rem; --btn-size:.95rem; }

.btn__play{
  width:0; height:0;
  border-left:8px solid currentColor;
  border-top:5px solid transparent;
  border-bottom:5px solid transparent;
}

/* Burger */
.burger{
  display:none; width:34px; height:24px;
  background:none; border:0; padding:0; cursor:pointer;
  position:relative;
}
.burger span{
  position:absolute; left:0; width:100%; height:1px; background:var(--fg);
  transition:transform .4s var(--ease), opacity .3s var(--ease);
}
.burger span:nth-child(1){ top:8px; }
.burger span:nth-child(2){ top:16px; }
.burger.is-open span:nth-child(1){ transform:translateY(4px) rotate(45deg); }
.burger.is-open span:nth-child(2){ transform:translateY(-4px) rotate(-45deg); }

/* Mobile menu */
.mobile-menu{
  position:fixed; inset:0; z-index:99;
  background:var(--bg);
  display:grid; place-items:center;
}
/* `display:grid` would otherwise beat the [hidden] attribute. */
.mobile-menu[hidden]{ display:none; }
.mobile-menu ul{ display:grid; gap:1.5rem; text-align:center; }
.mobile-menu a{
  font-family:var(--serif); font-weight:250; letter-spacing:-.02em; font-size:clamp(2rem,8.55vw,3.5rem);
  color:var(--fg-dim); transition:color .3s var(--ease);
}
.mobile-menu a:hover{ color:var(--fg); }

/* =========================================================
   Shared section furniture
   ========================================================= */
section{ padding-inline:var(--pad); }

.section-head{
  max-width:var(--maxw); margin:0 auto 1rem;
  text-align:center;
}
.tag{
  display:inline-block; margin-bottom:1.5rem;
  font-size:.7rem; letter-spacing:.24em; text-transform:uppercase;
  color:var(--accent);
}

.section-title{
  font-family:var(--serif); font-weight:600; letter-spacing:-.02em;
  font-size:clamp(2.2rem,3.5vw,4rem);
  line-height:1.02;
}
/* The emphasised word in a heading carries the periwinkle accent. */
.section-title em, .h1 em, .contact__title em{
  font-style:italic; color:var(--accent);
}
.section-lead {
    margin-top: 1.5rem;
    max-width: 90ch;
    margin-inline: auto;
    color: var(--fg-dim);
    font-size: 1.02rem;
}

/* split-text helper. No will-change: that kept every character of every
   heading on its own GPU layer for the life of the page. GSAP promotes the
   characters only while their reveal is running. */
[data-split] .char{ display:inline-block; }

/* generic reveal */
.reveal-fade{ opacity:0; }


/* =========================================================
   Marquee
   ========================================================= */
.marquee{
  padding-inline:0;
  border-block:1px solid var(--line-soft);
  overflow:hidden; padding-block:.75rem;
  background:rgba(var(--bg-rgb),.5);
}
.marquee__track{
  display:flex; align-items:center; gap:2.5rem;
  width:max-content;
  animation:slide 34s linear infinite;
}
.marquee__track span{
  font-family:var(--serif); font-weight:250; letter-spacing:-.02em; font-size:clamp(1.3rem,2.47vw,2.1rem);
  color:var(--fg-dim); white-space:nowrap;
}
.marquee__track i{ color:var(--accent-2); font-style:normal; font-size:.7rem; }
@keyframes slide{ to{ transform:translateX(-50%) } }

/* =========================================================
   Showreel
   ========================================================= */
.showreel{ padding-block:clamp(1.5rem,3vw,2.75rem); }
/* The logo marquee reads as a divider, so the section after it does not need
   its own full top pad on top of that. */
.marquee + section{ padding-top:clamp(1rem,2vw,1.5rem); }
.marquee + section .tag{ margin-bottom:.9rem; }

.reel{ max-width:var(--maxw); margin:0 auto; }
.reel__frame {
    position: relative;
    aspect-ratio: 20/7;
    border-radius: 6px;
    overflow: hidden;
    border: 1px solid var(--line);
    background: var(--surface);
}
.reel__frame video{
  width:100%; height:100%; object-fit:cover;
  filter:saturate(.9) contrast(1.05);
}
.reel__play{
  position:absolute; inset:0; margin:auto;
  width:110px; height:110px; border-radius:50%;
  background:rgba(var(--bg-rgb),.35);
  backdrop-filter:blur(8px);
  border:1px solid rgba(178,190,255,.35);
  display:grid; place-items:center; cursor:pointer;
  transition:transform .45s var(--ease), background-color .45s var(--ease), opacity .4s var(--ease);
}
.reel__play:hover{ transform:scale(1.08); background:rgba(var(--accent-rgb),.2); }
.reel__play-icon{
  width:0; height:0;
  border-left:16px solid var(--fg);
  border-top:11px solid transparent;
  border-bottom:11px solid transparent;
  margin-left:5px;
}
.reel__play.is-playing .reel__play-icon{
  border:0; width:14px; height:16px; margin:0;
  border-left:4px solid var(--fg); border-right:4px solid var(--fg);
  background:transparent;
}
.reel__play-ring{
  position:absolute; inset:-1px; border-radius:50%;
  border:1px solid rgba(178,190,255,.2);
  animation:ring 3s var(--ease) infinite;
}
@keyframes ring{
  0%{ transform:scale(1); opacity:.7 }
  100%{ transform:scale(1.45); opacity:0 }
}

.reel__meta{
  position:absolute; left:0; right:0; bottom:0;
  display:flex; gap:2rem; padding:1.25rem 1.5rem;
  font-size:.7rem; letter-spacing:.16em; text-transform:uppercase;
  color:rgba(255,255,255,.75);
  background:linear-gradient(to top, rgba(var(--bg-rgb),.85), transparent);
}
.reel figcaption{
  margin-top:1.25rem; font-size:.85rem; color:var(--fg-faint); text-align:center; line-height:1.4;
}
/* CTA row under the explainer — same button styles as everywhere else. */
.reel__cta{
  display:flex; flex-wrap:wrap; gap:1rem; justify-content: center;
  max-width:var(--maxw); margin:2.5rem auto 0;
}

/* =========================================================
   Work grid
   ========================================================= */
.work{ position:relative; }

/* ---------------------------------------------------------
   Work label — oversized "WORK" drifting right to left
   The heading itself stays in the DOM for screen readers while
   the visual treatment is carried by the four letter spans.
   --------------------------------------------------------- */
.visually-hidden{
  position:absolute; width:1px; height:1px;
  margin:-1px; padding:0; border:0;
  clip:rect(0 0 0 0); clip-path:inset(50%);
  overflow:hidden; white-space:nowrap;
}

/* The label sits in normal flow and is only as tall as the word itself, so
   nothing empty is left above or below it. */
.work-label{
  position:relative; z-index:0;   /* under the projects, which slide over it */
  display:flex;
  margin:0;
  /* Top padding separates the caps from the section above. The small
     bottom padding is not spacing — at line-height .72 the box is shorter
     than the glyphs, so without it overflow:hidden would shave the base of
     the letters. It is the minimum that keeps them whole. */
  padding:clamp(1.5rem,4vw,3rem) 0 .12em;
  pointer-events:none;
  /* The word is wider than the viewport and travels past both edges, so the
     track clips it here, keeping the drift from widening the page or
     producing a horizontal scrollbar. */
  overflow:hidden;
}

/* The drift itself. GSAP owns this element's transform, scrubbing it from
   xPercent 60 to -60 — percentages resolve against the word's own width, so
   the travel scales with the type and needs no per-breakpoint numbers.
   No transform is declared here: without JS the word simply sits centred by
   the auto margins, which is the correct static fallback. */
.work-label-item{
  display:flex;
  margin:0 auto;
  flex:0 0 auto;
  white-space:nowrap;
  font-family:var(--serif); font-weight:250; letter-spacing:-.02em;
  font-size:clamp(4rem,16.15vw,15rem);
  line-height:.72;
  text-transform:uppercase;
  gap:clamp(1.5rem,7vw,6.5rem);
  will-change:transform;

  /* Blue-to-violet wash lifted from the existing accent tokens, angled so
     the colour shifts along the direction of travel.
     The gradient paints through the glyphs via background-clip:text, which
     needs a transparent fill to show. That fill is applied with -webkit-
     text-fill-color rather than `color:transparent` on purpose: if the clip
     ever fails to paint, text-fill-color falls back to `color` and the word
     stays legible, whereas a transparent `color` would leave it invisible.
     A decorative wash must never be able to hide the heading. */
  color:var(--fg);
  background-image:linear-gradient(100deg,
    rgba(var(--blue-rgb),1) 0%,
    var(--accent) 42%,
    rgba(var(--violet-rgb),1) 100%);
  -webkit-background-clip:text;
  background-clip:text;
  -webkit-text-fill-color:transparent;
}

/* Each letter keeps its own wrapper. No negative margins here: the track
   clips with overflow:hidden and now sizes to its content, so pulling the
   wrappers' outer box in would crop the glyphs it is meant to reveal. The
   row's line-height of .72 is what keeps the box tight to the caps. */
.work-label-item > span{ display:block; }
.work-label-item span span{ display:block; }

@media (prefers-reduced-motion:reduce){
  /* No drift — the word sits centred and still. The JS bails out of all
     scroll animation in this mode, so the auto margins already centre it;
     this only guards against a transform left over from a mode switch. */
  .work-label-item{ transform:none !important; }
}

/* ---------------------------------------------------------
   Pinned project slideshow (mirrors the reference)

   .work__list is sticky and holds every project stacked in the
   same 100vh box. A column of .work__marker spacers below it
   supplies the scroll distance — one viewport per project — and
   an IntersectionObserver flips each project's data-status
   between previous / current / next as its marker passes.

   Only the `current` project is visible; images fly upward out
   of frame as it becomes `previous`, and wait below as `next`.
   --------------------------------------------------------- */
.work__list{
  position:sticky; top:0; left:0;
  height:100vh;
  max-width:none; margin:0;
  z-index:2;              /* above the markers and the sticky WORK label */
}

/* One 100vh spacer per project. The first pulls back under the
   sticky list so the scroll distance starts at the right place.
   These are pure scroll ballast — they must never take a click. */
.work__markers{ position:relative; z-index:0; pointer-events:none; }
.work__marker{ height:100vh; }
.work__marker:first-child{ margin-top:-100vh; }

.project{
  position:absolute; inset:0;
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(16rem,26%);
  align-content:center;
  align-items:end;
  gap:clamp(1.5rem,3vw,3rem);
  padding-inline:var(--pad);
  height:100vh;
  overflow:hidden;
  cursor:pointer;
}
/* Every second project mirrors, so the eye zig-zags down the page. */
.project:nth-child(even){ grid-template-columns:minmax(16rem,26%) minmax(0,1fr); }
.project:nth-child(even) .project__stage{ order:2; }
.project:nth-child(even) .project__meta{ order:1; }
.project:nth-child(even) .project__index{ left:auto; right:var(--pad); }

/* ---- Slideshow states ---- */
/* Off-state projects must not swallow clicks meant for the current one. */
.project[data-status]{ pointer-events:none; }
.project[data-status='current']{ pointer-events:auto; }

/* Images travel vertically through the frame: waiting below when
   `next`, centred when `current`, gone upward when `previous`. */
.project[data-status] .project__stage,
.project[data-status] .project__meta{
  transition:transform 1.2s var(--ease), opacity 1.2s var(--ease), visibility 0s 1.2s;
  opacity:0; visibility:hidden;
}
.project[data-status='current'] .project__stage,
.project[data-status='current'] .project__meta{
  opacity:1; visibility:visible; transform:translate3d(0,0,0);
  transition:transform 1.2s var(--ease), opacity 1.2s var(--ease);
}
.project[data-status='next'] .project__stage{ transform:translate3d(0,60vh,0); }
.project[data-status='next'] .project__meta{ transform:translate3d(0,40vh,0); }
.project[data-status='previous'] .project__stage{ transform:translate3d(0,-70vh,0); }
.project[data-status='previous'] .project__meta{ transform:translate3d(0,-50vh,0); }

/* Satellites drift at their own rate so the stack separates in depth. */
.project[data-status] .project__sat{
  transition:transform 1.2s var(--ease), opacity 1.2s var(--ease);
}
.project[data-status='next'] .project__sat--a{ transform:translate3d(0,42vh,0); }
.project[data-status='next'] .project__sat--b{ transform:translate3d(0,58vh,0); }
.project[data-status='previous'] .project__sat--a{ transform:translate3d(0,-64vh,0); }
.project[data-status='previous'] .project__sat--b{ transform:translate3d(0,-82vh,0); }

/* Text staggers in behind the image, one beat apart. */
.project[data-status] .project__client,
.project[data-status] .project__title,
.project[data-status] .project__cat,
.project[data-status] .project__actions{
  opacity:0; transform:translate3d(0,1.4rem,0);
  transition:opacity .72s var(--ease), transform .72s var(--ease);
}
.project[data-status='current'] .project__client,
.project[data-status='current'] .project__title,
.project[data-status='current'] .project__cat,
.project[data-status='current'] .project__actions{
  opacity:1; transform:translate3d(0,0,0);
}
.project[data-status='current'] .project__client { transition-delay:.4s; }
.project[data-status='current'] .project__title  { transition-delay:.5s; }
.project[data-status='current'] .project__cat    { transition-delay:.6s; }
.project[data-status='current'] .project__actions{ transition-delay:.7s; }

/* Fallback: with no JS/observer the rows stay a plain readable list. */
.work__list:not([data-slideshow]) { position:static; height:auto; max-width:var(--maxw); margin:0 auto; }
.work__list:not([data-slideshow]) .project{ position:relative; inset:auto; height:auto; padding-inline:0; margin-bottom:6rem; }

@media (prefers-reduced-motion:reduce){
  .project[data-status] .project__stage,
  .project[data-status] .project__meta,
  .project[data-status] .project__sat,
  .project[data-status] .project__client,
  .project[data-status] .project__title,
  .project[data-status] .project__cat,
  .project[data-status] .project__actions{
    transition-duration:.01ms; transform:none;
  }
}

/* Running counter, echoing the reference's 01 /06 marker. */
.project__index{
  position:absolute; top:-1.9rem; left:0; z-index:2;
  display:flex; align-items:baseline; gap:.35rem;
  font-size:.68rem; letter-spacing:.24em; text-transform:uppercase;
  color:var(--fg-faint);
}
.project__index span{ color:var(--accent); font-size:.78rem; }
.project__index i{ font-style:normal; }

/* ---- Stage: hero frame plus two offset satellite stills ---- */
.project__stage{ position:relative; min-width:0; }

.project__frame{
  position:relative; overflow:hidden;
  aspect-ratio:16/9;
  border:1px solid var(--line-soft); border-radius:6px;
  background:var(--bg-soft);
  transition:border-color .6s var(--ease);
}
.project:hover .project__frame{ border-color:var(--line); }

.project__still,
.project__video{
  position:absolute; inset:0;
  width:100%; height:100%; object-fit:cover;
  display:block;
}
.project__still{
  filter:grayscale(1) brightness(.68);
  transform:scale(1.02);
  transition:transform 1.2s var(--ease), filter .8s var(--ease), opacity .5s var(--ease);
}
.project:hover .project__still{
  transform:scale(1.07);
  filter:grayscale(0) brightness(.92);
}
/* GSAP scrubs the transform of parallax elements (main.js adds .is-scrubbed).
   A CSS transition on that same transform restarts on every scroll frame and
   drags the whole section, so those elements transition everything else only. */
.project__still.is-scrubbed{ transition:filter .8s var(--ease), opacity .5s var(--ease); }
.project[data-status] .project__sat.is-scrubbed{ transition:opacity 1.2s var(--ease); }

/* Video sits under the still until playback starts. */
.project__video{ opacity:0; pointer-events:none; background:#000; z-index:2; }
.project.is-playing .project__still{ opacity:0; }
.project.is-playing .project__video{ opacity:1; pointer-events:auto; }
.project.is-playing .project__play,
.project.is-playing .project__dur{ opacity:0; pointer-events:none; }

/* ---- Play button ---- */
.project__play{
  position:absolute; left:50%; top:50%; z-index:3;
  transform:translate(-50%,-50%);
  width:clamp(72px,8vw,104px); height:clamp(72px,8vw,104px);
  display:grid; place-items:center; gap:0;
  border:0; border-radius:50%; padding:0;
  background:rgba(var(--bg-rgb),.42);
  backdrop-filter:blur(10px);
  color:var(--fg); cursor:pointer;
  transition:background-color .45s var(--ease), transform .45s var(--ease), opacity .4s var(--ease);
}
.project__play > *{ grid-area:1/1; }
.project__play:hover{ background:rgba(var(--bg-rgb),.62); transform:translate(-50%,-50%) scale(1.06); }
.project__play:active{ transform:translate(-50%,-50%) scale(.97); }
.project__play:focus-visible{ outline:2px solid var(--accent); outline-offset:4px; }

.project__play-ring{
  width:100%; height:100%; border-radius:50%;
  border:1px solid rgba(178,190,255,.35);
  transition:border-color .45s var(--ease), transform .8s var(--ease);
}
.project:hover .project__play-ring{
  border-color:var(--accent); transform:scale(1.08);
}
.project__play-icon{
  justify-self:center; align-self:center;
  width:0; height:0; margin-left:4px;
  border-left:14px solid var(--fg);
  border-top:9px solid transparent;
  border-bottom:9px solid transparent;
  transition:border-left-color .45s var(--ease);
}
.project:hover .project__play-icon{ border-left-color:var(--accent); }
/* Label is for screen readers and hover intent, not permanent chrome. */
.project__play-text{
  position:absolute; width:1px; height:1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap;
}

.project__dur{
  position:absolute; right:1rem; bottom:1rem; z-index:3;
  padding:.35rem .75rem; border-radius:100px;
  background:rgba(var(--bg-rgb),.6);
  backdrop-filter:blur(8px);
  border:1px solid rgba(178,190,255,.18);
  font-size:.62rem; letter-spacing:.18em;
  color:rgba(255,255,255,.85);
  transition:opacity .4s var(--ease);
}

/* ---- Satellite stills, offset off the hero's edges ---- */
.project__sats{ position:absolute; inset:0; pointer-events:none; }
.project__sat{
  position:absolute; overflow:hidden;
  margin:0; border-radius:4px;
  border:1px solid var(--line-soft);
  background:var(--bg-soft);
  box-shadow:0 24px 60px rgba(0,0,0,.55);
}
.project__sat img{
  width:100%; height:100%; object-fit:cover; display:block;
  filter:grayscale(1) brightness(.6);
  transition:filter .8s var(--ease), transform 1.2s var(--ease);
}
.project:hover .project__sat img{ filter:grayscale(0) brightness(.85); transform:scale(1.05); }

.project__sat--a{
  width:clamp(90px,13%,170px); aspect-ratio:3/4;
  right:-3.5%; top:-12%;
}
.project__sat--b{
  width:clamp(110px,17%,220px); aspect-ratio:4/3;
  left:-4.5%; bottom:-14%;
}
.project:nth-child(even) .project__sat--a{ right:auto; left:-3.5%; }
.project:nth-child(even) .project__sat--b{ left:auto; right:-4.5%; }

/* ---- Meta column ---- */
.project__meta{
  min-width:0;
  display:grid; gap:.6rem; align-content:end;
  padding-bottom:.35rem;
}
.project__client{
  font-size:.99rem; letter-spacing:.22em; text-transform:uppercase;
  color:var(--accent-2);
}
.project__title{ margin:0; }
.project__link{
  display:inline; padding:0; border:0; background:none;
  font-family:var(--serif); font-weight:250; letter-spacing:-.02em; text-align:left;
  font-size:clamp(1.6rem,3.04vw,2.9rem); line-height:1.05;
  color:var(--fg); cursor:pointer;
  background-image:linear-gradient(var(--accent),var(--accent));
  background-repeat:no-repeat;
  background-size:0% 1px; background-position:0 100%;
  transition:color .4s var(--ease), background-size .55s var(--ease);
}
.project:hover .project__link,
.project__link:hover{ color:var(--accent); background-size:100% 1px; }
.project__link:focus-visible{ outline:2px solid var(--accent); outline-offset:4px; }

.project__cat{
  color:var(--fg-dim); font-size:.9rem;
}
.project__actions{
  display:flex; flex-wrap:wrap; gap:.6rem; margin-top:.6rem;
}

/* =========================================================
   Services
   ========================================================= */
.services{ padding-block:clamp(1.25rem,2.5vw,2.25rem); }
.services__list{ max-width:var(--maxw); margin:0 auto; border-top:1px solid var(--line-soft); }

.service{
  display:grid;
  grid-template-columns:5rem minmax(0,1fr) minmax(0,1.2fr);
  gap:2rem; align-items:baseline;
  padding-block:2.25rem;
  border-bottom:1px solid var(--line-soft);
  transition:background-color .5s var(--ease), padding-inline .5s var(--ease);
}
.service:hover{ background:rgba(150,170,255,.06); padding-inline:1.25rem; }
.service__no{ font-size:.72rem; letter-spacing:.2em; color:var(--fg-faint); }
.service h3{ font-family:var(--serif); font-weight:250; letter-spacing:-.02em; font-size:clamp(1.5rem,2.85vw,2.5rem); }
.service p{ color:var(--fg-dim); font-size:.95rem; }

/* =========================================================
   Packages carousel
   ========================================================= */
/* Card anatomy mirrors the reference: a coloured header band carrying the
   style name, a still beneath it, then the "What's included" checklist and
   the CTA. The band is the same blue-to-violet as .btn--solid so the card
   heads and the buttons read as one family. */
.pkgs{ padding-block:clamp(1.5rem,3vw,2.75rem); }

.pkgs__slider{
  max-width:var(--maxw); margin:clamp(2.5rem,6vw,4rem) auto 0;
  --slides:3;                       /* cards per view */
  --gap:clamp(1rem,1.6vw,1.5rem);
}
.pkgs__viewport{ overflow:hidden; padding:2px; margin:-2px; }
/* Focusable for keyboard paging; the ring belongs on the whole strip
   rather than on a clipped card edge. */
.pkgs__viewport:focus-visible{ outline:2px solid var(--accent); outline-offset:6px; }

.pkgs__track{
  display:flex; gap:var(--gap);
  align-items:stretch;              /* every card on a page matches height */
  transition:transform .6s var(--ease);
  will-change:transform;
}
.pkgs__slide{
  flex:0 0 calc((100% - (var(--slides) - 1) * var(--gap)) / var(--slides));
  display:flex;
}

/* ---- Card ---- */
.pkg{
  display:flex; flex-direction:column;
  width:100%;
  background:var(--bg-soft);
  border:1px solid var(--line-soft);
  border-radius:14px;
  overflow:hidden;
  transition:border-color .45s var(--ease), transform .45s var(--ease),
             box-shadow .45s var(--ease);
}
.pkg:hover{
  border-color:var(--line);
  transform:translateY(-4px);
  box-shadow:0 18px 40px -22px rgba(var(--violet-rgb),.75);
}

.pkg__head{
  padding:1rem 1.25rem;
  text-align:center;
  background:linear-gradient(135deg, var(--accent-3) 0%, var(--accent-2) 55%);
}
.pkg__head h3{
  font-family:var(--serif); font-weight:600; letter-spacing:-.01em;
  font-size:clamp(1.05rem,1.5vw,1.3rem); line-height:1.2;
  color:#fff;                       /* 6.1:1 on the violet end of the band */
}

/* The still is absolutely placed inside the ratio box: left in flow its
   own intrinsic height wins over aspect-ratio (a flex item's min-height is
   auto), and stock images of differing ratios would then give every card a
   different media height. */
.pkg__media{
  position:relative;
  flex:0 0 auto;
  aspect-ratio:16/9;
  overflow:hidden;
  background:var(--surface);
}
.pkg__media img{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
  transition:transform .8s var(--ease);
}
.pkg:hover .pkg__media img{ transform:scale(1.04); }

.pkg__label{
  padding:1.15rem 1.25rem .85rem;
  text-align:center;
  font-size:.7rem; letter-spacing:.24em; text-transform:uppercase;
  color:var(--fg-faint);
}

.pkg__list{
  padding:0 1.25rem;
  display:grid; gap:.5rem;
  flex:1 1 auto;                    /* pushes the CTA to the card foot */
  align-content:start;
}
.pkg__list li{
  position:relative;
  padding:.7rem .9rem .7rem 2.55rem;
  border:1px solid var(--line-soft); border-radius:8px;
  background:rgba(var(--accent-rgb),.04);
  color:var(--fg-dim);
  font-size:.85rem; line-height:1.45;
}
/* The tick is drawn rather than imaged: a filled blue disc with a white
   check cut into it by two borders on a rotated box. */
.pkg__list li::before{
  content:"";
  position:absolute; left:.9rem; top:50%;
  width:1.1rem; height:1.1rem; margin-top:-.55rem;
  border-radius:50%;
  background:var(--accent-3);
}
.pkg__list li::after{
  content:"";
  position:absolute; left:1.29rem; top:50%;
  width:.28rem; height:.52rem; margin-top:-.33rem;
  border:solid #fff; border-width:0 1.5px 1.5px 0;
  transform:rotate(45deg);
}

.pkg__cta{
  margin:1.25rem; margin-top:1.5rem;
  width:calc(100% - 2.5rem);
}

/* ---- Controls — same furniture as the testimonial slider ---- */
.pkgs__controls{
  display:flex; align-items:center; justify-content:space-between; gap:1.5rem;
  margin-top:clamp(1.5rem,3vw,2.25rem);
}
.pkgs__dots{ display:flex; align-items:center; gap:.6rem; }
.pkgs__dot{
  width:28px; height:2px; padding:0;
  border:0; border-radius:100px;
  background:var(--line);
  cursor:pointer;
  transition:background-color .45s var(--ease), width .45s var(--ease);
}
.pkgs__dot:hover{ background:var(--fg-faint); }
.pkgs__dot.is-active{ width:46px; background:var(--accent); }

.pkgs__arrows{ display:flex; gap:.6rem; }
.pkgs__arrow{
  display:grid; place-items:center;
  width:2.9rem; height:2.9rem; padding:0;
  border:1px solid var(--line); border-radius:50%;
  background:transparent; color:var(--fg);
  cursor:pointer;
  transition:background-color .35s var(--ease), color .35s var(--ease),
             border-color .35s var(--ease), opacity .35s var(--ease);
}
.pkgs__arrow svg{
  width:17px; height:17px;
  fill:none; stroke:currentColor; stroke-width:1.5;
  stroke-linecap:round; stroke-linejoin:round;
}
.pkgs__arrow:hover:not(:disabled){
  background:var(--fg); color:var(--ink); border-color:var(--fg);
}
.pkgs__arrow:disabled{ opacity:.3; cursor:default; }

/* =========================================================
   Specialties / chips
   ========================================================= */
.specialties{ padding-block:clamp(1rem,2vw,1.75rem); }
.chips{
  max-width:var(--maxw); margin:0 auto;
  display:flex; flex-wrap:wrap; gap:.75rem;
}
.chips li{
  padding:.7rem 1.4rem; border-radius:100px;
  border:1px solid var(--line-soft);
  font-size:.85rem; color:var(--fg-dim);
  transition:color .35s var(--ease), border-color .35s var(--ease),
             background-color .35s var(--ease);
}
.chips li:hover{ color:var(--ink); background:var(--accent); border-color:var(--accent); }

/* =========================================================
   Process
   ========================================================= */
/* Opaque through the stack: the pinned cards paint over one another, so
   the section needs its own ground rather than the fixed background plate. */
.process{ padding-block:clamp(1.25rem,2.5vw,2rem); background:var(--bg); position:relative; }

/* ---- Stat strip in the section head ---- */
.process__stats{
  display:flex; flex-wrap:wrap; gap:clamp(1.75rem,5vw,3.5rem);
  margin-top:2.25rem; padding-top:1.75rem;
  border-top:1px solid var(--line-soft);
}
.process__stats li{ display:grid; gap:.3rem; }
.process__stats strong{
  font-family:var(--serif); font-weight:250; letter-spacing:-.02em;
  font-size:clamp(1.75rem,3.23vw,2.6rem); line-height:1;
  color:var(--accent);
}
.process__stats span{
  font-size:.68rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--fg-faint);
}

/* ---- Process timeline — a vertical zigzag ---------------------------------
   A centre spine runs the height of the list and fills as the section passes
   the middle of the screen. Steps alternate to either side of it, each with a
   node sitting on the spine. JS adds .is-live to the step nearest the centre
   line and drives the fill; with no JS, or under reduced motion, every step
   sits at full contrast and only the fill is dropped. */
.ztl{
  --spine-w:1px;
  --node:11px;
  /* The gutter between the spine and a card — half of it on each side. */
  --lane-gap:clamp(1.75rem,4vw,3.5rem);
  margin-top:clamp(1.5rem,3vw,2.5rem);
  max-width:min(var(--maxw), 100%);
  margin-inline:auto;
}
.ztl__label{
  font-size:.7rem; font-weight:500;
  letter-spacing:.22em; text-transform:uppercase;
  color:var(--fg-faint);
  margin-bottom:clamp(1.75rem,3.5vw,2.75rem);
}

.ztl__body{ position:relative; }

/* The spine is inset from the list's top and bottom so it starts and ends at
   the first and last nodes rather than running past them into empty space. */
.ztl__spine{
  position:absolute;
  left:50%; transform:translateX(-50%);
  top:0; bottom:0;
  width:var(--spine-w);
  background:var(--line-soft);
}
.ztl__spine-fill{
  position:absolute; inset:0 0 auto 0;
  height:0;
  background:var(--accent);
  transition:height .18s linear;
}

.ztl__list{
  display:grid;
  gap:clamp(2.25rem,5vw,4rem);
}

/* Each step is a two-column row; the card occupies one lane and the other is
   left empty, which is what produces the zigzag. The node is positioned on
   the centre line and so is independent of which lane the card is in. */
.zstep{
  position:relative;
  display:grid;
  grid-template-columns:1fr 1fr;
  column-gap:var(--lane-gap);
  align-items:start;
}
.zstep:nth-child(odd) .zstep__card{ grid-column:1; text-align:right; }
.zstep:nth-child(even) .zstep__card{ grid-column:2; }

/* Odd cards are right-aligned, so their foot rule and meta line have to run
   to the right edge too — the card is a grid, and justify-items moves the
   inline-level children without stretching them. */
.zstep:nth-child(odd) .zstep__card{ justify-items:end; }

.zstep__node{
  position:absolute;
  left:50%; top:1.4rem;
  width:var(--node); height:var(--node);
  margin-left:calc(var(--node) / -2);
  margin-top:calc(var(--node) / -2);
  border-radius:50%;
  border:1px solid var(--line-soft);
  background:var(--bg);
  transition:border-color .4s ease, background-color .4s ease, transform .4s ease;
}

.zstep__card{
  display:grid;
  gap:1rem;
  padding:clamp(1.5rem,2.2vw,2.1rem);
  border:1px solid var(--line-soft);
  border-radius:6px;
  background:var(--bg);
  transition:border-color .4s ease, opacity .4s ease, transform .4s ease;
}

/* Only dimmed once JS is driving; otherwise every step reads at full
   contrast so nothing depends on script to be legible. */
.ztl.is-driven .zstep__card{ opacity:.42; }
.ztl.is-driven .zstep.is-live .zstep__card{
  opacity:1;
  border-color:var(--accent);
  transform:translateY(-6px);
}
.ztl.is-driven .zstep.is-live .zstep__node{
  border-color:var(--accent);
  background:var(--accent);
  transform:scale(1.25);
}

.zstep__no{
  font-family:var(--serif); font-weight:250;
  font-size:1.35rem; line-height:1;
  letter-spacing:.14em;
  color:var(--accent);
  font-variant-numeric:tabular-nums;
}
.zstep__title{
  font-family:var(--serif); font-weight:250;
  font-size:clamp(1.5rem,1.045vw + 1.15rem,2rem);
  line-height:1.15; letter-spacing:-.02em;
  color:var(--fg);
}
.zstep__desc{
  font-size:clamp(.98rem,0.332vw + .88rem,1.1rem);
  line-height:1.5;
  color:var(--fg-dim);
}
.zstep__meta{
  padding-top:1rem;
  border-top:1px solid var(--line-soft);
  font-size:.68rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--fg-faint);
  /* The rule should span the card whichever lane it is in, so it opts out of
     the justify-items:end that right-aligns the odd column's other children. */
  justify-self:stretch;
}

/* =========================================================
   About
   ========================================================= */
.about{
  padding-block:clamp(1.25rem,2.5vw,2.25rem);
  max-width:var(--maxw); margin-inline:auto;
  display:grid; grid-template-columns:1fr 1.1fr; gap:clamp(2rem,6vw,5rem);
  align-items:center;
}
.about__media{
  border-radius:6px; overflow:hidden; border:1px solid var(--line-soft);
  aspect-ratio:4/5;
}
.about__media img{
  width:100%; height:100%; object-fit:cover;
  filter:grayscale(1) contrast(1.05) brightness(.8);
}
.about__body p{ color:var(--fg-dim); margin-top:1.5rem; max-width:52ch; }
.about__body .section-title{ margin-top:0; }
.about__tools{
  display:flex; flex-wrap:wrap; gap:.6rem; margin-top:2.25rem;
}
.about__tools li{
  font-size:.75rem; letter-spacing:.08em;
  padding:.45rem 1rem; border:1px solid var(--line-soft); border-radius:4px;
  color:var(--fg-faint);
}

/* =========================================================
   Testimonials
   ========================================================= */
.quotes{ padding-block:clamp(1.5rem,3vw,2.75rem); }

/* ---- Stat strip — mirrors .process__stats ---- */
.quotes__stats{
  display:flex; flex-wrap:wrap; gap:clamp(1.75rem,5vw,3.5rem);
  margin-top:2.25rem; padding-top:1.75rem;
  border-top:1px solid var(--line-soft);
}
.quotes__stats li{ display:grid; gap:.3rem; }
.quotes__stats strong{
  font-family:var(--serif); font-weight:250; letter-spacing:-.02em;
  font-size:clamp(1.75rem,3.23vw,2.6rem); line-height:1;
  color:var(--accent);
}
.quotes__stats span{
  font-size:.68rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--fg-faint);
}

/* ---- Carousel ---- */
.quotes__slider{
  max-width:var(--maxw); margin:clamp(2.5rem,6vw,4rem) auto 0;
  --slides:3;                       /* cards per view */
  --gap:clamp(1rem,1.6vw,1.5rem);
}
.quotes__viewport{ overflow:hidden; }
/* The viewport is focusable for keyboard paging, but the ring belongs on the
   whole strip rather than a clipped edge. */
.quotes__viewport:focus-visible{ outline:2px solid var(--accent); outline-offset:6px; }

.quotes__track{
  display:flex; gap:var(--gap);
  /* JS drives translateX; the transition is the slide itself. */
  transition:transform .6s var(--ease);
  will-change:transform;
}
.quotes__slide{
  flex:0 0 calc((100% - (var(--slides) - 1) * var(--gap)) / var(--slides));
  display:flex;                     /* lets the card stretch to equal height */
}

/* ---- Controls ---- */
.quotes__controls{
  display:flex; align-items:center; justify-content:space-between; gap:1.5rem;
  margin-top:clamp(1.5rem,3vw,2.25rem);
}
.quotes__dots{ display:flex; align-items:center; gap:.6rem; }
.quotes__dot{
  width:28px; height:2px; padding:0;
  border:0; border-radius:100px;
  background:var(--line);
  cursor:pointer;
  transition:background-color .45s var(--ease), width .45s var(--ease);
}
.quotes__dot:hover{ background:var(--fg-faint); }
.quotes__dot.is-active{ width:46px; background:var(--accent); }

.quotes__arrows{ display:flex; gap:.6rem; }
.quotes__arrow{
  display:grid; place-items:center;
  width:2.9rem; height:2.9rem; padding:0;
  border:1px solid var(--line); border-radius:50%;
  background:transparent; color:var(--fg);
  cursor:pointer;
  transition:background-color .35s var(--ease), color .35s var(--ease),
             border-color .35s var(--ease), opacity .35s var(--ease);
}
.quotes__arrow svg{
  width:17px; height:17px;
  fill:none; stroke:currentColor; stroke-width:1.5;
  stroke-linecap:round; stroke-linejoin:round;
}
.quotes__arrow:hover:not(:disabled){
  background:var(--fg); color:var(--ink); border-color:var(--fg);
}
.quotes__arrow:disabled{ opacity:.3; cursor:default; }

.quote{
  position:relative; margin:0;
  /* Fills its slide so every card in a row matches height. */
  flex:1; min-width:0;
  padding:clamp(1.75rem,2.6vw,2.4rem);
  border:1px solid var(--line-soft); border-radius:8px;
  background:linear-gradient(180deg, rgba(150,170,255,.07), rgba(120,140,255,.02));
  display:grid; gap:1.5rem; align-content:space-between;
  overflow:hidden;
  transition:border-color .5s var(--ease), transform .5s var(--ease),
             background-color .5s var(--ease);
}

.quote:hover{
  border-color:var(--line);
  background:
    radial-gradient(120% 90% at 0% 0%, rgba(var(--violet-rgb),.20), transparent 62%),
    radial-gradient(110% 80% at 100% 100%, rgba(var(--blue-rgb),.14), transparent 60%),
    linear-gradient(180deg, rgba(178,190,255,.055), rgba(178,190,255,.014));
  transform:translateY(-4px);
}

/* Oversized serif quote mark, sunk behind the text. */
.quote__mark{
  position:absolute; top:0; right:.5rem;
  font-family:var(--serif); font-weight:250; letter-spacing:-.02em; font-size:7rem; line-height:.8;
  color:var(--accent); opacity:.09;
  pointer-events:none; user-select:none;
  transition:opacity .5s var(--ease);
}
.quote:hover .quote__mark{ opacity:.15; }

.quote blockquote{ margin:0; }
.quote blockquote p{
  font-family:var(--serif); font-weight:250; letter-spacing:-.02em;
  font-size:clamp(1.1rem,1.615vw,1.45rem);
  line-height:1.4; color:var(--fg);
}

/* ---- Attribution ---- */
.quote__by{
  display:flex; align-items:center; gap:.9rem;
  padding-top:1.25rem;
  border-top:1px solid var(--line-soft);
}
.quote__avatar{
  flex:none; display:grid; place-items:center;
  width:2.6rem; height:2.6rem; border-radius:50%;
  border:1px solid rgba(var(--accent-rgb),.25);
  background:rgba(var(--accent-rgb),.06);
  font-size:.7rem; letter-spacing:.1em; color:var(--accent);
  transition:background-color .5s var(--ease), border-color .5s var(--ease);
}
.quote:hover .quote__avatar{
  background:rgba(var(--accent-rgb),.13); border-color:rgba(var(--accent-rgb),.45);
}
.quote__who{ display:grid; gap:.2rem; min-width:0; }
.quote__who strong{ font-weight:400; font-size:.92rem; }
.quote__who > span{
  font-size:.72rem; color:var(--fg-faint); letter-spacing:.06em;
}

/* =========================================================
   FAQ
   ========================================================= */
.faq{ padding-block:clamp(1.25rem,2.5vw,2.25rem); }
.faq__list{ max-width:var(--maxw); margin:0 auto; border-top:1px solid var(--line-soft); }

.faq details{ border-bottom:1px solid var(--line-soft); }
.faq summary{
  list-style:none; cursor:pointer;
  padding:1.85rem 3rem 1.85rem 0; position:relative;
  font-family:var(--serif); font-weight:250; letter-spacing:-.02em; font-size:clamp(1.15rem,2.28vw,1.8rem);
  transition:color .35s var(--ease);
}
.faq summary::-webkit-details-marker{ display:none; }
.faq summary:hover{ color:var(--accent); }
.faq summary::after,
.faq summary::before{
  content:""; position:absolute; right:.25rem; top:50%;
  background:currentColor; transition:transform .4s var(--ease), opacity .4s var(--ease);
}
.faq summary::before{ width:16px; height:1px; margin-top:-.5px; }
.faq summary::after{ width:1px; height:16px; margin-top:-8px; right:calc(.25rem + 7.5px); }
.faq details[open] summary::after{ transform:rotate(90deg); opacity:0; }
.faq details p{
  padding:0 4rem 2rem 0; color:var(--fg-dim);
}

/* =========================================================
   Contact
   ========================================================= */
.contact{
  padding-block:clamp(1.5rem,3.25vw,3rem);
  text-align:center;
  border-top:1px solid var(--line-soft);
}
.contact__title{
  font-family:var(--serif); font-weight:600; letter-spacing:-.02em;
  font-size:clamp(2.5rem,4.75vw,4rem);
  line-height:1; margin-bottom:1.75rem;
}
.contact__lead{
  color:var(--fg-dim); max-width:90ch; margin:0 auto 3rem;
}
/* The fallback email line sits after the inline CTA button, so it needs its
   own top spacing to clear it. */
.contact__lead--alt{
  font-size:.9rem; margin:2rem auto 3rem;
}
.contact__lead--alt a{ color:var(--fg); text-decoration:underline; text-underline-offset:3px; }
.contact__links{
  display:flex; justify-content:center; flex-wrap:wrap; gap:2rem;
  margin-top:3.5rem;
}
.contact__links a{
  font-size:.8rem; letter-spacing:.14em; text-transform:uppercase;
  color:var(--fg-faint); transition:color .3s var(--ease);
}
.contact__links a:hover{ color:var(--fg); }

/* =========================================================
   Footer
   ========================================================= */
.site-footer{
  padding:4rem var(--pad) 2rem;
  border-top:1px solid var(--line-soft);
  background:
    radial-gradient(80% 120% at 50% 0%, rgba(var(--violet-rgb),.18), transparent 70%),
    var(--bg-soft);
}
.site-footer__top{
  max-width:var(--maxw); margin:0 auto;
  display:grid; grid-template-columns:1.4fr 2fr; gap:3rem;
  padding-bottom:3.5rem;
}
.site-footer__brand p{
  margin-top:1rem; color:var(--fg-faint); font-size:.88rem; max-width:34ch;
}
.site-footer nav{ display:grid; grid-template-columns:repeat(3,1fr); gap:2rem; }
.site-footer h4{
  font-size:.7rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--fg-faint); margin-bottom:1.1rem; font-weight:400;
}
.site-footer nav ul{ display:grid; gap:.65rem; }
.site-footer nav a{
  font-size:.88rem; color:var(--fg-dim);
  transition:color .3s var(--ease);
}
.site-footer nav a:hover{ color:var(--fg); }

.site-footer__bottom{
  max-width:var(--maxw); margin:0 auto;
  padding-top:2rem; border-top:1px solid var(--line-soft);
  display:flex; justify-content:space-between; flex-wrap:wrap; gap:1rem;
  color:var(--fg-faint); font-size:.78rem;
}
/* =========================================================
   Portfolio filter chips
   ========================================================= */
.work__filter{
  position:relative; z-index:3;   /* above both the label and the project list */
  max-width:var(--maxw); margin:0 auto 2rem;
  display:flex; flex-wrap:wrap; gap:.6rem; justify-content:center;
}
.filterchip{
  display:inline-flex; align-items:center; justify-content:center;
  min-height:2.35rem; padding:0 1.35rem; border-radius:100px;
  border:1px solid var(--line-soft); background:transparent;
  font-family:var(--sans); font-size:.78rem; line-height:1; letter-spacing:.04em;
  font-weight:400; color:var(--fg-dim); cursor:pointer; white-space:nowrap;
  transition:color .35s var(--ease), border-color .35s var(--ease),
             background-color .35s var(--ease), transform .35s var(--ease);
  -webkit-tap-highlight-color:transparent;
}
.filterchip:hover{
  color:var(--fg); border-color:var(--line);
  background:rgba(178,190,255,.04); transform:translateY(-2px);
}
.filterchip:active{ transform:translateY(0) scale(.98); }
.filterchip:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; }
.filterchip.is-active{
  background:var(--accent); border-color:var(--accent); color:var(--ink);
}
.filterchip.is-active:hover{ background:var(--accent); color:var(--ink); }

/* Cards hidden by the filter — animated out, then pulled from layout. */
.vcard.is-filtered{ display:none; }

.work__note{
  max-width:var(--maxw); margin:2.5rem auto 0;
  text-align:center;
  color:var(--fg-faint); font-size:.9rem;
}
.work__note a{
  color:var(--fg); text-decoration:underline; text-underline-offset:3px;
}
.work__note a:hover{ color:var(--accent); }

/* =========================================================
   Video cards — preview affordance + actions
   ========================================================= */
.project__actions{
  display:flex; flex-wrap:wrap; align-items:center;
  gap:.85rem; margin-top:1.5rem;
}
.btn--sm{ --btn-h:2.35rem; --btn-pad:1.15rem; --btn-size:.75rem; }
/* Borderless variant keeps the shared height so it sits level with its row. */
.btn--text{
  border-color:transparent; background:transparent;
  color:var(--accent-2); --btn-pad:.85rem;
}
.btn--text:hover{
  color:var(--accent-2-hi); border-color:transparent;
  background:rgba(178,190,255,.04);
}

/* =========================================================
   Video detail modal
   ========================================================= */
.vmodal{
  position:fixed; inset:0; z-index:200;
  display:grid; place-items:center;
  padding:clamp(1rem,4vw,3rem);
}
/* `display:grid` would otherwise beat the [hidden] attribute. */
.vmodal[hidden]{ display:none; }

.vmodal__backdrop{
  position:absolute; inset:0;
  background:rgba(5,6,12,.86);
  backdrop-filter:blur(10px) saturate(120%);
}
.vmodal__panel{
  position:relative;
  width:min(940px,100%); max-height:90vh; overflow-y:auto;
  /* Stacked, not side-by-side: the clip led one column while the copy led the
     other, so whichever was shorter left a dead band. Now the video sets the
     panel's width and the copy simply follows it. */
  display:flex; flex-direction:column;
  background:var(--bg-soft);
  border:1px solid var(--line); border-radius:12px;
  overflow-x:hidden;
  box-shadow:0 40px 90px -20px rgba(0,0,0,.75);
}
.vmodal__media{
  position:relative;
  background:#000;
  border-bottom:1px solid var(--line-soft);
}
.vmodal__media video{
  /* No forced aspect-ratio: the clips are not all 16:9, and pinning one
     letterboxed the others inside their own frame. Letting the video keep its
     intrinsic ratio means the black box always matches the picture. */
  width:100%; height:auto; max-height:46vh; object-fit:contain;
  display:block; background:#000;
}
/* The browser paints its own fullscreen backdrop; letterboxing keeps the
   aspect ratio correct instead of stretching to the screen. */
.vmodal__media video:fullscreen{ object-fit:contain; aspect-ratio:auto; }
.vmodal__body{
  padding:clamp(1.35rem,2.4vw,1.9rem);
  display:grid; gap:1.15rem; align-content:start;
}
.vmodal__head{ display:grid; gap:.5rem; }
/* The eyebrow used to repeat the title verbatim; JS now feeds it the run
   time instead, so it reads as a caption rather than an echo. */
.vmodal__kind{
  font-size:.64rem; letter-spacing:.24em; text-transform:uppercase;
  color:var(--accent); font-weight:500;
}
.vmodal__title{
  font-family:var(--serif); font-weight:250; letter-spacing:-.02em;
  font-size:clamp(1.5rem,2.47vw,2.1rem); line-height:1.15;
}

/* Description and the "best suited to" list sit side by side under the clip,
   which keeps the panel wide and short instead of tall and narrow. */
.vmodal__cols{
  display:grid; grid-template-columns:1.15fr 1fr;
  gap:clamp(1.5rem,4vw,2.5rem);
  padding-top:1.15rem; border-top:1px solid var(--line-soft);
}
.vmodal__desc{ color:var(--fg-dim); font-size:.95rem; margin:0; }

.vmodal__uses h4{
  font-size:.68rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--fg-faint); font-weight:400; margin-bottom:.9rem;
}
.vmodal__uses ul{ display:grid; gap:.55rem; }
.vmodal__uses li{
  position:relative; padding-left:1.4rem;
  font-size:.9rem; color:var(--fg-dim);
}
.vmodal__uses li::before{
  content:""; position:absolute; left:0; top:.62em;
  width:6px; height:1px; background:var(--accent-2);
}

.vmodal__cta{
  display:flex; align-items:center; flex-wrap:wrap; gap:1rem;
  margin-top:.5rem;
}
/* Sits over the clip's top-right corner. It used to overlap the copy
   column's eyebrow line; anchoring it to the media keeps the text clear. */
.vmodal__close{
  position:absolute; top:.9rem; right:.9rem; z-index:3;
  width:40px; height:40px; border-radius:50%;
  background:rgba(var(--bg-rgb),.72); backdrop-filter:blur(8px);
  border:1px solid var(--line);
  cursor:pointer; display:grid; place-items:center;
  transition:background-color .35s var(--ease), transform .35s var(--ease);
}
.vmodal__close:hover{ background:var(--accent); transform:rotate(90deg); }
.vmodal__close span{
  position:absolute; width:14px; height:1px; background:var(--fg);
}
.vmodal__close:hover span{ background:var(--ink); }
.vmodal__close span:nth-child(1){ transform:rotate(45deg); }
.vmodal__close span:nth-child(2){ transform:rotate(-45deg); }

body.modal-open{ overflow:hidden; }

/* =========================================================
   Enquiry form
   ========================================================= */
.eform{
  position:relative;
  max-width:820px; margin:0 auto; text-align:left;
  padding:3rem 3rem 3.25rem;
  border:1px solid var(--line-soft); border-radius:14px;
  /* Translucent so the starfield still drifts behind the panel. */
  background:
    linear-gradient(180deg, rgba(var(--accent-rgb),.045) 0%, rgba(var(--accent-rgb),0) 42%),
    rgba(26,32,73,.72);
  backdrop-filter:blur(14px) saturate(1.15);
  -webkit-backdrop-filter:blur(14px) saturate(1.15);
  box-shadow:0 1px 0 rgba(var(--accent-rgb),.06) inset,
             0 30px 70px -30px rgba(0,0,0,.75);
}
/* Accent hairline along the top edge of the panel. */
.eform::before{
  content:''; position:absolute; inset:0 0 auto; height:1px;
  border-radius:14px 14px 0 0;
  background:linear-gradient(90deg,
    transparent 0%,
    rgba(var(--accent-rgb),.4) 50%,
    transparent 100%);
  pointer-events:none;
}
/* Shows which style the visitor came from — filled in by main.js. */
.eform__for{
  display:inline-flex; align-items:center; gap:.55rem;
  margin-bottom:2.25rem; padding:.7rem 1.3rem;
  border:1px solid var(--line-soft); border-radius:100px;
  background:rgba(var(--accent-rgb),.05);
  font-size:.82rem; letter-spacing:.03em; color:var(--fg-dim);
}
.eform__for strong{
  font-weight:400; color:var(--accent);
}
.eform__for.is-set{ border-color:rgba(var(--accent-rgb),.3); }

.eform__grid{
  display:grid; grid-template-columns:repeat(2,1fr); gap:1.5rem;
}
/* align-content:start — a taller neighbour (e.g. one showing an error) must
   not stretch this field's label/input rows. */
.field{ display:grid; gap:.6rem; align-content:start; }
.field--wide{ grid-column:span 2; }
.field__label{
  font-size:.72rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--fg-faint);
}
.field__label i{ color:var(--accent-2); font-style:normal; }

.field input,
.field select,
.field textarea{
  width:100%;
  font-family:var(--sans);
  font-size:.95rem;
  font-weight:400;
  line-height:1.5;
  color:var(--fg);
  background:rgba(150,170,255,.05);
  border:1px solid var(--line-soft);
  border-radius:4px;
  padding:.9rem 1rem;
  transition:border-color .35s var(--ease), background-color .35s var(--ease);
  -webkit-transition:border-color .35s var(--ease), background-color .35s var(--ease);
  -moz-transition:border-color .35s var(--ease), background-color .35s var(--ease);
  -ms-transition:border-color .35s var(--ease), background-color .35s var(--ease);
  -o-transition:border-color .35s var(--ease), background-color .35s var(--ease);
}
.field textarea{ resize:vertical; line-height:1.5; resize: none;}
.field input:hover,
.field select:hover,
.field textarea:hover{ border-color:var(--line); }
.field input:focus,
.field select:focus,
.field textarea:focus{
  outline:none;
  border-color:var(--accent);
  background:rgba(150,170,255,.09);
}
.field input::placeholder,
.field textarea::placeholder{ color:var(--fg-faint); }

/* Browser autofill: keep the dark field. Chrome forces a light fill with
   !important; a transition outranks that and is too slow to ever finish. */
.field input:-webkit-autofill,
.field select:-webkit-autofill{
  -webkit-text-fill-color:var(--fg);
  caret-color:var(--fg);
  transition:background-color 600000s;
  transition:background-color 600000s, background-image 600000s allow-discrete; /* keeps the select arrow too */
}

/* Native pickers render dark-on-dark otherwise. */
.field select{
  appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,var(--fg-dim) 50%),
                   linear-gradient(135deg,var(--fg-dim) 50%,transparent 50%);
  background-position:calc(100% - 1.15rem) 50%, calc(100% - .8rem) 50%;
  background-size:5px 5px, 5px 5px;
  background-repeat:no-repeat;
  padding-right:2.5rem; cursor:pointer;
}
.field select option{ background:var(--surface); color:var(--fg); }
.field input[type="date"],
.field input[type="time"]{ cursor:pointer; }
.field input[type="date"]::-webkit-calendar-picker-indicator,
.field input[type="time"]::-webkit-calendar-picker-indicator{
  filter:invert(1) opacity(.5); cursor:pointer;
}

.field.has-error input,
.field.has-error select,
.field.has-error textarea{ border-color:var(--accent-2); }

.eform__foot{
  display:flex; align-items:center; flex-wrap:wrap;
  gap:1.25rem; margin-top:2.25rem;
}
.eform__note{ font-size:.8rem; color:var(--fg-faint); }

.eform__status{
  margin-top:1.5rem; font-size:.9rem;
  color:var(--accent); min-height:1.2em;
}
.eform__status.is-error{ color:var(--accent-2); }

/* ---- Grouped sections ---------------------------------- */
.eform__set{
  border:0; padding:0; margin:0 0 2.75rem;
}
.eform__set + .eform__set{
  padding-top:2.5rem; border-top:1px solid var(--line-soft);
}
/* A native <legend> notches into the fieldset's top border, so the set's
   padding-top lands *below* it as dead space. Floating it takes it out of
   that flow and makes it behave as an ordinary block heading. */
.eform__legend{
  float:left; width:100%;
  display:flex; align-items:center; gap:.75rem;
  padding:0; margin:0 0 1.5rem;
  font-size:.78rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--fg-dim);
}
/* Clear the float so the grid starts on a fresh line. */
.eform__legend + *{ clear:both; }
.eform__step{
  display:inline-flex; align-items:center; justify-content:center;
  width:1.7rem; height:1.7rem; border-radius:50%;
  border:1px solid rgba(var(--accent-rgb),.35);
  background:rgba(var(--accent-rgb),.06);
  font-size:.68rem; letter-spacing:.04em; color:var(--accent);
}


/* ---- Choice cards (style / length) --------------------- */
.choice{
  display:grid; gap:.75rem;
  grid-template-columns:repeat(auto-fit,minmax(165px,1fr));
}
.choice--length{ grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); }

.choice__item{ display:block; cursor:pointer; }
/* Visually hidden, still focusable and reachable by arrow keys. */
.choice__item input{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}
.choice__box{
  display:flex; flex-direction:column; gap:.3rem;
  height:100%; padding:.95rem 1.05rem;
  border:1px solid var(--line-soft); border-radius:6px;
  background:rgba(178,190,255,.02);
  transition:border-color .3s var(--ease), background-color .3s var(--ease),
             transform .3s var(--ease);
}
.choice__box--pill{ padding:.8rem .95rem; }
/* Keeps the card rows even when a hint wraps onto two lines. */
.choice__box{ justify-content:flex-start; }
.choice__name{
  font-size:.92rem; color:var(--fg); line-height:1.25;
}
.choice__hint{
  font-size:.74rem; letter-spacing:.02em; color:var(--fg-faint); line-height:1.3;
}

.choice__item:hover .choice__box{
  border-color:var(--line); background:rgba(178,190,255,.04);
}
.choice__item input:focus-visible + .choice__box{
  outline:2px solid var(--accent); outline-offset:2px;
}
.choice__item input:checked + .choice__box{
  border-color:var(--accent);
  background:rgba(var(--accent-rgb),.09);
  transform:translateY(-2px);
}
.choice__item input:checked + .choice__box .choice__name{ color:var(--accent); }
.choice__item input:checked + .choice__box .choice__hint{ color:var(--fg-dim); }

.field.has-error .choice__box{ border-color:var(--accent-2); }
#header .brand img{
  width: 170px;
}


/* =========================================================
   Responsive
   ========================================================= */
@media (max-width:1080px){
  .project, .project:nth-child(even){ grid-template-columns:minmax(0,1fr); align-items:start; }
  .project:nth-child(even) .project__stage{ order:1; }
  .project:nth-child(even) .project__meta{ order:2; }

  /* Stacked into one column the slide is taller, so centre the
     content and let it size to the copy rather than overflowing. */
  .project{
    align-content:center;
    gap:clamp(1rem,3vw,1.75rem);
    padding-block:clamp(4.5rem,12vh,7rem);
  }
  .project__index{ top:auto; }
  .quotes__slider{ --slides:2; }
  .pkgs__slider{ --slides:2; }
  /* Two lanes leave too little measure for the copy on a narrow screen, so
     the timeline straightens: the spine moves to the left edge and every card
     sits in a single column beside it. */
  .ztl{ --lane-gap:1.5rem; }
  .ztl__spine{ left:0; transform:none; }
  .zstep{ grid-template-columns:1fr; }
  .zstep__node{ left:0; }
  .zstep:nth-child(odd) .zstep__card,
  .zstep:nth-child(even) .zstep__card{
    grid-column:1;
    text-align:left;
    justify-items:start;
  }
  .zstep__card{ margin-left:var(--lane-gap); }
}

@media (max-width:960px){
  /* The panel itself is always stacked now; below this width the copy pair
     under the clip collapses to a single column too. */
  .vmodal__cols{ grid-template-columns:1fr; gap:1.5rem; }
  .vmodal__media{ width:100%; overflow:hidden; }
  /* max-width keeps the frame inside the panel once it is the full width. */
  .vmodal__media video{ height:auto; max-width:100%; max-height:44vh; }
}

@media (max-width:860px){
  .nav, .site-header .btn--pill{ display:none; }
  .burger{ display:block; }

  /* WORK label on small screens — the drift and the flow layout are the
     same as on desktop, so only the type needs bringing down. */
  .work-label-item{ font-size:clamp(3.2rem,20.9vw,7rem); gap:clamp(1rem,6vw,2.5rem); }

  .about{ grid-template-columns:1fr; }
  .about__media{ aspect-ratio:16/10; }

  /* One card per view once there is no room for two. */
  .quotes__slider{ --slides:1; }
  .pkgs__slider{ --slides:1; }

  .service{ grid-template-columns:3rem 1fr; gap:1rem 1.25rem; }
  .service p{ grid-column:2; }

  .site-footer__top{ grid-template-columns:1fr; }
}

@media (max-width:560px){
  .project__sats{ display:none; }
  .project__index{ position:static; margin-bottom:.75rem; }
  .site-footer nav{ grid-template-columns:1fr 1fr; }
  .reel__play{ width:80px; height:80px; }

  .process__stats,
  .quotes__stats{ gap:1.5rem 2.25rem; }
  .quote{ padding:1.5rem 1.25rem; }
  .quotes__controls,
  .pkgs__controls{ flex-direction:column-reverse; align-items:stretch; gap:1.25rem; }
  .quotes__arrows,
  .pkgs__arrows{ justify-content:center; }
  .quotes__dots,
  .pkgs__dots{ justify-content:center; }
  .eform__grid{ grid-template-columns:1fr; }
  .field--wide{ grid-column:span 1; }
  .eform__foot{ flex-direction:column; align-items:stretch; }
  .eform__foot .btn{ width:100%; }
  .choice{ grid-template-columns:repeat(2,1fr); }
  .choice--length{ grid-template-columns:repeat(2,1fr); }
  .eform__set + .eform__set{ padding-top:2rem; }
  .eform{ padding:1.75rem 1.25rem 2rem; border-radius:12px; }
  .eform::before{ border-radius:12px 12px 0 0; }
  .vmodal{ padding:0; }
  .vmodal__panel{ max-height:100vh; border-radius:0; border:0; }
}

/* =========================================================
   Reduced motion
   ========================================================= */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
  html{ scroll-behavior:auto; }
  .reveal-fade{ opacity:1 !important; }
  #bg-canvas{ display:none; }
  /* Filtering still needs to hide cards — only the tween is dropped. */
  .vcard.is-filtered{ display:none !important; }
  /* Paging still works; it just jumps rather than slides. */
  .quotes__track,
  .pkgs__track{ transition:none; }
  .pkg, .pkg__media img{ transition:none; }
  .pkg:hover{ transform:none; }
  .pkg:hover .pkg__media img{ transform:none; }
  /* Without motion the steps are not dimmed or lifted and the spine simply
     stays unfilled — the timeline reads as a plain, fully legible list.
     JS also skips driving it in this mode. */
  .ztl.is-driven .zstep__card{
    opacity:1 !important; transform:none !important;
  }
  .ztl.is-driven .zstep__node{ transform:none !important; }
  .ztl__spine-fill{ transition:none; }

  }



