/*
Theme Name: Forma Film Studio
Theme URI: https://formafilmstudio.com/
Description: Forma Film Studio front end. Child of Rally: the parent theme and its licence stay intact, but every template and stylesheet is overridden so the site renders the approved Forma design.
Author: Forma Film Studio
Author URI: https://formafilmstudio.com/
Version: 1.0.0
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: forma
Template: rally
*/

/* Compiled from the approved static build. Do not edit here: edit
   forma/build.py + forma/assets/css/style.css and re-export. */

/* ==========================================================================
   FORMA FILM STUDIO — single stylesheet (preview build)
   Ported later into the WordPress Rally child theme. Sections are banner-
   commented so each block can be lifted out individually.

   ART DIRECTION OVERRIDE (deliberate): there is NO light/dark mode toggle on
   this site. Forma is a single-mode cinematic site — dark-dominant (--ink)
   with intentional bone-colored editorial sections. A sun/moon switcher would
   cheapen the reference-driven art direction, so it is intentionally omitted.
   ========================================================================== */

/* --------------------------------------------------------------------------
   01 · TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* Palette — one accent only (ember). No second accent anywhere. */
  --ink: #100e0c;
  --ink-2: #17140f;
  --ink-3: #221d17;
  --bone: #f4efe7;
  --bone-2: #e8e1d5;
  --text-on-dark: #f4efe7;
  --text-on-dark-mute: #9b9285;
  --text-on-light: #100e0c;
  --text-on-light-mute: #6b6358;
  --ember: #d9542a;
  --ember-hot: #f06335;

  --hair-dark: rgba(244, 239, 231, 0.12);
  --hair-light: rgba(16, 14, 12, 0.12);

  /* Type */
  /* FONT SYSTEM UPDATE: Clash Display dropped at the client's request — the real
     wordmark is a wide geometric grotesque, so display and body both run on
     Satoshi and contrast comes from weight (400/500 body, 700 UI, 900 display). */
  --font-display: "Satoshi", "Helvetica Neue", Arial, sans-serif;
  --font-body: "Satoshi", "Helvetica Neue", Arial, sans-serif;
  --font-serif: "Instrument Serif", Georgia, serif;

  --text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
  --text-sm: clamp(0.875rem, 0.8rem + 0.35vw, 1rem);
  --text-base: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  --text-lg: clamp(1.125rem, 1rem + 0.75vw, 1.5rem);
  --text-xl: clamp(1.5rem, 1.2rem + 1.25vw, 2.25rem);
  --text-2xl: clamp(2rem, 1.2rem + 2.5vw, 3.5rem);
  --text-3xl: clamp(2.5rem, 1rem + 4vw, 5rem);
  --text-hero: clamp(2.75rem, 0.9rem + 5.4vw, 6.5rem);

  /* Spacing (4px system) */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;
  --space-24: 6rem;
  --space-32: 8rem;

  --gutter: 40px;
  --max-w: 1280px;
  --max-w-wide: 1480px;
  --nav-h: 84px;
  --nav-h-shrunk: 62px;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

/* --------------------------------------------------------------------------
   02 · RESET / BASE
   -------------------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--text-on-dark);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, svg, iframe { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin: 0;
}
p { margin: 0 0 var(--space-5); }
p:last-child { margin-bottom: 0; }

:focus-visible {
  outline: 2px solid var(--ember-hot);
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--ember);
  color: #fff;
  padding: var(--space-3) var(--space-5);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.skip-link:focus { left: var(--space-4); top: var(--space-4); }

/* --------------------------------------------------------------------------
   03 · LAYOUT PRIMITIVES
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--max-w);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--wide { max-width: var(--max-w-wide); }

.section { padding-block: clamp(var(--space-20), 11vw, var(--space-32)); }
.section--ink { background: var(--ink); color: var(--text-on-dark); }
.section--ink-2 { background: var(--ink-2); color: var(--text-on-dark); }
.section--bone { background: var(--bone); color: var(--text-on-light); }
.section--bone .eyebrow { color: var(--ember); }

.eyebrow {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ember);
  margin: 0 0 var(--space-5);
}
.muted { color: var(--text-on-dark-mute); }
.section--bone .muted { color: var(--text-on-light-mute); }
.measure-52 { max-width: 52ch; }
.measure-62 { max-width: 62ch; }
.measure-64 { max-width: 64ch; }
.measure-68 { max-width: 68ch; }
.measure-70 { max-width: 70ch; }

.hairline { height: 1px; background: var(--hair-dark); border: 0; margin: 0; }
.section--bone .hairline { background: var(--hair-light); }

/* --------------------------------------------------------------------------
   04 · BUTTONS & LINKS
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: var(--space-4) var(--space-8);
  border: 1px solid transparent;
  border-radius: 2px;
  cursor: pointer;
  transition: background 0.35s ease-in-out, color 0.35s ease-in-out,
    border-color 0.35s ease-in-out, transform 0.35s ease-in-out;
}
.btn--ember { background: var(--ember); color: #fff; }
.btn--ember:hover { background: var(--ember-hot); }
.btn--ghost {
  border-color: rgba(244, 239, 231, 0.4);
  color: var(--text-on-dark);
}
.btn--ghost:hover { border-color: var(--text-on-dark); background: rgba(244, 239, 231, 0.08); }
.btn--sm { padding: var(--space-3) var(--space-5); }

.textlink {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-on-dark);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  border-bottom: 1px solid transparent;
  transition: color 0.35s ease-in-out, border-color 0.35s ease-in-out;
}
.textlink:hover { color: var(--ember-hot); border-color: var(--ember-hot); }
.section--bone .textlink { color: var(--text-on-light); }
.section--bone .textlink:hover { color: var(--ember); border-color: var(--ember); }

/* --------------------------------------------------------------------------
   05 · NAV
   -------------------------------------------------------------------------- */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: height 0.35s ease-in-out, background 0.35s ease-in-out,
    border-color 0.35s ease-in-out;
}
.nav.is-solid {
  height: var(--nav-h-shrunk);
  background: var(--ink);
  border-bottom-color: var(--hair-dark);
}
.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-8);
  width: 100%;
}
.nav__logo { display: block; line-height: 0; }
.brand-mark {
  height: 34px;
  width: auto;
  transform-origin: left center;
  transition: transform 0.35s ease-in-out;
}
/* nav shrink-on-scroll also scales the wordmark down slightly */
.nav.is-solid .brand-mark { transform: scale(0.86); }
.brand-mark--footer { height: 30px; }
.nav__links {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav__link {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-on-dark);
  padding-block: var(--space-2);
  border-bottom: 1px solid transparent;
  transition: color 0.35s ease-in-out, border-color 0.35s ease-in-out;
}
.nav__link:hover { color: var(--ember-hot); }
.nav__link[aria-current="page"] { border-bottom-color: var(--ember); }

.nav__toggle {
  display: none;
  background: none;
  border: 0;
  padding: var(--space-2);
  cursor: pointer;
  color: var(--text-on-dark);
}
.nav__toggle span {
  display: block;
  width: 26px;
  height: 1.5px;
  background: currentColor;
  margin: 6px 0;
  transition: transform 0.35s ease-in-out, opacity 0.35s ease-in-out;
}

/* Mobile overlay menu */
.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 99;
  background: var(--ink);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-6);
  padding: var(--space-24) var(--gutter) var(--space-16);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-12px);
  transition: opacity 0.35s ease-in-out, transform 0.35s ease-in-out,
    visibility 0.35s;
}
.mobile-menu.is-open { opacity: 1; visibility: visible; transform: none; }
.mobile-menu a {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2rem, 9vw, 3rem);
  letter-spacing: -0.02em;
  color: var(--text-on-dark);
}
.mobile-menu a:hover { color: var(--ember-hot); }
.mobile-menu .btn { align-self: flex-start; margin-top: var(--space-6); }
body.menu-open { overflow: hidden; }

@media (max-width: 900px) {
  .nav__links { display: none; }
  .nav__toggle { display: block; }
}

/* --------------------------------------------------------------------------
   06 · HERO (home) — full-bleed Vimeo background video
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  min-height: 640px;
  height: 100dvh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: var(--ink);
}
/* Poster fallback sits on the wrapper so there is never a black flash before
   the Vimeo player loads (and it shows through if the embed is domain-blocked). */
/* container-type: size lets the iframe below size against THIS box rather than
   the viewport, so the cover math survives `min-height` winning over `100dvh`
   on short screens and in landscape. */
.hero-video { position: absolute; inset: 0; z-index: 0; overflow: hidden; container-type: size; }
/* Poster lives on a pseudo-element so its softening filter never touches the
   iframe. The Vimeo still has burned-in title type, so it is blurred and
   darkened to read as texture behind the headline rather than competing copy. */
.hero-video::before {
  content: "";
  position: absolute;
  inset: -3%;
  background-image: url("https://i.vimeocdn.com/video/2192636362-cfe3a86a7cd89b85333220700bb672a07ae22ea9a647dadcd62ce928884b619d-d?f=webp&region=us");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  filter: blur(20px) brightness(0.42) saturate(0.8);
  transform: scale(1.12);
}
/* object-fit:cover emulation for a 16:9 iframe: always overfill the hero box.
   Whichever axis is short gets driven by min-*, the other overhangs and is
   clipped by the parent's overflow:hidden. */
.hero-video iframe {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* CRITICAL: the global `img, svg, iframe { max-width: 100% }` reset on line 93
     otherwise clamps this to the hero width, which collapses the overfill and
     letterboxes the 16:9 reel inside a portrait hero with black bands and a
     hard seam. max-width must be released for the cover math to work at all. */
  max-width: none;
  max-height: none;
  width: 177.7778vh;
  height: 56.25vw;
  min-width: 100%;
  min-height: 100%;
  border: 0;
  pointer-events: none;
  /* Hidden until the Vimeo player reports ready (see main.js). If the embed is
     blocked for this domain, Vimeo serves a spinner shell — keeping the iframe
     hidden means the poster frame shows instead of a black box + spinner. */
  opacity: 0;
  transition: opacity 0.9s ease-in-out;
}
.hero-video.is-playing iframe { opacity: 1; }
/* Preferred: size against the hero box, not the viewport. Falls back to the
   vh/vw values above where container query units are unsupported. */
@supports (width: 1cqh) {
  .hero-video iframe {
    width: 177.7778cqh;
    height: 56.25cqw;
    min-width: 100cqw;
    min-height: 100cqh;
  }
}
/* Two stacked gradients, because a vertical-only scrim can't hold contrast
   against a live reel: the footage cuts between a dim interview and a
   sunlit stadium, and on the bright frames the ember eyebrow and the subhead
   washed out. The horizontal pass anchors a darker wedge under the left-aligned
   copy column so type contrast is frame-independent, while the right side stays
   clear enough to read as picture. It also pushes the reel's burned-in
   lower-third graphics further back. */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  /* Tuned by measuring composited screenshots of the running reel across 12
     frames, sampling only the glyph boxes: eyebrow 6.3:1, headline 3.4:1,
     subhead 7.6:1 against the brightest frame. The previous values measured
     11.0 / 6.8 / 10.5 — far past what the text needed, which is what made the
     picture look flat and heavily veiled. The headline is the binding
     constraint, not the small text: it runs nearly the full width, so its
     right end sits out in the clear part of the frame. */
  background:
    linear-gradient(
      to right,
      rgba(16, 14, 12, 0.58) 0%,
      rgba(16, 14, 12, 0.42) 40%,
      rgba(16, 14, 12, 0.15) 76%,
      rgba(16, 14, 12, 0.21) 100%
    ),
    linear-gradient(
      to bottom,
      rgba(16, 14, 12, 0.30) 0%,
      rgba(16, 14, 12, 0.04) 36%,
      rgba(16, 14, 12, 0.38) 60%,
      rgba(16, 14, 12, 0.84) 100%
    );
}
/* Measured 1.90:1 for the ember eyebrow against the brightest frames of the
   reel. Ember sits mid-luminance, so over moving footage it can never clear
   4.5:1 no matter how the scrim is tuned — and unlike the headline it is small
   text with no large-scale exemption. In the hero only, the words go bone
   (measures >10:1) and the ember accent is carried by a short leading rule,
   which is decoration and therefore not doing legibility work. */
.hero .eyebrow {
  color: var(--bone);
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.hero .eyebrow::before {
  content: "";
  flex: none;
  width: 30px;
  height: 2px;
  background: var(--ember-hot);
}
/* Four locations is a long string at tracking. Keep it one flex child so the
   rule stays put and the text wraps internally instead of the middots being
   spaced out by the parent's gap. */
.eyebrow--hero > span { display: block; }
.eyebrow--hero i {
  font-style: normal;
  color: var(--ember-hot);
  margin: 0 0.25em;
}
/* On phones the copy spans the full width, so the left wedge would leave the
   right edge of the headline unprotected — go back to a straight vertical wash. */
@media (max-width: 760px) {
  .hero__scrim {
    /* The mid stop is load-bearing. On a phone the copy starts around 46% of
       the hero, which the old two-stop ramp left in its lightest zone — that
       only passed while the scrim was mis-anchored and the light band sat off
       screen. Measured on the live reel across 9 frames: eyebrow 5.4:1,
       headline 6.4:1, subhead 8.9:1. Stops then nudged +0.04/+0.06 for
       margin, because the reel's brightest frames move the floor by ~0.7. */
    background: linear-gradient(
      to bottom,
      rgba(16, 14, 12, 0.58) 0%,
      rgba(16, 14, 12, 0.46) 26%,
      rgba(16, 14, 12, 0.72) 52%,
      rgba(16, 14, 12, 0.94) 100%
    );
  }
}
.hero__inner {
  position: relative;
  z-index: 2;
  padding-bottom: clamp(var(--space-20), 10vh, var(--space-32));
  padding-top: var(--space-32);
  width: 100%;
}
.hero h1 {
  font-size: var(--text-hero);
  font-weight: 900;
  max-width: 20ch;
  margin: 0 0 var(--space-6);
  text-wrap: balance;
}
/* Client wants the headline set in caps. Caps at display size need the
   tracking pulled in, and 20ch of caps is far wider than 20ch of mixed case. */
.hero__h1 {
  text-transform: uppercase;
  letter-spacing: -0.015em;
  max-width: 14ch;
}
.hero h1 .word {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.4em);
  animation: wordIn 0.8s var(--ease-out) forwards;
}
@keyframes wordIn {
  to { opacity: 1; transform: none; }
}
.hero__sub { color: var(--bone-2); margin-bottom: var(--space-8); }
.hero__ctas { display: flex; flex-wrap: wrap; gap: var(--space-4); }

.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: var(--space-8);
  z-index: 2;
  transform: translateX(-50%);
  width: 1px;
  height: 56px;
  overflow: hidden;
  background: rgba(244, 239, 231, 0.2);
}
.scroll-cue::after {
  content: "";
  position: absolute;
  inset: 0 auto auto 0;
  width: 1px;
  height: 24px;
  background: var(--ember);
  animation: cue 2.2s ease-in-out infinite;
}
@keyframes cue {
  0% { transform: translateY(-24px); }
  60%, 100% { transform: translateY(56px); }
}

/* --------------------------------------------------------------------------
   07 · PAGE HEADER (interior pages)
   -------------------------------------------------------------------------- */
.page-head {
  background: var(--ink);
  padding-top: calc(var(--nav-h) + clamp(var(--space-16), 9vw, var(--space-32)));
  padding-bottom: clamp(var(--space-12), 6vw, var(--space-24));
}
.page-head h1 {
  font-size: var(--text-3xl);
  font-weight: 900;
  margin: 0 0 var(--space-6);
  text-wrap: balance;
}
.page-head__lead { font-size: var(--text-lg); line-height: 1.5; color: var(--bone-2); }
/* the page header already carries generous space — don't double it up with the
   first content section below */
.page-head { padding-bottom: clamp(var(--space-10), 5vw, var(--space-16)); }
.page-head + .section,
.page-head + .filter-bar + .section { padding-top: clamp(var(--space-10), 4vw, var(--space-16)); }

/* --------------------------------------------------------------------------
   08 · PARTNERS — marquee + static grid
   Logos are mixed formats/colors, so they are normalised to a uniform white
   silhouette with `brightness(0) invert(1)`. Swap for real white-variant
   assets when the client supplies them, then drop the filter.
   -------------------------------------------------------------------------- */
.partners { padding-block: clamp(var(--space-12), 6vw, var(--space-20)); background: var(--ink); }
.partners__label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-on-dark-mute);
  text-align: center;
  /* padding, not margin — a bottom margin here would collapse through the
     container and close the gap above the marquee */
  margin: 0;
  padding-bottom: var(--space-10);
}
.marquee {
  position: relative;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}
.marquee + .marquee { margin-top: var(--space-8); }
.marquee__track {
  display: flex;
  width: max-content;
  align-items: center;
  gap: var(--space-16);
  animation: marquee 45s linear infinite;
}
.marquee__track--reverse { animation-direction: reverse; }
.marquee:hover .marquee__track { animation-play-state: paused; }
@keyframes marquee {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* Row height must clear the tallest optically-sized mark (44px), not the
   average one. Per-logo heights are set inline by build.py from each asset's
   real aspect ratio — see _optical_height(). */
.logo-slot {
  flex: 0 0 auto;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.logo-slot img {
  height: var(--lh, 32px); /* --lh is set inline per logo by build.py */
  width: auto;
  max-width: 250px; /* widest wordmark is Tony Robbins at ~247px */
  object-fit: contain;
  filter: brightness(0) invert(1);
  /* several marks (Boston Harbor, Pelican Hill, Ojai) are fine-line engravings
     that disappear below ~0.7 once flattened to a silhouette */
  opacity: 0.72;
  transition: opacity 0.35s ease-in-out;
}
.logo-slot:hover img,
.logo-slot:hover .logo-slot__text { opacity: 1; }
/* in the static grid the cells get narrow on phones — logos must never
   bleed past the cell border */
.logo-grid .logo-slot { min-width: 0; }
/* Keep the pinned optical height here too — max-height alone would let a small
   intrinsic asset (tony-robbins.svg is only 188x16) render at its raw size
   instead of its optical height. Double-width cells give the wide marks room. */
.logo-grid .logo-slot img { max-width: 100%; }
.logo-grid .logo-slot--wide { grid-column: span 2; }
.logo-grid .logo-slot__text { white-space: normal; text-align: center; line-height: 1.35; }
.logo-slot__text {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15px;
  line-height: 32px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-on-dark);
  opacity: 0.72;
  white-space: nowrap;
  transition: opacity 0.35s ease-in-out;
}

.logo-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  /* safety net: if a wide mark ever can't fit the tail of a row, backfill the
     gap with the next single rather than leaving an empty bordered cell */
  grid-auto-flow: row dense;
  border-top: 1px solid var(--hair-dark);
  border-left: 1px solid var(--hair-dark);
}
.logo-grid .logo-slot {
  height: auto;
  min-height: 108px;
  padding: var(--space-6);
  border-right: 1px solid var(--hair-dark);
  border-bottom: 1px solid var(--hair-dark);
}
/* 6 / 3 / 2 columns all divide the 30 grid slots evenly, so the grid never
   ends on a ragged row of empty bordered cells. */
@media (max-width: 1024px) { .logo-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 760px) {
  /* the stacked CTAs reach the bottom of the hero on phones — the centre
     scroll cue would draw a line straight through them */
  .scroll-cue { display: none; }
  .hero__ctas .btn { width: 100%; }
}

@media (max-width: 640px) { .logo-grid { grid-template-columns: repeat(2, 1fr); } .logo-grid .logo-slot { padding: var(--space-4); } }

/* --------------------------------------------------------------------------
   09 · STATEMENT (Instrument Serif editorial block)
   -------------------------------------------------------------------------- */
.statement { border-left: 2px solid var(--ember); padding-left: clamp(var(--space-6), 3vw, var(--space-12)); }
.statement p:first-of-type {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  font-size: var(--text-2xl);
  line-height: 1.18;
  letter-spacing: -0.01em;
  margin-bottom: var(--space-8);
}
.statement__kicker { font-size: var(--text-base); }

.pullquote {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--text-xl);
  line-height: 1.25;
  border-left: 2px solid var(--ember);
  padding-left: var(--space-6);
  margin: var(--space-10) 0 0;
  max-width: 40ch;
}

/* --------------------------------------------------------------------------
   10 · SECTION HEADER ROW
   -------------------------------------------------------------------------- */
.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-8);
  flex-wrap: wrap;
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--hair-dark);
  margin-bottom: clamp(var(--space-10), 4vw, var(--space-16));
}
.section--bone .section-head { border-bottom-color: var(--hair-light); }
.section-head h2 { font-size: var(--text-2xl); font-weight: 900; margin: 0; }
.section-head .eyebrow { margin-bottom: var(--space-3); }

/* --------------------------------------------------------------------------
   11 · WORK GRID + PLACEHOLDER TILES (film-frame motif)
   -------------------------------------------------------------------------- */
/* Two-up at desktop: real film stills need room. At three-up the tiles were
   450x253 and the always-on caption swallowed half the frame. */
.work-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
}
@media (max-width: 640px) { .work-grid { grid-template-columns: 1fr; } }

/* featured tile runs the full width of the grid as a banner, still 16:9 */
.work-grid.is-featured .tile--featured { grid-column: 1 / -1; }

.tile {
  position: relative;
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 2px;
  background: linear-gradient(135deg, #1a1611, #241c14);
  color: var(--text-on-dark);
  transition: transform 0.35s ease-in-out;
}
.tile.is-hidden { display: none; }

/* real poster frame — fills the tile, warms and lifts slightly on hover */
.tile__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  object-fit: cover;
  filter: saturate(0.86) contrast(1.03);
  transform: scale(1.001);
  transition: transform 0.6s ease-in-out, filter 0.45s ease-in-out;
}
.tile:hover .tile__img,
.tile:focus-visible .tile__img {
  transform: scale(1.045);
  filter: saturate(1) contrast(1);
}
/* unlinked tiles (film not on Vimeo yet) shouldn't imply interactivity */
div.tile { cursor: default; }
div.tile:hover { transform: none; }
div.tile:hover .tile__img { transform: scale(1.001); filter: saturate(0.86) contrast(1.03); }
/* film-frame motif: inset hairline + sprocket columns */
.tile__frame {
  position: absolute;
  inset: 10px;
  border: 1px solid rgba(244, 239, 231, 0.1);
  border-radius: 1px;
  transition: border-color 0.35s ease-in-out;
  pointer-events: none;
}
.tile__sprockets {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.55;
}
/* two sprocket-hole columns along the inner left/right edges */
.tile__sprockets::before,
.tile__sprockets::after {
  content: "";
  position: absolute;
  top: 18px;
  bottom: 18px;
  width: 5px;
  border-radius: 2px;
  background: repeating-linear-gradient(
    to bottom,
    rgba(244, 239, 231, 0.38) 0 6px,
    rgba(244, 239, 231, 0) 6px 18px
  );
}
.tile__sprockets::before { left: 18px; }
.tile__sprockets::after { right: 18px; }
.tile__wash {
  position: absolute;
  inset: 0;
  background: var(--ember);
  opacity: 0;
  transition: opacity 0.35s ease-in-out;
  pointer-events: none;
}
.tile__num {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3rem, 6vw, 6rem);
  letter-spacing: -0.03em;
  color: rgba(244, 239, 231, 0.09);
  pointer-events: none;
}
/* play glyph sits top-right, diagonally opposite the caption, so it reads
   against the image rather than getting lost inside the caption scrim */
.tile__play {
  position: absolute;
  top: var(--space-5);
  right: var(--space-5);
  bottom: auto;
  left: auto;
  transform: scale(1);
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  color: var(--bone);
  background: rgba(16, 14, 12, 0.42);
  backdrop-filter: blur(3px);
  border: 1px solid rgba(244, 239, 231, 0.55);
  border-radius: 50%;
  transition: transform 0.35s ease-in-out, border-color 0.35s ease-in-out,
              background-color 0.35s ease-in-out;
  pointer-events: none;
}
.tile:hover .tile__play { background: rgba(217, 84, 42, 0.85); }
.tile__play svg { width: 12px; height: 14px; }
.tile__caption {
  position: absolute;
  inset: auto 0 0 0;
  padding: var(--space-3) var(--space-5) var(--space-4);
  /* Scrim is anchored to the TEXT BOX, not a fixed height: the box itself
     carries the tint and ::before feathers it upward over the image.
     A fixed-height gradient darkened ~85% of the shorter tiles and buried the
     photography; this keeps the darkened area proportional to the caption.

     0.62 is the floor, not a taste call: against the worst case of a blowout
     white frame it still measures 4.8:1 for the bone client name. Going lighter
     drops small text under 4.5:1 on the brightest stills. Subtlety is bought
     with a longer, gentler feather instead. */
  background: rgba(16, 14, 12, 0.62);
}
/* feather sitting directly on top of the caption box — long and eased, so the
   scrim reads as the image getting darker rather than as a band across it */
.tile__caption::before {
  content: "";
  position: absolute;
  inset: -84px 0 100% 0;
  pointer-events: none;
  background: linear-gradient(
    to top,
    rgba(16, 14, 12, 0.62) 0%,
    rgba(16, 14, 12, 0.38) 26%,
    rgba(16, 14, 12, 0.18) 55%,
    rgba(16, 14, 12, 0.06) 78%,
    rgba(16, 14, 12, 0) 100%
  );
}
/* client name is the primary label */
.tile__client {
  display: block;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: var(--text-lg);
  line-height: 1.12;
  letter-spacing: -0.015em;
  color: var(--bone);
  margin: 0 0 2px;
  text-wrap: balance;
}
.tile--featured .tile__client { font-size: var(--text-xl); }
/* single-column tiles are only ~188px tall, so the scrim has to be tighter
   here or it covers well over half the still */
@media (max-width: 640px) {
  .tile__client,
  .tile--featured .tile__client { font-size: var(--text-base); }
  .tile__caption { padding: var(--space-2) var(--space-4) var(--space-3); }
  .tile__caption::before { inset: -48px 0 100% 0; }
  .tile__play { width: 34px; height: 34px; top: var(--space-4); right: var(--space-4); }
  .tile__play svg { width: 10px; height: 12px; }
  .tile__frame { inset: 7px; }
}
.tile__cat {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ember-hot);
  margin: 0 0 var(--space-1);
}
/* project title is secondary to the client name */
.tile__title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--text-sm);
  line-height: 1.25;
  margin: 0;
  color: rgba(244, 239, 231, 0.78);
  border-bottom: 1px solid transparent;
  display: inline-block;
  transition: border-color 0.35s ease-in-out, color 0.35s ease-in-out;
}
.tile--featured .tile__title { font-size: var(--text-base); }
.tile:hover .tile__title { color: var(--bone); }
.tile:hover { transform: translateY(-4px); }
.tile:hover .tile__wash { opacity: 0.12; }
.tile:hover .tile__frame { border-color: rgba(244, 239, 231, 0.32); }
.tile:hover .tile__play { transform: scale(1.15); border-color: var(--bone); }
.tile:hover .tile__title { border-bottom-color: currentColor; }
.tile:focus-visible { outline-offset: -4px; }

/* Panel variant used on What We Do (no caption, larger motif) */
.panel { aspect-ratio: 16 / 9; width: 100%; }

/* work archive sits directly under the sticky filter bar — tighten the top */
.section--grid { padding-top: clamp(var(--space-10), 4vw, var(--space-16)); }

/* Filter bar */
.filter-bar {
  position: sticky;
  top: var(--nav-h-shrunk);
  z-index: 40;
  background: var(--ink);
  border-bottom: 1px solid var(--hair-dark);
  padding-block: var(--space-4);
}
.filter-bar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  flex-wrap: wrap;
}
.filters { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.filter {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-on-dark);
  background: transparent;
  border: 1px solid var(--hair-dark);
  border-radius: 999px;
  padding: var(--space-2) var(--space-5);
  cursor: pointer;
  transition: background 0.35s ease-in-out, color 0.35s ease-in-out,
    border-color 0.35s ease-in-out;
}
.filter:hover { border-color: rgba(244, 239, 231, 0.4); }
.filter.is-active {
  background: var(--ember);
  border-color: var(--ember);
  color: var(--ink);
}
.filter-count {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-on-dark-mute);
}

.admin-note {
  border: 1px dashed rgba(244, 239, 231, 0.28);
  border-radius: 2px;
  padding: var(--space-4) var(--space-5);
  color: var(--text-on-dark-mute);
  font-size: var(--text-sm);
  margin-bottom: var(--space-10);
}

/* --------------------------------------------------------------------------
   12 · SERVICES PREVIEW (3 columns)
   -------------------------------------------------------------------------- */
.svc-cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; }
.svc-col { padding: 0 clamp(var(--space-6), 3vw, var(--space-10)); border-left: 1px solid var(--hair-light); }
.svc-col:first-child { padding-left: 0; border-left: 0; }
.svc-col:last-child { padding-right: 0; }
.svc-col__num {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-xl);
  color: var(--ember);
  display: block;
  margin-bottom: var(--space-4);
}
.svc-col h3 { font-size: var(--text-lg); margin: 0 0 var(--space-4); }
.svc-col p { font-size: var(--text-base); margin-bottom: var(--space-6); }
@media (max-width: 860px) {
  .svc-cols { grid-template-columns: 1fr; }
  .svc-col { padding: var(--space-10) 0 0; border-left: 0; border-top: 1px solid var(--hair-light); }
  .svc-col:first-child { padding-top: 0; border-top: 0; }
}

/* --------------------------------------------------------------------------
   13 · CTA SECTION
   -------------------------------------------------------------------------- */
.cta { position: relative; text-align: center; overflow: hidden; }
.cta::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(900px, 90vw);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(217, 84, 42, 0.16) 0%, rgba(217, 84, 42, 0) 68%);
  pointer-events: none;
}
.cta__inner { position: relative; z-index: 1; }
.cta h2 {
  font-size: var(--text-3xl);
  font-weight: 900;
  max-width: 24ch;
  margin: 0 auto var(--space-10);
  text-wrap: balance;
}

/* --------------------------------------------------------------------------
   14 · ABOUT — sticky two-column blocks
   -------------------------------------------------------------------------- */
.split {
  display: grid;
  grid-template-columns: minmax(220px, 0.8fr) minmax(0, 1.6fr);
  gap: clamp(var(--space-8), 5vw, var(--space-24));
  align-items: start;
}
.split__title { position: sticky; top: calc(var(--nav-h-shrunk) + var(--space-10)); }
.split__title h2 { font-size: var(--text-xl); margin: 0 0 var(--space-5); }
.split__title .rule { display: block; width: 48px; height: 2px; background: var(--ember); }
@media (max-width: 860px) {
  .split { grid-template-columns: 1fr; }
  .split__title { position: static; }
}

.capability-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-4);
  margin-top: var(--space-10);
  list-style: none;
  padding: 0;
}
.capability-strip li {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
  gap: var(--space-4);
}
.capability-strip li:not(:last-child)::after {
  content: "";
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--ember);
}

/* --------------------------------------------------------------------------
   15 · WHAT WE DO — alternating service rows
   -------------------------------------------------------------------------- */
.svc-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(var(--space-8), 5vw, var(--space-20));
  align-items: center;
}
.svc-row--flip .svc-row__media { order: -1; }
.svc-row__num {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-2xl);
  color: var(--ember);
  display: block;
  line-height: 1;
  margin-bottom: var(--space-5);
}
.svc-row h2 { font-size: var(--text-3xl); font-weight: 900; margin: 0 0 var(--space-6); }
.svc-row p { font-size: var(--text-lg); line-height: 1.5; }
@media (max-width: 860px) {
  .svc-row { grid-template-columns: 1fr; }
  .svc-row--flip .svc-row__media { order: 0; }
}

/* --------------------------------------------------------------------------
   16 · CONTACT
   -------------------------------------------------------------------------- */
.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: clamp(var(--space-10), 6vw, var(--space-24));
  align-items: start;
}
@media (max-width: 900px) { .contact-grid { grid-template-columns: 1fr; } }

.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-8); }
.field--full { grid-column: 1 / -1; }
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }

.field label {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-on-dark-mute);
  margin-bottom: var(--space-3);
}
.field input,
.field select,
.field textarea {
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--hair-dark);
  color: var(--text-on-dark);
  font-family: var(--font-body);
  font-size: var(--text-base);
  padding: var(--space-2) 0 var(--space-3);
  border-radius: 0;
  transition: border-color 0.35s ease-in-out;
}
.field select { appearance: none; background-image: none; cursor: pointer; }
.field select option { background: var(--ink-2); color: var(--text-on-dark); }
.field textarea { resize: vertical; min-height: 132px; }
.field input:focus,
.field select:focus,
.field textarea:focus { outline: none; border-bottom-color: var(--ember); }
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible { outline: none; }

.form-success {
  display: none;
  border: 1px solid var(--ember);
  border-left-width: 2px;
  padding: var(--space-6);
  margin-top: var(--space-8);
  background: rgba(217, 84, 42, 0.08);
}
.form-success.is-visible { display: block; }

.detail-block { border-top: 1px solid var(--hair-dark); padding-top: var(--space-5); margin-bottom: var(--space-10); }
.detail-block__label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-on-dark-mute);
  margin: 0 0 var(--space-2);
}
.detail-block a:hover { color: var(--ember-hot); }

/* --------------------------------------------------------------------------
   17 · FOOTER
   -------------------------------------------------------------------------- */
.footer { background: var(--ink); border-top: 1px solid var(--hair-dark); padding-block: clamp(var(--space-16), 7vw, var(--space-24)) var(--space-8); }
.footer__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-10);
  flex-wrap: wrap;
}
.footer__tag { color: var(--text-on-dark-mute); font-size: var(--text-sm); margin: var(--space-5) 0 0; }
.footer__social { display: flex; gap: var(--space-5); }
.footer__social a {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: 1px solid var(--hair-dark);
  border-radius: 50%;
  color: var(--text-on-dark-mute);
  transition: color 0.35s ease-in-out, border-color 0.35s ease-in-out;
}
.footer__social a:hover { color: var(--ember-hot); border-color: var(--ember); }
.footer__social svg { width: 17px; height: 17px; }
.footer__contact {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-10);
  margin-top: clamp(var(--space-12), 5vw, var(--space-20));
}
.footer__contact .detail-block { margin-bottom: 0; min-width: 220px; }
.footer__bottom {
  margin-top: var(--space-10);
  padding-top: var(--space-6);
  border-top: 1px solid var(--hair-dark);
  font-size: var(--text-xs);
  color: var(--text-on-dark-mute);
}

/* --------------------------------------------------------------------------
   18 · SCROLL REVEAL
   -------------------------------------------------------------------------- */
/* Content must never depend on the script to become visible. The hidden state
   is gated behind a class main.js sets on <html> the moment it takes charge of
   the reveals, so if the script is blocked, errors out earlier on the page, or
   the observer never fires, every .reveal simply renders as normal content. */
html.has-reveal .reveal:not(.is-in) { opacity: 0; transform: translateY(24px); }
.reveal.is-in {
  opacity: 1;
  transform: none;
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; }
  .hero h1 .word { opacity: 1; transform: none; animation: none; }
  .marquee__track { animation: none; }
  .scroll-cue::after { animation: none; }
  * { transition-duration: 0.01ms !important; }
}

/* --------------------------------------------------------------------------
   19 · RESPONSIVE TUNING
   -------------------------------------------------------------------------- */
@media (max-width: 640px) {
  :root { --gutter: 20px; --nav-h: 68px; --nav-h-shrunk: 58px; }
  .hero { min-height: 600px; }
  .hero h1 { max-width: 16ch; }
  .hero__h1 { max-width: 11ch; }
  .marquee__track { gap: var(--space-10); }
  .filter-bar__inner { gap: var(--space-3); }
}

/* --------------------------------------------------------------------------
   22 · VIDEO LIGHTBOX
   Work tiles play in place instead of opening vimeo.com in a new window.
   -------------------------------------------------------------------------- */
html.is-locked,
html.is-locked body {
  overflow: hidden;
}

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  padding: clamp(var(--space-4), 5vw, var(--space-16));
}

.lightbox[hidden] {
  display: none;
}

.lightbox__backdrop {
  position: absolute;
  inset: 0;
  /* near-opaque plus a light blur, so the tile caption underneath cannot
     bleed through and compete with the player's own caption */
  background: rgba(16, 14, 12, 0.97);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 0.24s var(--ease-out);
  cursor: pointer;
}

.lightbox.is-open .lightbox__backdrop {
  opacity: 1;
}

.lightbox__panel {
  position: relative;
  width: min(100%, 1200px);
  opacity: 0;
  transform: translateY(14px) scale(0.99);
  transition: opacity 0.28s var(--ease-out), transform 0.28s var(--ease-out);
}

.lightbox.is-open .lightbox__panel {
  opacity: 1;
  transform: none;
}

.lightbox__frame {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #000;
  border: 1px solid var(--hair-dark);
  overflow: hidden;
}

.lightbox__frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

.lightbox__close {
  position: absolute;
  right: 0;
  bottom: calc(100% + var(--space-3));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  color: var(--text-on-dark);
  background: transparent;
  border: 1px solid var(--hair-dark);
  border-radius: 50%;
  cursor: pointer;
  transition: color 0.2s var(--ease-out), border-color 0.2s var(--ease-out),
    background-color 0.2s var(--ease-out);
}

.lightbox__close:hover,
.lightbox__close:focus-visible {
  color: var(--bone);
  border-color: var(--ember);
  background: var(--ember);
}

.lightbox__caption {
  margin: var(--space-4) 0 0;
  font-size: var(--text-sm);
  color: var(--text-on-dark-mute);
}

.lightbox__client {
  font-weight: 700;
  color: var(--text-on-dark);
}

@media (max-width: 640px) {
  .lightbox__close {
    top: auto;
    bottom: calc(100% + var(--space-2));
    width: 40px;
    height: 40px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .lightbox__backdrop,
  .lightbox__panel {
    transition: none;
  }
}

/* --------------------------------------------------------------------------
   18 · PROJECT PAGE — hero, brief, cutdown grid, stills gallery
   Used by uncover-ojai.html. The hero reuses .hero wholesale (and therefore
   the Elementor positioning fix in elementor-bridge.css); only the height and
   the poster differ, because a project hero should not claim a full viewport
   the way the homepage does.
   -------------------------------------------------------------------------- */
.hero--project {
  min-height: 520px;
  height: min(82dvh, 780px);
}
/* The homepage poster is hard-coded on .hero-video::before. Project heroes
   pass their own frame in as --poster on the element, so each page can carry
   its own still without a new rule per project. */
.hero--project .hero-video::before {
  background-image: var(--poster);
  /* This still has no burned-in type to hide, so it needs far less blur than
     the homepage reel — just enough to read as texture, not as a photo. */
  filter: blur(12px) brightness(0.5) saturate(0.85);
}
/* The base cover math on .hero-video iframe assumes the film fills its 16:9
   player. This film is 2.39:1, so Vimeo letterboxes it INSIDE the player and
   the picture is only 16/9 / 2.39 = 74% of the iframe's height - which left a
   black band across the bottom of the hero. So overfill against the film's own
   ratio instead of the player's: make the iframe wide enough that the
   letterboxed picture alone covers the hero, and let the player's own black
   bars overhang and get clipped.
     picture height = iframe width / 2.39  >=  hero height  ->  w >= 239cqh
     picture width  = iframe width         >=  hero width   ->  w >= 100cqw */
.hero--project .hero-video iframe {
  width: max(100vw, 239vh);
  height: auto;
  aspect-ratio: 16 / 9;
}
@supports (width: 1cqh) {
  .hero--project .hero-video iframe {
    width: max(100cqw, 239cqh);
    height: auto;
    min-height: 0;
  }
}
.btn__dur {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  opacity: 0.72;
}

/* ---- brief -------------------------------------------------------------- */
.brief__facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-6) var(--space-8);
  margin: var(--space-10) 0 0;
  padding-top: var(--space-8);
  border-top: 1px solid var(--hair-light);
}
.brief__facts dt {
  font-family: var(--font-display);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ember);
  margin-bottom: var(--space-2);
}
.brief__facts dd {
  margin: 0;
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--text-on-light);
}

/* ---- cutdowns ---------------------------------------------------------- */
.cut-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(var(--space-5), 2.2vw, var(--space-8));
}
.cut {
  display: block;
  text-decoration: none;
  color: inherit;
}
.cut__media {
  position: relative;
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 2px;
  background: var(--ink-2);
}
.cut__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1),
              filter 0.4s ease;
  filter: saturate(0.94);
}
.cut:hover .cut__img,
.cut:focus-visible .cut__img {
  transform: scale(1.045);
  filter: saturate(1.04);
}
.cut__wash {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(16, 14, 12, 0) 45%,
                                      rgba(16, 14, 12, 0.42) 100%);
  transition: opacity 0.4s ease;
}
.cut:hover .cut__wash { opacity: 0.55; }
.cut__play {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(0.92);
  width: 54px;
  height: 54px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: #fff;
  background: rgba(16, 14, 12, 0.42);
  border: 1px solid rgba(244, 239, 231, 0.55);
  backdrop-filter: blur(3px);
  transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1),
              background 0.3s ease, border-color 0.3s ease;
}
.cut__play svg { width: 13px; height: 15px; margin-left: 2px; }
.cut:hover .cut__play,
.cut:focus-visible .cut__play {
  transform: translate(-50%, -50%) scale(1);
  background: var(--ember);
  border-color: var(--ember);
}
.cut__meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid rgba(244, 239, 231, 0.14);
  margin-top: var(--space-4);
}
.cut__label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-sm);
  letter-spacing: 0.02em;
}
.cut__dur {
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--text-on-dark-mute);
  letter-spacing: 0.06em;
}
.cut:hover .cut__label { color: var(--ember-hot); }

/* Campaign spots carry two extra caption lines (the city, then the traveller
   the film follows), so the meta block becomes a small stack rather than the
   single label/duration row a cutdown uses. */
.cut--spot .cut__sub,
.cut--spot .cut__who {
  display: block;
  margin-top: var(--space-2);
}
.cut--spot .cut__sub {
  font-size: var(--text-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-on-dark-mute);
}
.cut--spot .cut__who {
  font-size: var(--text-sm);
  line-height: 1.45;
  color: var(--text-on-dark);
  opacity: 0.82;
  max-width: 32ch;
}
/* Only three cards, so the generic 2-column step would strand one on a row of
   its own. Hold three across until they are genuinely too narrow, then go to
   a single column and skip the orphan entirely. */
.cut-grid--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* ---- stills gallery ---------------------------------------------------- */
.still-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* the one double-width still would otherwise leave a hole where it wraps */
  grid-auto-flow: dense;
  gap: clamp(var(--space-3), 1.4vw, var(--space-5));
}
.still {
  position: relative;
  display: block;
  padding: 0;
  margin: 0;
  border: 0;
  border-radius: 2px;
  overflow: hidden;
  background: var(--bone-2);
  cursor: zoom-in;
  aspect-ratio: 3 / 2;
  -webkit-appearance: none;
  appearance: none;
}
/* The double-width still spans two ROWS as well as two columns. Spanning only
   columns made its row as tall as a 900px-wide 3:2 frame while its single-column
   neighbour was only 293px tall, leaving dead space beside it. Two rows lines up
   with two stacked neighbours instead - and the row heights then define its
   height, so its own aspect-ratio has to come off. */
.still--wide {
  grid-column: span 2;
  grid-row: span 2;
  aspect-ratio: auto;
}
.still img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.8s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.still:hover img,
.still:focus-visible img { transform: scale(1.04); }
.still::after {
  content: "";
  position: absolute;
  inset: 0;
  box-shadow: inset 0 0 0 1px rgba(16, 14, 12, 0.1);
  pointer-events: none;
}
.still:focus-visible { outline: 2px solid var(--ember); outline-offset: 3px; }

/* An image lightbox reuses the video lightbox chrome, but the frame has to
   drop the 16:9 box and size to the picture instead. */
.lightbox--img .lightbox__panel { width: min(100%, 1500px); }
.lightbox--img .lightbox__frame {
  aspect-ratio: auto;
  background: transparent;
  display: grid;
  place-items: center;
}
.lightbox--img .lightbox__frame img {
  max-width: 100%;
  max-height: 82dvh;
  width: auto;
  height: auto;
  display: block;
}

@media (max-width: 1100px) {
  .cut-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cut-grid--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .still-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* at two columns a 2x2 span is the entire row, which is not a feature */
  .still--wide { grid-row: span 1; aspect-ratio: 3 / 2; }
}
@media (max-width: 860px) {
  /* three across has run out of room; one column reads better than 2 + orphan */
  .cut-grid--three { grid-template-columns: 1fr; }
  .cut--spot .cut__who { max-width: none; }
}
@media (max-width: 700px) {
  .hero--project { height: min(74dvh, 620px); min-height: 460px; }
  /* The three-part eyebrow wraps on a phone and strands its separator dot at
     the end of the first line, which reads as a typo. Drop the third term -
     the cutdowns get their own section heading a screen later. */
  .eyebrow__last { display: none; }
  .cut-grid,
  .cut-grid--three { grid-template-columns: 1fr; }
  .still-grid { grid-template-columns: 1fr; }
  .still--wide { grid-column: span 1; grid-row: span 1; aspect-ratio: 3 / 2; }
  .brief__facts { grid-template-columns: 1fr; }
  .cut__play { width: 46px; height: 46px; }
}

/* --------------------------------------------------------------------------
   19 · PODCASTS PAGE — still hero, featured card, typographic episode index
   Used by podcasts.html. There are no episode posters on this page on purpose:
   the only thumbnails the channel publishes are the client's marketing artwork
   with their logo burned in, so the index is set in type instead and the one
   photographic asset is Forma's own frame.
   -------------------------------------------------------------------------- */

/* A hero with no film behind it. .hero--project supplies the height; this
   paints the frame straight onto the section, so there is no .hero-video
   element and nothing to autoplay. */
.hero--still { background: var(--ink); }
.hero__still { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.hero__still picture,
.hero__still img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Bias up: the two chairs sit low in the frame and the headline sits low in
     the hero, so pulling the crop up keeps faces out from behind the type. */
  object-position: 50% 38%;
}
/* The still is busy through the middle where the headline sits, so it needs a
   heavier scrim than a blurred reel does. */
.hero--still .hero__scrim {
  background: linear-gradient(180deg, rgba(16, 14, 12, 0.58) 0%,
                                      rgba(16, 14, 12, 0.42) 42%,
                                      rgba(16, 14, 12, 0.88) 100%);
}

/* ---- featured card ---- */
/* Fills the same text column the episode index uses, so the card and the
   rows below it share one left and right edge. */
.feat-wrap { max-width: none; }
.feat {
  display: block;
  position: relative;
  text-decoration: none;
  color: inherit;
}
.feat__img,
.feat picture {
  display: block;
  width: 100%;
}
.feat picture {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 2px;
  background: var(--ink-2);
}
.feat__img {
  height: 100%;
  object-fit: cover;
  transition: transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1), filter 0.4s ease;
  filter: saturate(0.94);
}
a.feat:hover .feat__img,
a.feat:focus-visible .feat__img {
  transform: scale(1.03);
  filter: saturate(1.04);
}
.feat__wash {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(16, 14, 12, 0) 50%,
                                      rgba(16, 14, 12, 0.5) 100%);
}
.feat__play {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(0.92);
  width: 68px;
  height: 68px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: #fff;
  background: rgba(16, 14, 12, 0.42);
  border: 1px solid rgba(244, 239, 231, 0.55);
  backdrop-filter: blur(3px);
  transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1),
              background 0.3s ease, border-color 0.3s ease;
}
.feat__play svg { width: 17px; height: 19px; margin-left: 3px; }
a.feat:hover .feat__play,
a.feat:focus-visible .feat__play {
  transform: translate(-50%, -50%) scale(1);
  background: var(--ember);
  border-color: var(--ember);
}
.feat__meta {
  display: flex;
  align-items: baseline;
  gap: var(--space-4);
  padding-top: var(--space-4);
  margin-top: var(--space-4);
  border-top: 1px solid rgba(244, 239, 231, 0.14);
}
.feat__label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-base);
  letter-spacing: 0.02em;
}
.feat__sub {
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-on-dark-mute);
}
.feat__dur {
  margin-left: auto;
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
  color: var(--text-on-dark-mute);
}
a.feat:hover .feat__label { color: var(--ember-hot); }
/* No player yet, so nothing should suggest one is a click away. */
.feat--still { cursor: default; margin: 0; }

/* ---- episode index ---- */
.ep-list {
  display: flex;
  flex-direction: column;
  border-top: 1px solid rgba(16, 14, 12, 0.14);
}
.ep {
  display: flex;
  align-items: center;
  gap: clamp(var(--space-4), 2.4vw, var(--space-8));
  padding: clamp(var(--space-4), 1.8vw, var(--space-6)) 0;
  border-bottom: 1px solid rgba(16, 14, 12, 0.14);
  text-decoration: none;
  color: inherit;
  transition: background 0.25s ease, padding-left 0.3s ease;
}
.ep:hover,
.ep:focus-visible {
  /* Bleeds a touch past the text column so the row reads as one target. */
  box-shadow: -12px 0 0 0 rgba(217, 84, 42, 0.06),
               12px 0 0 0 rgba(217, 84, 42, 0.06);
  background: rgba(217, 84, 42, 0.06);
  padding-left: var(--space-3);
}
.ep__num {
  flex: 0 0 auto;
  min-width: 3.2ch;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-base);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: var(--ember);
}
.ep__body {
  display: flex;
  flex-direction: column;
  gap: 0.25em;
  min-width: 0;
}
.ep__guest {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-lg);
  line-height: 1.15;
  letter-spacing: -0.005em;
  transition: color 0.25s ease;
}
.ep:hover .ep__guest,
.ep:focus-visible .ep__guest { color: var(--ember-hot); }
.ep__title {
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--text-on-light-mute);
}
.ep__end {
  margin-left: auto;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--space-4);
}
.ep__dur {
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
  color: var(--text-on-light-mute);
  white-space: nowrap;
}
.ep__play {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--ink);
  border: 1px solid rgba(16, 14, 12, 0.26);
  transition: background 0.3s ease, border-color 0.3s ease, color 0.3s ease,
              transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.ep__play svg { width: 11px; height: 13px; margin-left: 2px; }
.ep:hover .ep__play,
.ep:focus-visible .ep__play {
  background: var(--ember);
  border-color: var(--ember);
  color: #fff;
  transform: scale(1.06);
}

@media (max-width: 700px) {
  /* The runtime and the play badge together crowd the title on a phone, and
     the badge is redundant when the whole row is the tap target. */
  .ep__play { display: none; }
  .ep {
    align-items: flex-start;
    gap: var(--space-4);
    padding: var(--space-5) 0;
  }
  .ep__num { min-width: 2.6ch; font-size: var(--text-sm); padding-top: 0.15em; }
  .ep__guest { font-size: var(--text-base); }
  .ep__end { align-self: flex-start; padding-top: 0.2em; }
  .feat__meta { flex-wrap: wrap; }
  .feat__dur { margin-left: 0; }
}

/* --------------------------------------------------------------------------
   23 · ELEMENTOR BRIDGE
   The pages are edited in Elementor but must keep the studio's design system.
   Elementor supplies the layout scaffolding (sections, columns, widgets) and
   this block re-asserts our type, spacing and grid on top of it, so a page
   assembled in the builder is visually identical to the hand-built version.
   Nothing here styles the design itself — it only stops Elementor's resets
   from winning the cascade.
   -------------------------------------------------------------------------- */

/* Elementor sets line-height:1 on every heading it renders, which overrides our
   element-level rules. Restate ours at higher specificity. */
.elementor-widget-heading h1.elementor-heading-title,
.elementor-widget-heading h2.elementor-heading-title,
.elementor-widget-heading h3.elementor-heading-title,
.elementor-widget-heading h4.elementor-heading-title {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin: 0;
}

/* A heading widget standing in for a <p> (the eyebrow) must not inherit the
   heading treatment. */
.elementor-widget-heading p.elementor-heading-title {
  line-height: inherit;
  letter-spacing: inherit;
}

/* Our sections own their vertical rhythm, so the widget wrap must not add to
   it, and the column must be free to carry .container. */
.elementor-section > .elementor-container {
  max-width: 100%;
}

.elementor-column > .elementor-widget-wrap {
  padding: 0;
}

/* Widgets stack on our spacing scale rather than Elementor's 20px default. */
.elementor-widget:not(:last-child) {
  margin-bottom: var(--space-5);
}

/* --- .split as an Elementor inner section ---------------------------------
   In the hand-built pages .split IS the grid. Here the class sits on the
   section while the real children live one level down inside
   .elementor-container, so the grid has to move down with them — otherwise the
   container becomes a single grid item in the narrow title track and the body
   copy collapses to one word per line. */
.split.elementor-section {
  display: block;
}

.split > .elementor-container {
  display: grid;
  grid-template-columns: minmax(220px, 0.8fr) minmax(0, 1.6fr);
  gap: clamp(var(--space-8), 5vw, var(--space-24));
  align-items: start;
}

.split > .elementor-container > .elementor-column {
  width: auto;
  min-width: 0;
}

@media (max-width: 860px) {
  .split > .elementor-container {
    grid-template-columns: 1fr;
  }
}

/* The rule under a split title is a widget here, not a bare span. */
.split__title .elementor-widget-html .rule {
  display: block;
  width: 48px;
  height: 2px;
  background: var(--ember);
}

/* A button widget puts our .btn classes on the widget wrapper rather than on
   the <a>, so the wrapper becomes the pill: it shrink-wraps, Elementor's own
   two intermediate wrappers step out of the layout with display:contents, and
   the anchor's default styling is flattened so it simply carries the label.
   This keeps the button editable in Elementor with no duplicated styling. */
/* Elementor prints its global kit styles inline, after this stylesheet, so the
   neutralising declarations below are marked important. They are the only ones
   in the project that need to be. */
.elementor .elementor-widget-button.btn {
  display: inline-flex !important;
  width: auto !important;
}

/* .cta centres its children with text-align, which cannot centre a
   block-level widget wrapper, so the button is centred explicitly. */
.cta .elementor-widget-button.btn {
  margin-inline: auto;
}

.elementor .elementor-widget-button.btn > .elementor-widget-container,
.elementor .elementor-widget-button.btn .elementor-button-wrapper {
  display: contents !important;
}

.elementor .elementor-widget-button.btn .elementor-button,
.elementor .elementor-widget-button.btn .elementor-button:hover,
.elementor .elementor-widget-button.btn .elementor-button:focus {
  background: none !important;
  border: 0 !important;
  padding: 0 !important;
  color: inherit !important;
  font: inherit !important;
  letter-spacing: inherit !important;
  text-transform: inherit !important;
  fill: currentColor;
}

/* Elementor renders the text editor inside a wrapper that adds its own
   bottom margin on the last paragraph. */
.elementor-widget-text-editor > .elementor-widget-container > :last-child {
  margin-bottom: 0;
}

/* ---------------------------------------------------------------------------
   HERO — restore .hero as the positioning context

   The hero's markup lives in a single HTML widget, so Elementor inserts
   section > container > column > widget-wrap > widget > widget-container
   between .hero and the absolutely positioned .hero-video / .hero__scrim /
   .scroll-cue. Elementor sets position:relative on most of that chain, so
   `inset: 0` resolved to the WIDGET box instead of the hero: because .hero is
   `display:flex; align-items:flex-end`, that box is only as tall as the copy
   and sits at the bottom, so on desktop the reel filled a ~620px band in the
   middle of a 900px hero — black above and below, and the 16:9 frame cropped
   top and bottom to fit the short box.

   Making the chain position:static hands the containing block back to .hero,
   so inset:0 covers the full hero again and the cover math has the real hero
   height to work against. The copy stays bottom-aligned because the container
   is still a flex child of .hero — only the positioning context changes, not
   the layout. Mobile hid the bug: the band happened to be taller than the
   viewport there, so the video already looked full-bleed.
   --------------------------------------------------------------------------- */
.hero.elementor-section > .elementor-container,
.hero .elementor-column,
.hero .elementor-column > .elementor-widget-wrap,
.hero .elementor-widget-html,
.hero .elementor-widget-html > .elementor-widget-container {
  position: static;
}
/* the widget-wrap's default 15px padding also inset the video box and knocked
   the centred copy column 7.5px off the page grid */
.hero .elementor-column > .elementor-widget-wrap { padding: 0; }
/* the section is full-width, so the container must not clamp to 1140px */
.hero.elementor-section > .elementor-container {
  width: 100%;
  max-width: none;
}
