/* ------------------------------------------------------------------------
   MEISNER — a vertical short AI production company.
   A full-screen landing over film, then a packed mosaic of concepts: one tile
   each, 9:16 and 4:3 mixed, every tile a four-second loop. Hovering one dims
   the rest; clicking one opens its logline.
   ------------------------------------------------------------------------ */

/* One display face for the whole brand: the wordmark, the logline titles and
   the Setara credit. Pirata One is the closest free match to the meisner logo —
   the same wide, upright blackletter with diamond terminals. Drop the real face
   in /fonts, add an @font-face, and point --font-logo at it. */
:root {
  --color-white: #fff;
  --color-black: #000;
  --color-grey: #999;
  --unit-100vh: 100vh;
  --unit-gap: 40px;
  --font-primary: "Poppins", "Helvetica Neue", Arial, sans-serif;   /* Poppins Regular from Google Fonts for all the running text; the blackletter below is for the titles */
  --font-logo: "Pirata One", "UnifrakturCook", serif;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --tile-gap: 6px;
  --cols: 4;
}
@supports (height: 100svh) { :root { --unit-100vh: 100svh; } }

* { box-sizing: border-box; }
[hidden] { display: none !important; }

/* clip sideways overflow at the root as well as on body: on iOS, body alone
   does not stop a wide element widening the layout viewport, and a fixed
   element centred with left:50% then centres on that wider box — the mark
   drifting to the right while the page is otherwise fine */
html { background: var(--color-black); overflow-x: hidden; overflow-x: clip; }
body {
  -webkit-font-smoothing: antialiased;
  background-color: var(--color-black);
  color: var(--color-white);
  font-family: var(--font-primary);
  font-size: 16px;
  margin: 0;
  overflow-x: hidden;
}
body.sheet-is-open, body.scroll-is-locked { overflow: hidden; }
h1, h2, h3 { font-weight: 400; margin: 0; }
a { color: inherit; text-decoration: none; }
p { margin: 0; }
img, video { display: block; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }

/* ---------- the mark: blackletter, dead centre of the landing ---------- */

/* The mark is centred by LAYOUT, never by a percentage transform. It grows to
   three times its width on the way to the landing, and Safari resolves a
   percentage translate against the size at the START of a transition and holds
   it — so a -50% computed for the small mark left the big one hanging off the
   right of the screen until the animation ended and it snapped into place. A
   full-width fixed strip with the mark flex-centred inside it stays centred at
   every frame regardless of width, and the only thing that animates is a
   translateY in pixels. */
.global-logo {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  z-index: 600;
  display: flex;
  justify-content: center;
  pointer-events: none;            /* the strip is as wide as the screen: only the mark itself is clickable */
  text-align: center;
  mix-blend-mode: difference;
  transform: translateY(0);
  /* no transition: the mark is placed by scroll position each frame in
     placeMark(), so it moves exactly with the page and never on its own clock */
  will-change: transform;
}
/* while the landing is being measured the mark is snapped to its full size:
   no transition, so nothing of the change is ever painted */
.global-logo.is-measuring, .global-logo.is-measuring * { transition: none !important; }
.global-logo .mark { display: block; padding: 18px 10px; pointer-events: auto; cursor: pointer; }
.global-logo .mark picture, .landing-mark picture, .powered picture { display: contents; }
/* the wordmark is the logo artwork itself — assets/logos/meisner.png, the
   supplied render cut out of its background at full resolution, so it is 1920px
   wide against a 640px largest display size and stays sharp on any screen */
.global-logo .mark img {
  display: block;
  width: 112px;
  height: auto;
  aspect-ratio: 3.9588;         /* known before the file loads, so nothing shifts */
  transition: filter 1.2s var(--ease);   /* width is driven by scroll, see placeMark() */
}
/* over the landing film it is solid white rather than inverted */
.global-logo.is-large {
  /* position comes from placeMark() as an inline pixel transform */
  mix-blend-mode: normal;
  pointer-events: none;
}
.global-logo.is-large .mark { pointer-events: none; }
/* padding is the same in both states so the docking hand-off has nothing to jump */
.global-logo.is-large .mark img {
  width: clamp(230px, 36vw, 640px);
  filter: drop-shadow(0 2px 40px rgba(0, 0, 0, 0.55));
}

/* ---------- the landing ---------- */

.page { position: relative; z-index: 100; text-align: center; }

.intro-cover {
  background: var(--color-black);
  height: var(--unit-100vh);
  left: 0; top: 0;
  opacity: 0;                      /* never shown: the inlined first frame is under everything from the first paint */
  position: absolute;
  width: 100%;
  z-index: 20;
  transition: opacity 0.8s var(--ease);
}
.intro-cover.has-faded { opacity: 0; pointer-events: none; }

.intro { height: var(--unit-100vh); position: relative; overflow: hidden; }
.intro-bg { position: absolute; inset: 0; z-index: 0; }
.intro-bg .intro-still, .intro-bg .intro-still img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }   /* the base layer, inlined in the page: never black */
.intro-bg video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.2s var(--ease);
}
.intro-bg video.is-on { opacity: 1; }
.intro-bg::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.12) 38%, rgba(0, 0, 0, 0.7) 100%);
}

/* everything under the mark sits in the lower half */
.intro-inner {
  position: absolute;
  z-index: 2;
  left: 0; right: 0;
  top: var(--inner-top, calc(50% + clamp(52px, 6vw, 96px)));
}
/* once the stage has lifted the lines under the mark rise in one after another;
   the phone's wordmark (.landing-mark) is not among them: it is the anchor the
   opening lands on, so it is simply there */
.intro-inner > .statement, .intro-inner > .logo-marquee, .intro-inner > .cta { transition: opacity 0.9s var(--ease), transform 0.9s var(--ease); }
.intro-inner:not(.is-visible) > .statement, .intro-inner:not(.is-visible) > .logo-marquee, .intro-inner:not(.is-visible) > .cta { opacity: 0; transform: translateY(16px); }
.intro-inner.is-visible > .statement { transition-delay: 0.45s; }
.intro-inner.is-visible > .logo-marquee { transition-delay: 0.6s; }
.intro-inner.is-visible > .cta { transition-delay: 0.75s; }
.intro .statement {
  font-size: 18px;
  font-weight: 400;
  line-height: 1.35;
  margin: 0 auto 30px;
  max-width: 620px;
  padding: 0 var(--unit-gap);
  text-shadow: 0 1px 18px rgba(0, 0, 0, 0.6);
}

.logo-marquee {
  overflow: hidden;
  width: 100%;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.logo-marquee .track { display: flex; width: max-content; animation: marquee 48s linear infinite; }
.logo-marquee .set { display: flex; align-items: center; gap: 96px; padding-right: 96px; }
.logo-marquee img {
  height: var(--h, 30px);
  width: auto;
  filter: brightness(0) invert(1) drop-shadow(0 1px 12px rgba(0, 0, 0, 0.5));
  opacity: 0.95;
}
@keyframes marquee { to { transform: translateX(-50%); } }

.powered {
  margin-top: 26px;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.62);
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.55em;
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.6);
}
/* the supplied Setara wordmark, cut out of its background — sized to the same
   ink height the typed version had (18.5px), so the line reads as it did */
.powered .setara {
  display: block;
  height: 19px;
  width: auto;
  aspect-ratio: 4.0412;         /* known before the file loads, so nothing shifts */
  position: relative;
  top: 2px;
}

/* explore cue */
.scroll-to.explore { position: fixed; left: 50%; top: var(--unit-100vh); transform: translateX(-50%) translateY(-100%); z-index: 200; animation: exploreIn 0.8s var(--ease) 2.7s backwards; }
@keyframes exploreIn { from { opacity: 0; } to { opacity: 1; } }
.scroll-to { color: var(--color-white); cursor: pointer; transition: opacity 0.4s var(--ease); }
.scroll-to .line { background: var(--color-white); display: block; height: 30px; margin: 0 auto; width: 2px; }
.scroll-to .text { display: block; font-size: 18px; line-height: 1.3; margin-bottom: 10px; text-shadow: 0 1px 14px rgba(0, 0, 0, 0.6); }
.scroll-to .line.grow { animation: grow 2.4s var(--ease) infinite; transform-origin: top; }
.scroll-to.is-hidden { opacity: 0; pointer-events: none; }
@keyframes grow {
  0%, 20%, 50%, 80%, 100% { transform: scaleY(1.1); }
  40% { transform: scaleY(0.666); }
  60% { transform: scaleY(1.333); }
}

/* ---------- the mosaic ----------
   Equal-width columns, each a plain stack. Every tile fills its column and
   keeps its own aspect, so there is never a hole: the only ragged edge is the
   bottom, and the scroll keeps adding tiles so you never reach it. Fewer
   columns means larger frames — that is the one number to change. */

.mosaic {
  display: flex;
  align-items: flex-start;
  gap: var(--tile-gap);
  padding: var(--tile-gap);
  text-align: left;
}
/* one justified row: the tiles share a height and their widths come out of
   their own aspect ratios, so the row fills the width exactly */
.mcol { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: var(--tile-gap); }

.tile {
  width: 100%;
  position: relative;
  overflow: hidden;
  background: #0b0b0b;
  cursor: pointer;
  transition: filter 0.35s var(--ease);   /* never invisible: a tile shows its stand-in from its first frame */
}
/* each tile's aspect-ratio is set inline from the clip's own pixel size */
.tile.is-in { opacity: 1; }
.tile-media { position: absolute; inset: 0; transition: opacity 0.35s var(--ease), filter 0.35s var(--ease); }
.svc-media { position: relative; overflow: hidden; }
.tile video, .tile img { width: 100%; height: 100%; object-fit: cover; }
/* the clip sits over its still and only appears once it has drawn a frame */
.tile-media video { position: absolute; inset: 0; opacity: 0; transition: opacity 0.3s var(--ease); }
.tile-media video.is-live { opacity: 1; }

/* the title rides above the media layer, so the hover dim never touches it.
   Same face as the logline panel. */
.tile-title {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 34px 16px 14px;
  z-index: 2;
  font-family: var(--font-logo);
  font-weight: 400;
  font-size: clamp(19px, 2.1vw, 30px);
  line-height: 1.05;
  letter-spacing: 0.01em;
  color: var(--color-white);
  text-shadow: 0 1px 20px rgba(0, 0, 0, 0.85);
  background: linear-gradient(to top, rgba(0, 0, 0, 0.55), transparent);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
  pointer-events: none;
}
/* the tile is already the clip's exact shape, so cover crops nothing */

/* every tile sits bright; the one under the cursor darkens and names itself */
.tile.is-in { opacity: 1; filter: none; }
.mosaic.is-dimming .tile.is-hot .tile-media, .reels.is-dimming .tile.is-hot .tile-media { opacity: 0.34; filter: saturate(0.85) brightness(0.72); }
.mosaic.is-dimming .tile.is-hot .tile-title, .reels.is-dimming .tile.is-hot .tile-title { opacity: 1; transform: none; }
/* a brand mark in the caption's place: same corner, same gradient, drawn white
   like the marquee, at the height the marquee gave it (a touch larger here) */
.tile-title.is-mark { line-height: 0; }
.tile.is-bright .tile-title { background: linear-gradient(to top, rgba(0, 0, 0, 0.62), rgba(0, 0, 0, 0.28) 55%, transparent); }   /* white frames (Meta Muse) */
.tile-title.is-mark img {
  display: block;
  height: calc(var(--h, 30px) * 1.15);
  width: auto;
  max-width: 60%;
  object-fit: contain; object-position: left center;   /* the tile's cover rule must never crop a wide mark */
  filter: brightness(0) invert(1) drop-shadow(0 1px 18px rgba(0, 0, 0, 0.85));
}

/* ---------- the logline ---------- */

.sheet {
  position: fixed;
  inset: 0;
  z-index: 900;
  background: rgba(0, 0, 0, 0.94);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  display: grid;
  place-items: center;
  padding: clamp(16px, 3vw, 40px);
  animation: sheetIn 0.35s var(--ease);
}
@keyframes sheetIn { from { opacity: 0; } to { opacity: 1; } }
.sheet-inner {
  display: flex;
  align-items: center;
  justify-content: center;              /* the clip and its copy sit in the middle as one group */
  gap: clamp(28px, 4vw, 64px);
  max-width: 1600px;
  width: 100%;
}
.sheet-media { flex: 0 0 auto; background: #0b0b0b; overflow: hidden; }
/* the panel's width is set inline from the clip's own shape */
.sheet-media video { width: 100%; height: auto; }
.sheet-copy { flex: 0 1 auto; min-width: 0; max-width: 620px; text-align: left; }   /* only as wide as its lines, so the pair centres */
.sheet-genre { display: none; }   /* the genre line was dropped at the user's request */
.sheet-title {
  font-family: var(--font-logo);
  font-weight: 400;
  font-size: clamp(38px, 5.4vw, 76px);
  line-height: 1.02;
  letter-spacing: 0.01em;
  margin-bottom: 20px;
}
.sheet-logline { font-size: clamp(16px, 1.5vw, 21px); line-height: 1.5; color: rgba(255, 255, 255, 0.86); max-width: 46ch; }
.panel-x {
  position: fixed; top: 12px; right: 12px; z-index: 990;
  background: rgba(0, 0, 0, 0.55); border: 0; border-radius: 50%;
  color: rgba(255, 255, 255, 0.85); cursor: pointer; padding: 8px; line-height: 0;
  transition: color 0.3s var(--ease), transform 0.5s var(--ease);
}
.panel-x:hover { color: #fff; transform: rotate(90deg); }
.panel-x[hidden] { display: none; }
@media (min-width: 700px) { .panel-x { top: 20px; right: 20px; } }

/* ---------- breakpoints ---------- */

/* stays at four: the foot is levelled by three cropped clips, one per short
   column, so a fifth column would leave one of them with nothing to cover */
@media (min-width: 1800px) { :root { --cols: 4; } }
@media (max-width: 1279px) { :root { --cols: 3; } }
@media (max-width: 979px)  { :root { --cols: 3; } }
.landing-mark { display: none; }          /* desktop: the fixed mark does the docking */

@media (max-width: 699px) {
  :root { --cols: 2; --unit-gap: 20px; --tile-gap: 4px; }
  /* On a phone the wordmark on the landing is static page content, stacked
     above the statement with the same 38px the desktop lockup uses, so the two
     scroll together and can never meet. The fixed header mark never moves or
     resizes: it is invisible while the landing mark is on screen and fades in
     once that has scrolled off. */
  .landing-mark { display: block; }
  .landing-mark img {
    display: block;
    margin: 0 auto 38px;
    width: clamp(290px, 82vw, 460px);
    height: auto;
    aspect-ratio: 3.9588;
    filter: drop-shadow(0 2px 40px rgba(0, 0, 0, 0.55));
  }
  .global-logo { opacity: 0; transition: opacity 0.35s var(--ease); pointer-events: none; }
  .global-logo .mark { pointer-events: none; }
  .global-logo.is-shown { opacity: 1; }
  .global-logo.is-shown .mark { pointer-events: auto; }
  /* On a phone the desktop rule bottoms out at its 230px floor, which leaves the
     wordmark small against the width of the screen. Scale it to the viewport
     instead, with a floor and a cap of its own. */
  /* On a phone the wordmark carries the screen and everything under it is
     dialled back to supporting size. The spacing between them is left as it
     was — only the parts themselves are smaller. */
  .intro .statement { font-size: 15px; }
  .logo-marquee .set { gap: 46px; padding-right: 46px; }
  .logo-marquee img { height: calc(var(--h, 30px) * 0.56); }
  .powered { margin-top: 20px; font-size: 10px; letter-spacing: 0.16em; }
  .powered .setara { height: 12px; top: 1px; }
  .intro-inner .cta { margin-top: 26px; font-size: 10.5px; letter-spacing: 0.14em; padding: 11px 20px; }
  /* a phone: the preview runs edge to edge, the copy under it; the panel scrolls if the clip is tall */
  .sheet { padding: 0 0 20px; display: flex; flex-direction: column; overflow: hidden; --copy-h: 200px; }
  .sheet-inner { flex-direction: column; align-items: stretch; gap: 14px; margin: auto 0; }
  .sheet-media { width: 100% !important; max-width: none; align-self: stretch; }
  /* a vertical clip: as tall as the screen allows once the copy has its room, centred, never scrolling */
  .sheet:not(.is-spot) .sheet-media { width: auto !important; height: calc(100vh - var(--copy-h) - 48px); height: calc(100svh - var(--copy-h) - 48px); max-width: 100%; align-self: center; }
  .sheet-copy { padding: 0 18px; max-width: none; }
  .sheet.is-spot .sheet-copy { width: 100% !important; }   /* as the film is on a phone */
  /* no hover on a phone: a commercial tile always carries its brand mark (the shorts stay bare) */
  .mosaic .tile-title.is-mark { opacity: 1; transform: none; }
  .mosaic .tile-title.is-mark img { height: auto; max-height: calc(var(--h, 30px) * 0.9); max-width: 42%; }   /* scales down whole when the tile is narrow */
  .sheet.is-spot .sheet-inner { gap: 16px; }
  .sheet-logline { font-size: 16px; }
}

@media (prefers-reduced-motion: reduce) {
  .tile, .tile-media, .tile-title, .global-logo, .global-logo .mark, .intro-inner > * { transition: none !important; }
  .logo-marquee .track, .scroll-to .line.grow { animation: none; }
}

/* ---------- enterprise sales ----------
   Two ways in: one under the statement on the landing, one waiting at the end
   of the mosaic for anyone who has scrolled the whole slate. Both open the same
   panel. */

.cta {
  appearance: none;
  font-family: var(--font-primary);
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-white);
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: 999px;
  padding: 13px 26px;
  cursor: pointer;
  transition: background 0.3s var(--ease), border-color 0.3s var(--ease), color 0.3s var(--ease);
}
.cta:hover { background: var(--color-white); border-color: var(--color-white); color: var(--color-black); }
.cta:focus-visible { outline: 2px solid var(--color-white); outline-offset: 3px; }
.cta.is-solid { background: var(--color-white); border-color: var(--color-white); color: var(--color-black); }
.cta.is-solid:hover { background: rgba(255, 255, 255, 0.86); }
.cta.is-large { font-size: 12px; padding: 14px 28px; }

.intro-inner .cta { margin-top: 26px; }

.endcap {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: clamp(70px, 11vw, 150px) clamp(20px, 5vw, 60px) clamp(80px, 12vw, 170px);
  text-align: center;
}
/* A wide plate behind the close. The blur and the crop are baked into the file
   — see tools/endcap.sh — so nothing is filtered at runtime; all that is left
   here is a scrim heavy enough to hold white text over any part of it. If the
   plate is missing the section simply stays black, as it was. */
.endcap::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  background: #000 58% center / cover no-repeat;
}
.endcap.is-near::before { background-image: url("assets/endcap.jpg?v=20261023b"); }   /* fetched only once the close is near */
.endcap::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(105% 74% at 50% 50%, rgba(0, 0, 0, 0.58) 0%, rgba(0, 0, 0, 0.26) 58%, rgba(0, 0, 0, 0.1) 100%),
    /* fixed distances, not percentages: the section is barely a third as tall on
       a phone, and a percentage fade compresses there into a black bar sitting
       between the last tiles and the picture */
    linear-gradient(to bottom,
      rgba(0, 0, 0, 0.62) 0,
      rgba(0, 0, 0, 0.22) 64px,
      rgba(0, 0, 0, 0.22) calc(100% - 96px),
      var(--color-black) 100%);
}
.endcap-title, .endcap-copy, .endcap .cta { position: relative; }
.endcap-title { text-shadow: 0 2px 30px rgba(0, 0, 0, 0.75); }
.endcap-copy { text-shadow: 0 1px 18px rgba(0, 0, 0, 0.8); color: rgba(255, 255, 255, 0.82); }
.endcap-title {
  font-family: var(--font-logo);
  font-size: clamp(34px, 5.6vw, 82px);
  line-height: 1.04;
  letter-spacing: 0.01em;
  text-wrap: balance;
}
.endcap-copy {
  margin: 20px auto 34px;
  max-width: 52ch;
  font-size: clamp(15px, 1.4vw, 19px);
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.72);
}
/* with no title the line carries the close on its own: larger, brighter, tighter */
.endcap-title[hidden] + .endcap-copy { margin: 0 auto 30px; max-width: 34ch; font-size: clamp(20px, 2.2vw, 30px); line-height: 1.4; color: rgba(255, 255, 255, 0.92); text-wrap: balance; }

/* the panel */
.enq {
  position: fixed;
  inset: 0;
  z-index: 950;
  background: rgba(0, 0, 0, 0.93);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  display: grid;
  place-items: start center;
  overflow-y: auto;
  padding: clamp(16px, 4vw, 56px);
  animation: sheetIn 0.3s var(--ease);
}
.enq-panel {
  position: relative;
  width: 100%;
  max-width: 760px;
  background: #0a0a0a;
  border: 1px solid rgba(255, 255, 255, 0.14);
  padding: clamp(26px, 4vw, 52px);
  text-align: left;
}
.enq-close:focus-visible { outline: 2px solid var(--color-white); outline-offset: 2px; }

.enq-eyebrow { font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase; color: var(--color-grey); }
.enq-title {
  font-family: var(--font-logo);
  font-size: clamp(30px, 4.2vw, 50px);
  line-height: 1.05;
  margin: 12px 0 10px;
  text-wrap: balance;
}
.enq-sub { font-size: 15px; line-height: 1.5; color: rgba(255, 255, 255, 0.66); max-width: 48ch; }

.enq-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 22px 20px;
  margin-top: 30px;
}
.f { display: flex; flex-direction: column; gap: 11px; min-width: 0; border: 0; padding: 0; margin: 0; }
.f-wide { grid-column: 1 / -1; }
.f-label {
  font-size: 11px;
  line-height: 1.3;                /* uppercase at 11px clips its own cap height on "normal" */
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
  padding: 0;
}
.f-label i { font-style: normal; color: rgba(255, 255, 255, 0.4); }
/* the spam trap: off-screen rather than display:none, because some bots skip
   anything that is not rendered. No person can see it or tab into it. */
.f-trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.enq input, .enq select, .enq textarea {
  font-family: var(--font-primary);
  font-size: 15px;
  color: var(--color-white);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 2px;
  padding: 12px 13px;
  width: 100%;
  transition: border-color 0.25s var(--ease), background 0.25s var(--ease);
}
.enq textarea { resize: vertical; line-height: 1.45; }
.enq input::placeholder, .enq textarea::placeholder { color: rgba(255, 255, 255, 0.32); }
.enq input:focus, .enq select:focus, .enq textarea:focus {
  outline: none;
  border-color: rgba(255, 255, 255, 0.7);
  background: rgba(255, 255, 255, 0.07);
}
.enq .is-invalid { border-color: #ff6b5e; }

/* ---------- the dropdowns ----------
   A native <select> draws its list with the operating system, which cannot be
   styled and lands a grey system menu in the middle of the page. So the select
   stays in the form — it is still what carries the value and what FormData
   reads — and a listbox built from its own options is drawn over it. */
.sel { position: relative; }
.sel select {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  overflow: hidden;
}
.sel-btn {
  font-family: var(--font-primary);
  font-size: 15px;
  text-align: left;
  color: var(--color-white);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 2px;
  padding: 12px 34px 12px 13px;
  width: 100%;
  cursor: pointer;
  transition: border-color 0.25s var(--ease), background 0.25s var(--ease);
}
.sel-btn:hover { background: rgba(255, 255, 255, 0.07); }
.sel-btn:focus-visible { outline: none; border-color: rgba(255, 255, 255, 0.7); background: rgba(255, 255, 255, 0.07); }
.sel.is-open .sel-btn { border-color: rgba(255, 255, 255, 0.7); background: rgba(255, 255, 255, 0.07); }
.sel.is-invalid .sel-btn { border-color: #ff6b5e; }
.sel-btn.is-empty { color: rgba(255, 255, 255, 0.32); }
.sel-btn::after {
  content: "";
  position: absolute;
  right: 14px; top: 50%;
  width: 7px; height: 7px;
  margin-top: -5px;
  border-right: 1px solid rgba(255, 255, 255, 0.55);
  border-bottom: 1px solid rgba(255, 255, 255, 0.55);
  transform: rotate(45deg);
  transition: transform 0.25s var(--ease);
  pointer-events: none;
}
.sel.is-open .sel-btn::after { transform: rotate(-135deg); margin-top: -2px; }

.sel-list {
  position: absolute;
  z-index: 5;
  top: calc(100% + 4px);
  left: 0; right: 0;
  max-height: 264px;
  overflow-y: auto;
  background: #121212;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 2px;
  box-shadow: 0 18px 46px rgba(0, 0, 0, 0.7);
  padding: 4px;
}
.sel-list[hidden] { display: none !important; }
.sel-opt {
  padding: 10px 12px;
  font-size: 15px;
  color: rgba(255, 255, 255, 0.88);
  cursor: pointer;
  border-radius: 2px;
}
.sel-opt:hover, .sel-opt.is-active { background: rgba(255, 255, 255, 0.12); color: var(--color-white); }
.sel-opt[aria-selected="true"] { color: var(--color-white); }
.sel-opt[aria-selected="true"]::after { content: " ✓"; color: rgba(255, 255, 255, 0.6); }

.enq-error { margin-top: 18px; font-size: 14px; color: #ff6b5e; }
.enq-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 16px; margin-top: 28px; }
.enq-brief {
  margin: 22px 0 0;
  padding: 18px;
  max-height: 300px;
  overflow: auto;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.14);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.82);
  white-space: pre-wrap;
}

@media (max-width: 699px) {
  /* has to live after .cta.is-large rather than with the other phone rules:
     same specificity, so whichever comes last in the file wins */
  .endcap .cta { font-size: 11px; letter-spacing: 0.13em; padding: 12px 22px; }
}
@media (max-width: 640px) {
  .enq-grid { grid-template-columns: minmax(0, 1fr); }
  .enq-panel { padding: 24px 18px 28px; }
}
@media (prefers-reduced-motion: reduce) {
  .enq, .cta { animation: none; transition: none; }
}

/* Commercials are wide frames: two to a row, one on a phone. The same column
   engine lays them; with no levellers the short column's own tiles stretch a
   few percent to meet the line. */
body[data-section="commercial"] { --cols: 2; }
@media (max-width: 699px) { body[data-section="commercial"] { --cols: 1; } }

/* A commercial opens as the full spot with sound: the film across the panel,
   its title and note beneath, rather than beside a silent loop. */
.sheet { --sheet-max-h: 86vh; }        /* a preview fills the screen's height, whatever its shape */
.sheet.is-spot .sheet-inner { flex-direction: column; align-items: center; gap: 22px; max-width: 1600px; }
.sheet.is-spot { --sheet-max-h: 74vh; }   /* the film plus its mark beneath must still fit */
.sheet.is-spot .sheet-media { background: transparent; }        /* the frame is the film's own size: nothing to fill */
.sheet.is-spot .sheet-media video { display: block; width: 100%; height: 100%; }
.sheet.is-spot .sheet-copy { width: 100%; max-width: none; }
.sheet.is-spot .sheet-logline { max-width: 70ch; }
/* the brand's mark in place of a typed title, and nothing else beside the film */
.sheet.is-mark .sheet-genre, .sheet.is-mark .sheet-logline { display: none; }
.sheet.is-mark .sheet-title { margin: 6px 0 0; line-height: 0; }
.sheet.is-mark .sheet-title img {
  display: block;
  height: calc(var(--h, 30px) * 1.5);
  width: auto;
  max-width: 50%;
  filter: brightness(0) invert(1);
}

@media (max-width: 699px) {
  .sheet { --sheet-max-h: 56vh; }
  .sheet.is-mark .sheet-title img { height: var(--h, 30px); }   /* the mark under a phone-width film: marquee size, not larger */
}

/* ---------- section labels ----------
   One heading above each block of work, in the same face and weight as the
   statement on the landing, a size up, set to the tiles' left edge. */
.section-label {
  font-family: var(--font-logo);
  font-weight: 400;
  font-size: clamp(28px, 2.3vw, 38px);
  line-height: 1.1;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--color-white);
  text-align: center;
  padding: 44px calc(var(--tile-gap) + 14px) 16px;
  margin: 0;
}
@media (max-width: 699px) {
  .section-label { font-size: 24px; padding: 30px calc(var(--tile-gap) + 10px) 12px; }
}

/* ---------- the reels ----------
   The vertical series, under the commercials: three rows of clips that drift
   sideways, each the opposite way to the one above, forever. A row is one set
   of tiles repeated until it is wider than the screen; the track slides by
   exactly one set and starts again, so the loop never shows a seam. Hovering
   a row holds it still so a tile can be clicked. */
.reels {
  --row-h: clamp(360px, 58vh, 640px);
  display: flex;
  flex-direction: column;
  gap: var(--tile-gap);
  padding: 0 0 var(--tile-gap);         /* the mosaic's own bottom gap is the seam: the rows run straight on from it */
  overflow: hidden;
  text-align: left;
}
.reel { position: relative; height: var(--row-h); overflow: hidden; }
.reel-track {
  display: flex;
  gap: var(--tile-gap);
  height: 100%;
  width: max-content;
  will-change: transform;
  animation: reelLeft var(--dur, 90s) linear infinite;
}
.reel.is-reverse .reel-track { animation-name: reelRight; }
.reel:hover .reel-track { animation-play-state: paused; }
.reel .tile { flex: 0 0 auto; width: auto; height: 100%; }
@keyframes reelLeft  { from { transform: translateX(0); } to { transform: translateX(calc(-1 * var(--set))); } }
@keyframes reelRight { from { transform: translateX(calc(-1 * var(--set))); } to { transform: translateX(0); } }
@media (max-width: 699px) {
  .reels { --row-h: clamp(260px, 42vh, 400px); }
}
@media (prefers-reduced-motion: reduce) {
  .reel-track { animation: none; }
  .reel { overflow-x: auto; }
}

/* ---------- services ----------
   Laid like the mosaic: columns of pictures in different shapes, the same gap
   as the tiles, the foot brought level. The title and its line sit inside
   each picture over a foot of shadow, like a tile's caption, always showing. */
.services {
  --svc-cols: 3;
  display: flex;
  align-items: flex-start;
  gap: var(--tile-gap);
  padding: var(--tile-gap);
  text-align: left;
}
.scol { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: var(--tile-gap); }
.svc-box { position: relative; overflow: hidden; width: 100%; background: #0b0b0b; color: var(--color-white); font-family: var(--font-primary); }
.svc-media { position: absolute; inset: 0; background: #111; overflow: hidden; }
.svc-media img { display: block; width: 100%; height: 100%; object-fit: cover; }
.svc-text {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 56px 22px 20px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.78), rgba(0, 0, 0, 0.35) 55%, transparent);
  pointer-events: none;                 /* the wipe underneath still takes the drag */
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.6);
}
.svc-box h3 { font-family: var(--font-logo); font-weight: 400; font-size: clamp(26px, 2.1vw, 34px); line-height: 1.05; letter-spacing: 0.01em; margin: 0 0 8px; }
.svc-box p { font-size: 16px; font-weight: 400; line-height: 1.4; color: rgba(255, 255, 255, 0.74); margin: 0; max-width: 50ch; }   /* the statement's face, a step smaller and greyer than the title */
@media (max-width: 1099px) { .services { --svc-cols: 2; } }
@media (max-width: 699px) {
  .services { --svc-cols: 1; }
  .svc-text { padding: 44px 16px 16px; }
  .svc-box p { font-size: 14px; }
}


/* three vertical frames side by side, filling whatever shape the box has */
.svc-media.is-triptych { display: grid; grid-template-columns: repeat(3, 1fr); gap: 3px; background: #0b0b0b; }
.svc-media.is-triptych img { width: 100%; height: 100%; object-fit: cover; }

/* before/after: the original sits on top, cut off at --split; drag anywhere to move it */
.svc-media.is-compare { --split: 50%; user-select: none; touch-action: pan-y; cursor: ew-resize; }
.svc-media.is-compare img { position: absolute; inset: 0; }
.svc-media.is-compare .before { clip-path: inset(0 calc(100% - var(--split)) 0 0); }
.svc-media.is-compare .cmp-handle {
  position: absolute; top: 0; bottom: 0; left: var(--split); width: 2px; margin-left: -1px; z-index: 3;
  background: var(--color-white); box-shadow: 0 0 12px rgba(0, 0, 0, 0.6); pointer-events: none;
}
.svc-media.is-compare .cmp-handle::after {
  content: ""; position: absolute; top: 50%; left: 50%; width: 34px; height: 34px; margin: -17px 0 0 -17px;
  border-radius: 50%; background: var(--color-white) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 12h18M7.5 7.5 3 12l4.5 4.5M16.5 7.5 21 12l-4.5 4.5'/%3E%3C/svg%3E") center / 20px 20px no-repeat;
  box-shadow: 0 2px 14px rgba(0, 0, 0, 0.5);
}
.svc-media.is-compare .cmp-range {
  position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; pointer-events: none;
  -webkit-appearance: none; appearance: none;
}


/* the panel */
.svc {
  position: fixed;
  inset: 0;
  z-index: 940;
  background: rgba(0, 0, 0, 0.93);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  display: grid;
  place-items: start center;
  overflow-y: auto;
  padding: clamp(16px, 4vw, 56px);
  animation: sheetIn 0.3s var(--ease);
}
.svc-panel {
  position: relative;
  width: 100%;
  max-width: 720px;
  background: #0a0a0a;
  border: 1px solid rgba(255, 255, 255, 0.14);
  padding: clamp(26px, 4vw, 52px);
  text-align: left;
}
.svc-eyebrow { font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase; color: var(--color-grey); }
.svc-title { font-family: var(--font-primary); font-size: clamp(26px, 3vw, 36px); font-weight: 500; line-height: 1.1; margin: 12px 0 14px; letter-spacing: -0.01em; text-wrap: balance; }
.svc-intro { font-size: 17px; line-height: 1.5; color: rgba(255, 255, 255, 0.86); margin: 0 0 22px; max-width: 58ch; }
.svc-body ul, .svc-body ol { list-style: none; margin: 0; padding: 0; border-top: 1px solid rgba(255, 255, 255, 0.1); }
.svc-body li { display: flex; gap: 16px; padding: 12px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.1); font-size: 15px; line-height: 1.5; color: rgba(255, 255, 255, 0.8); }
.svc-body li strong { color: var(--color-white); font-weight: 500; }
.svc-body ol { counter-reset: step; }
.svc-body ol li::before { counter-increment: step; content: counter(step, decimal-leading-zero); flex: 0 0 26px; font-size: 12px; font-weight: 500; letter-spacing: 0.06em; color: rgba(255, 255, 255, 0.45); padding-top: 3px; font-variant-numeric: tabular-nums; }
.svc-note { font-size: 15px; line-height: 1.5; color: rgba(255, 255, 255, 0.6); margin: 20px 0 26px; }
.svc-note:empty { display: none; }
.svc .cta { margin: 0; }
@media (max-width: 699px) {
  .svc-intro { font-size: 15px; }
  .svc-body li { font-size: 14px; gap: 12px; }
}

/* ---------- the opening ----------
   A black stage over everything. A few thousand points of light gather out of
   the dark, from all round the screen on curving paths, sweeping left to
   right, and settle into the letters of the wordmark in the exact box the
   real mark occupies; the letters ignite, the bloom dies down, the stage
   lifts while the film behind eases in from a touch closer, and the lockup
   rises in line by line. The real mark is under the canvas at the same size,
   so the hand-over is invisible. Drawn by main.js runOpening(); the <img> is
   the sampling source and, with reduced motion or no canvas, the stand-in. */
.loader {
  position: fixed; inset: 0; z-index: 2000;
  background: var(--color-black);
  transition: opacity 0.75s var(--ease);
}
.loader.is-done { opacity: 0; pointer-events: none; }
.loader canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.loader-mark { position: absolute; left: 50%; top: 42%; width: clamp(230px, 36vw, 640px); transform: translate(-50%, -50%); opacity: 0; }
.loader-mark img { display: block; width: 100%; height: auto; }
.loader.is-plain .loader-mark { opacity: 1; }
.loader.is-plain canvas { display: none; }
/* the film behind starts a touch closer and settles as the stage lifts */
.intro-bg { transform-origin: 50% 45%; transition: transform 1.7s cubic-bezier(0.2, 0.7, 0.2, 1); }
#loader:not(.is-done) ~ .layout .intro-bg { transform: scale(1.07); }
@media (prefers-reduced-motion: reduce) {
  .intro-bg { transition: none; }
  #loader:not(.is-done) ~ .layout .intro-bg { transform: none; }
  .scroll-to.explore { animation: none; }
}
