/* ==========================================================================
   Virazz Productions
   Luxury wedding film studio. Warm ivory editorial ground, deep ink type,
   a single muted bronze accent. Display type is Cormorant Garamond: a serif
   is deliberate here, this is a bridal luxury brand where editorial serif
   is the native register, not a decorative default.
   ========================================================================== */

:root {
  --ivory: #f7f3ed;
  --ivory-deep: #efe8dd;
  --ivory-warm: #f2ece2;
  --ink: #1c1a17;
  --ink-soft: #46413a;
  --muted: #8b8377;
  --accent: #96805c;
  --accent-light: #b9a37c;
  --line: rgba(28, 26, 23, 0.13);
  --line-strong: rgba(28, 26, 23, 0.28);
  --shadow: 0 30px 80px -40px rgba(28, 26, 23, 0.35);

  --maxw: 1320px;
  --narrow: 780px;
  --gutter: clamp(22px, 5.5vw, 78px);
  --ease: cubic-bezier(0.19, 1, 0.22, 1);
  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
}

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

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

body {
  margin: 0;
  background: var(--ivory);
  color: var(--ink);
  font-family: "Jost", -apple-system, "Segoe UI", sans-serif;
  font-weight: 300;
  font-size: 1rem;
  line-height: 1.68;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; }

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

:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 3px;
}

/* ---------- Type primitives ---------- */

.display {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-weight: 300;
  letter-spacing: -0.005em;
  line-height: 1.02;
  margin: 0;
}

h1.display { font-size: clamp(2.9rem, 7.6vw, 6.6rem); }
h2.display { font-size: clamp(2.2rem, 5.2vw, 4.3rem); }
h3.display { font-size: clamp(1.7rem, 3.2vw, 2.7rem); line-height: 1.1; }

.display em {
  font-style: italic;
  color: var(--accent);
  padding-bottom: 0.06em;
  display: inline-block;
}

.label {
  font-family: "Jost", sans-serif;
  font-weight: 400;
  font-size: 0.66rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 16px;
}
.label::before {
  content: "";
  width: 34px;
  height: 1px;
  background: var(--accent);
  flex: none;
}
.label.no-rule::before { display: none; }
.label.centered { justify-content: center; }

.body-lg {
  font-size: clamp(1.02rem, 1.3vw, 1.16rem);
  line-height: 1.78;
  color: var(--ink-soft);
  max-width: 62ch;
}

.body-sm {
  font-size: 0.95rem;
  line-height: 1.75;
  color: var(--ink-soft);
  max-width: 58ch;
}

/* ---------- Layout ---------- */

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.wrap-narrow {
  width: 100%;
  max-width: var(--narrow);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

section { position: relative; }
.pad { padding: clamp(84px, 12vh, 152px) 0; }
.pad-sm { padding: clamp(60px, 8vh, 96px) 0; }
.rule { height: 1px; background: var(--line); border: 0; margin: 0; }

/* ---------- Header ---------- */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 90;
  padding: 30px 0;
  transition: padding 0.5s var(--ease), background-color 0.5s var(--ease),
              box-shadow 0.5s var(--ease), border-color 0.5s var(--ease);
  border-bottom: 1px solid transparent;
}
.site-header .wrap {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
}

.site-header.on-dark { color: var(--ivory); }
.site-header.on-dark .nav a { color: rgba(247, 243, 237, 0.78); }
.site-header.on-dark .nav a:hover,
.site-header.on-dark .nav a[aria-current="page"] { color: var(--ivory); }
.site-header.on-dark .brand-rule { background: rgba(247, 243, 237, 0.4); }
.site-header.on-dark .nav-toggle span { background: var(--ivory); }

.site-header.is-scrolled {
  padding: 16px 0;
  background: rgba(247, 243, 237, 0.72);
  backdrop-filter: blur(22px) saturate(165%);
  -webkit-backdrop-filter: blur(22px) saturate(165%);
  box-shadow: 0 18px 40px -34px rgba(28, 26, 23, 0.6);
  border-bottom-color: var(--line);
  color: var(--ink);
}
.site-header.is-scrolled .nav a { color: var(--muted); }
.site-header.is-scrolled .nav a:hover,
.site-header.is-scrolled .nav a[aria-current="page"] { color: var(--ink); }
.site-header.is-scrolled .brand-rule { background: var(--line-strong); }
.site-header.is-scrolled .nav-toggle span { background: var(--ink); }

.brand {
  grid-column: 2;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
}
.brand-name {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: clamp(1.15rem, 1.9vw, 1.55rem);
  font-weight: 400;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  line-height: 1;
}
.brand-rule { width: 100%; height: 1px; background: var(--line-strong); transition: background-color 0.5s var(--ease); }
.brand-sub {
  font-size: 0.55rem;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: currentColor;
  opacity: 0.62;
  line-height: 1;
}

.nav {
  display: flex;
  align-items: center;
  gap: clamp(20px, 2.6vw, 42px);
}
.nav.left { grid-column: 1; justify-content: flex-start; }
.nav.right { grid-column: 3; justify-content: flex-end; }
.nav a {
  position: relative;
  font-size: 0.68rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 6px 0;
  transition: color 0.35s var(--ease);
}
.nav a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 1px;
  background: var(--accent);
  transition: width 0.45s var(--ease);
}
.nav a:hover::after,
.nav a[aria-current="page"]::after { width: 100%; }

.nav-toggle {
  display: none;
  grid-column: 3;
  justify-self: end;
  background: none;
  border: 0;
  padding: 10px;
  cursor: pointer;
  flex-direction: column;
  gap: 6px;
  width: 44px;
}
.nav-toggle span {
  display: block;
  height: 1px;
  width: 24px;
  background: var(--ink);
  transition: transform 0.4s var(--ease), opacity 0.3s var(--ease), background-color 0.5s var(--ease);
}
.nav-toggle.is-open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle.is-open span:nth-child(2) { opacity: 0; }
.nav-toggle.is-open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

.mobile-nav {
  position: fixed;
  inset: 0;
  z-index: 89;
  background: var(--ivory);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 30px;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.5s var(--ease), visibility 0.5s;
}
.mobile-nav.is-open { opacity: 1; visibility: visible; }
.mobile-nav a {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: clamp(1.9rem, 8vw, 2.8rem);
  font-weight: 300;
  color: var(--ink);
}
.mobile-nav a:hover { color: var(--accent); font-style: italic; }

/* Raised from 940px when Teasers became a fourth link on the left. Measured at
   940px, where the links plus the centered brand wanted more room than the
   content width allowed and the nav collided with the logo. Recalculated after
   Wedding Teasers and Wedding Highlights replaced shorter labels. The full nav
   only shows where it actually fits; everything below gets the menu button. */
@media (max-width: 1140px) {
  .nav { display: none; }
  .nav-toggle { display: flex; }
  .site-header .wrap { grid-template-columns: 1fr auto; }
  .brand { grid-column: 1; align-items: flex-start; text-align: left; }
  .nav-toggle { grid-column: 2; }
}

/* ---------- Hero ---------- */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: #100e0c;
  color: var(--ivory);
  isolation: isolate;
}

.hero-media {
  position: absolute;
  inset: 0;
  z-index: -2;
  overflow: hidden;
}
.hero-media iframe,
.interlude-media iframe,
.bg-still {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100vw;
  height: 56.25vw;
  min-height: 100svh;
  min-width: 177.78svh;
  border: 0;
  pointer-events: none;
}
/* The still frame behind a playing film. It carries the hero until the video
   has something to show, and it is also what replaces the film entirely for
   anyone who has asked their system to reduce motion. */
.bg-still { object-fit: cover; }
.interlude-media .bg-still { min-height: 74svh; }

/* Script hides the player until it is genuinely playing, then dissolves it up
   over the still. The hiding is applied BY script, so with scripting off the
   film simply shows as normal rather than staying invisible forever.
   The fade is long and linear on purpose: a slow cross dissolve reads as a
   deliberate transition, where a short one reads as a jump cut. */
.hero-media iframe,
.interlude-media iframe { transition: opacity 0.5s linear; }

/* transition:none matters. Without it the player fades OUT over 1.6s when it
   is first hidden, and since it is black at that point the hero shows black
   for the whole fade. Hiding must be instant; only the reveal is a dissolve. */
.hero-media.film-pending iframe,
.interlude-media.film-pending iframe {
  opacity: 0;
  transition: none;
}

/* The still must NOT move. It is the film's own first frame, so any drift on it
   means the picture jumps size at the moment the video takes over. Held dead
   still, the handover reads as a photograph beginning to move. */

.hero-veil {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(to bottom, rgba(16, 14, 12, 0.62) 0%, rgba(16, 14, 12, 0.2) 34%, rgba(16, 14, 12, 0.42) 68%, rgba(16, 14, 12, 0.86) 100%),
    radial-gradient(115% 85% at 50% 100%, rgba(16, 14, 12, 0.55), transparent 62%);
}

.hero-inner {
  position: relative;
  width: 100%;
  padding-bottom: clamp(64px, 11vh, 128px);
  padding-top: 180px;
}
.hero-inner .label { color: rgba(247, 243, 237, 0.8); margin-bottom: 30px; }
.hero-inner .label::before { background: var(--accent-light); }

.hero h1 {
  max-width: 17ch;
  margin-bottom: 34px;
  line-height: 1.08;
  text-shadow: 0 2px 40px rgba(16, 14, 12, 0.45);
}
.hero h1 em { color: var(--accent-light); }

.hero-foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 48px;
  flex-wrap: wrap;
}
.hero-foot p {
  margin: 0;
  max-width: 40ch;
  color: rgba(247, 243, 237, 0.82);
  font-size: clamp(0.98rem, 1.2vw, 1.1rem);
  line-height: 1.72;
}

/* word-rise entrance. The padding keeps italic descenders (y, g, p) from being
   clipped by the overflow mask that makes the rise read cleanly. */
.rise-line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.08em;
}
.rise-word {
  display: inline-block;
  transform: translateY(105%);
  animation: riseIn 1.15s var(--ease) forwards;
}
@keyframes riseIn { to { transform: translateY(0); } }

/* The same rise as the hero, for every other display heading. It waits for the
   heading to be revealed rather than firing on load, and the stagger is a touch
   quicker because these are read on the way past, not landed on. */
.has-words .word-rise {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.42em);
}
.reveal.is-visible .word-rise,
.is-visible .has-words .word-rise {
  animation: wordRise 0.95s var(--ease) forwards;
  animation-delay: calc(var(--wi) * 0.05s);
}
@keyframes wordRise {
  to { opacity: 1; transform: translateY(0); }
}

/* ---------- Buttons ---------- */

.cta-underline {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  font-size: 0.7rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  padding-bottom: 10px;
  position: relative;
  color: inherit;
}
.cta-underline::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  opacity: 0.45;
  transform-origin: left;
  transition: transform 0.6s var(--ease), opacity 0.4s var(--ease);
}
.cta-underline:hover::after { transform: scaleX(1.06); opacity: 1; }
.cta-underline .arrow { transition: transform 0.5s var(--ease); }
.cta-underline:hover .arrow { transform: translateX(7px); }

.cta-fill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  font-size: 0.68rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  padding: 19px 40px;
  border: 1px solid var(--accent);
  color: var(--accent);
  background: transparent;
  position: relative;
  overflow: hidden;
  cursor: pointer;
  transition: color 0.5s var(--ease), border-color 0.5s var(--ease);
}
.cta-fill span { position: relative; z-index: 1; }
.cta-fill::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform: translateY(101%);
  transition: transform 0.6s var(--ease);
}
.cta-fill:hover { color: var(--ivory); }
.cta-fill:hover::before { transform: translateY(0); }
.cta-fill:active { transform: translate(var(--mx, 0px), calc(var(--my, 0px) + 1px)); }

.cta-frame {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  font-size: 0.68rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  padding: 18px 34px;
  border: 1px solid rgba(247, 243, 237, 0.42);
  color: var(--ivory);
  transition: border-color 0.5s var(--ease), background-color 0.5s var(--ease), color 0.5s var(--ease);
}
.cta-frame:hover {
  border-color: var(--ivory);
  background: var(--ivory);
  color: var(--ink);
}

/* ---------- Manifesto ---------- */

.manifesto { background: var(--ivory); text-align: center; }
.manifesto .label { margin-bottom: 40px; }
.manifesto p.statement {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-weight: 300;
  font-size: clamp(1.5rem, 3.1vw, 2.55rem);
  line-height: 1.32;
  color: var(--ink);
  margin: 0 auto 34px;
  max-width: 26ch;
}
.manifesto p.statement em { font-style: italic; color: var(--accent); }
.manifesto .body-lg { margin: 0 auto; text-align: center; max-width: 56ch; }
.manifesto .body-lg + .body-lg { margin-top: 24px; }

/* ---------- Featured film ---------- */

.featured { background: var(--ivory-deep); }
.featured-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 40px;
  flex-wrap: wrap;
  margin-bottom: 46px;
}
.featured-head h2 { max-width: 22ch; }
.featured-head .label { margin-bottom: 22px; }

/* Featured films: one large, three across, then the widescreen band.
   Every one is a real player, not a thumbnail. */
.featured-stack {
  display: grid;
  gap: clamp(18px, 2.6vw, 38px);
}
.featured-item { margin: 0; }
.featured-trio {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 1.8vw, 24px);
}
@media (max-width: 880px) {
  .featured-trio { grid-template-columns: 1fr; gap: clamp(18px, 4vw, 28px); }
}

/* ---------- Film player frame ---------- */

.film-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #100e0c;
  overflow: hidden;
  box-shadow: var(--shadow);
}
/* Films graded for the wider cinema frame keep their own shape. */
.film-frame.wide { aspect-ratio: 2.35 / 1; }
@media (max-width: 700px) {
  .film-frame.wide { aspect-ratio: 16 / 9; }
}
.film-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.film-meta {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  margin-top: 20px;
  font-size: 0.66rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---------- Portfolio grid ---------- */

.portfolio { background: var(--ivory); }
.portfolio-head { text-align: center; margin-bottom: 62px; }
.portfolio-head .label { margin-bottom: 26px; }
.portfolio-head h2 { margin: 0 auto 22px; max-width: 24ch; }
.portfolio-head .body-lg { margin: 0 auto; text-align: center; max-width: 54ch; }

.film-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr));
  gap: clamp(16px, 2vw, 30px);
}

.film-card {
  appearance: none;
  border: 0;
  padding: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  display: block;
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.9s var(--ease), transform 0.9s var(--ease);
}
.film-card.is-visible { opacity: 1; transform: translateY(0); }

/* Pictures arrive as a wipe, not a fade. The frame opens from the bottom edge
   while the still inside it settles back from slightly over scale, which is
   how a shot lands in an edit: the frame is revealed, the image is already
   there. A fade, by contrast, always reads as something loading. */
.film-card .film-card-media,
.split-media,
.partner-media,
.inquire-media,
.hero-media {
  clip-path: inset(0 0 0 0);
}
.film-card .film-card-media {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1.05s var(--ease), box-shadow 0.6s var(--ease);
}
.film-card.is-visible .film-card-media { clip-path: inset(0 0 0 0); }
/* The settle rides on the image, which already has a transform transition. The
   drift layer is left alone: the parallax writes to it every frame, and a
   transition there would damp the scroll into feeling laggy. */

/* The same wipe for the standing pictures on the page. */
.reveal .split-media,
.reveal .partner-media,
.reveal .inquire-media,
.reveal.split-media,
.reveal.partner-media {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1.15s var(--ease);
}
.reveal.is-visible .split-media,
.reveal.is-visible .partner-media,
.reveal.is-visible .inquire-media,
.reveal.is-visible.split-media,
.reveal.is-visible.partner-media { clip-path: inset(0 0 0 0); }

.film-card-media {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: linear-gradient(140deg, var(--ivory-deep), #ded4c5);
}
/* The drift layer. It is taller than the frame that clips it, by exactly the
   parallax amplitude on each side, so the still can move without ever showing
   an edge. The script writes --py here and nothing else, which leaves the image
   free to run its own hover scale without the two fighting over transform. */
.film-card-drift {
  position: absolute;
  inset: -13px 0;
  display: block;
  transform: translate3d(0, var(--py, 0px), 0);
  will-change: transform;
}
.film-card-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  /* --crop is set only when the picture turns out to have black bars baked
     into it. It multiplies into the scale so the bars are pushed outside
     the frame and the card fills like every other one. */
  transform: scale(calc(var(--is, 1.02) * var(--crop, 1)));
  transition: opacity 1s var(--ease-soft), transform 1.3s var(--ease);
}
.film-card-media img.is-loaded { opacity: 1; }
/* Arrives slightly over scale and settles back as the frame wipes open. */
.film-card .film-card-media img { --is: 1.1; }
.film-card.is-visible .film-card-media img { --is: 1.02; }

/* The hover preview sits above the still and below the frame and play mark, so
   those keep reading over the moving picture. It is only ever added by script,
   and only on a pointer device. */
.film-card-preview {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  opacity: 0;
  transition: opacity 0.55s var(--ease-soft);
  pointer-events: none;
}
.film-card-preview.is-live { opacity: 1; }
.film-card-preview iframe {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  pointer-events: none;
}
/* A portrait film in a portrait card, and a 2.35:1 film in a 16:9 card, both
   need their own sizing or the player letterboxes itself inside the frame. */
.film-card-preview.is-vertical iframe { width: auto; height: 100%; aspect-ratio: 9 / 16; }
.film-card-preview.is-wide iframe { width: 134%; aspect-ratio: 2.35 / 1; }
.film-card:hover .film-card-media img { --is: 1.07; }

.film-card-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(16, 14, 12, 0.5), rgba(16, 14, 12, 0.05) 55%);
  opacity: 0;
  transition: opacity 0.6s var(--ease);
}
.film-card:hover .film-card-media::after { opacity: 1; }

.film-card-inset {
  position: absolute;
  inset: 12px;
  border: 1px solid rgba(247, 243, 237, 0.5);
  opacity: 0;
  transform: scale(1.03);
  transition: opacity 0.6s var(--ease), transform 0.7s var(--ease);
  z-index: 2;
  pointer-events: none;
}
.film-card:hover .film-card-inset { opacity: 1; transform: scale(1); }

.film-card-play {
  position: absolute;
  z-index: 3;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(0.86);
  width: 62px;
  height: 62px;
  border-radius: 50%;
  border: 1px solid rgba(247, 243, 237, 0.7);
  display: grid;
  place-items: center;
  color: var(--ivory);
  opacity: 0;
  transition: opacity 0.5s var(--ease), transform 0.6s var(--ease), background-color 0.5s var(--ease);
  pointer-events: none;
}
.film-card-play svg { width: 13px; height: 13px; margin-left: 2px; }
.film-card:hover .film-card-play {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
  background: rgba(150, 128, 92, 0.5);
}

/* When a thumbnail cannot be reached, the card still reads as a designed
   object rather than an empty box: the mark and play glyph sit at rest. */
.film-card-media.no-thumb {
  background:
    radial-gradient(120% 100% at 30% 0%, #e7ddcd, transparent 60%),
    linear-gradient(145deg, var(--ivory-deep), #d6cab7);
}
.film-card-media.no-thumb::before {
  content: "V";
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 4.2rem;
  font-weight: 300;
  font-style: italic;
  color: rgba(28, 26, 23, 0.13);
  line-height: 1;
}
.film-card-media.no-thumb .film-card-play {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
  border-color: rgba(28, 26, 23, 0.3);
  color: var(--ink);
}
.film-card:hover .film-card-media.no-thumb .film-card-play {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--ivory);
}
.film-card-media.no-thumb + .film-card-info { border-top-color: var(--line); }

/* Touch and pen devices never fire :hover, so the affordance rests visible. */
@media (hover: none) {
  .film-card-play { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  .film-card-inset { opacity: 1; transform: scale(1); }
  .film-card-media::after { opacity: 0.7; }
  .film-card-info { border-top-color: var(--line); }
  .marquee-item img { filter: none; }
}

.film-card-info {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 2px 0;
  border-top: 1px solid transparent;
  transition: border-color 0.5s var(--ease);
}
.film-card:hover .film-card-info { border-top-color: var(--line-strong); }
.film-card-title {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 1.16rem;
  font-weight: 400;
  line-height: 1.25;
  color: var(--ink);
  transition: color 0.4s var(--ease);
}
.film-card:hover .film-card-title { color: var(--accent); }
.film-card-index {
  font-size: 0.6rem;
  letter-spacing: 0.24em;
  color: var(--muted);
  flex: none;
}

.portfolio-foot { text-align: center; margin-top: 64px; }

/* ---------- Vertical films ---------- */

/* A 9:16 film keeps its own shape rather than being letterboxed into 16:9. */
.film-card.is-vertical .film-card-media { aspect-ratio: 9 / 16; }
.film-card.is-vertical .film-card-media.no-thumb::before { font-size: 3.2rem; }

.film-grid.vertical {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 270px), 1fr));
  gap: clamp(14px, 1.6vw, 22px);
}

/* Exactly three across, for a section that holds three films and should read as
   one deliberate row rather than a grid that happens to have a gap on the right.
   The max-width matters: at the full 1320px a 9:16 card would be 420px wide and
   750px tall, so the row would tower over every other section on the page.
   Below 620px three portrait cards are too narrow to carry a title, so they
   stack to one per row and get to be properly large instead. */
.film-grid.trio {
  grid-template-columns: repeat(3, 1fr);
  max-width: 1080px;
  margin-inline: auto;
}

/* Two up, for the wedding grids on the home page. Cards land around 570px wide
   at full width, which is roughly double the old three column size, so a
   thumbnail actually reads as a frame from a film rather than a tile. */
.film-grid.duo { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 700px) {
  .film-grid.duo { grid-template-columns: 1fr; }
}
/* Several Beyond Weddings strands hold one film. Left in a two column grid it
   would sit in the left half with a hole beside it, so on its own it spans the
   row and centers, capped so it does not become a banner. */
.film-grid.duo > :only-child {
  grid-column: 1 / -1;
  width: 100%;
  max-width: 860px;
  margin-inline: auto;
}

/* Cards in a dark feature section get more presence than a card in a normal
   grid, which is what makes Teasers read as the best work on the site. Three
   things do it, all on the card rather than the section: a warm rim that is
   always there instead of only on hover, a drop that lifts the frame off the
   dark band, and a larger title. Concerts picks this up too, being the other
   ink coloured section, and that is deliberate rather than a side effect. */
.strand.on-ink .film-card-media {
  box-shadow:
    0 0 0 1px rgba(185, 163, 124, 0.24),
    0 26px 60px -34px rgba(0, 0, 0, 0.95);
  transition: box-shadow 0.6s var(--ease);
}
.strand.on-ink .film-card:hover .film-card-media {
  box-shadow:
    0 0 0 1px rgba(185, 163, 124, 0.62),
    0 36px 84px -30px rgba(0, 0, 0, 1);
}
.strand.on-ink .film-card-title { font-size: 1.3rem; }
.strand.on-ink .film-card-info { padding-top: 18px; }
@media (max-width: 620px) {
  .film-grid.trio { grid-template-columns: 1fr; max-width: 420px; }
}

/* ---------- Beyond Weddings ---------- */

.strand { position: relative; }
.strand + .strand { border-top: 1px solid var(--line); }
.strand.on-ivory { background: var(--ivory); }
.strand.on-deep { background: var(--ivory-deep); }
.strand.on-warm { background: var(--ivory-warm); }

/* The feature strand. Reusing the .process conventions for text on ink, so the
   dark treatment already used elsewhere on the site is not reinvented here. */
.strand.on-ink { background: var(--ink); color: var(--ivory); }
.strand.on-ink .label { color: rgba(247, 243, 237, 0.66); }
.strand.on-ink .label::before { background: var(--accent-light); }
.strand.on-ink h2 em { color: var(--accent-light); }
.strand.on-ink .strand-note { color: rgba(247, 243, 237, 0.68); }
.strand.on-ink .film-card-title { color: var(--ivory); }
.strand.on-ink .film-card:hover .film-card-title { color: var(--accent-light); }
.strand.on-ink .film-card-index { color: rgba(247, 243, 237, 0.45); }
.strand.on-ink .film-card:hover .film-card-info {
  border-top-color: rgba(247, 243, 237, 0.3);
}
/* The placeholder is built for a light background, so it needs inverting or a
   film with no reachable thumbnail would punch a pale hole in the dark band. */
.strand.on-ink .film-card-media.no-thumb {
  background: linear-gradient(145deg, #2a2622, #171512);
}
.strand.on-ink .film-card-media.no-thumb::before { color: rgba(247, 243, 237, 0.14); }
.strand.on-ink .film-card-media.no-thumb .film-card-play {
  border-color: rgba(247, 243, 237, 0.4);
  color: var(--ivory);
}

/* Stacked rather than split left and right: label, headline, then the note
   directly under it, so a strand reads top to bottom in one column. */
.strand-head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 20px;
  margin-bottom: 46px;
}
.strand-head .label { margin-bottom: 20px; }
.strand-head h2 { max-width: 22ch; }
.strand-head p { margin: 0; max-width: 58ch; color: var(--ink-soft); font-size: 0.98rem; }
.strand-head .strand-title { flex: 0 1 auto; }
.strand-head .strand-note { flex: 0 1 auto; }

/* The centered variant, for a section meant to read as a feature rather than as
   one more strand in the list. Only Teasers and Concerts use it. */
.strand-head.centered {
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 18px;
}
.strand-head.centered .strand-title { flex: 0 1 auto; }
.strand-head.centered .strand-note { flex: 0 1 auto; max-width: 52ch; }

/* ---------- Disciplines ---------- */

/* Seven cards, tuned to fill their rows exactly: four across, then three where
   the last one spans the spare track. Add or remove a discipline and that sum
   changes, so adjust the :last-child span at the same time.
   The old version used a 1px gap over a grey backing to draw the hairlines,
   which meant the empty cells in the last row showed up as a grey block. Each
   card owns its own background now, so leftover space is simply page. */
.disciplines {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  margin-top: 8px;
}
.disciplines > :last-child { grid-column: span 2; }

@media (max-width: 1000px) {
  .disciplines { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .disciplines { grid-template-columns: 1fr; }
  .disciplines > :last-child { grid-column: span 1; }
}

/* Tones step through the palette rather than repeating one ivory, so the block
   reads as a designed set. Concerts takes the ink card on purpose: it matches
   the dark strand further down the page and gives the eye somewhere to land. */
.discipline {
  position: relative;
  display: block;
  padding: 32px 28px 30px;
  background: var(--ivory-warm);
  border: 1px solid var(--line);
  overflow: hidden;
  isolation: isolate;
  transition: background-color 0.55s var(--ease), border-color 0.55s var(--ease),
              transform 0.55s var(--ease), box-shadow 0.55s var(--ease);
}
.disciplines > :nth-child(3n + 2) { background: var(--ivory-deep); }
.disciplines > :nth-child(3n)     { background: #e9dfd0; }

/* The two ink cards. Concerts sits second in the top row and Reels last in the
   bottom one, which puts the dark weight on opposite corners instead of pooling
   in one place. Both are also the two vertical, phone shaped strands, so the
   pairing means something rather than being decoration. */
.discipline[data-target="concerts"],
.discipline[data-target="reels"] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--ivory);
}
.discipline[data-target="concerts"] h4,
.discipline[data-target="reels"] h4 { color: var(--ivory); }
.discipline[data-target="concerts"] p,
.discipline[data-target="reels"] p { color: rgba(247, 243, 237, 0.7); }
.discipline[data-target="concerts"] .discipline-num,
.discipline[data-target="reels"] .discipline-num { color: var(--accent-light); }
.discipline[data-target="concerts"] .discipline-go,
.discipline[data-target="reels"] .discipline-go { color: var(--accent-light); }

/* A hairline that sweeps in from the left on hover, the same gesture the nav
   links and the underlined calls to action use. */
.discipline::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  height: 2px;
  width: 0;
  background: var(--accent);
  transition: width 0.6s var(--ease);
  z-index: 2;
}
a.discipline:hover {
  transform: translateY(-4px);
  box-shadow: 0 22px 44px -28px rgba(28, 26, 23, 0.55);
  border-color: var(--line-strong);
}
a.discipline:hover::before { width: 100%; }
a.discipline:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.discipline-num {
  display: block;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 1.5rem;
  font-style: italic;
  font-weight: 300;
  line-height: 1;
  color: var(--accent);
  margin-bottom: 18px;
}
.discipline h4 {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 1.42rem;
  font-weight: 400;
  line-height: 1.15;
  margin: 0 0 12px;
  color: var(--ink);
}
.discipline p {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.7;
  color: var(--ink-soft);
  max-width: 34ch;
}
.discipline-go {
  display: block;
  margin-top: 20px;
  font-size: 0.9rem;
  color: var(--accent);
  opacity: 0;
  transform: translateX(-8px);
  transition: opacity 0.5s var(--ease), transform 0.6s var(--ease);
}
a.discipline:hover .discipline-go { opacity: 1; transform: translateX(0); }

/* A strand with no films removes itself, so its card stops being a link. It
   keeps the description, because the discipline is still something you shoot. */
.discipline.is-quiet { cursor: default; }
.discipline.is-quiet .discipline-go { display: none; }
.discipline.is-quiet:hover { transform: none; box-shadow: none; }
.discipline.is-quiet:hover::before { width: 0; }

/* Touch devices never hover, so the arrow rests visible instead of hiding. */
@media (hover: none) {
  a.discipline .discipline-go { opacity: 1; transform: translateX(0); }
}

/* ---------- Highlight films / split blocks ---------- */

.split { background: var(--ivory-warm); }
.split-block {
  display: grid;
  grid-template-columns: 1fr 1.25fr;
  gap: clamp(30px, 5vw, 86px);
  align-items: center;
}
.split-block + .split-block { margin-top: clamp(64px, 9vh, 120px); }
.split-block.flip .split-media { order: -1; }
.split-copy .label { margin-bottom: 24px; }
.split-copy h3 { margin-bottom: 22px; max-width: 20ch; }
.split-copy .body-sm { margin-bottom: 30px; }

@media (max-width: 900px) {
  .split-block { grid-template-columns: 1fr; }
  .split-block.flip .split-media { order: 0; }
}

/* ---------- Process ---------- */

.process { background: var(--ink); color: var(--ivory); }
.process .label { color: rgba(247, 243, 237, 0.66); }
.process .label::before { background: var(--accent-light); }
.process-head { text-align: center; margin-bottom: 70px; }
.process-head h2 { margin: 22px auto 0; max-width: 22ch; }
.process-head h2 em { color: var(--accent-light); }

.process-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
  gap: 1px;
  background: rgba(247, 243, 237, 0.16);
  border: 1px solid rgba(247, 243, 237, 0.16);
}
.process-step {
  background: var(--ink);
  padding: clamp(32px, 4vw, 48px);
  transition: background-color 0.6s var(--ease);
}
.process-step:hover { background: #26231f; }
.process-step .step-num {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 2.4rem;
  font-weight: 300;
  font-style: italic;
  color: var(--accent-light);
  line-height: 1;
  display: block;
  margin-bottom: 26px;
}
.process-step h4 {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 1.42rem;
  font-weight: 400;
  line-height: 1.2;
  margin: 0 0 14px;
}
.process-step p {
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.72;
  color: rgba(247, 243, 237, 0.68);
}

/* ---------- Preferred photographer ---------- */

.partner { background: var(--ivory-warm); }
.partner-grid {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: clamp(40px, 6vw, 100px);
  align-items: center;
}

/* A thin bronze rule offset behind the frame. Small detail, reads expensive. */
.partner-media {
  position: relative;
  padding: 0 18px 18px 0;
}
.partner-media::before {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  width: calc(100% - 34px);
  height: calc(100% - 34px);
  border: 1px solid var(--accent);
  opacity: 0.55;
}
/* ---------- Slideshow ---------- */

.slideshow {
  position: relative;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  background: linear-gradient(150deg, var(--ivory-deep), #dcd1c0);
  box-shadow: var(--shadow);
}
.slideshow-track {
  position: absolute;
  inset: 0;
}
.slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: scale(1.06);
  transition: opacity 1.25s var(--ease-soft), transform 7s linear;
  will-change: opacity, transform;
}
.slide.is-active {
  opacity: 1;
  transform: scale(1);
  z-index: 1;
}

/* A soft floor so the counter and controls stay legible over pale frames. */
.slideshow::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 34%;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(to top, rgba(16, 14, 12, 0.5), transparent);
}

.slide-count {
  position: absolute;
  z-index: 4;
  left: 20px;
  bottom: 18px;
  font-family: "Jost", sans-serif;
  font-size: 0.62rem;
  letter-spacing: 0.26em;
  color: rgba(247, 243, 237, 0.9);
}
.slide-count b { font-weight: 400; }

.slide-nav {
  position: absolute;
  z-index: 4;
  top: 50%;
  transform: translateY(-50%);
  width: 46px;
  height: 46px;
  border: 1px solid rgba(247, 243, 237, 0.45);
  background: rgba(16, 14, 12, 0.2);
  backdrop-filter: blur(4px);
  color: var(--ivory);
  cursor: pointer;
  display: grid;
  place-items: center;
  opacity: 0;
  transition: opacity 0.45s var(--ease), background-color 0.4s var(--ease), border-color 0.4s var(--ease);
}
.slide-nav.prev { left: 16px; }
.slide-nav.next { right: 16px; }
.slide-nav svg { width: 15px; height: 15px; }
.slideshow:hover .slide-nav,
.slide-nav:focus-visible { opacity: 1; }
.slide-nav:hover {
  background: var(--accent);
  border-color: var(--accent);
}

.slide-dots {
  position: absolute;
  z-index: 4;
  right: 20px;
  bottom: 20px;
  display: flex;
  gap: 7px;
}
.slide-dots button {
  width: 15px;
  height: 2px;
  border: 0;
  padding: 0;
  background: rgba(247, 243, 237, 0.42);
  cursor: pointer;
  transition: background-color 0.4s var(--ease), width 0.4s var(--ease);
}
.slide-dots button:hover { background: rgba(247, 243, 237, 0.8); }
.slide-dots button[aria-current="true"] {
  background: var(--accent-light);
  width: 26px;
}

@media (hover: none) {
  .slide-nav { opacity: 1; }
}
@media (max-width: 560px) {
  .slide-nav { width: 40px; height: 40px; }
  .slide-dots { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .film-card-drift { transform: none; }
  .film-card .film-card-media img { --is: 1.02; }
  .film-card .film-card-media,
  .reveal .split-media, .reveal .partner-media, .reveal .inquire-media,
  .reveal.split-media, .reveal.partner-media { clip-path: none; }
  .hero-media, .hero-inner { transform: none; opacity: 1; }
  .curtain { display: none; }
  main, .page-in main { opacity: 1; animation: none; transform: none; }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
  .cursor-ring { display: none; }
  .hero::after, .strand.on-ink::after, .interlude::after,
  .process::after, .site-footer::after { display: none; }
  .has-words .word-rise { opacity: 1; transform: none; animation: none; }
  .slide { transform: none !important; transition: opacity 0.001ms; }
}

.partner-copy .label { margin-bottom: 24px; }
.partner-copy h2 { margin-bottom: 10px; }
.partner-byline {
  font-size: 0.68rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 26px;
}
.partner-copy .body-sm { margin-bottom: 22px; }

.partner-pull {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.2rem, 1.9vw, 1.55rem);
  line-height: 1.4;
  color: var(--ink);
  border-left: 1px solid var(--accent);
  padding: 4px 0 4px 24px;
  margin: 0 0 30px;
  max-width: 42ch;
}

.partner-specs {
  border-top: 1px solid var(--line);
  padding-top: 24px;
  margin-bottom: 34px;
  display: grid;
  gap: 14px;
}
.partner-specs div {
  display: flex;
  gap: 18px;
  align-items: baseline;
  font-size: 0.92rem;
  color: var(--ink-soft);
}
.partner-specs .k {
  font-size: 0.62rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--muted);
  min-width: 108px;
  flex: none;
}

.partner-links { display: flex; gap: 16px; flex-wrap: wrap; }
.partner-link {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  font-size: 0.66rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  padding: 16px 26px;
  border: 1px solid var(--line-strong);
  color: var(--ink);
  transition: border-color 0.45s var(--ease), color 0.45s var(--ease), background-color 0.45s var(--ease);
}
.partner-link svg { width: 15px; height: 15px; flex: none; }
.partner-link:hover {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--ivory);
}

@media (max-width: 900px) {
  .partner-grid { grid-template-columns: 1fr; }
  .partner-media { order: -1; max-width: 420px; }
}

.cta-strip {
  background: var(--ivory-warm);
  border-top: 1px solid var(--line);
}

/* ---------- Quote ---------- */

.quote { background: var(--ivory); text-align: center; }
.quote blockquote {
  margin: 0;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-weight: 300;
  font-style: italic;
  font-size: clamp(1.55rem, 3.4vw, 2.8rem);
  line-height: 1.3;
  color: var(--ink);
  max-width: 24ch;
  margin-inline: auto;
}
.quote .attrib {
  margin-top: 34px;
  font-size: 0.64rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---------- Interlude ----------
   The second film that plays on its own. A full bleed cinematic band that
   breaks the ivory page open once, just before the inquiry. */

.interlude {
  position: relative;
  min-height: 74svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: #100e0c;
  color: var(--ivory);
  isolation: isolate;
}
.interlude-media {
  position: absolute;
  inset: 0;
  z-index: -2;
  overflow: hidden;
}
.interlude-media iframe { min-height: 74svh; }
.interlude-veil {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(to bottom, rgba(16, 14, 12, 0.5) 0%, rgba(16, 14, 12, 0.14) 38%, rgba(16, 14, 12, 0.72) 100%),
    radial-gradient(105% 70% at 20% 100%, rgba(16, 14, 12, 0.6), transparent 60%);
}
.interlude-inner {
  position: relative;
  width: 100%;
  padding-bottom: clamp(48px, 8vh, 92px);
  padding-top: clamp(120px, 22vh, 200px);
}
.interlude-inner .label { color: rgba(247, 243, 237, 0.8); margin-bottom: 24px; }
.interlude-inner .label::before { background: var(--accent-light); }
.interlude-inner h2 {
  max-width: 20ch;
  line-height: 1.08;
  margin-bottom: 20px;
  text-shadow: 0 2px 40px rgba(16, 14, 12, 0.45);
}
.interlude-inner h2 em { color: var(--accent-light); }
.interlude-inner p {
  margin: 0;
  max-width: 46ch;
  color: rgba(247, 243, 237, 0.82);
  font-size: clamp(0.96rem, 1.15vw, 1.08rem);
  line-height: 1.72;
}

/* The inquire block sitting on the film. The section keeps all of the interlude
   machinery, so only the pieces that assumed dark text on a light page need
   overriding: the hairline above the notes and the two greys in them.
   Vertically centered rather than bottom aligned, because this is a full block
   of copy now and not a caption sitting under a picture. */
.interlude.on-film {
  align-items: center;
  min-height: 90svh;
}
.interlude.on-film .interlude-inner {
  padding-top: clamp(96px, 15vh, 150px);
  padding-bottom: clamp(96px, 15vh, 150px);
}
.interlude-inner .inquire-copy { max-width: 660px; }
.interlude-inner .inquire-copy .label { margin-bottom: 26px; }
.interlude-inner .inquire-copy h2 { max-width: 18ch; margin-bottom: 24px; }
.interlude-inner .inquire-copy .body-lg {
  margin: 0 0 36px;
  max-width: 48ch;
  color: rgba(247, 243, 237, 0.86);
  text-shadow: 0 1px 24px rgba(16, 14, 12, 0.5);
}
.interlude-inner .inquire-notes {
  margin-top: 40px;
  border-top-color: rgba(247, 243, 237, 0.3);
}
.interlude-inner .inquire-notes div { color: rgba(247, 243, 237, 0.84); }
.interlude-inner .inquire-notes .k { color: rgba(247, 243, 237, 0.55); }

/* One gradient, not two. Two stacked layers multiply: 0.86 over 0.5 came out
   near 0.93 on the left, which is why the film had all but disappeared. A
   single pass fades from enough cover for the copy to almost nothing on the
   right, so the picture is visible across most of the frame. */
.interlude.on-film .interlude-veil {
  background: linear-gradient(to right,
    rgba(16, 14, 12, 0.68) 0%,
    rgba(16, 14, 12, 0.42) 44%,
    rgba(16, 14, 12, 0.12) 100%);
}

/* A lift on the footage itself, since the veil can only be taken so far before
   the text stops being readable. Applied to the still and the player together:
   they cross dissolve, so any difference between them would show as a flicker
   at the handover. */
.interlude.on-film .interlude-media iframe,
.interlude.on-film .interlude-media .bg-still {
  filter: brightness(1.22) saturate(1.06);
}

/* Less picture behind the words means the words carry their own contrast. */
.interlude.on-film .interlude-inner .label,
.interlude.on-film .interlude-inner .inquire-notes { text-shadow: 0 1px 18px rgba(16, 14, 12, 0.75); }

@media (max-width: 700px) {
  /* No left side to protect on a phone, the copy runs the full width, so this
     one stays a flat wash and takes the brightness lift back down. */
  .interlude.on-film .interlude-veil {
    background: linear-gradient(to bottom, rgba(16, 14, 12, 0.66), rgba(16, 14, 12, 0.76));
  }
  .interlude.on-film .interlude-media iframe,
  .interlude.on-film .interlude-media .bg-still { filter: brightness(1.1) saturate(1.04); }
}

/* The hero does not just scroll away. As it goes the picture drifts up at half
   the speed of the page and the words fade and lift a little faster, so the
   section reads as being left behind rather than as a strip of image sliding
   past. --hero-out is written by the script, 0 at rest and 1 once the hero has
   fully gone. */
.hero-media { transform: translate3d(0, calc(var(--hero-out, 0) * 12vh), 0); }
.hero-inner {
  opacity: calc(1 - var(--hero-out, 0) * 1.35);
  transform: translate3d(0, calc(var(--hero-out, 0) * -7vh), 0);
}

/* ---------- Page transitions ---------- */

/* Browsers with cross document view transitions need nothing but this. The
   whole page cross fades, and anything given a view-transition-name is matched
   between the two documents and animated between its old and new position
   rather than fading with everything else. */
@view-transition { navigation: auto; }

::view-transition-old(root) {
  animation: vtOut 0.42s var(--ease-soft) both;
}
::view-transition-new(root) {
  animation: vtIn 0.52s var(--ease) both;
}
@keyframes vtOut { to { opacity: 0; transform: scale(0.995); } }
@keyframes vtIn { from { opacity: 0; transform: scale(1.008); } }

/* The header and the logo hold their place across the swap instead of fading
   out and back in, which is what makes it read as one site rather than two
   pages. */
.site-header { view-transition-name: site-header; }
.brand { view-transition-name: brand; }
.site-footer { view-transition-name: site-footer; }

/* The fallback, for browsers without the API. A panel closes over the page,
   the navigation happens behind it, and the next page lifts it away. Ink rather
   than cream: a dark wipe reads as a cut between shots, a light one reads as a
   page failing to load. */
.curtain {
  position: fixed;
  inset: 0;
  z-index: 300;
  background: var(--ink);
  pointer-events: none;
  transform: scaleY(1);
  transform-origin: bottom;
  transition: transform 0.62s var(--ease);
}
.page-in .curtain {
  transform: scaleY(0);
  transform-origin: top;
}
/* Content settles in behind the lifting curtain, a beat later so the two
   movements are read as one.
   Gated on .has-curtain, which the script adds only when it actually builds a
   curtain. Without that gate this would hide the page on browsers that use the
   native transition instead, and on browsers with no JavaScript at all, where
   nothing would ever arrive to reveal it again. */
body.has-curtain:not(.page-in) main { opacity: 0; }
body.has-curtain.page-in main {
  animation: pageIn 0.7s var(--ease) 0.12s both;
}
@keyframes pageIn {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}

/* ---------- Cursor ---------- */

/* Added by script and only on a pointer device, so nothing here can strand a
   touch user with an invisible cursor. The system cursor is left visible: this
   sits with it rather than replacing it, which keeps text selection, links and
   form fields behaving exactly as people expect. */
.cursor-ring {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 200;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid rgba(150, 128, 92, 0.55);
  background: rgba(150, 128, 92, 0.06);
  color: transparent;
  display: grid;
  place-items: center;
  pointer-events: none;
  opacity: 0;
  transition: width 0.45s var(--ease), height 0.45s var(--ease),
              background-color 0.45s var(--ease), border-color 0.45s var(--ease),
              color 0.35s var(--ease), opacity 0.35s var(--ease);
  mix-blend-mode: normal;
}
.cursor-ring.is-on { opacity: 1; }
.cursor-ring svg {
  width: 9px;
  height: 9px;
  margin-left: 2px;
  opacity: 0;
  transform: scale(0.6);
  transition: opacity 0.35s var(--ease), transform 0.4s var(--ease);
}

/* Over a link: smaller and firmer, so it reads as a point rather than a target. */
.cursor-ring.is-link {
  width: 12px;
  height: 12px;
  background: var(--accent);
  border-color: var(--accent);
}

/* Over anything that opens a film: a play mark. */
.cursor-ring.is-film {
  width: 62px;
  height: 62px;
  background: rgba(150, 128, 92, 0.45);
  border-color: rgba(247, 243, 237, 0.75);
  color: var(--ivory);
  backdrop-filter: blur(2px);
}
.cursor-ring.is-film svg { opacity: 1; transform: scale(1); }

/* The card already draws its own play mark on hover. With the cursor carrying
   one there would be two, so the card yields to the cursor on pointer devices
   and keeps its own everywhere else. */
.has-cursor .film-card:hover .film-card-play { opacity: 0; }

/* The lean is written as two custom properties, not as the transform, so the
   pressed state below can still add its own pixel instead of being overwritten
   by an inline style. */
.cta-fill,
.cta-frame {
  transform: translate(var(--mx, 0px), var(--my, 0px));
  transition: transform 0.5s var(--ease), color 0.5s var(--ease),
              border-color 0.5s var(--ease), background-color 0.5s var(--ease);
}

/* ---------- Grain and depth ---------- */

/* A single tile of monochrome noise, generated by the browser from an SVG
   filter, so it costs no request and no image file. Laid over the dark surfaces
   only: on ivory it would read as dirt, on a dark photograph it reads as film.
   Fixed rather than scrolling, which is how grain behaves in a projected image:
   it belongs to the light, not to the thing being lit. */
.hero::after,
.strand.on-ink::after,
.interlude::after,
.process::after,
.site-footer::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  opacity: 0.15;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
  background-size: 160px 160px;
}
.process, .site-footer, .strand.on-ink { position: relative; }

/* Film frames get a vignette, the way a lens falls off at the corners. Inset
   shadow rather than a gradient overlay so it sits under everything already
   layered in the frame and needs no extra element. */
.film-card-media::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  box-shadow: inset 0 0 60px -18px rgba(16, 14, 12, 0.55);
  opacity: 0.9;
  transition: opacity 0.6s var(--ease);
}
.film-card:hover .film-card-media::before { opacity: 0.45; }
/* On the dark sections the frame already carries a rim, so the vignette
   stays lighter throughout and lets the rim do the work. */
.strand.on-ink .film-card-media::before { opacity: 0.55; }

/* Cards lift on hover. The shadow is warm rather than neutral grey, because a
   grey shadow on a cream page reads as dirty. */
.film-card-media {
  transition: box-shadow 0.6s var(--ease), transform 0.6s var(--ease);
}
.film-card:hover .film-card-media {
  box-shadow: 0 30px 60px -34px rgba(60, 46, 28, 0.55);
}
/* ---------- Marquee ---------- */

.marquee-wrap {
  overflow: hidden;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 26px 0;
  background: var(--ivory-deep);
}
.marquee {
  display: flex;
  gap: 18px;
  width: max-content;
  animation: slide 64s linear infinite;
}
.marquee-wrap:hover .marquee { animation-play-state: paused; }
/* Each still is a button that opens the film, so it needs the button reset the
   film cards get, and a pointer. The strip pauses on hover, which is what makes
   a moving target clickable. */
.marquee-item {
  appearance: none;
  border: 0;
  padding: 0;
  margin: 0;
  background: none;
  cursor: pointer;
  display: block;
  position: relative;
  flex: none;
  overflow: hidden;
}
.marquee-item img {
  display: block;
  width: clamp(180px, 22vw, 290px);
  aspect-ratio: 16 / 9;
  object-fit: cover;
  transform: scale(var(--crop, 1));
  filter: grayscale(1) contrast(1.02);
  transition: filter 0.7s var(--ease), transform 0.9s var(--ease),
              opacity 0.6s var(--ease);
}
/* Color arrives on hover, one still at a time. The focus state matches it so a
   keyboard reaches the same behavior as a mouse. */
.marquee-item:hover img,
.marquee-item:focus-visible img {
  filter: grayscale(0);
  transform: scale(calc(var(--crop, 1) * 1.05));
}
/* A bronze frame draws in on hover, the same signal the film cards use. */
.marquee-item::after {
  content: "";
  position: absolute;
  inset: 8px;
  border: 1px solid rgba(247, 243, 237, 0.6);
  opacity: 0;
  transform: scale(1.04);
  transition: opacity 0.5s var(--ease), transform 0.6s var(--ease);
  pointer-events: none;
}
.marquee-item:hover::after { opacity: 1; transform: scale(1); }
.marquee-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
@keyframes slide {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* ---------- Inquire ---------- */

.inquire { background: var(--ivory-warm); }
.inquire-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(36px, 6vw, 96px);
  align-items: center;
}
.inquire-copy .label { margin-bottom: 26px; }
.inquire-copy h2 { margin-bottom: 24px; max-width: 18ch; }
.inquire-copy .body-lg { margin-bottom: 34px; }
.inquire-notes {
  border-top: 1px solid var(--line);
  padding-top: 26px;
  display: grid;
  gap: 14px;
}
.inquire-notes div {
  display: flex;
  gap: 14px;
  align-items: baseline;
  font-size: 0.9rem;
  color: var(--ink-soft);
}
.inquire-notes .k {
  font-size: 0.62rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--muted);
  min-width: 96px;
  flex: none;
}
.inquire-media {
  aspect-ratio: 4 / 5;
  background: linear-gradient(150deg, var(--ivory-deep), #dcd1c0);
  overflow: hidden;
  position: relative;
  box-shadow: var(--shadow);
}
.inquire-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity 1.1s var(--ease-soft);
}
/* Only frames filled in by script start hidden and fade up. A plain photograph
   in the markup is visible straight away. */
.inquire-media img[data-still] { opacity: 0; }
.inquire-media img.is-loaded { opacity: 1; }

.media-credit {
  margin: 14px 0 0;
  font-size: 0.6rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--muted);
}
.media-credit a {
  color: var(--accent);
  border-bottom: 1px solid transparent;
  transition: border-color 0.35s var(--ease);
}
.media-credit a:hover { border-bottom-color: var(--accent); }

@media (max-width: 900px) {
  .inquire-grid { grid-template-columns: 1fr; }
  /* The photograph leads on narrow screens. It stays portrait, since it is a
     real portrait photograph rather than a video frame. */
  .inquire-visual { order: -1; }
  .inquire-visual .inquire-media { aspect-ratio: 4 / 5; max-width: 460px; }
}

/* ---------- Forms ---------- */

.form-shell { max-width: 720px; }
.field { margin-bottom: 30px; }
.field label {
  display: block;
  font-size: 0.62rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 12px;
}
.field input,
.field select,
.field textarea {
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line-strong);
  color: var(--ink);
  font-family: "Jost", sans-serif;
  font-weight: 300;
  font-size: 1.02rem;
  padding: 12px 2px;
  border-radius: 0;
  transition: border-color 0.45s var(--ease);
}
.field textarea { min-height: 130px; resize: vertical; }
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-bottom-color: var(--accent);
}
.field input::placeholder,
.field textarea::placeholder { color: rgba(139, 131, 119, 0.65); }
.field select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 12px) 55%, calc(100% - 7px) 55%;
  background-size: 5px 5px;
  background-repeat: no-repeat;
  cursor: pointer;
}
.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 30px;
}
@media (max-width: 700px) { .field-row { grid-template-columns: 1fr; } }

.form-status {
  margin-top: 24px;
  font-size: 0.92rem;
  color: var(--accent);
  display: none;
}
.form-status.is-visible { display: block; }

/* ---------- Page header (inner pages) ---------- */

.page-head {
  padding: clamp(150px, 22vh, 230px) 0 clamp(50px, 7vh, 84px);
  background: var(--ivory);
}
.page-head .label { margin-bottom: 28px; }
.page-head h1 { max-width: 20ch; margin-bottom: 26px; }
.page-head .body-lg { max-width: 54ch; }

/* ---------- Footer ---------- */

.site-footer {
  background: var(--ink);
  color: var(--ivory);
  padding: clamp(64px, 9vh, 104px) 0 34px;
}
.footer-top {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: clamp(32px, 5vw, 70px);
  padding-bottom: 56px;
  border-bottom: 1px solid rgba(247, 243, 237, 0.16);
}
.footer-brand .brand-name { color: var(--ivory); margin-bottom: 20px; display: block; }
.footer-brand p {
  color: rgba(247, 243, 237, 0.6);
  font-size: 0.94rem;
  max-width: 34ch;
  margin: 0 0 28px;
}
.footer-col h5 {
  font-size: 0.62rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: rgba(247, 243, 237, 0.5);
  margin: 0 0 22px;
  font-weight: 400;
}
.footer-col a,
.footer-col p {
  display: block;
  color: rgba(247, 243, 237, 0.8);
  font-size: 0.94rem;
  margin: 0 0 12px;
  transition: color 0.35s var(--ease);
}
.footer-col a:hover { color: var(--accent-light); }
.footer-bottom {
  padding-top: 28px;
  display: flex;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  font-size: 0.74rem;
  letter-spacing: 0.12em;
  color: rgba(247, 243, 237, 0.42);
}
@media (max-width: 800px) {
  .footer-top { grid-template-columns: 1fr; }
}

/* ---------- Lightbox ---------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: clamp(16px, 5vw, 60px);
  background: rgba(16, 14, 12, 0.94);
  backdrop-filter: blur(10px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.5s var(--ease), visibility 0.5s;
}
.lightbox.is-open { opacity: 1; visibility: visible; }
.lightbox-stage {
  width: 100%;
  max-width: 1240px;
  aspect-ratio: 16 / 9;
  background: #000;
  position: relative;
  transform: scale(0.97);
  transition: transform 0.6s var(--ease);
}
.lightbox.is-open .lightbox-stage { transform: scale(1); }
/* Films shot wider than 16:9 open in their own shape rather than letterboxed. */
.lightbox-stage.wide { aspect-ratio: 2.35 / 1; }

/* Portrait films get a portrait stage, height led so it always fits the screen. */
.lightbox-stage.tall {
  aspect-ratio: 9 / 16;
  width: auto;
  max-width: min(100%, 460px);
  height: min(84vh, 820px);
}
.lightbox-stage iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.lightbox-close {
  position: absolute;
  top: clamp(14px, 3vw, 30px);
  right: clamp(14px, 3vw, 30px);
  width: 46px;
  height: 46px;
  border: 1px solid rgba(247, 243, 237, 0.35);
  background: transparent;
  color: var(--ivory);
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background-color 0.4s var(--ease), border-color 0.4s var(--ease);
}
.lightbox-close:hover { background: rgba(247, 243, 237, 0.12); border-color: var(--ivory); }
.lightbox-close svg { width: 16px; height: 16px; }
.lightbox-caption {
  position: absolute;
  left: 0;
  bottom: -40px;
  font-size: 0.64rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: rgba(247, 243, 237, 0.6);
}

/* ---------- Reveal ---------- */

.reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 1s var(--ease), transform 1s var(--ease);
}
.reveal.is-visible { opacity: 1; transform: translateY(0); }
.reveal.d1 { transition-delay: 0.1s; }
.reveal.d2 { transition-delay: 0.2s; }
.reveal.d3 { transition-delay: 0.3s; }

/* ---------- Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .reveal, .film-card { opacity: 1 !important; transform: none !important; }
  .rise-word { transform: none; }
  .marquee { animation: none; }
}
