/* ==========================================================================
   FRACTR’D — Version 1
   --------------------------------------------------------------------------
   Contents
     1.  Design tokens
     2.  Reset & base
     3.  Shared primitives (container, section, eyebrow, buttons, links)
     4.  Header & navigation
     5.  Hero
     6.  Works
     7.  Work detail sheet
     8.  Client banner
     9.  Ways to work with us
     10. Proof of work
     11. Contact
     12. Footer
     13. Responsive
     14. Reduced motion
   ========================================================================== */

/* ==========================================================================
   1. DESIGN TOKENS — change these to retheme the whole site
   ========================================================================== */
:root {
  /* Colour — white canvas, single blue accent */
  --bg:            #ffffff;
  --bg-alt:        #f5f6f8;
  --surface:       #ffffff;
  --surface-2:     #f1f3f6;
  --border:        rgba(11, 12, 14, .12);
  --border-strong: rgba(11, 12, 14, .30);
  --text:          #0b0c0e;
  --muted:         #5f6672;
  --accent:        #2d17f6;
  --accent-hover:  #2311c9;
  --accent-ink:    #ffffff;

  /* Type */
  --font: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji", sans-serif;
  --mono: ui-monospace, "Cascadia Code", "SFMono-Regular", Menlo, Consolas, monospace;

  /* Space & shape */
  --container: none;
  --gutter: clamp(1.5rem, 4vw, 3.5rem);
  --section-y: clamp(4.5rem, 9vw, 8rem);
  --header-h: 68px;
  --r-sm: 8px;
  --r:    14px;
  --r-lg: 20px;

  /* Motion (hover states only) */
  --t: 140ms ease;
}

/* ==========================================================================
   2. RESET & BASE
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.6;
  letter-spacing: -.005em;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;          /* guards against accidental mobile overflow */
}

body.is-locked { overflow: hidden; }

/* Android and iOS paint a translucent block over whatever was just tapped.
   On a dark full-bleed control like a work category that lands as a bright
   cyan rectangle across the whole row for a frame or two — the "fast flash"
   on tap. Every control here already has its own press state. */
a, button, [role="button"], summary, label, input, select, textarea {
  -webkit-tap-highlight-color: transparent;
}

h1, h2, h3, h4 { margin: 0; line-height: 1.1; letter-spacing: -.03em; font-weight: 600; }
p { margin: 0; }
ul, ol, dl, dd { margin: 0; padding: 0; }
ul, ol { list-style: none; }
img, video { max-width: 100%; display: block; }
button { font: inherit; color: inherit; }

/* Author `display` rules otherwise beat the UA style for [hidden]. */
[hidden] { display: none !important; }

a { color: inherit; }

:where(a, button, video, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Section targets clear the sticky header when scrolled to. */
:target,
section[id],
#main,
#top { scroll-margin-top: calc(var(--header-h) + 1.25rem); }

section[id]:focus,
#main:focus { outline: none; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: 1rem;
  top: -4rem;
  z-index: 200;
  padding: .7rem 1.1rem;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
  border-radius: var(--r-sm);
  text-decoration: none;
}
.skip-link:focus { top: 1rem; }

/* ==========================================================================
   3. SHARED PRIMITIVES
   ========================================================================== */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: var(--section-y);
  border-top: 1px solid var(--border);
}

/* No rule here: the works section fades straight into this one. */
.section--clients {
  position: relative;
  overflow: hidden;
  padding-top: clamp(3rem, 5vw, 4rem);
  background: #0b0c0e;
  border-top: 0;
}
.section--contact {
  background: var(--accent);
  color: var(--accent-ink);
  border-top: 0;
}

.section__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1.25rem, 4vw, 3rem);
  align-items: end;
  margin-bottom: clamp(2.25rem, 5vw, 3.5rem);
}

.section__title { font-size: clamp(2.5rem, 4vw, 5rem); }

.section__lead {
  justify-self: end;
  width: min(100%, 52ch);
  color: var(--muted);
  max-width: 52ch;
  font-size: clamp(1.0625rem, 1.25vw, 1.375rem);
  line-height: 1.55;
}

.eyebrow {
  font-family: var(--mono);
  font-size: .75rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .75rem;
}

.notice {
  padding: 1rem 1.25rem;
  border: 1px solid var(--border);
  border-radius: var(--r);
  color: var(--muted);
}

/* Buttons ---------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .8rem 1.5rem;
  background: var(--accent);
  color: var(--accent-ink);
  border: 1px solid var(--accent);
  border-radius: 999px;
  font-size: .9375rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--t), border-color var(--t), color var(--t);
}
.btn:hover { background: var(--accent-hover); border-color: var(--accent-hover); }

.btn--ghost {
  background: transparent;
  color: var(--text);
  border-color: var(--border-strong);
}
.btn--ghost:hover { background: var(--surface-2); border-color: var(--text); }

.btn--sm { padding: .55rem 1.1rem; font-size: .875rem; }

/* Links ------------------------------------------------------------------ */
.link {
  color: var(--text);
  text-decoration: none;
  border-bottom: 1px solid var(--border-strong);
  padding-bottom: 1px;
  transition: color var(--t), border-color var(--t);
}
.link:hover { color: var(--accent); border-color: var(--accent); }
.link--lg { font-size: clamp(1.125rem, 2.5vw, 1.5rem); font-weight: 500; }

.inline-list {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1.25rem;
}

/* ==========================================================================
   4. HEADER & NAVIGATION
   ========================================================================== */
/* Transparent and sticky. `mix-blend-mode: difference` over white text makes
   the header read black on the white page, and invert to light wherever dark
   content scrolls underneath it.

   The blend lives on .header itself, not its children: `position: sticky`
   always creates a stacking context, which would isolate any descendant blend
   from the page content behind it. */
.header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: transparent;
  color: #fff;
  mix-blend-mode: difference;
  padding-block: clamp(.875rem, 1.8vw, 1.375rem);
}

/* While the mobile panel is open it needs an opaque background, which the
   blend would invert — so drop out of blend mode entirely. */
.header.is-menu-open {
  mix-blend-mode: normal;
  color: var(--text);
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

.header__inner {
  display: grid;
  grid-template-columns: 1fr 3fr;
  gap: var(--gutter);
  align-items: start;
  padding-inline: var(--gutter);
}

.brand {
  display: inline-flex;
  align-items: flex-start;
  font-size: clamp(1.125rem, 1.9vw, 1.625rem);
  font-weight: 800;
  line-height: .95;
  letter-spacing: -.04em;
  text-decoration: none;
  color: inherit;
}
.brand__logo {
  display: block;
  height: clamp(26px, 3vw, 38px);
  width: auto;
  aspect-ratio: 2727 / 1181;
  flex: none;
  background: currentColor;
  -webkit-mask: url("../img/brand/logo-white.png") no-repeat center / contain;
  mask: url("../img/brand/logo-white.png") no-repeat center / contain;
}

.nav { display: contents; }

.nav__menu {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gutter);
  align-items: start;
}

/* Size and leading live on the column so the list items inherit them — left to
   the body's 1.6 line-height the rows sit far further apart than the links. */
.nav__col {
  display: flex;
  flex-direction: column;
  font-size: .75rem;
  line-height: 1.35;
}

/* Right-hand column hangs off the right edge, like the reference. */
.nav__col--end { text-align: right; }

/* Middle items sit indented — the small stagger from the reference layout. */
.nav__col:not(.nav__col--end) li:not(:first-child):not(:last-child) {
  padding-left: 1.4em;
}

.nav__link,
.nav__note {
  display: inline-block;
  font-size: inherit;
  line-height: inherit;
  font-weight: 700;
  letter-spacing: .01em;
  text-transform: uppercase;
  text-decoration: none;
  color: inherit;
}

.nav__note { opacity: .6; }

/* Colour shifts are unreliable under a difference blend, so hover and the
   active state use an underline instead. */
.nav__link { text-decoration: underline transparent 1px; text-underline-offset: .2em; }
.nav__link:hover { text-decoration-color: currentColor; }
.nav__link[aria-current="true"] { text-decoration-color: currentColor; }

.nav__toggle {
  display: none;
  width: 42px;
  height: 32px;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  justify-self: center;
}

.nav__toggle-arrow {
  width: 12px;
  height: 12px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform .35s cubic-bezier(.2, .8, .2, 1);
}

.nav__toggle[aria-expanded="true"] .nav__toggle-arrow {
  transform: rotate(225deg);
}

/* ==========================================================================
   5. HERO
   ========================================================================== */
.hero {
  padding-top: clamp(5rem, 12vw, 10rem);   /* clear separation from the nav */
  text-align: center;
  overflow-x: clip;                        /* safety net if font metrics differ */
}

/* --- the giant wordmark ------------------------------------------------- */
.wordmark {
  margin: clamp(1.5rem, 4vw, 3rem) 0 clamp(4rem, 9vw, 7rem);
  padding-inline: clamp(.5rem, 1.5vw, 1rem);
  text-align: center;
  font-weight: 800;
  line-height: .82;
  letter-spacing: -.045em;
}

.wordmark__word {
  display: inline-block;
  white-space: nowrap;
  font-size: 20vw;                  /* fallback — main.js fits it exactly */
}

/* Each letter grows up from its own baseline, staggered left to right. */
.wordmark__char {
  display: inline-block;
  transform-origin: 50% 100%;
}

/* Idle (un-sprouted) state. Scoped to .js-reveal so the wordmark is only ever
   hidden when JavaScript is actually able to animate it back in. */
.js-reveal .wordmark:not(.is-inview) .wordmark__char {
  transform: scaleY(0) translateY(.1em);
  opacity: 0;
}

/* main.js removes .is-inview when the wordmark leaves the viewport and adds it
   again on re-entry, which restarts the animation — so it replays on every
   pass rather than only on first load. */
.wordmark.is-inview .wordmark__char {
  animation: sprout .8s cubic-bezier(.2, .85, .3, 1) backwards;
  animation-delay: calc(var(--i) * 70ms);
}

@keyframes sprout {
  0%   { transform: scaleY(0) translateY(.1em); opacity: 0; }
  55%  { transform: scaleY(1.07) translateY(0); opacity: 1; }
  100% { transform: scaleY(1) translateY(0); opacity: 1; }
}

/* --- copy below the wordmark ------------------------------------------- */
.hero__lower {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1.75rem, 4vw, 2.5rem);
}

.hero__body {
  color: var(--muted);
  max-width: 46ch;
  font-size: clamp(1rem, 1.6vw, 1.1875rem);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .75rem;
}

/* --- blue stats band closing the hero ---------------------------------- */
.hero__band {
  margin-top: clamp(4rem, 9vw, 7rem);
  margin-bottom: 0;
  padding-block: clamp(2.5rem, 5vw, 4rem);
  background: #0b0c0e;
  color: var(--accent-ink);
}

.hero__stats {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: clamp(2.5rem, 8vw, 7rem);
}
.hero__stat { display: flex; flex-direction: column; align-items: center; gap: .4rem; }
.hero__stat-value {
  font-size: clamp(2.75rem, 5.5vw, 4.5rem);
  font-weight: 700;
  letter-spacing: -.03em;
  line-height: 1.02;
}
.hero__stat-label { font-size: clamp(.9375rem, 1.3vw, 1.125rem); color: rgba(255, 255, 255, .78); }

/* ==========================================================================
   6. WORKS — filter bar, list, cross-fading backdrop
   ========================================================================== */
.section--works {
  position: relative;
  /* Keep the dark transitions visible without leaving a full fade-height of
     empty space between the neighbouring content blocks. */
  padding-top: clamp(5rem, 8vw, 7rem);
  padding-bottom: clamp(4rem, 7vw, 6rem);
  background: #0b0c0e;
  color: #fff;
  border-top: 0;
  overflow: hidden;
}
.section--works .eyebrow { color: #8f9bff; }

/* Selected Work runs nearly edge-to-edge — just a small gutter — rather than
   being capped at the standard container width. */
.section--works .container {
  max-width: none;
  padding-inline: clamp(1.5rem, 4vw, 3.5rem);
}

.works__head { position: relative; text-align: center; }
.works__eyebrow { margin-bottom: clamp(1.5rem, 3vw, 2.5rem); font-weight: 400; }

.works__bar {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: .75rem 1rem;
}
.works__bar-label,
.works__count {
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .45);
}


.works__filters { display: flex; flex-wrap: wrap; gap: .5rem; }

.chip-filter {
  padding: .5rem 1.1rem;
  background: transparent;
  color: rgba(255, 255, 255, .6);
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color var(--t), border-color var(--t), background var(--t);
}
.chip-filter:hover { color: #fff; border-color: rgba(255, 255, 255, .5); }
.chip-filter[aria-pressed="true"] {
  color: #0b0c0e;
  background: #fff;
  border-color: #fff;
}

/* The list sits over a stack of posters; the hovered row's layer fades in. */
.works__bg { position: absolute; inset: 0; overflow: hidden; }

/* Seamless joins: the hero's blue band bleeds into the top of this section,
   and the bottom melts into the pale clients section below. */
.section--works::before,
.section--works::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  z-index: 1;
  pointer-events: none;
}
.section--works::before {
  top: 0;
  height: clamp(120px, 18vw, 240px);
  background: linear-gradient(180deg, #0b0c0e 0%, rgba(11, 12, 14, 0) 100%);
}
.section--works::after {
  bottom: 0;
  height: clamp(120px, 18vw, 240px);
  background: linear-gradient(180deg, rgba(11, 12, 14, 0) 0%, #0b0c0e 100%);
}

.works__head, .works__list { z-index: 2; }
.works__layer {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0;
  transition: opacity .5s ease;
}
.works__layer.is-active { opacity: .55; }
.works__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(11, 12, 14, .92) 0%, rgba(11, 12, 14, .45) 38%, rgba(11, 12, 14, .55) 100%),
    linear-gradient(90deg, rgba(11, 12, 14, .85) 0%, rgba(11, 12, 14, .25) 70%);
}

.works__list { position: relative; padding-top: clamp(2.5rem, 6vw, 4.5rem); }

.work-row {
  border-top: 1px solid rgba(255, 255, 255, .14);
}
.work-row:last-child { border-bottom: 1px solid rgba(255, 255, 255, .14); }

.work-row__btn {
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 1rem;
  width: 100%;
  padding: clamp(.9rem, 2vw, 1.5rem) 0;
  background: none;
  border: 0;
  text-align: left;
  cursor: pointer;
  color: rgba(255, 255, 255, .45);
  transition: color var(--t);
}
.work-row__btn:hover,
.work-row__btn:focus-visible { color: #fff; }

.work-row__num {
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .1em;
  opacity: .55;
}
.work-row__title {
  font-size: clamp(1.5rem, 3.6vw, 2.75rem);
  font-weight: 300;
  letter-spacing: -.02em;
  line-height: 1.2;
}
.work-row__client {
  justify-self: end;
  text-align: right;
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  opacity: .7;
}

/* ==========================================================================
   7. WORK DETAIL MEDIA
   Shared by the project detail view inside the category browser.
   ========================================================================== */
.sheet__media { grid-column: span 1; }
.sheet__media.is-wide { grid-column: 1 / -1; }
@media (max-width: 640px) {
  .sheet__media, .sheet__media.is-wide { grid-column: 1 / -1; }
}
/* Natural aspect so mixed orientations (landscape / square / portrait) never
   crop. Capped at 85vh so a tall still can't dominate the scroll. */
.sheet__media { margin: 0; }
.sheet__media img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: var(--r);
  background: var(--surface-2);
}
.sheet__media video {
  width: 100%;
  height: auto;
  background: #000;
  border-radius: var(--r);
}

/* ==========================================================================
   8. CLIENT BANNER
   ========================================================================== */
.band__title {
  text-align: center;
  font-family: var(--mono);
  font-size: .75rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .5);
  font-weight: 400;
  margin-bottom: clamp(1.75rem, 4vw, 2.75rem);
}

.bands { display: flex; flex-direction: column; gap: clamp(1rem, 2vw, 1.75rem); }

/* The logo run. It drifts on its own and can be grabbed and thrown by hand,
   so the motion is driven from initLogoMarquee() rather than a CSS animation:
   a keyframe cannot be scrubbed, and handing a drag to it would mean fighting
   the animation's own clock. This element only supplies the frame. */
.logos {
  position: relative;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}

.logos__track {
  display: flex;
  width: max-content;
  will-change: transform;
  cursor: grab;
  /* Horizontal drags belong to the row, vertical ones stay with the page, so
     a phone can still scroll past this without catching on it. */
  touch-action: pan-y;
}
.logos.is-dragging .logos__track { cursor: grabbing; }

.logos__group {
  display: flex;
  align-items: center;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Back to one shared height with width left free. The row is unbounded again,
   so nothing has to be squeezed into a column, and matching cap-height is
   what actually reads as "the same size" across marks as different as a
   square badge and a wide wordmark. */
.client {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  padding-inline: clamp(1.25rem, 2.75vw, 2.75rem);
}
.client__logo {
  height: clamp(3rem, 5vw, 4.5rem);
  width: auto;
  opacity: .78;
  transition: opacity .2s ease;
  /* The row is draggable, so the browser's own image drag has to be off or
     it hijacks the gesture and starts a file drag instead. */
  -webkit-user-drag: none;
  user-select: none;
  pointer-events: none;
}
.logos:hover .client__logo { opacity: 1; }
.client__name {
  font-size: clamp(1.125rem, 2vw, 1.625rem);
  font-weight: 600;
  letter-spacing: -.02em;
  color: #fff;
  user-select: none;
}


/* ==========================================================================
   9. WAYS TO WORK WITH US
   ========================================================================== */
.section__lead p + p { margin-top: .875rem; }

/* Category accordion ------------------------------------------------------ */
.ways__hint {
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 1rem;
}

.ways { border-top: 1px solid var(--border); }

.ways__row {
  display: flex;
  align-items: stretch;
  min-height: clamp(300px, 40vw, 430px);
}

/* Each panel starts at zero width and grows to its share. Because they share
   one flex line, a panel growing in compresses the ones already there — the
   "filling in" effect from the reference. */
/* Defaults to visible: only the .js-reveal rule below collapses it, so a
   script failure leaves the panels laid out normally. */
.way {
  display: flex;
  flex-direction: column;
  flex: 1 1 0;
  min-width: 0;
  border-right: 1px solid var(--border);
  transition: flex-grow .65s cubic-bezier(.22, .9, .3, 1);
}
.way:first-child { border-left: 1px solid var(--border); }

.js-reveal .ways:not(.is-inview) .way { flex-grow: 0; }

.ways.is-inview .way {
  flex-grow: 1;
  transition-delay: calc(var(--i) * 190ms);
}

/* The open panel takes the room; its siblings squeeze down. */
.ways.is-inview .way.is-open { flex-grow: 8; transition-delay: 0s; }

.way__heading { display: flex; flex: 1 1 auto; margin: 0; font: inherit; min-height: 0; }

.way__head {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: flex-start;
  gap: .75rem;
  width: 100%;
  padding: clamp(1.25rem, 2vw, 1.75rem);
  background: none;
  border: 0;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
}

.way__num {
  font-size: clamp(3.5rem, 9vw, 7rem);
  font-weight: 800;
  line-height: .85;
  letter-spacing: -.05em;
  transition: color var(--t);
}
.way:hover .way__num { color: var(--accent); }
.way.is-open .way__num { color: var(--accent); }

.way__text { display: block; margin-top: auto; min-width: 0; }

.way__name {
  display: block;
  font-size: clamp(1.25rem, 2.2vw, 1.75rem);
  font-weight: 600;
  letter-spacing: -.03em;
  line-height: 1.1;
  white-space: nowrap;          /* clips as the panel narrows, like the reference */
}

.way__blurb {
  display: block;
  margin-top: .75rem;
  font-family: var(--mono);
  font-size: .6875rem;
  line-height: 1.6;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}

.way__more {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--accent);
  white-space: nowrap;
}
.way__more-close { display: none; }
.way.is-open .way__more-open { display: none; }
.way.is-open .way__more-close { display: inline; }

/* Plus turning into a minus. */
.way__sign {
  position: relative;
  width: 10px; height: 10px;
  flex: none;
}
.way__sign::before,
.way__sign::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  background: currentColor;
}
.way__sign::before { width: 10px; height: 1.5px; }
.way__sign::after  { width: 1.5px; height: 10px; transition: transform var(--t); }
.way.is-open .way__sign::after { transform: scaleY(0); }

/* Vertical split reveal --------------------------------------------------- */
/* The row collapses from 0fr to 1fr for height, while the panel itself is
   clipped open from its centre line outward — the "split". */
.way__body {
  flex: 0 0 auto;
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .55s cubic-bezier(.22, .9, .3, 1);
}
.way.is-open .way__body { grid-template-rows: 1fr; }

.way__detail {
  overflow: hidden;
  min-height: 0;
  clip-path: inset(50% 0 50% 0);
  transition: clip-path .55s cubic-bezier(.22, .9, .3, 1);
}
.way.is-open .way__detail { clip-path: inset(0 0 0 0); }

.way__packages {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .875rem;
  padding: 0 clamp(1.25rem, 2vw, 1.75rem) clamp(1.25rem, 2vw, 1.75rem);
}

@media (max-width: 900px) {
  .way__packages { grid-template-columns: minmax(0, 1fr); }
}

/* Package card ------------------------------------------------------------ */
.pkg {
  display: flex;
  flex-direction: column;
  gap: .625rem;
  padding: clamp(1.5rem, 2.5vw, 2rem);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
}

.pkg__name { font-size: 1.125rem; }
.pkg__hook { font-weight: 600; font-size: .9375rem; }
.pkg__desc { color: var(--muted); font-size: .9375rem; }

.pkg__list {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  margin-top: .375rem;
  padding-top: 1.125rem;
  border-top: 1px solid var(--border);
  font-size: .9375rem;
  color: var(--muted);
}
.pkg__list li { position: relative; padding-left: 1.25rem; }
.pkg__list li::before {
  content: "";
  position: absolute;
  left: 0; top: .55em;
  width: 8px; height: 8px;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
}

.pkg__cta { align-self: flex-start; margin-top: auto; padding-top: 0; }

.work__note {
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  padding-top: clamp(1.5rem, 3vw, 2rem);
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: .875rem;
  max-width: 72ch;
}

/* ==========================================================================
   10. PROOF OF WORK
   ========================================================================== */
.results {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  gap: 1.25rem;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

.result {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
}
.result__value { font-size: clamp(2rem, 3.4vw, 4rem); font-weight: 600; letter-spacing: -.03em; }
.result__label { font-size: .9375rem; }
.result__note {
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: .25rem;
}

.testimonials {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: 1.25rem;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

.testimonial {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding: clamp(1.5rem, 2.5vw, 2rem);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
}
.testimonial__quote {
  margin: 0;
  font-size: clamp(1.0625rem, 1.2vw, 1.35rem);
  line-height: 1.55;
}
.testimonial__by { display: flex; flex-direction: column; gap: .125rem; margin-top: auto; }
.testimonial__name { font-weight: 600; font-size: .9375rem; }
.testimonial__role { color: var(--muted); font-size: .875rem; }
.testimonial__project {
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--accent);
  margin-top: .375rem;
}

.proofs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: 1.25rem;
}
.proof figure { margin: 0; }
.proof img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
}
.proof figcaption {
  margin-top: .75rem;
  color: var(--muted);
  font-size: .875rem;
}

/* ==========================================================================
   11. CONTACT
   ========================================================================== */
.contact {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}

.contact__body {
  color: rgba(255, 255, 255, .78);
  max-width: 44ch;
  margin-top: 1rem;
  font-size: clamp(1.0625rem, 1.25vw, 1.375rem);
  line-height: 1.55;
}

.section--contact .eyebrow { color: rgba(255, 255, 255, .72); }

.contact__status {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  margin-top: 1.5rem;
  padding: .4rem .875rem;
  border: 1px solid rgba(255, 255, 255, .35);
  border-radius: 999px;
  font-size: .875rem;
  color: rgba(255, 255, 255, .82);
}
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; }
.section--contact .dot { background: #fff; }

.contact__form { align-self: start; }
.section--contact .field > span { color: #fff; }
.section--contact .field em { color: rgba(255, 255, 255, .62); }
.section--contact .field input,
.section--contact .field select,
.section--contact .field textarea {
  color: #fff;
  background: rgba(255, 255, 255, .08);
  border-color: rgba(255, 255, 255, .42);
}
.section--contact .field select { color-scheme: dark; }
.section--contact .field select option {
  color: var(--text);
  background: var(--bg);
}
.section--contact .field input:focus,
.section--contact .field select:focus,
.section--contact .field textarea:focus {
  color: #fff;
  background: rgba(255, 255, 255, .14);
  border-color: #fff;
}
.section--contact .btn {
  color: var(--accent);
  background: #fff;
  border-color: #fff;
}
.section--contact .btn:hover {
  color: #fff;
  background: transparent;
  border-color: #fff;
}
.section--contact .enquiry__status { color: rgba(255, 255, 255, .78); }
.section--contact .enquiry__status.is-ok,
.section--contact .enquiry__status.is-err { color: #fff; }
.section--contact :where(a, button, input, select, textarea):focus-visible {
  outline-color: #fff;
}

/* ==========================================================================
   12. FOOTER
   ========================================================================== */
.footer {
  border-top: 1px solid var(--border);
  padding-block: clamp(2.5rem, 5vw, 3.5rem);
}

.footer__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1.75rem, 4vw, 3rem);
  align-items: start;
}

.footer__tagline { color: var(--muted); font-size: .875rem; margin-top: .5rem; max-width: 32ch; }

.footer__nav ul,
.footer__social ul { display: flex; flex-direction: column; gap: .625rem; }
.footer__nav .link,
.footer__social .link { border-bottom-color: transparent; font-size: .9375rem; }
.footer__nav .link:hover,
.footer__social .link:hover { border-bottom-color: var(--accent); }

.footer__copy {
  grid-column: 1 / -1;
  padding-top: clamp(1.5rem, 3vw, 2rem);
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: .8125rem;
}

/* ==========================================================================
   13. RESPONSIVE
   ========================================================================== */
@media (max-width: 1024px) {
  .modal__panel { grid-template-columns: minmax(0, 1fr) 300px; }
}

@media (max-width: 900px) {
  .modal__panel {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    overflow-y: auto;
  }
  .modal__info {
    border-left: 0;
    border-top: 1px solid var(--border);
    padding-top: clamp(1.5rem, 2.5vw, 2rem);
    overflow: visible;
  }
  .modal__stage { --stage-max-h: 52vh; }
}

@media (max-width: 860px) {
  .header {
    padding-block: .75rem;
    transition: background .3s ease, border-color .3s ease;
  }

  .header.is-menu-open {
    max-height: 100vh;
    overflow-y: auto;
  }

  .header__inner {
    grid-template-columns: minmax(0, 1fr);
    gap: .125rem;
    align-items: center;
    justify-items: center;
  }

  .brand {
    justify-self: center;
    align-items: center;
  }

  .brand__logo { height: clamp(30px, 8vw, 36px); }

  .nav {
    display: grid;
    width: 100%;
    justify-items: center;
  }

  /* No JavaScript leaves the centred menu visible. Once JS has wired the
     disclosure, the arrow takes over as the mobile control. */
  .is-ready .nav__toggle { display: inline-flex; }

  .nav__menu {
    display: grid;
    width: 100%;
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    gap: 1.5rem;
    padding-block: 1.5rem 2rem;
  }

  /* Reveal outwards from the centre seam instead of sliding in like a
     conventional hamburger drawer. */
  .is-ready .nav__menu {
    max-height: 0;
    padding-block: 0;
    overflow: hidden;
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    clip-path: inset(0 50%);
    transform: translateY(-.5rem);
    transition:
      max-height .55s cubic-bezier(.2, .8, .2, 1),
      padding .55s cubic-bezier(.2, .8, .2, 1),
      clip-path .55s cubic-bezier(.2, .8, .2, 1),
      opacity .22s ease,
      transform .4s ease,
      visibility 0s linear .55s;
  }

  .is-ready .nav__menu[data-open="true"] {
    max-height: 32rem;
    padding-block: 1.5rem 2rem;
    visibility: visible;
    opacity: 1;
    pointer-events: auto;
    clip-path: inset(0);
    transform: none;
    transition-delay: 0s;
  }

  /* Flat, centred lists on mobile — no stagger or right-hang. */
  .nav__col,
  .nav__col--end {
    align-items: center;
    text-align: center;
  }
  .nav__col:empty { display: none; }
  .nav__col:not(.nav__col--end) li:not(:first-child):not(:last-child) { padding-left: 0; }

  /* Roomier again on mobile, where the rows are tap targets. */
  .nav__col { gap: .5rem; font-size: .9375rem; line-height: 1.45; }

  .section__head { grid-template-columns: minmax(0, 1fr); align-items: start; }
  .hero__lower { align-items: center; }
  .hero__body {
    width: 100%;
    margin-inline: auto;
    text-align: center;
  }

  /* Panels stack instead of compressing — no room to squeeze sideways. */
  .ways__row { flex-direction: column; min-height: 0; }
  .way,
  .ways.is-inview .way,
  .ways.is-inview .way.is-open { flex: 0 0 auto; }
  .way { border-right: 0; border-bottom: 1px solid var(--border); }
  .way:first-child { border-left: 0; }
  .way__name { white-space: normal; }
  .way__num { font-size: 3rem; }
  .way__head { flex-direction: row; align-items: center; gap: 1rem; flex-wrap: wrap; }
  .way__text { margin-top: 0; flex: 1 1 12rem; }
  .way__more { width: 100%; }

  /* The reveal wipes each panel in vertically rather than growing its width. */
  .js-reveal .ways:not(.is-inview) .way { opacity: 0; transform: translateY(12px); }
  .way { transition: opacity .5s ease, transform .5s ease; }
  .ways.is-inview .way { opacity: 1; transform: none; transition-delay: calc(var(--i) * 120ms); }
  .contact { grid-template-columns: minmax(0, 1fr); }
  .footer__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .footer__brand { grid-column: 1 / -1; }
}

@media (max-width: 560px) {
  .hero__stats { gap: 1.25rem 2rem; }
  .footer__inner { grid-template-columns: minmax(0, 1fr); }
  .modal { padding: 0; }
  .modal__panel { max-height: 100vh; height: 100%; width: 100%; border: 0; border-radius: 0; }
  .modal__stage { --stage-max-h: 46vh; }
}

/* ==========================================================================
   14. REDUCED MOTION — honour the OS setting
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }

  .card:hover { transform: none; }

  /* The wordmark simply appears, and is never held in its hidden idle state. */
  .wordmark .wordmark__char,
  .wordmark.is-inview .wordmark__char { animation: none; }
  .js-reveal .wordmark:not(.is-inview) .wordmark__char { transform: none; opacity: 1; }

  /* The logo run stops drifting on its own — initLogoMarquee() holds it
     still — but stays draggable, since that is a response to input rather
     than motion the visitor did not ask for. */
  .logos__track { will-change: auto; }
}

/* Clients now sits in the dark block; fade back to white before the next section. */
.section--clients::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: clamp(80px, 12vw, 160px);
  background: linear-gradient(180deg, rgba(11, 12, 14, 0), var(--bg));
  pointer-events: none;
  z-index: 1;
}
#work-with-us,
[data-liquid-source-id="work-with-us"] { border-top: 0; }
#work-with-us .section__title,
[data-liquid-source-id="work-with-us"] .section__title {
  max-width: none;
  width: 100%;
  text-align: center;
}

#work-with-us .section__lead,
[data-liquid-source-id="work-with-us"] .section__lead {
  justify-self: stretch;
  width: 100%;
  max-width: none;
}

/* ==========================================================================
   15. SOCIAL SECTION
   ========================================================================== */
.section--social .container {
  max-width: none;
  padding-inline: clamp(1.5rem, 4vw, 3.5rem);
}
.section--social .section__head {
  gap: clamp(2.5rem, 4vw, 5rem);
  align-items: start;
}
.section--social .section__title {
  max-width: none;
  font-size: clamp(5rem, calc(4vw + 3rem), 8rem);
  line-height: .94;
  letter-spacing: -.055em;
}
.social__copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-self: stretch;
  width: 100%;
  max-width: none;
}
.social__copy .section__lead { max-width: none; }

.social__stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  padding-block: clamp(1.75rem, 4vw, 3rem);
  margin-bottom: clamp(2rem, 4vw, 3rem);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.sstat {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: .35rem;
  min-width: 0;
  padding-inline: clamp(1.25rem, 3vw, 2.5rem);
  border-left: 1px solid var(--border);
}
.sstat:first-child {
  padding-left: 0;
  border-left: 0;
}
.sstat:last-child { padding-right: 0; }
.sstat__v { font-size: clamp(1.75rem, 3.6vw, 2.75rem); font-weight: 700; letter-spacing: -.03em; line-height: 1.05; }
.sstat__l { font-size: .875rem; color: var(--muted); }

@media (max-width: 560px) {
  .social__stats {
    grid-template-columns: minmax(0, 1fr);
    padding-block: 0;
  }
  .sstat {
    padding: 1.25rem 0;
    border-top: 1px solid var(--border);
    border-left: 0;
  }
  .sstat:first-child { border-top: 0; }
}

.stiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr));
  gap: clamp(.75rem, 1.5vw, 1.25rem);
}

.stile {
  position: relative;
  overflow: hidden;
  border-radius: var(--r);
  background: #0b0c0e;
  aspect-ratio: 9 / 16;
}
.stile__img { width: 100%; height: 100%; object-fit: cover; }
.stile::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(11,12,14,0) 45%, rgba(11,12,14,.85));
}
.stile__cap {
  position: absolute;
  left: .75rem; right: .75rem; bottom: .7rem;
  z-index: 1;
  color: #fff;
}
.stile__views { display: block; font-size: 1.25rem; font-weight: 700; letter-spacing: -.02em; }
.stile__meta {
  display: block;
  font-family: var(--mono);
  font-size: .5625rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: rgba(255,255,255,.7);
  margin-top: .15rem;
}
.stile__play {
  position: absolute; top: .7rem; right: .7rem;
  z-index: 1;
  width: 0; height: 0;
  border-style: solid;
  border-width: 6px 0 6px 10px;
  border-color: transparent transparent transparent #fff;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.5));
}

.social__cta { margin-top: clamp(1.5rem, 3vw, 2rem); }

@media (max-width: 860px) {
  .section--social .section__head { gap: 1.5rem; }
  .section--social .section__title {
    max-width: 8ch;
    font-size: clamp(3.25rem, 14vw, 4.25rem);
  }
  .social__copy {
    justify-self: start;
    width: 100%;
  }
}

@media (min-width: 861px) {
  .section--social .stiles {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

/* ==========================================================================
   16. ENQUIRY MODAL
   ========================================================================== */
.enquiry {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  place-items: center;
  padding: clamp(1rem, 4vw, 2.5rem);
}
.enquiry[hidden] { display: none; }

.enquiry__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(11, 12, 14, .6);
  opacity: 0;
  transition: opacity .3s ease;
}
.enquiry.is-open .enquiry__backdrop { opacity: 1; }

.enquiry__panel {
  position: relative;
  z-index: 1;
  width: min(680px, 100%);
  max-height: 92vh;
  overflow-y: auto;
  padding: clamp(1.75rem, 4vw, 2.75rem);
  background: var(--bg);
  border-radius: var(--r-lg);
  transform: translateY(16px) scale(.98);
  opacity: 0;
  transition: transform .35s cubic-bezier(.22,.9,.3,1), opacity .3s ease;
}
.enquiry.is-open .enquiry__panel { transform: none; opacity: 1; }

.enquiry__close {
  position: absolute;
  top: .875rem; right: 1rem;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  font-size: 1.5rem; line-height: 1;
  background: none; border: 0; cursor: pointer;
  color: var(--muted);
}
.enquiry__close:hover { color: var(--text); }

.enquiry__title { font-size: clamp(1.5rem, 3vw, 2rem); margin-bottom: .5rem; }
.enquiry__sub { color: var(--muted); font-size: .9375rem; margin-bottom: 1.5rem; }

.enquiry__form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
.field { display: flex; flex-direction: column; gap: .375rem; }
.field--full { grid-column: 1 / -1; }
.field > span { font-size: .8125rem; font-weight: 600; }
.field em { color: var(--muted); font-weight: 400; font-style: normal; }
.field input,
.field select,
.field textarea {
  font: inherit;
  width: 100%;
  padding: .7rem .85rem;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--bg);
}
.field textarea { resize: vertical; min-height: 5.5rem; }

.field__hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

.enquiry__actions {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .75rem 1.25rem;
  margin-top: .25rem;
}
.enquiry__status { font-size: .875rem; color: var(--muted); }
.enquiry__status.is-ok { color: #0a7d34; }
.enquiry__status.is-err { color: #c0261c; }

@media (max-width: 560px) {
  .enquiry__form { grid-template-columns: 1fr; }
}

/* ==========================================================================
   17. BRIEF REBUILD — hero mix, portfolio strip, categories, offerings,
       who we are, final CTA, expanded enquiry form
   ========================================================================== */

/* --- hero ---------------------------------------------------------------- */
.hero__sub {
  color: var(--muted);
  max-width: 60ch;
  margin-inline: auto;
  font-size: clamp(1.0625rem, 1.6vw, 1.375rem);
  font-weight: 700;
  line-height: 1.4;
  text-align: center;
}
.hero__line {
  margin-top: 1rem;
  font-style: italic;
  font-weight: 600;
  font-size: clamp(1rem, 1.4vw, 1.1875rem);
}

.hvis-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  /* Reserve the finished four-card row before data.js replaces the empty
     hook. This stops every section below the films jumping on first paint. */
  aspect-ratio: 7 / 3;
  gap: clamp(.5rem, 1.2vw, 1rem);
  margin-top: clamp(2.5rem, 5vw, 4rem);
}
.hvis {
  position: relative;
  overflow: hidden;
  border-radius: var(--r);
  aspect-ratio: 9 / 16;
  background: #0b0c0e;
}
.hvis__media,
.hvis__video,
.hvis__button {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.hvis__video {
  object-fit: cover;
  pointer-events: none;
}
.hvis__button {
  z-index: 1;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  padding: .75rem;
  background: linear-gradient(180deg, transparent 52%, rgba(0, 0, 0, .72));
  border: 0;
  color: #fff;
  text-align: left;
  cursor: pointer;
}
.hvis__button::after {
  content: '';
  position: absolute;
  inset: 0;
  border: 1px solid rgba(255, 255, 255, 0);
  border-radius: inherit;
  transition: border-color var(--t), background-color var(--t);
}
.hvis__button:hover::after,
.hvis__button:focus-visible::after {
  border-color: rgba(255, 255, 255, .72);
  background: rgba(45, 23, 246, .12);
}
.hvis__label {
  position: relative;
  z-index: 1;
  font-family: var(--mono);
  font-size: .5625rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 1px 4px rgba(0, 0, 0, .6);
}
.hvis__action {
  position: relative;
  z-index: 1;
  flex: none;
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
@media (max-width: 700px) {
  .hvis-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    aspect-ratio: 4 / 7;
  }
  .hvis__action { display: none; }
}

/* --- portfolio disclosure: the logo wall + the numbers -------------------- */
/* The block owns its own breathing room now. The label used to carry a lone
   padding-top and the section had none of its own, so the dark band hugged
   both the glass above it and the work section below. */
.hero__proof {
  margin-top: clamp(3.5rem, 7vw, 6rem);
  padding-block: clamp(3rem, 6vw, 5.5rem);
  background: #0b0c0e;
  color: #fff;
}

.strip__label {
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .45);
  text-align: center;
  margin-bottom: clamp(1.75rem, 3.5vw, 2.75rem);
}
/* Full-bleed: the run sits outside .container so it reaches both edges and
   the fade mask has somewhere to fade into. */
.strip .client { height: clamp(5.5rem, 9vw, 7.5rem); }
.strip .client__logo { opacity: .82; }

/* A phone gets a shorter row but not a smaller mark — vw alone would shrink
   the logos to nothing at 375px, so the floor of the clamp does the work. */
@media (max-width: 860px) {
  .strip .client { height: clamp(5rem, 20vw, 6.5rem); }
  .strip .client__logo { height: clamp(2.75rem, 11vw, 3.75rem); }
  .client { padding-inline: clamp(1rem, 4.5vw, 1.75rem); }
}
.hero__proof .hero__stats {
  min-height: clamp(8.625rem, 16.5vw, 14.8125rem);
  padding-block: clamp(2.5rem, 5vw, 4rem);
}

/* --- work categories ----------------------------------------------------- */
.cats { position: relative; z-index: 2; }

.cat { border-top: 1px solid rgba(255, 255, 255, .16); }
.cat:last-child { border-bottom: 1px solid rgba(255, 255, 255, .16); }

.cat__heading { margin: 0; font: inherit; }
.cat__head {
  display: grid;
  grid-template-columns: 3rem minmax(0, 1fr) 2rem;
  gap: clamp(1rem, 2vw, 2rem);
  align-items: start;
  width: 100%;
  padding: clamp(1.5rem, 3vw, 2.25rem) 0;
  background: none;
  border: 0;
  text-align: left;
  cursor: pointer;
  color: #fff;
}
.cat__num {
  font-family: var(--mono);
  font-size: .875rem;
  color: var(--accent);
  padding-top: .35rem;
}
.cat__text { display: block; min-width: 0; }
.cat__name {
  display: block;
  font-size: clamp(1.75rem, 4vw, 3.25rem);
  font-weight: 300;
  letter-spacing: -.03em;
  line-height: 1.1;
  transition: opacity var(--t);
}
.cat__head:hover .cat__name { opacity: .7; }
.cat__desc {
  display: block;
  margin-top: .75rem;
  max-width: 60ch;
  color: rgba(255, 255, 255, .6);
  font-size: .9375rem;
  line-height: 1.55;
}
.cat__clients {
  display: block;
  margin-top: .625rem;
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .4);
}

/* plus turning into a minus */
.cat__sign {
  position: relative;
  width: 16px; height: 16px;
  margin-top: .5rem;
  justify-self: end;
}
.cat__sign::before,
.cat__sign::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  background: currentColor;
}
.cat__sign::before { width: 16px; height: 1.5px; }
.cat__sign::after  { width: 1.5px; height: 16px; transition: transform var(--t); }
.cat.is-open .cat__sign::after { transform: scaleY(0); }

.cat__body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .5s cubic-bezier(.22, .9, .3, 1);
}
.cat.is-open .cat__body { grid-template-rows: 1fr; }
.cat__panel { overflow: hidden; min-height: 0; }

.cat .works__list { padding-bottom: clamp(1.5rem, 3vw, 2.5rem); }
.cat .work-row { border-top: 1px solid rgba(255, 255, 255, .08); }

.work-row__btn {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) auto;
  gap: 1rem;
  align-items: baseline;
  width: 100%;
  padding: clamp(.7rem, 1.4vw, 1rem) 0 clamp(.7rem, 1.4vw, 1rem) 4rem;
  background: none;
  border: 0;
  text-align: left;
  cursor: pointer;
  color: rgba(255, 255, 255, .55);
  transition: color var(--t);
}
.work-row__btn:hover,
.work-row__btn:focus-visible { color: #fff; }
.work-row__title {
  font-size: clamp(1rem, 1.6vw, 1.375rem);
  font-weight: 400;
  letter-spacing: -.01em;
}
.work-row__client,
.work-row__meta {
  font-family: var(--mono);
  font-size: .625rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  opacity: .7;
}
.work-row__meta { justify-self: end; color: var(--accent); opacity: 1; }

@media (max-width: 700px) {
  .cat__head { grid-template-columns: 2rem minmax(0, 1fr) 1.25rem; gap: .875rem; }
  .work-row__btn { grid-template-columns: minmax(0, 1fr) auto; padding-left: 0; }
  .work-row__client { display: none; }
}

/* --- work with us -------------------------------------------------------- */
.section--offers { overflow: clip; }
.offers {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(1.25rem, 2.5vw, 2rem);
  margin-top: clamp(2rem, 4vw, 3rem);
}
.offer {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .625rem;
  padding: clamp(1.5rem, 2.5vw, 2rem);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
}
.offer__num { font-family: var(--mono); font-size: .75rem; color: var(--accent); }
.offer__name { font-size: clamp(1.25rem, 2vw, 1.625rem); }
.offer__tagline {
  font-family: var(--mono);
  font-size: .75rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.offer__body {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  color: var(--muted);
  font-size: .9375rem;
}
.offer__cta {
  align-self: flex-start;
  margin-top: auto;
  padding: .75rem 0 0;
  background: none;
  border: 0;
  border-bottom: 1px solid currentColor;
  color: var(--accent);
  font-weight: 600;
  font-size: .875rem;
  letter-spacing: .02em;
  text-transform: uppercase;
  cursor: pointer;
  transition: opacity var(--t);
}
.offer__cta:hover { opacity: .65; }

/* The four offers read as one system, so they stay on a single line through
   tablet widths and arrive together from above when the section enters view.
   The idle state is scoped beneath .js-reveal: if JS cannot observe the grid,
   the content remains fully visible. */
.js-reveal .offers[data-animate]:not(.is-inview) .offer {
  opacity: 0;
  transform: translate3d(0, -2.75rem, 0);
}
.offers[data-animate] .offer {
  transition:
    opacity .55s ease,
    transform .72s cubic-bezier(.2, .8, .25, 1);
  transition-delay: calc(var(--offer-index, 0) * 70ms);
}
.offers[data-animate] .offer:nth-child(1) { --offer-index: 0; }
.offers[data-animate] .offer:nth-child(2) { --offer-index: 1; }
.offers[data-animate] .offer:nth-child(3) { --offer-index: 2; }
.offers[data-animate] .offer:nth-child(4) { --offer-index: 3; }

/* Four columns still fit at the narrowest non-mobile canvas, but the padding
   and copy scale tighten so the tablet row feels intentional rather than
   squeezed. The site switches to its mobile composition at 860px. */
@media (min-width: 861px) and (max-width: 1100px) {
  .offers { gap: clamp(.65rem, 1.4vw, 1rem); }
  .offer {
    gap: .55rem;
    padding: clamp(1rem, 1.8vw, 1.35rem);
  }
  .offer__name { font-size: clamp(1.05rem, 1.85vw, 1.25rem); }
  .offer__tagline,
  .offer__num { font-size: .6875rem; }
  .offer__body { font-size: clamp(.8125rem, 1.4vw, .9rem); }
  .offer__cta {
    font-size: clamp(.6875rem, 1.2vw, .8rem);
    line-height: 1.25;
    text-align: left;
  }
}

@media (max-width: 860px) {
  .offers { grid-template-columns: minmax(0, 1fr); }

  /* The idle reveal state parks even-numbered cards 2.5rem to the right. That
     sits outside the viewport and was extending the page's scrollable width,
     so the whole site had a horizontal scrollbar before this section had even
     been reached. Clipping contains the parked cards; they still slide in from
     beyond the edge because the clip is only horizontal. */
  .section--offers { overflow-x: clip; }

  /* On mobile the cards alternate in from both edges. The first left/right
     pair shares a delay, as does the second, keeping the reveal coordinated. */
  .js-reveal .offers[data-animate]:not(.is-inview) .offer:nth-child(odd) {
    transform: translate3d(-2.5rem, 0, 0);
  }
  .js-reveal .offers[data-animate]:not(.is-inview) .offer:nth-child(even) {
    transform: translate3d(2.5rem, 0, 0);
  }
  .offers[data-animate] .offer:nth-child(1),
  .offers[data-animate] .offer:nth-child(2) { --offer-index: 0; }
  .offers[data-animate] .offer:nth-child(3),
  .offers[data-animate] .offer:nth-child(4) { --offer-index: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .offers[data-animate] .offer,
  .js-reveal .offers[data-animate]:not(.is-inview) .offer {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* --- who we are ---------------------------------------------------------- */
.section--who {
  padding-block: clamp(3rem, 5vw, 4.5rem);
  background: var(--bg-alt);
  border-top: 0;
}
.who {
  width: min(100%, 76rem);
  max-width: none;
  margin-inline: auto;
  text-align: center;
}
.who > .eyebrow {
  color: var(--accent);
  font-family: var(--font);
  font-size: clamp(2.5rem, 5.5vw, 4.5rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.03em;
  text-transform: uppercase;
}
.who__body {
  max-width: 48ch;
  margin: clamp(1.5rem, 3vw, 2.25rem) auto 0;
  font-size: clamp(1.35rem, 2.2vw, 2rem);
  line-height: 1.35;
}
.who__line {
  max-width: 52ch;
  margin: clamp(1.125rem, 2vw, 1.5rem) auto 0;
  color: var(--muted);
  font-style: italic;
  font-size: clamp(1rem, 1.4vw, 1.2rem);
}

/* --- final CTA ----------------------------------------------------------- */
.section--final {
  background: var(--accent);
  color: var(--accent-ink);
  border-top: 0;
  text-align: center;
}
.final__title,
.final__body { white-space: nowrap; }
.final__body {
  margin: 1rem auto 2rem;
  max-width: none;
  font-size: clamp(1rem, 1.6vw, 1.25rem);
  opacity: .85;
}
.final__enquiry {
  width: min(100%, 860px);
  margin: clamp(2rem, 4vw, 3rem) auto 0;
  padding: clamp(1.25rem, 3vw, 2.25rem);
  border: 1px solid rgba(255, 255, 255, .38);
  border-radius: calc(var(--r) * 1.5);
  background: rgba(11, 12, 14, .08);
  color: #fff;
  text-align: left;
}
.final__enquiry--liquid-placeholder { visibility: hidden; }
.final__noscript { font-size: .9375rem; text-align: center; }
.final__noscript a { text-decoration: underline; text-underline-offset: .2em; }

.section--final .enquiry__progress,
.section--final .enquiry__step-head > p:last-child:not(.eyebrow),
.section--final .field__hint,
.section--final .review__group dt { color: rgba(255, 255, 255, .72); }
.section--final .enquiry__progress-track { background: rgba(255, 255, 255, .28); }
.section--final .enquiry__progress-track::after { background: #fff; }
.section--final .enquiry__step-head h3 { max-width: none; }
.section--final .field label,
.section--final .choice__legend { color: #fff; }
.section--final .field__req { color: #fff; }
.section--final .field input,
.section--final .field textarea {
  color: #fff;
  background: rgba(255, 255, 255, .1);
  border-color: rgba(255, 255, 255, .46);
}
.section--final .field input:focus,
.section--final .field textarea:focus {
  color: #fff;
  background: rgba(255, 255, 255, .16);
  border-color: #fff;
}
.section--final .field.is-invalid input,
.section--final .field.is-invalid textarea {
  border-color: #fff;
  background: rgba(255, 255, 255, .18);
}
.section--final .opt {
  color: #fff;
  background: rgba(255, 255, 255, .08);
  border-color: rgba(255, 255, 255, .38);
}
.section--final .opt:hover { background: rgba(255, 255, 255, .14); border-color: #fff; }
.section--final .opt:has(input:checked) {
  color: var(--accent);
  background: #fff;
  border-color: #fff;
}
.section--final .opt input { accent-color: var(--accent); }
.section--final .choice.is-invalid .opt { border-color: #fff; }
.section--final .btn {
  color: var(--accent);
  background: #fff;
  border-color: #fff;
}
.section--final .btn:hover,
.section--final .btn:focus-visible {
  color: #fff;
  background: transparent;
  border-color: #fff;
}
.section--final .btn--ghost { color: #fff; background: transparent; }
.section--final .review__group { border-color: rgba(255, 255, 255, .3); }
.section--final .review__group h4 { color: #fff; }
.section--final .enquiry__status,
.section--final .enquiry__status.is-ok,
.section--final .enquiry__status.is-err { color: #fff; }
.section--final .enquiry__success { justify-items: center; text-align: center; }
.section--final :where(button, input, textarea):focus-visible { outline-color: #fff; }

@media (max-width: 420px) {
  .section--final .container { padding-inline: .75rem; }
  .final__title {
    font-size: clamp(1.1rem, 5.7vw, 1.5rem);
    letter-spacing: -.035em;
  }
  .final__body { font-size: clamp(.625rem, 2.7vw, .75rem); }
  .final__enquiry { padding: 1rem; }
}

/* --- footer contact ------------------------------------------------------ */
.footer__contact { display: flex; flex-direction: column; gap: .5rem; font-size: .9375rem; }
.footer__loc { color: var(--muted); font-size: .875rem; }

/* --- enquiry: stepped CTA questionnaire ---------------------------------- */
.enquiry__form { display: block; }

.enquiry__progress {
  --progress: 25%;
  display: grid;
  gap: .55rem;
  margin-bottom: clamp(1.5rem, 3vw, 2rem);
  color: var(--muted);
  font-family: var(--mono);
  font-size: .625rem;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.enquiry__progress-track {
  position: relative;
  display: block;
  height: 2px;
  overflow: hidden;
  background: var(--border);
}
.enquiry__progress-track::after {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--progress);
  background: var(--accent);
  transition: width .35s cubic-bezier(.22, .9, .3, 1);
}

.enquiry__step { min-width: 0; }
.enquiry__step-head { margin-bottom: 1.5rem; }
.enquiry__step-head .eyebrow { margin-bottom: .5rem; }
.enquiry__step-head h3 {
  max-width: 24ch;
  font-size: clamp(1.35rem, 3vw, 2rem);
  line-height: 1.12;
  letter-spacing: -.025em;
}
.enquiry__step-head h3:focus { outline: 0; }
.enquiry__step-head > p:last-child:not(.eyebrow) {
  margin-top: .6rem;
  color: var(--muted);
  font-size: .875rem;
}

.enquiry__fields { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }

.field__hint { font-size: .8125rem; color: var(--muted); margin-bottom: .25rem; }
.field__req { color: var(--accent); margin-left: .2rem; }
.field.is-invalid input,
.field.is-invalid textarea { border-color: #c0261c; background: #fff5f4; }

.choice { border: 0; padding: 0; margin: 0; }
.choice__legend {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.choice__opts {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: .65rem;
}
.opt {
  display: flex;
  align-items: center;
  gap: .65rem;
  width: 100%;
  padding: .85rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-size: .9375rem;
  cursor: pointer;
  transition: border-color var(--t), background var(--t);
}
.opt:hover { border-color: var(--border-strong); background: #fff; }
.opt input { accent-color: var(--accent); margin: 0; }
.opt:has(input:checked) { border-color: var(--accent); background: rgba(45, 23, 246, .08); }
.choice.is-invalid .opt { border-color: #e2a5a0; }

.enquiry__actions {
  display: flex;
  justify-content: space-between;
  gap: .75rem;
  margin-top: 1.5rem;
}
.enquiry__actions--end { justify-content: flex-end; }
.enquiry__status {
  min-height: 1.25rem;
  margin-top: 1rem;
}

.enquiry__review { display: grid; gap: 1rem; }
.review__group {
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}
.review__group:first-child { padding-top: 0; border-top: 0; }
.review__group h4 {
  margin-bottom: .65rem;
  color: var(--accent);
  font-family: var(--mono);
  font-size: .625rem;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.review__group dl { display: grid; gap: .55rem; }
.review__group dl > div {
  display: grid;
  grid-template-columns: minmax(8rem, .7fr) minmax(0, 1.3fr);
  gap: 1rem;
}
.review__group dt { color: var(--muted); font-size: .8125rem; }
.review__group dd {
  margin: 0;
  min-width: 0;
  font-size: .875rem;
  font-weight: 600;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

.enquiry__success {
  display: grid;
  gap: 1rem;
  justify-items: start;
  padding-block: clamp(2rem, 6vw, 4rem);
}
.enquiry__success h3 {
  max-width: 18ch;
  font-size: clamp(1.75rem, 4vw, 2.75rem);
  line-height: 1.05;
  letter-spacing: -.035em;
}
.enquiry__success:focus { outline: 0; }

@media (max-width: 560px) {
  .enquiry__fields { grid-template-columns: 1fr; }
  .enquiry__actions .btn { flex: 1 1 0; padding-inline: 1rem; }
  .enquiry__actions--end .btn { flex: 0 1 auto; }
  .review__group dl > div { grid-template-columns: minmax(0, 1fr); gap: .15rem; }
}

/* ==========================================================================
   18. WORK — "START HERE" folders + proof line
   ========================================================================== */
.works__head { position: relative; z-index: 2; margin-bottom: clamp(2rem, 4vw, 3rem); }
.works__title,
#work-with-us .section__title,
[data-liquid-source-id="work-with-us"] .section__title,
.final__title {
  max-width: none;
  font-size: clamp(2.5rem, 6vw, 4.5rem);
  font-weight: 800;
  letter-spacing: -.03em;
  text-transform: uppercase;
  line-height: 1;
}
.works__sub {
  margin-top: .875rem;
  color: rgba(255, 255, 255, .6);
  font-size: clamp(1rem, 1.5vw, 1.25rem);
}

/* The folder rows carry a count and lose the old number / client list. */
.cat__count {
  justify-self: end;
  align-self: center;
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .1em;
  color: rgba(255, 255, 255, .35);
}
.cat__head {
  grid-template-columns: minmax(0, 1fr) auto 2rem;
  align-items: center;
}
.cat__name { font-weight: 700; text-transform: uppercase; }
.cat__sign { margin-top: 0; align-self: center; }

/* Proof line closing the section. */
.wproof {
  position: relative;
  z-index: 2;
  margin-top: clamp(3rem, 6vw, 5rem);
  color: #fff;
}
.wproof__heading {
  font-size: clamp(1.5rem, 3.2vw, 2.5rem);
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.15;
  max-width: 22ch;
}
.wproof__body {
  margin-top: .875rem;
  max-width: 54ch;
  color: rgba(255, 255, 255, .6);
  font-size: clamp(.9375rem, 1.3vw, 1.0625rem);
}

@media (max-width: 700px) {
  .cat__head { grid-template-columns: minmax(0, 1fr) auto 1.25rem; }
}

/* The brief mock is left-aligned; overrides the older centred works head. */
.section--works .works__head { text-align: left; }


/* ==========================================================================
   19. WORK FOLDERS — horizontal accordion (reference: client's pin video)
   --------------------------------------------------------------------------
   Panels sit side by side and share one flex line, so opening one compresses
   the others automatically. Titles stay HORIZONTAL and simply clip as a panel
   narrows — never rotated. Each panel carries its number at the top and its
   name across the bottom; the open one reveals its description and projects
   between them, and choosing a project pans the detail across the panel.
   ========================================================================== */
.cats {
  display: flex;
  align-items: stretch;
  min-height: clamp(440px, 58vh, 620px);
  scroll-margin-top: calc(var(--header-h) + 1rem);
  border-top: 1px solid rgba(255, 255, 255, .16);
  border-bottom: 1px solid rgba(255, 255, 255, .16);
}

.folder {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
  scroll-margin-top: calc(var(--header-h) + 1rem);
  border-right: 1px solid rgba(255, 255, 255, .14);
  background: rgba(11, 12, 14, .5);
  transition: flex-grow .6s cubic-bezier(.22, .9, .3, 1), background .3s ease;
}
.folder:last-child { border-right: 0; }
.folder.is-open { flex-grow: 5.5; background: rgba(11, 12, 14, .7); }

/* Every :hover on a folder is gated behind a real hovering pointer, and this
   is the reason: a touchscreen applies :hover on tap and leaves it applied.
   So tapping a category fired all three hover states at once — the panel
   darkened, the teaser jumped from .78 to .9 opacity, and its image jumped
   from .62 to .82 brightness and scaled up — and then .is-open landed a
   frame later, which stopped `:not(.is-open)` matching and snapped all of it
   straight back off. That double state change on a single tap is the flash,
   and it happened on every category because every category has these rules.
   Do not un-gate them. */
@media (hover: hover) and (pointer: fine) {
  .folder:not(.is-open):hover { background: rgba(11, 12, 14, .3); }
}

/* The tab fills the panel so any dead space toggles it; the project list
   sits above it and swallows its own clicks. */
.folder__heading { margin: 0; font: inherit; }
.folder__tab {
  position: absolute;
  inset: 0;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  width: 100%;
  padding: clamp(1rem, 2vw, 1.75rem) clamp(.75rem, 1.5vw, 2rem);
  background: none;
  border: 0;
  text-align: left;
  color: #fff;
  cursor: pointer;
}

.folder__teaser {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: block;
  overflow: hidden;
  opacity: .64;
  pointer-events: none;
  transition: opacity .35s ease;
}
.folder__teaser picture,
.folder__teaser img,
.folder__teaser video {
  display: block;
  width: 100%;
  height: 100%;
}
.folder__teaser img,
.folder__teaser video {
  object-fit: cover;
  filter: saturate(.72) contrast(1.08) brightness(.72);
  transform: scale(1.02);
  transition: filter .35s ease, transform .7s cubic-bezier(.22, .9, .3, 1);
}
.folder__teaser::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(11, 12, 14, .42), rgba(11, 12, 14, .14) 42%, rgba(11, 12, 14, .78)),
    linear-gradient(90deg, rgba(11, 12, 14, .18), transparent 45%, rgba(11, 12, 14, .12));
}
/* Gated for the reason given above .folder:hover — on a touchscreen these
   two fire together on tap and then snap off, which is the flash. */
@media (hover: hover) and (pointer: fine) {
  .folder:not(.is-open):hover .folder__teaser { opacity: .9; }
  .folder:not(.is-open):hover .folder__teaser img,
  .folder:not(.is-open):hover .folder__teaser video {
    filter: saturate(.92) contrast(1.06) brightness(.82);
    transform: scale(1.045);
  }
}
.folder.is-open .folder__teaser { opacity: .14; }

.folder__head,
.folder__foot {
  position: relative;
  z-index: 1;
}
.folder__head {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  width: 100%;
  min-width: 0;
  min-height: 54%;
}
.folder.is-open .folder__head {
  display: block;
  min-height: 0;
}
.folder__num {
  display: block;
  font-size: clamp(1.25rem, 2.6vw, 2.75rem);
  font-weight: 800;
  letter-spacing: -.04em;
  line-height: 1;
  color: #fff;
}
.folder__desc {
  display: block;
  margin-top: .65rem;
  min-height: 4.35em;
  max-width: 22ch;
  color: rgba(255, 255, 255, .56);
  font-size: clamp(.6875rem, 1vw, .8125rem);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.45;
  opacity: 1;
  transition: color .3s ease, font-size .6s cubic-bezier(.22, .9, .3, 1),
              margin .6s cubic-bezier(.22, .9, .3, 1);
}
.folder.is-open .folder__desc {
  min-height: 2.9em;
  max-width: 44ch;
  color: rgba(255, 255, 255, .68);
  font-size: .9375rem;
}

/* Name across the bottom — horizontal, clipped by the panel as it narrows. */
.folder__foot {
  display: block;
  min-width: 0;
  transition: padding .6s cubic-bezier(.22, .9, .3, 1);
}
.folder.is-open .folder__foot { padding-right: clamp(9.25rem, 14vw, 11rem); }
.folder__title-row {
  display: flex;
  align-items: baseline;
  gap: .75rem;
  min-width: 0;
}
.folder__name {
  font-size: clamp(.875rem, 1.2vw, 1.125rem);
  font-weight: 800;
  letter-spacing: -.02em;
  line-height: .95;
  text-transform: uppercase;
  white-space: nowrap;
  transition: font-size .6s cubic-bezier(.22, .9, .3, 1),
              letter-spacing .6s cubic-bezier(.22, .9, .3, 1);
}
.folder.is-open .folder__name {
  font-size: clamp(1.4rem, 2.5vw, 2.25rem);
  letter-spacing: -.035em;
}
.folder__count {
  font-family: var(--mono);
  font-size: .625rem;
  letter-spacing: .1em;
  color: rgba(255, 255, 255, .4);
  flex: none;
}
.folder.is-open .folder__count { display: none; }

.folder__view {
  position: absolute;
  z-index: 4;
  right: clamp(.75rem, 1.5vw, 2rem);
  bottom: clamp(1rem, 2vw, 1.75rem);
  display: inline-flex;
  align-items: center;
  gap: .65rem;
  padding: .65rem .9rem;
  border: 1px solid rgba(255, 255, 255, .42);
  border-radius: 999px;
  background: rgba(11, 12, 14, .36);
  color: #fff;
  font-family: var(--mono);
  font-size: .625rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px);
  transition: opacity .3s ease, transform .4s cubic-bezier(.22, .9, .3, 1),
              background .2s ease, border-color .2s ease;
}
.folder.is-open .folder__view {
  opacity: 1;
  pointer-events: auto;
  transform: none;
  transition-delay: .22s, .22s, 0s, 0s;
}
.folder__view:hover,
.folder__view:focus-visible {
  border-color: #fff;
  background: rgba(255, 255, 255, .14);
}
/* --- open panel contents ------------------------------------------------- */
.folder__content {
  position: absolute;
  left: clamp(.75rem, 1.5vw, 2rem);
  right: clamp(.75rem, 1.5vw, 2rem);
  top: clamp(7rem, 13vw, 11rem);
  /* The footer now carries title + description + action, so reserve its full
     height instead of allowing the thumbnail to run underneath the copy. */
  bottom: clamp(6.5rem, 10vw, 8.5rem);
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transition: opacity .35s ease;
}
.folder.is-open .folder__content { opacity: 1; pointer-events: auto; transition-delay: .15s; }

.folder__inner { height: 100%; }
.folder__preview {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  overflow: hidden;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .2);
  background: #0b0c0e;
  color: #fff;
  opacity: 0;
  transform: translateY(26px);
  cursor: pointer;
}
.folder.is-open .folder__preview {
  opacity: 1;
  transform: none;
  transition: opacity .5s .2s ease,
              transform .55s .2s cubic-bezier(.22, .9, .3, 1);
}
.folder__preview picture,
.folder__preview img,
.folder__preview video {
  display: block;
  width: 100%;
  height: 100%;
}
.folder__preview img,
.folder__preview video {
  object-fit: cover;
  filter: saturate(.92) contrast(1.04);
  transition: transform .7s cubic-bezier(.22, .9, .3, 1), filter .3s ease;
}
.folder__preview::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 50%, rgba(0, 0, 0, .28));
  pointer-events: none;
}
.folder__preview:hover img,
.folder__preview:hover video,
.folder__preview:focus-visible img,
.folder__preview:focus-visible video {
  transform: scale(1.025);
  filter: saturate(1) contrast(1.06);
}
.folder__preview-mark {
  position: absolute;
  z-index: 1;
  right: 1rem;
  top: 1rem;
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border: 1px solid rgba(255, 255, 255, .7);
  border-radius: 50%;
  background: rgba(11, 12, 14, .38);
  font-size: 1rem;
  backdrop-filter: blur(8px);
}

.detail__back {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  margin-bottom: .875rem;
  padding: 0;
  background: none;
  border: 0;
  color: var(--accent);
  font-family: var(--mono);
  font-size: .6875rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  cursor: pointer;
}
.detail__back:hover { opacity: .7; }

.detail__title {
  color: #fff;
  font-size: clamp(1.25rem, 2.2vw, 1.875rem);
  font-weight: 600;
  letter-spacing: -.02em;
}
.detail__meta {
  display: flex;
  flex-wrap: wrap;
  gap: .625rem 1.75rem;
  margin: .875rem 0 1.25rem;
  padding-bottom: .875rem;
  border-bottom: 1px solid rgba(255, 255, 255, .14);
}
.detail__meta dt {
  font-family: var(--mono);
  font-size: .5625rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .45);
  margin-bottom: .2rem;
}
.detail__meta dd { margin: 0; color: #fff; font-size: .875rem; font-weight: 500; }

.detail__stack {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-auto-rows: 8px;
  gap: .75rem;
  align-items: start;
}

/* --- mobile: stack the panels vertically --------------------------------- */
@media (max-width: 860px) {
  .cats { display: block; min-height: 0; }
  .folder {
    display: block;
    border-right: 0;
    border-bottom: 1px solid rgba(255, 255, 255, .14);
    background: none;
  }
  .folder.is-open { background: none; }

  /* A phone gets the picture, not the paragraph. Each row is the category's
     own looping preview with a small label sitting on it, rather than a
     heading over a description — five stacked descriptions was more reading
     than a phone screen can carry, and the work is the thing being sold. */
  .folder__tab {
    position: relative;         /* the teaser positions against this */
    flex-direction: row;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    min-height: clamp(8.5rem, 32vw, 12rem);
    /* Inset on all four sides now the row is a picture rather than a line of
       text — the label sat hard against the top-left corner of its own
       image. The teaser is absolutely positioned so it still fills the tile;
       only the label moves in. */
    padding: clamp(.875rem, 3.5vw, 1.25rem);
    overflow: hidden;
  }

  /* Was display:none here. The loop now runs on a phone too — the <source>
     that used to swap in a still poster below 861px has gone with it. */
  .folder__teaser {
    display: block;
    opacity: .78;
  }
  .folder__teaser img,
  .folder__teaser video {
    /* Faces sit in the upper third of all five previews, and a centred crop
       cut them off at this row height. Tune per category with
       [data-folder="…"] if a replacement clip frames differently. */
    object-position: 50% 30%;
    filter: saturate(.8) contrast(1.06) brightness(.62);
    animation: teaser-drift 22s ease-in-out infinite;
  }
  .folder.is-open .folder__teaser { opacity: .3; }

  /* Both sit above the picture. */
  .folder__head,
  .folder.is-open .folder__head,
  .folder__foot,
  .folder.is-open .folder__foot {
    position: relative;
    z-index: 1;
  }
  .folder__head,
  .folder.is-open .folder__head {
    display: block;
    width: auto;
    min-height: 0;
  }
  .folder__num {
    font-size: .6875rem;
    font-family: var(--mono);
    color: rgba(255, 255, 255, .5);
  }
  .folder__desc,
  .folder.is-open .folder__desc {
    display: block;
    font-size: .625rem;
    line-height: 1.35;
    margin-top: .35rem;
    min-height: 0;
    max-width: none;
    color: rgba(255, 255, 255, .5);
  }

  /* Quiet label, not a headline: the image is doing the work now. */
  .folder__name,
  .folder.is-open .folder__name {
    font-family: var(--mono);
    font-size: .75rem;
    font-weight: 400;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .68);
    white-space: normal;
  }
  .folder__count { color: rgba(255, 255, 255, .38); }
  .folder.is-open .folder__foot { padding-right: 8.5rem; }
  /* Matches the tab's new inset so it lines up with the label rather than
     sitting hard against the edge of the picture. */
  .folder__view {
    top: clamp(.875rem, 3.5vw, 1.25rem);
    right: clamp(.875rem, 3.5vw, 1.25rem);
    bottom: auto;
    padding: .55rem .7rem;
    font-size: .5625rem;
  }

  .folder__content {
    position: static;
    inset: auto;
    display: grid;
    grid-template-rows: 0fr;
    opacity: 1;
    pointer-events: auto;
    overflow: hidden;
    transition: grid-template-rows .45s cubic-bezier(.22, .9, .3, 1);
  }
  .folder.is-open .folder__content { grid-template-rows: 1fr; padding-bottom: 1.25rem; }
  .folder__inner { min-height: 0; overflow: hidden; }
  .folder__preview { height: auto; aspect-ratio: 16 / 9; }
  .detail__stack { grid-template-columns: minmax(0, 1fr); }

  /* Each category arrives from the left as it comes into view. initReveal()
     observes every [data-animate] separately, so they animate one at a time
     as the scroll reaches them — no stagger needed, the scroll is the
     stagger. Phone only: on a browser the five sit side by side and are all
     on screen at once, where sliding them in reads as a glitch. */
  .js-reveal .folder[data-animate]:not(.is-inview) {
    opacity: 0;
    transform: translate3d(-2.5rem, 0, 0);
  }
  .folder[data-animate] {
    transition:
      opacity .5s ease,
      transform .7s cubic-bezier(.2, .8, .25, 1);
  }
}

/* The slow breath on each category's preview. Scale never returns to 1, so
   the crop stays inside the frame and no edge is ever pulled into view. */
@keyframes teaser-drift {
  0%   { transform: scale(1.06) translate3d(-1.5%, -1%, 0); }
  50%  { transform: scale(1.13) translate3d(1.5%, 1.5%, 0); }
  100% { transform: scale(1.06) translate3d(-1.5%, -1%, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .folder__teaser img,
  .folder__teaser video { animation: none; }
  .js-reveal .folder[data-animate]:not(.is-inview) { opacity: 1; transform: none; }
}

/* ==========================================================================
   20. PROJECT BROWSER - bottom category drawer + right project detail
   ========================================================================== */
.project-drawer {
  position: fixed;
  inset: 0;
  z-index: 115;
  display: grid;
  align-items: end;
}
.project-drawer[hidden] { display: none; }

.project-drawer__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(11, 12, 14, .72);
  opacity: 0;
  transition: opacity .4s ease;
}
.project-drawer.is-open .project-drawer__backdrop { opacity: 1; }

.project-drawer__panel {
  position: relative;
  z-index: 1;
  width: 100%;
  height: min(88dvh, 900px);
  max-height: calc(100dvh - 1rem);
  overflow: hidden;
  border-top: 1px solid rgba(255, 255, 255, .16);
  border-radius: 1.25rem 1.25rem 0 0;
  background: #0b0c0e;
  color: #fff;
  box-shadow: 0 -24px 70px rgba(0, 0, 0, .28);
  transform: translateY(102%);
  transition: transform .55s cubic-bezier(.22, .9, .3, 1);
}
.project-drawer.is-open .project-drawer__panel { transform: none; }

.project-drawer__close {
  position: absolute;
  z-index: 5;
  top: clamp(1rem, 2vw, 1.5rem);
  right: var(--gutter);
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .3);
  border-radius: 50%;
  background: rgba(11, 12, 14, .74);
  color: #fff;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  backdrop-filter: blur(10px);
}
.project-drawer__close:hover { background: rgba(255, 255, 255, .12); }

.project-drawer__list,
.project-drawer__detail {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, .24) transparent;
  padding: clamp(1.5rem, 4vw, 3.5rem) var(--gutter) clamp(3rem, 6vw, 5rem);
}
.project-drawer__list::-webkit-scrollbar,
.project-drawer__detail::-webkit-scrollbar { width: 3px; }
.project-drawer__list::-webkit-scrollbar-track,
.project-drawer__detail::-webkit-scrollbar-track { background: transparent; }
.project-drawer__list::-webkit-scrollbar-thumb,
.project-drawer__detail::-webkit-scrollbar-thumb {
  border-radius: 999px;
  background: rgba(255, 255, 255, .24);
}
.project-drawer__list::-webkit-scrollbar-thumb:hover,
.project-drawer__detail::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, .46);
}

.project-drawer__list {
  will-change: transform, opacity;
  transition: transform .55s cubic-bezier(.16, 1, .3, 1), opacity .4s ease;
}
.project-drawer.is-detail .project-drawer__list {
  transform: translate3d(-3%, 0, 0);
  opacity: 0;
  pointer-events: none;
}

.project-drawer__head {
  max-width: min(62rem, calc(100% - 4rem));
  margin-bottom: clamp(1.75rem, 4vw, 3rem);
}
.project-drawer__heading-row {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  margin-top: .45rem;
}
.project-drawer__heading-row h2 {
  font-size: clamp(2rem, 5vw, 4.75rem);
  font-weight: 800;
  letter-spacing: -.045em;
  line-height: .95;
  text-transform: uppercase;
}
.project-drawer__heading-row h2:focus,
.project-drawer__detail .detail__title:focus { outline: 0; }
.project-drawer__count {
  flex: none;
  color: rgba(255, 255, 255, .45);
  font-family: var(--mono);
  font-size: .625rem;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.project-drawer__head > p:last-child {
  max-width: 54ch;
  margin-top: .9rem;
  color: rgba(255, 255, 255, .64);
  font-size: clamp(.9375rem, 1.3vw, 1.0625rem);
}

.project-drawer__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.5rem, 3vw, 2.75rem) clamp(1rem, 2vw, 1.75rem);
}
.project-card { min-width: 0; }
.project-card__button {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: #fff;
  text-align: left;
  cursor: pointer;
}
.project-card__media {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: 4 / 3;
  border: 1px solid rgba(255, 255, 255, .14);
  background: #16181c;
}
.project-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(.88) contrast(1.03);
  transition: transform .55s cubic-bezier(.22, .9, .3, 1), filter .25s ease;
}
.project-card__button:hover .project-card__media img,
.project-card__button:focus-visible .project-card__media img {
  transform: scale(1.035);
  filter: saturate(1) contrast(1.05);
}
.project-card__arrow {
  position: absolute;
  right: .75rem;
  top: .75rem;
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border: 1px solid rgba(255, 255, 255, .62);
  border-radius: 50%;
  background: rgba(11, 12, 14, .42);
  backdrop-filter: blur(8px);
}
.project-card__copy { display: block; padding-top: .8rem; }
.project-card__title {
  display: block;
  font-size: clamp(1.05rem, 1.5vw, 1.35rem);
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.2;
}
.project-card__meta {
  display: block;
  margin-top: .35rem;
  color: rgba(255, 255, 255, .48);
  font-family: var(--mono);
  font-size: .6rem;
  letter-spacing: .07em;
  line-height: 1.45;
  text-transform: uppercase;
}

.project-drawer__detail {
  z-index: 2;
  background: #0b0c0e;
  backface-visibility: hidden;
  transform: translate3d(100%, 0, 0);
  will-change: transform;
  transition: transform .65s cubic-bezier(.16, 1, .3, 1);
}
.project-drawer.is-detail .project-drawer__detail { transform: translate3d(0, 0, 0); }
.project-drawer__detail .detail__back { margin-right: 4rem; }
.project-drawer__detail .detail__title {
  max-width: 20ch;
  font-size: clamp(2rem, 5vw, 4.5rem);
  font-weight: 700;
  letter-spacing: -.045em;
  line-height: .95;
}
.project-drawer__detail .detail__meta {
  margin: clamp(1.25rem, 3vw, 2rem) 0 clamp(1.5rem, 3vw, 2.5rem);
}
.project-drawer__detail .detail__stack {
  width: min(100%, 1100px);
}

@media (max-width: 900px) {
  .project-drawer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 560px) {
  .project-drawer__panel {
    height: calc(100dvh - .5rem);
    max-height: none;
    border-radius: .75rem .75rem 0 0;
  }
  .project-drawer__list,
  .project-drawer__detail {
    padding-top: 1.5rem;
    padding-bottom: 3rem;
  }
  .project-drawer__head { max-width: calc(100% - 2.5rem); }
  .project-drawer__heading-row { display: block; }
  .project-drawer__count { display: block; margin-top: .65rem; }
  .project-drawer__grid { grid-template-columns: minmax(0, 1fr); }
  .project-card__media { aspect-ratio: 16 / 10; }
}

/* ===========================================================================
   21. LIQUID HERO + REFERENCE NAVIGATION
   ========================================================================== */

/* The reference keeps navigation as one compact control in the top-right
   corner. It belongs to the opening stage rather than following the page. */
.header {
  position: absolute;
  inset: 0 0 auto auto;
  z-index: 60;
  width: auto;
  padding: clamp(1.25rem, 1.8vw, 2rem);
  color: var(--text);
  background: transparent;
  border: 0;
  mix-blend-mode: normal;
  pointer-events: none;
}
.header.is-menu-open {
  color: var(--text);
  background: transparent;
  border: 0;
  mix-blend-mode: normal;
}
.header__inner {
  display: flex;
  justify-content: flex-end;
  width: auto;
  padding: 0;
}
.nav {
  position: relative;
  display: block;
  width: auto;
  pointer-events: auto;
}
.nav__toggle {
  display: none;
  align-items: center;
  justify-content: flex-end;
  gap: .45rem;
  width: auto;
  height: auto;
  min-height: 2.4rem;
  padding: .2rem 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: inherit;
  font-size: clamp(.92rem, 1.08vw, 1.12rem);
  font-weight: 900;
  line-height: 1;
  letter-spacing: -.015em;
  text-transform: uppercase;
}
.is-ready .nav__toggle { display: inline-flex; }

/* The trigger reads as the wordmark plus the four squares instead of the word
   "Menu". It is painted as a mask rather than an <img> so it takes
   `currentColor` — the same paint as the squares beside it. That matters
   because the header blends with `mix-blend-mode: difference` while closed and
   drops to `normal` while open; a mask follows both states on its own, where an
   image would need the invert filter the mobile brand mark carries.
   logo-white.png is the mask source purely because it is 110KB against the
   black file's 1.1MB — a mask only reads the alpha channel, so the colour of
   the source art is irrelevant. */
.nav__toggle-logo {
  display: block;
  /* The mark is a full wordmark where "Menu" was four letters, so it needs more
     height than the text it replaced to stay legible — but less than the hero
     brand mark, or the trigger stops reading as a control. */
  height: clamp(20px, 1.9vw, 26px);
  aspect-ratio: 2727 / 1181;
  background: currentColor;
  -webkit-mask: url("../img/brand/logo-white.png") no-repeat center / contain;
  mask: url("../img/brand/logo-white.png") no-repeat center / contain;
}

.nav__toggle-dots {
  display: grid;
  grid-template-columns: repeat(2, 4px);
  grid-template-rows: repeat(2, 4px);
  gap: 3px;
  transition: transform .35s cubic-bezier(.16, 1, .3, 1);
}
.nav__toggle-dots i {
  display: block;
  width: 4px;
  height: 4px;
  background: currentColor;
  transition: transform .35s cubic-bezier(.16, 1, .3, 1);
}
.nav__toggle[aria-expanded="true"] .nav__toggle-dots { transform: rotate(45deg); }
.nav__toggle[aria-expanded="true"] .nav__toggle-dots i:nth-child(1) { transform: translate(1px, 1px); }
.nav__toggle[aria-expanded="true"] .nav__toggle-dots i:nth-child(4) { transform: translate(-1px, -1px); }

.nav__menu {
  position: absolute;
  top: calc(100% - .1rem);
  right: 0;
  display: grid;
  grid-template-columns: minmax(max-content, 1fr);
  justify-items: end;
  width: max-content;
  max-height: 10rem;
  padding: .1rem 0 0;
  gap: 0;
  overflow: hidden;
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  clip-path: inset(0);
  transform: none;
  transition:
    max-height .42s cubic-bezier(.16, 1, .3, 1),
    clip-path .42s cubic-bezier(.16, 1, .3, 1),
    opacity .18s ease,
    transform .42s cubic-bezier(.16, 1, .3, 1),
    visibility 0s linear .42s;
}
.is-ready .nav__menu {
  max-height: 0;
  padding: 0;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  clip-path: inset(0 0 100% 0);
  transform: translateY(-.35rem);
}
.nav__menu[data-open="true"],
.is-ready .nav__menu[data-open="true"] {
  max-height: 10rem;
  padding: .1rem 0 0;
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  clip-path: inset(0);
  transform: none;
  transition-delay: 0s;
}
.nav__col,
.nav__col--end {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .05rem;
  text-align: right;
  font-size: clamp(.9rem, 1.1vw, 1.15rem);
  line-height: .95;
}
.nav__col:not(.nav__col--end) li:not(:first-child):not(:last-child) { padding-left: 0; }
.is-ready .nav__col li {
  opacity: 0;
  transform: translateY(-.35rem);
  transition: opacity .22s ease, transform .35s cubic-bezier(.16, 1, .3, 1);
}
.nav__menu[data-open="true"] .nav__col li { opacity: 1; transform: none; }
.nav__menu[data-open="true"] .nav__col li:nth-child(2) { transition-delay: 35ms; }
.nav__menu[data-open="true"] .nav__col li:nth-child(3) { transition-delay: 70ms; }
.nav__link {
  display: block;
  padding: .08rem 0 .08rem .45rem;
  color: inherit;
  font-size: inherit;
  font-weight: 900;
  line-height: inherit;
  letter-spacing: -.02em;
  text-align: right;
  text-decoration: none;
  text-transform: uppercase;
  transition: transform .2s ease, opacity .2s ease;
}
/* No transform here — deliberately. A slide on hover was tried twice: first
   it shared one value with aria-current, so a link that was already "current"
   showed no movement on hover (nothing left to animate). Giving the two
   states different offsets fixed that, but broke something worse once the
   water effect could reach the nav: the white copy behind the mask is inert
   and never receives :hover, so it never moved with the real link, and the
   two text layers fell out of alignment by however far the slide went —
   visible as a jagged black glitch wherever the mask cut through the seam.
   Any transform on the real link without an equal one on the mirror will
   always do this. Feedback stays on the underline (line 341 above), which is
   a decoration rather than a position and cannot desync the two layers. */

/* A white foreground over a blue inverse layer. Desktop height follows a
   capped 16:9 canvas so tall browser windows do not turn the hero into a square. */
.hero {
  padding-top: 0;
  overflow: clip;
  text-align: left;
}
.hero__stage {
  --hero-pad: clamp(1.25rem, 1.8vw, 2rem);
  position: relative;
  isolation: isolate;
  width: 100%;
  height: clamp(32rem, min(100svh, 56.25vw), 67.5rem);
  min-height: 0;
  overflow: hidden;
  background: var(--accent);
  color: var(--text);
}
.hero__underlay,
.hero__surface,
.hero__liquid {
  position: absolute;
  inset: 0;
}
.hero__underlay {
  z-index: 0;
  display: grid;
  place-items: center;
  padding-inline: var(--hero-pad);
  background: var(--accent);
  overflow: hidden;
}
.hero__surface {
  z-index: 1;
  background: #fff;
}
.hero__liquid {
  z-index: 4;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.hero__inverse-shell {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--accent);
  color: #fff;
}
.hero__stage-content--inverse {
  z-index: 0;
  color: #fff;
}
.hero__stage .hero__stage-content--inverse .wordmark { color: #fff; }
.hero__stage-content--inverse .hero__cta {
  border-color: #fff;
  background: #fff;
  color: var(--accent);
}
.hero__stage-content--inverse .hero__social-link,
.hero__stage-content--inverse .hero__social-label { color: #fff; }
.hero__stage.is-liquid-disabled .hero__liquid { display: none; }

.hero__stage-content {
  position: relative;
  z-index: 3;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr) auto;
  height: 100%;
  min-height: 0;
  min-width: 0;
  padding: var(--hero-pad);
  pointer-events: none;
}
.hero__intro,
.hero__meta,
.header { pointer-events: auto; }
.hero__intro {
  align-self: start;
  width: max-content;
  max-width: calc(100% - 8rem);
}
.hero__manifesto {
  width: max-content;
  max-width: none;
  white-space: pre;
  font-size: clamp(1.1rem, 1.5vw, 1.5rem);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -.035em;
  text-transform: uppercase;
}
.hero__cta {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  margin-top: clamp(1.25rem, 1.8vw, 1.75rem);
  padding: .98rem 1.4rem;
  border: 1px solid #0b0c0e;
  border-radius: 999px;
  background: #0b0c0e;
  color: #fff;
  font-size: clamp(.78rem, .92vw, .94rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: .02em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color .25s ease, background .25s ease, transform .25s ease;
}
.hero__cta:hover {
  color: #0b0c0e;
  background: transparent;
  transform: translateY(-2px);
}
.hero__cta span:last-child { font-size: 1.2em; transition: transform .25s ease; }
.hero__cta:hover span:last-child { transform: translateX(.25rem); }

.hero__stage .wordmark {
  align-self: center;
  justify-self: center;
  width: min(94%, 96rem);
  min-width: 0;
  max-width: 100%;
  margin: 0;
  padding: 0;
  color: #0b0c0e;
  font-family: Arial, Helvetica, sans-serif;
  font-weight: 900;
  line-height: .76;
  letter-spacing: -.07em;
  text-align: center;
  pointer-events: none;
}
.hero__stage .wordmark__word {
  display: inline-block;
  white-space: nowrap;
  font-size: 20vw;
}
.hero__stage .wordmark__char { transform: none; opacity: 1; }
.js-reveal .hero__stage .wordmark:not(.is-inview) .wordmark__char,
.hero__stage .wordmark.is-inview .wordmark__char {
  animation: none;
  transform: none;
  opacity: 1;
}
.wordmark--underlay {
  align-self: center;
  width: min(94%, 96rem);
}
.hero__underlay .wordmark { color: #fff; }

.hero__meta {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  min-width: 0;
  font-size: clamp(.85rem, 1vw, 1rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.02em;
  text-transform: uppercase;
}
.hero__location { white-space: nowrap; }
.hero__socials {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .75rem;
}
.hero__social-link,
.hero__social-label {
  color: inherit;
  text-decoration: none;
}
.hero__social-link { border-bottom: 1px solid transparent; }
.hero__social-link:hover { border-bottom-color: currentColor; }
.hero__social-divider { opacity: .55; }

.hero__after {
  padding-top: clamp(4rem, 8vw, 7rem);
  padding-bottom: clamp(1rem, 3vw, 2rem);
}

@media (max-width: 860px) {
  .header,
  .header.is-menu-open {
    inset: 0 0 auto auto;
    width: auto;
    max-height: none;
    padding: 1rem;
    overflow: visible;
    background: transparent;
  }
  .header__inner {
    display: flex;
    width: auto;
    gap: 0;
    justify-items: initial;
  }
  .nav {
    display: block;
    width: auto;
  }
  .nav__menu {
    width: max-content;
    max-height: 10rem;
    padding: .1rem 0 0;
    justify-items: end;
    gap: 0;
    clip-path: inset(0);
    transform: none;
  }
  .is-ready .nav__menu {
    max-height: 0;
    padding: 0;
    clip-path: inset(0 0 100% 0);
    transform: translateY(-.35rem);
  }
  .is-ready .nav__menu[data-open="true"],
  .nav__menu[data-open="true"] {
    max-height: 10rem;
    padding: .1rem 0 0;
    clip-path: inset(0);
    transform: none;
  }
  .nav__col,
  .nav__col--end {
    align-items: flex-end;
    gap: .05rem;
    text-align: right;
    font-size: .95rem;
    line-height: .98;
  }
  .hero__stage,
  .hero__stage-content {
    height: max(38rem, 100svh);
    min-height: 0;
  }
  .hero__intro {
    width: max-content;
    max-width: calc(100% - 6.5rem);
  }
  .hero__manifesto { font-size: clamp(.82rem, 3.4vw, 1rem); }
  .hero__cta {
    gap: 1.2rem;
    padding: .92rem 1.2rem;
    font-size: .78rem;
  }
  .hero__stage .wordmark,
  .wordmark--underlay { width: 100%; }
  .hero__meta { font-size: clamp(.72rem, 3vw, .84rem); }
}

@media (max-width: 520px) {
  .hero__stage { --hero-pad: 1rem; }
  .header { padding: 1rem; }
  .hero__intro { width: 61vw; }
  .hero__cta { margin-top: 1rem; }
  .hero__meta { gap: .75rem; }
  .hero__socials { gap: .45rem; }
}

/* Touch used to be excluded here. It is not any more — a tap now throws a
   splash and a drag paints a trail, so the effect is reachable on a phone.
   Reduced motion is still the one case that turns it off outright. */
@media (prefers-reduced-motion: reduce) {
  .hero__liquid { display: none; }
}

/* YouTube embeds fill their figure like the old <video> element did. */
.sheet__embed {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: inherit;
  background: #000;
}

/* ==========================================================================
   21. MOBILE — folder copy sits with its number
   --------------------------------------------------------------------------
   The narrow layout used `justify-content: space-between`, which parked the
   number on the left edge and pushed the description and title hard against
   the right, leaving a ragged gap down the middle. On a phone that reads as a
   mistake rather than a layout. Number and copy now share one left-aligned
   column, with the copy taking the remaining width.
   ========================================================================== */
@media (max-width: 860px) {
  .folder__tab {
    justify-content: flex-start;
    align-items: flex-start;
    gap: .875rem;
  }

  /* The number keeps its natural width and stays at the top of the row. */
  .folder__head,
  .folder.is-open .folder__head {
    flex: 0 0 auto;
    width: auto;
  }

  /* Copy fills what's left, flush left under/next to the number. */
  .folder__foot,
  .folder.is-open .folder__foot {
    flex: 1 1 auto;
    min-width: 0;
    text-align: left;
  }

  .folder__desc {
    max-width: none;
    text-align: left;
  }

  .folder__title-row {
    justify-content: flex-start;
    flex-wrap: wrap;
  }
}

/* ==========================================================================
   22. MOBILE — stats as an even 2 x 2 block
   --------------------------------------------------------------------------
   Three arrangements have been tried here. The desktop row (flex-wrap +
   space-between) wrapped on a phone into a ragged 2/1/1 with random gaps. A
   single centred column fixed the raggedness but used four screens' worth of
   height for four numbers.

   A grid is what solves it: four equal `1fr` columns cannot wrap unevenly the
   way flex did, so the row stays balanced by construction and reads the same
   as the desktop layout. The type is sized right down to fit — a ~76px column
   is all four get on a 375px screen, so the longest label wraps over several
   lines. That is the trade for keeping them on one line.
   ========================================================================== */
@media (max-width: 860px) {
  .hero__stats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: clamp(.4rem, 2vw, .9rem);
    /* Top-aligned so all four values share a baseline however far their
       labels wrap below them. */
    align-items: start;
  }
  .hero__stat {
    width: auto;
    align-items: center;
    text-align: center;
    gap: .25rem;
  }
  /* The desktop sizes are built for a quarter of a wide viewport. A quarter of
     a phone is roughly a fifth of that, so both drop hard. */
  .hero__stat-value { font-size: clamp(1.05rem, 5.4vw, 1.75rem); }
  .hero__stat-label {
    font-size: clamp(.5rem, 2.4vw, .75rem);
    line-height: 1.25;
    letter-spacing: -.01em;
  }
}

/* ==========================================================================
   23. MOBILE — work section heading
   --------------------------------------------------------------------------
   The base heading is clamp(2.5rem, 6vw, 4.5rem), so its 2.5rem floor stays
   40px on a phone. That was fine for a two-word title ("SELECTED WORK") but
   the proof sentence is long and uppercase, so it filled most of the screen
   before any work was visible. Scale it down and let it breathe.
   ========================================================================== */
@media (max-width: 860px) {
  .works__title,
  #work-with-us .section__title,
  [data-liquid-source-id="work-with-us"] .section__title,
  .final__title {
    font-size: clamp(1.5rem, 7vw, 2.5rem);
    letter-spacing: -.02em;
    line-height: 1.08;
  }
  /* Split back out of the shared heading rule above. This one is
     `white-space: nowrap` by design, so its scale has to be governed by the
     length of the sentence rather than by what suits the other headings: at
     7vw the line measured 561px inside a 474px column anywhere between 420
     and 860px, and was being silently clipped by the body's overflow. */
  .final__title { font-size: clamp(1.1rem, 5.6vw, 2.5rem); }

  .works__sub {
    font-size: clamp(.9375rem, 3.6vw, 1.0625rem);
    line-height: 1.45;
  }
}

@media (max-width: 420px) {
  .works__title,
  #work-with-us .section__title,
  [data-liquid-source-id="work-with-us"] .section__title { font-size: 1.5rem; }

  /* This heading is intentionally a single line. Its own fluid scale keeps
     the full sentence inside a 375px canvas instead of forcing overflow. */
  .final__title { font-size: clamp(1.1rem, 5.7vw, 1.35rem); }
}

/* ==========================================================================
   24. MOBILE — logo + arrow only, everything else inside the menu
   --------------------------------------------------------------------------
   The phone header carried the manifesto, the enquiry CTA and a "MENU" label
   all at once, which crowded the top of the hero. It is now just the logo and
   a down arrow; the manifesto, the links and the CTA live inside the
   disclosure. Desktop is untouched.
   ========================================================================== */

/* The logo is a mobile-only element. */
.brand--mobile { display: none; }
.nav__extra { display: none; }

@media (max-width: 860px) {
  /* The header was sized around a lone Menu button, so it sat as a narrow box
     pinned to the right. A centred logo needs it to span the screen.

     The open state is listed too. An earlier rule sets "inset: 0 0 auto auto"
     on ".header, .header.is-menu-open" — at specificity (0,2,0) that beats a
     bare ".header", so the header snapped back to 92px the moment the menu
     opened and the panel ran off the right edge. Matching the selector pair
     lets source order decide instead. */
  .header,
  .header.is-menu-open {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    width: auto;
    background: #fff;
    color: #0b0c0e;
  }
  .header.is-menu-open {
    background: #0b0c0e;
    color: #fff;
  }
  /* Logo centred with the disclosure arrow directly beneath it. */
  .header__inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: .15rem;
    width: 100%;
  }

  .brand--mobile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
  }
  .brand--mobile .brand__logo {
    height: 26px;
    width: auto;
  }

  /* The control becomes a bare chevron. */
  .nav__toggle,
  .is-ready .nav__toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 28px;
    min-height: 0;
    padding: 0;
    justify-self: auto;
  }
  /* The brand mark above the arrow already carries the logo here, so the one
     on the trigger would only repeat it. */
  .nav__toggle-logo,
  .nav__toggle-dots { display: none; }
  .nav__toggle-arrow { display: block; }

  /* The panel used to hang off the toggle, which is now only 40px wide, so its
     contents ran off the screen. Making .nav static lets the absolutely
     positioned menu resolve against the full-width header instead. */
  .nav { position: static; }

  .nav__menu,
  .is-ready .nav__menu[data-open="true"] {
    left: 0;
    right: 0;
    top: 100%;
    width: auto;
    max-height: 30rem;
    padding: 1.25rem 0 1.5rem;
    justify-items: center;
    text-align: center;
    background: #0b0c0e;
    color: #fff;
  }
  .is-ready .nav__menu[data-open="true"] {
    max-height: 30rem;
    padding: 1.25rem 0 1.5rem;
  }

  .nav__col,
  .nav__col--end {
    align-items: center;
    text-align: center;
    gap: 0;
    width: 100%;
    font-size: 1.25rem;
  }
  .nav__col li { width: 100%; }
  .nav__link {
    width: 100%;
    padding: .65rem 1.1rem;
    border-radius: 0;
    text-align: center;
    transition: background-color .2s ease, color .2s ease;
  }
  .nav__link:hover,
  .nav__link:focus-visible,
  .nav__link:active {
    background: var(--accent);
    color: #fff;
    transform: none;
  }

  .nav__extra {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid rgba(255, 255, 255, .24);
    width: 100%;
    text-align: center;
  }
  .nav__manifesto {
    margin: 0;
    font-size: clamp(1rem, 4.5vw, 1.125rem);
    font-weight: 800;
    line-height: 1.15;
    text-transform: uppercase;
    letter-spacing: -.01em;
    white-space: pre-line;
  }
  .nav__cta {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    min-height: 44px;
    padding: .6rem 1rem;
    background: transparent;
    color: #fff;
    border: 1px solid #fff;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background-color .2s ease, border-color .2s ease;
  }
  .nav__cta:hover,
  .nav__cta:focus-visible {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
  }

  /* The manifesto and CTA now live in the mobile menu. Remove their empty grid
     row and give the remaining wordmark + location a shorter, content-led
     canvas; the previous 100svh distribution created hundreds of pixels of
     blank space above and below BE KNOWN on tall phones. */
  .hero__stage,
  .hero__stage-content {
    height: clamp(32rem, 72svh, 36rem);
  }
  .hero__stage-content {
    grid-template-rows: minmax(0, 1fr) auto;
  }
  .hero__intro {
    display: none;
    pointer-events: none;
  }
}

/* The arrow is mobile-only; desktop keeps the word + dots control. */
@media (min-width: 861px) {
  .nav__toggle-arrow { display: none; }
}

/* ==========================================================================
   25. SITE-WIDE LIQUID REVEAL
   --------------------------------------------------------------------------
   One fixed circular clip reveals an inert blue/white copy of the rendered
   main page and footer. JS translates that copy against scrollY so the reveal
   remains registered with the live page from hero through footer.
   ========================================================================== */
.site-liquid {
  --site-liquid-x: -10rem;
  --site-liquid-y: -10rem;
  --site-liquid-radius: 62px;
  position: fixed;
  inset: 0;
  z-index: 49;
  overflow: hidden;
  visibility: hidden;
  opacity: 0;
  clip-path: circle(var(--site-liquid-radius) at var(--site-liquid-x) var(--site-liquid-y));
  background: var(--accent);
  color: #fff;
  pointer-events: none;
  user-select: none;
  contain: layout paint style;
  will-change: clip-path, opacity;
}
.site-liquid.is-visible {
  visibility: visible;
  opacity: 1;
}
.site-liquid__page {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  min-height: 100%;
  overflow: visible;
  background: var(--accent);
  color: #fff;
  font: inherit;
  transform: translate3d(0, 0, 0);
  will-change: transform;
}
.site-liquid__page *,
.site-liquid__page *::before,
.site-liquid__page *::after {
  color: #fff !important;
  border-color: rgba(255, 255, 255, .42) !important;
  box-shadow: none !important;
}
.site-liquid__page *:not(img):not(picture) {
  background-color: transparent !important;
  background-image: none !important;
}
.site-liquid__page img {
  opacity: .58;
  filter: grayscale(1) contrast(1.12);
  mix-blend-mode: screen;
}
.site-liquid__page video { display: none !important; }
.site-liquid__page .hero__stage,
.site-liquid__page .hero__proof,
.site-liquid__page .section,
.site-liquid__page .footer {
  background: transparent !important;
}

/* The accent contact canvas needs the opposite reveal: the same circle turns
   white there, with dark type, so it reads as a true contextual inversion. */
.site-liquid__page .section--final,
.site-liquid__page .section--contact {
  background: #fff !important;
  color: var(--text) !important;
}
.site-liquid__page .section--final *,
.site-liquid__page .section--final *::before,
.site-liquid__page .section--final *::after,
.site-liquid__page .section--contact *,
.site-liquid__page .section--contact *::before,
.site-liquid__page .section--contact *::after {
  color: var(--text) !important;
  border-color: rgba(11, 12, 14, .32) !important;
}
.site-liquid__page .section--final .btn,
.site-liquid__page .section--contact .btn {
  background: var(--accent) !important;
  color: #fff !important;
  border-color: var(--accent) !important;
}

@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .site-liquid { display: none !important; }
}

/* ==========================================================================
   25. HERO WATER — the brand mark behind the surface
   --------------------------------------------------------------------------
   The stage stacks a blue underlay holding the mark, an opaque white surface
   over it, and the type above that. initHeroWater() paints stamps into an SVG
   mask; the masked layer draws a clone of the underlay, so the surface and the
   words on it are eaten away wherever the pointer goes.

   The numbers below are the whole feel of the effect and JS reads them from
   here at run time, so they can be tuned in this file or live in devtools
   without touching main.js:

     --water-size     blob radius as a fraction of stage width
     --water-trail    how many stamps stay alive at once (the pool)
     --water-life     ms for one stamp to close up
     --water-spacing  px of travel between stamps — the sensitivity dial;
                      lower reacts to smaller movements and costs more
     --water-splash   stamps thrown by a single tap
     --water-charge   px of travel needed to reach full energy
     --water-calm     energy kept per frame while idling (lower settles sooner)
     --water-boost    extra blob radius at full energy
     --water-spray    satellite drops thrown per stamp at full energy
     --water-scatter  how far satellites fly, in radii — beyond ~2 they stop
                      fusing with the main body and read as loose specks
     --water-stretch  most a stamp may elongate along its heading
     --water-idle     ms of stillness before the trail starts draining
     --water-drain    ms for the whole trail to clear once draining
   ========================================================================== */

.hero__stage {
  --water-size: .036;
  --water-trail: 46;
  --water-life: 620;
  --water-spacing: 5;
  --water-splash: 7;
  --water-charge: 700;
  --water-calm: .965;
  --water-boost: .85;
  --water-spray: 1.1;
  --water-scatter: 1.5;
  --water-stretch: 2.6;
  --water-idle: 90;
  --water-drain: 260;
}

/* Fingers are blunter than a cursor and phones have less to spend: a bigger,
   longer-lived blob, a shorter pool, and less spray per stamp. */
@media (pointer: coarse) {
  .hero__stage {
    --water-size: .075;
    --water-trail: 34;
    --water-life: 720;
    --water-spacing: 7;
    --water-spray: .9;
    --water-stretch: 2.2;
  }
}

/* The mark fills the stage the way the wordmark does, and is capped so a very
   wide viewport cannot push it taller than the stage it sits in. */
/* The mirrored hero furniture sits over the mark, in the same place as the
   real thing so the two register exactly when the water cuts between them.
   Its white treatment comes from the existing .hero__stage-content--inverse
   rules; all this does is position it and make sure it can never be hit. */
.hero__underlay .hero__stage-content--inverse {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.hero__brand {
  display: block;
  width: 100%;
  /* `height: auto` is load-bearing. The <img> carries width/height attributes
     so the browser can reserve its box before the file arrives, and those act
     as a presentational hint — without this the mark rendered at its natural
     1181px inside a 672px stage and got cropped top and bottom. */
  height: auto;
  max-height: 100%;
  object-fit: contain;
}

/* The water cuts through these two and nothing else. Both share the stage's
   exact border box, which is what makes one `userSpaceOnUse` mask land in the
   same place on both — the mask's coordinates are resolved per element, so
   layers of differing size would tear apart.

   The class is added by initHeroWater() only after the mask is built and sized.
   Masking against a reference that does not exist can blank an element, so the
   unstyled state has to be the safe one. */
/* Direct children only. The white mirror in the underlay is a clone and still
   carries `.hero__stage-content`, so an unscoped selector masked it too — it
   was being cut away in exactly the places the water reveals, which is why the
   manifesto and CTA never appeared in the blue. Only the real content on top
   may be masked; the mirror underneath must stay whole. */
.hero__stage.is-water-ready > .hero__surface,
.hero__stage.is-water-ready > .hero__stage-content {
  -webkit-mask: url("#hero-cursor-mask");
  mask: url("#hero-cursor-mask");
}

/* The supporting line moved into the meta row so the water can reach it. That
   row is a space-between flex line built for two items, so give the line its
   own full-width row rather than letting it share one. */
/* Wordmark + supporting line, stacked in the stage's middle row. */
.hero__headline {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(.7rem, 1.5vw, 1.15rem);
  min-width: 0;
  min-height: 0;
}

/* Short supporting line: intentionally calmer than the display wordmark but
   large enough to read as part of the hero rather than fine print. */
.hero__headline .hero__sub {
  color: var(--accent);
  max-width: none;
  margin: 0 auto;
  white-space: nowrap;
  font-family: var(--mono);
  font-size: clamp(1.25rem, 2.2vw, 1.75rem);
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
}

/* The new line is short enough to remain comfortably on one line on phones. */
@media (max-width: 860px) {
  .hero__headline .hero__sub {
    white-space: nowrap;
    max-width: none;
    font-size: clamp(1.0625rem, 5.4vw, 1.5rem);
  }
}

/* ==========================================================================
   26. FILM SHOWCASE — glass, scroll scrub, in-card playback
   --------------------------------------------------------------------------
   The four landing films sit on a translucent panel that drags itself up over
   the bottom of the hero as you scroll, ending across the lower part of
   BE KNOWN. and the line beneath it. Those then read blurred through the
   glass, as though the hero carries on underneath it.

   Scroll position drives the movement directly (initFilmScroll writes
   `--film-rest` and `--card-in`); nothing here is a triggered animation, so
   scrolling back up runs it backwards.
   ========================================================================== */

/* The stage clips on both axes, which would cut off both the lift and the
   hover scale. `clip` on one axis is the one overflow value that lets the
   other stay visible, so the horizontal safety net survives. */
.hero {
  overflow-x: clip;
  overflow-y: visible;
}

/* The lift lives here, not on the grid: a negative margin keeps the panel in
   normal flow, so everything below it moves up by the same amount and nothing
   has to be positioned out of the document. */
/* Bottom padding goes too, so the glass runs into the section below it rather
   than floating with a strip of page showing underneath. */
.hero__after {
  padding-top: 0;
  padding-bottom: 0;
  /* This box is exactly where the panel ends up, so clipping to it stops the
     panel spilling downward while it is parked at the start of the scrub.
     Without it the glass sat as an empty frosted slab across the top of the
     dark strip below, and only climbed off it once you scrolled. Now it rises
     out of the join instead.

     The clip margin leaves room for the panel's own shadow and for the glow on
     a hovered card, neither of which should be cut. */
  overflow: clip;
  overflow-clip-margin: 48px;
}

/* The proof strip carries its own top margin, which left a 90px band of page
   between the foot of the glass and the dark section. With the panel now
   running full width and square along the bottom, the two are meant to meet. */
.hero__after + .hero__proof { margin-top: 0; }

.filmglass {
  /* One number owns the effect. The margin pulls the panel to its final
     overlapped home, and the scrub pushes it back down by the same distance
     at rest — so at zero progress the panel sits exactly at the foot of the
     stage with no overlap, and at full progress it is fully overlapped.
     Tracking the stage's own vw-driven height keeps the two in proportion at
     any width. */
  --film-overlap: clamp(8rem, 26vw, 24rem);

  position: relative;
  z-index: 2;
  margin-top: calc(-1 * var(--film-overlap));
  opacity: var(--film-in, 1);
  /* Defaults to the settled state, so the panel is in the right place even if
     the script never runs. */
  transform: translate3d(0, calc(var(--film-rest, 0) * var(--film-overlap)), 0);
  will-change: transform;

  /* Edge to edge. The panel sits inside .container, so cancelling that
     container's inline padding is what takes it to the screen edges; its own
     padding then becomes the gutter, which is why it has to be at least as
     wide as the one it replaced. */
  margin-inline: calc(-1 * var(--gutter));
  padding: clamp(1.5rem, 3vw, 3rem);
  /* Only the top corners round — the foot of the panel meets the section
     below it, so a radius there would cut a notch out of the join. */
  border-radius: calc(var(--r) * 1.6) calc(var(--r) * 1.6) 0 0;
  /* Translucent, not opaque — the hero stays readable through it, and the
     blur is what makes the glass read as glass. */
  background: rgba(255, 255, 255, .42);
  border: 1px solid rgba(255, 255, 255, .55);
  box-shadow:
    0 24px 60px -24px rgba(11, 12, 14, .28),
    0 2px 10px -4px rgba(11, 12, 14, .12);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
  backdrop-filter: blur(18px) saturate(150%);
  /* Cards scale on hover and must be free to grow past the panel edge. */
  overflow: visible;
}

/* Without backdrop-filter there is no blur to carry the effect, so lean on a
   more solid fill instead of leaving a washed-out transparent box. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .filmglass {
    background: rgba(255, 255, 255, .88);
    border-color: rgba(11, 12, 14, .1);
  }
}

/* The grid carried the spacing that the panel now owns. */
.filmglass .hvis-grid { margin-top: 0; }

/* --- the cards -----------------------------------------------------------
   .hvis carries the scroll scrub, .hvis__inner carries the hover. They are
   separate elements because the scrub rewrites transform every frame, and a
   hover transition on the same property would smear it into lag. */
.hvis {
  overflow: visible;
  background: none;
  opacity: var(--card-in, 1);
  /* Rise plus a touch of scale, so the four read as popping onto the glass
     rather than sliding up it. The scale stays subtle — anything more and the
     covers look like they are being thrown at the screen. */
  transform:
    translate3d(0, calc((1 - var(--card-in, 1)) * var(--card-rise, 30px)), 0)
    scale(calc(.94 + .06 * var(--card-in, 1)));
}
.hvis__inner {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  overflow: hidden;
  background: #0b0c0e;
}

@media (hover: hover) and (pointer: fine) {
  .hvis__inner {
    transition:
      transform .45s cubic-bezier(.22, 1, .36, 1),
      box-shadow .45s cubic-bezier(.22, 1, .36, 1);
  }
  .hvis:hover,
  .hvis:focus-within { z-index: 3; }
  .hvis:hover .hvis__inner,
  .hvis:focus-within .hvis__inner {
    transform: scale(1.045);
    box-shadow:
      0 26px 60px -18px rgba(45, 23, 246, .42),
      0 0 0 1px rgba(255, 255, 255, .5);
  }
}

/* --- playing state -------------------------------------------------------
   The active card stays lifted so it is obvious which film has the sound. */
.hvis.is-playing { z-index: 4; }
.hvis.is-playing .hvis__inner {
  box-shadow:
    0 26px 60px -18px rgba(45, 23, 246, .5),
    0 0 0 1px rgba(45, 23, 246, .55);
}
@media (hover: hover) and (pointer: fine) {
  .hvis.is-playing .hvis__inner { transform: scale(1.03); }
}
/* The preview ignores pointers so the overlay button owns the whole tile.
   Once it is the player it needs its own clicks back for the native controls. */
.hvis.is-playing .hvis__video {
  pointer-events: auto;
  object-fit: contain;
  background: #000;
}
.hvis__video:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* --- responsive ----------------------------------------------------------
   The phone gets the same climb, just measured differently. Its stage height
   is set by the 32rem floor rather than by width, so there is a deep run of
   empty stage below the copy — a vw-based overlap like the desktop one left
   the panel roughly 210px short of the text with a dead gap above it. Mostly
   rem, so it stays put across phone widths, with a vw term so tablets get
   proportionally more. */
@media (max-width: 700px) {
  .filmglass {
    /* Tuned so the panel's top edge lands just under the supporting line
       rather than through it: at 375px that line ends at 329 and the panel
       starts at ~335. Any more overlap and the glass cuts across the type. */
    --film-overlap: clamp(14rem, 64vw, 17rem);
    padding: clamp(1rem, 4vw, 1.5rem);
    border-radius: calc(var(--r) * 1.2) calc(var(--r) * 1.2) 0 0;
  }
}

/* --- mobile film viewer --------------------------------------------------
   Phone taps get a focused full player instead of turning the small preview
   tile into native controls. The translucent backdrop and panel form one
   glass surface while keeping the film itself crisp. */
.film-modal {
  position: fixed;
  inset: 0;
  z-index: 240;
  display: grid;
  place-items: center;
  padding:
    max(.75rem, env(safe-area-inset-top))
    .75rem
    max(.75rem, env(safe-area-inset-bottom));
  opacity: 0;
  pointer-events: none;
  transition: opacity .26s ease;
}
.film-modal.is-open {
  opacity: 1;
  pointer-events: auto;
}
.film-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(7, 8, 11, .58);
  -webkit-backdrop-filter: blur(18px) saturate(135%);
  backdrop-filter: blur(18px) saturate(135%);
}
.film-modal__panel {
  position: relative;
  z-index: 1;
  width: min(92vw, 26rem);
  max-height: calc(100dvh - 1.5rem);
  padding: .7rem;
  overflow: hidden;
  color: #fff;
  background:
    linear-gradient(145deg, rgba(255, 255, 255, .2), rgba(255, 255, 255, .06)),
    rgba(11, 12, 14, .72);
  border: 1px solid rgba(255, 255, 255, .32);
  border-radius: 1.2rem;
  box-shadow: 0 28px 80px rgba(0, 0, 0, .42);
  -webkit-backdrop-filter: blur(24px) saturate(125%);
  backdrop-filter: blur(24px) saturate(125%);
  opacity: 0;
  transform: translate3d(0, 1.5rem, 0) scale(.97);
  transition:
    opacity .26s ease,
    transform .36s cubic-bezier(.22, 1, .36, 1);
}
.film-modal.is-open .film-modal__panel {
  opacity: 1;
  transform: none;
}
.film-modal__head {
  min-height: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0 .1rem .65rem .35rem;
}
.film-modal__title {
  margin: 0;
  overflow: hidden;
  font-family: var(--mono);
  font-size: clamp(.7rem, 3vw, .82rem);
  font-weight: 600;
  letter-spacing: .08em;
  line-height: 1.25;
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}
.film-modal__close {
  width: 2.75rem;
  height: 2.75rem;
  flex: none;
  display: grid;
  place-items: center;
  padding: 0;
  color: #fff;
  background: rgba(255, 255, 255, .1);
  border: 1px solid rgba(255, 255, 255, .45);
  border-radius: 50%;
  font-size: 1.65rem;
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--t), transform var(--t);
}
.film-modal__close:hover,
.film-modal__close:focus-visible {
  background: var(--accent);
  transform: scale(1.05);
}
.film-modal__close:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}
.film-modal__video {
  display: block;
  width: 100%;
  max-height: calc(100dvh - 6.25rem);
  aspect-ratio: 9 / 16;
  object-fit: contain;
  background: #000;
  border-radius: .75rem;
}
@media (min-width: 861px) {
  .film-modal { display: none !important; }
}

/* --- motion preferences --------------------------------------------------
   initFilmScroll settles everything to its final state and never binds a
   listener under reduced motion; these rules make that state unconditional in
   case the properties are missing entirely. */
@media (prefers-reduced-motion: reduce) {
  .film-modal,
  .film-modal__panel { transition: none; }
  .filmglass { transform: none; opacity: 1; }
  .hvis {
    opacity: 1;
    transform: none;
  }
  .hvis__inner,
  .hvis:hover .hvis__inner,
  .hvis:focus-within .hvis__inner,
  .hvis.is-playing .hvis__inner {
    transform: none;
    transition: none;
  }
}

/* The cursor lens clones the page; a backdrop-filter inside that clone would
   be re-rasterised every frame for no visible gain, since the clone is only
   ever seen through a small hole. The clone is also static — it must not
   inherit a half-finished scrub state. */
.site-liquid__page .filmglass {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  background: rgba(255, 255, 255, .5);
  transform: none;
  opacity: 1;
}
.site-liquid__page .hvis {
  opacity: 1;
  transform: none;
}
/* ==========================================================================
   27. NAV IN THE WATER — the trigger and links read white under the cursor
   --------------------------------------------------------------------------
   The nav sits outside .hero__stage, so the water could not reach it: the
   dark trigger stayed painted over the blue and went unreadable, and hovering
   the open menu's links did nothing at all. It now works the same way as the
   rest of the hero — a white copy sits in the underlay and the real one is
   cut by the same mask, so the water swaps one for the other — and
   initHeroWater() wires the same pointer handlers onto .nav directly, since
   .nav intercepts its own pointer events and nothing bubbles from it up to
   .hero__stage's listeners.

   The mask now stays on while the menu is open, which needs the mirror's
   copy of .nav__menu to be trustworthy rather than frozen at whatever state
   it was in when the page loaded. initNav()'s setMenu() is the single place
   that decides open or closed, so it is also the one place that keeps the
   mirror's copy in sync — see header.navMirrorMenu there.

   Desktop only. On a phone the header is a centred brand mark, and the menu
   panel takes over the full screen with its own opaque background rather
   than sitting over the hero, so there is nothing for the water to reveal. */
@media (min-width: 861px) {
  /* Full width so the mask lines up. `userSpaceOnUse` resolves against the
     masked element's own box, so a header shrink-wrapped to the right would
     sample the mask from the wrong origin. Both boxes now start at the
     document's top-left, which is also where the stage starts. */
  .header {
    inset: 0 0 auto 0;
    width: auto;
    /* The box now spans the page, so it must not swallow clicks meant for the
       hero underneath. Only the controls inside it take pointer events. */
    pointer-events: none;
  }
  .header__inner { width: auto; }
  .header .nav,
  .header .brand { pointer-events: auto; }

  /* Only once the mask exists and is sized. A mask pointing at nothing can
     blank the element it is applied to. No longer excludes .is-menu-open —
     the open menu is exactly the state this is meant to reach now. */
  .header.is-water-cut {
    -webkit-mask: url("#hero-cursor-mask");
    mask: url("#hero-cursor-mask");
  }

  /* The rule above lines the mask up horizontally; this one gives it something
     to cut vertically. A mask only ever applies over the masked element's own
     box, and .header is `inset: 0 0 auto 0` — auto height, so its box stops at
     the bottom of the trigger row. .nav__menu is absolutely positioned, which
     keeps it out of that height entirely, so an open menu hung ~30px below the
     box with no mask over it: the first link fell inside and turned white
     while the ones under it stayed black on top of the blue. That is the black
     glitch on the links, and it was never a misalignment — those links were
     simply outside the only region the mask could reach.

     Padding rather than a height keeps the box growing downwards from the same
     top-left origin, which is what `userSpaceOnUse` samples the mask from —
     changing the origin would shift the cut instead of extending it. The value
     only has to clear the tallest menu the nav can produce; it is deliberately
     far past that, because the extra box costs nothing. It paints no
     background, and .header is already pointer-events: none here with only
     .nav and .brand taking input, so the overhang cannot swallow a click meant
     for the hero. */
  .header.is-water-cut.is-menu-open { padding-bottom: 16rem; }

  .header--mirror {
    z-index: 1;
    color: #fff;
    background: transparent;
    pointer-events: none;
    /* The copy is what the water reveals; it must never be cut itself. */
    -webkit-mask: none;
    mask: none;
  }
  /* Everything else in the mirror reads .nav__link's own `color: inherit`
     and this container's white, so no further per-element rule is needed —
     that includes the links themselves once the clone stopped stripping
     .nav__menu out. Stated explicitly for the toggle only because it is
     painted from a CSS mask via currentColor, not text, and deserves to be
     obviously intentional rather than incidental. */
  .header--mirror .nav__toggle { color: #fff; }
}

/* The mobile brand mark is a black PNG, which would read as a hole in the
   blue rather than a white mark. Nothing below 861px shows the copy at all. */
@media (max-width: 860px) {
  .header--mirror { display: none; }
}

/* ==========================================================================
   28. LOADING SCREEN + WORDMARK DROP
   --------------------------------------------------------------------------
   Blue field, white monospace, in the same voice as the hero's supporting
   line. It blinks "Loading . ." twice, counts to 100, then lifts off the top
   of the screen — and the wordmark drops in behind it, letter by letter in a
   random order.

   The whole thing is gated on .is-preloading, which an inline script in the
   head sets before first paint and removes when the sequence ends. No script
   or reduced motion means the class is never added and none of this displays,
   so the site can never end up stuck behind it.
   ========================================================================== */

.loader { display: none; }

.is-preloading,
.is-preloading body { overflow: hidden; }

.is-preloading .loader {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: grid;
  place-items: center;
  background: var(--accent);
  color: #fff;
  overflow: hidden;
  transform: translateY(0);
  transition: transform .62s cubic-bezier(.7, 0, .2, 1);
}

/* The contour field that used to sit behind this section is gone, along with
   the feTurbulence filter that drew it. Worth knowing why, before anyone
   reaches for a full-section SVG filter again: an animated filter of that
   size has to be re-rasterised whenever the layer beneath it is invalidated,
   and on a phone the accordion opening was enough to trigger exactly that —
   the section flashed pale for a frame or two on every tap. */
.section--works .works__bg { z-index: 1; }
.section--works .container { position: relative; z-index: 2; }

.loader__inner {
  position: relative;
  display: grid;
  justify-items: center;
  gap: clamp(1.25rem, 4vw, 2.25rem);
}

.loader__logo {
  display: block;
  width: min(58vw, 24rem);
  height: auto;
}

/* Thin rule that fills with the count. The transition is matched to the step
   interval, so it slides between numbers instead of snapping. */
.loader__bar {
  width: min(58vw, 24rem);
  height: 2px;
  background: rgba(255, 255, 255, .26);
  overflow: hidden;
}
.loader__fill {
  display: block;
  width: 0;
  height: 100%;
  background: #fff;
  transition: width .17s linear;
}

.loader__count {
  margin: 0;
  font-family: var(--mono);
  font-size: clamp(1.05rem, 3.4vw, 2.25rem);
  font-weight: 700;
  letter-spacing: .18em;
  /* The number jumps between one, two and three digits. A tabular figure
     width stops the whole line shifting sideways as it counts. */
  font-variant-numeric: tabular-nums;
}

.loader.is-done { transform: translateY(-100%); }

/* --- the drop ------------------------------------------------------------
   The hero wordmark is otherwise pinned visible (`transform: none`), so this
   needs a class and the extra specificity to take over. `backwards` is what
   holds each letter above the fold through its delay — that delay covers the
   entire loading sequence, so the letters are already waiting off-screen by
   the time the blue lifts. */
/* The `.js-reveal` copy is not redundant. An earlier rule kills the sprout
   animation via `.js-reveal .hero__stage .wordmark:not(.is-inview)
   .wordmark__char`, and the hero wordmark never gets `.is-inview` — it is not
   a `[data-animate]` target — so that selector matches permanently at
   specificity (0,4,0) and was setting `animation: none` here too. This pair
   outranks it whether or not the reveal system is running. */
.hero__stage .wordmark.is-dropping .wordmark__char,
.js-reveal .hero__stage .wordmark.is-dropping .wordmark__char {
  animation: wordmark-drop .95s cubic-bezier(.22, .95, .25, 1) backwards;
  animation-delay: var(--d, 0ms);
}

@keyframes wordmark-drop {
  0%   { transform: translateY(-118vh); opacity: 0; }
  6%   { opacity: 1; }
  100% { transform: translateY(0); opacity: 1; }
}

/* The cursor lens clones the page. A clone that re-ran the drop every time it
   was rebuilt would show letters mid-fall inside the circle. */
.site-liquid__page .hero__stage .wordmark.is-dropping .wordmark__char {
  animation: none;
  transform: none;
  opacity: 1;
}

/* ======================================================================
   VIDEO GLASS MODAL
   ====================================================================== */
.video-glass {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity .3s ease;
}
.video-glass.is-open { opacity: 1; pointer-events: auto; }

.video-glass__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .55);
  -webkit-backdrop-filter: blur(24px) saturate(.7);
  backdrop-filter: blur(24px) saturate(.7);
}

.video-glass__container {
  position: relative;
  width: 90vw;
  max-width: 960px;
  transform: scale(.92) translateY(20px);
  transition: transform .35s cubic-bezier(.22, .9, .3, 1);
}
.video-glass.is-open .video-glass__container {
  transform: scale(1) translateY(0);
}

.video-glass__close {
  position: absolute;
  top: -40px;
  right: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .15);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: #fff;
  cursor: pointer;
  transition: background .2s ease;
}
.video-glass__close:hover,
.video-glass__close:focus-visible {
  background: rgba(255, 255, 255, .3);
}
.video-glass__close:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

.video-glass__frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 12px;
  overflow: hidden;
  background: #000;
  box-shadow: 0 24px 80px rgba(0, 0, 0, .5);
}
.video-glass__frame iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* --- Project card video thumbnails --- */
.project-card__media video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --- Mobile --- */
@media (max-width: 700px) {
  .video-glass__container {
    width: 96vw;
  }
  .video-glass__close {
    top: -36px;
    width: 28px;
    height: 28px;
  }
  .video-glass__frame {
    border-radius: 8px;
  }
}
