/* ============================================================================
   NIMMERSATT x OTTOLINGER — Berlin Fashion Week
   Client layer on top of: tokens → pitch → deck → client-cc-tapis →
   client-sprs → client-otto. This file only holds what the Ottolinger deck
   needs on top of that stack:
     1. a centred hero (the cc-tapis layer splits it into two columns)
     2. the "What we delivered" ledger, read as full-width rows
     3. the project index tiles used by Fashion Week / Index / Recaps
     4. placeholder cards for reference stacks whose stills are still missing
   ========================================================================== */

body.ol-pitch {
  --bg: #fafafa;
  --fg: #0d0d0d;
  --ink: rgba(13, 13, 13, 0.72);
  --ink-strong: rgba(13, 13, 13, 0.9);
  --client: #0d0d0d;
  --client-brown: #1a1a1a;
  --client-line: rgba(13, 13, 13, 0.18);
  /* Plain ground. The cc-tapis layer paints three vertical hairlines at 25 /
     50 / 75 % of the page width via a background gradient on <body>; this deck
     runs without them. */
  background: var(--bg);
}

/* The intro footage was mastered on pure white. Multiply lets that white matte
   resolve to the deck's #fafafa ground without re-colouring the moving image. */
.ol-pitch .preloader {
  background: var(--bg);
  isolation: isolate;
}

.ol-pitch .preloader__media {
  mix-blend-mode: multiply;
}

/* The full navigation bar is gone. The remaining brand behaves like a small
   physical sticker: black artwork, off-white fill, crisp white contour. */
.ol-pitch .nav,
.ol-pitch .nav.is-stuck {
  inset: var(--space-4) auto auto var(--space-4);
  width: auto;
  padding: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  transform: none;
  pointer-events: none;
}

.ol-pitch .nav__brand {
  position: relative;
  display: inline-flex;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  color: var(--fg);
  background: var(--bg);
  border: var(--space-1) solid #fff;
  pointer-events: auto;
}

.ol-pitch .nav__mark {
  width: var(--space-5);
  color: var(--fg);
}

.ol-pitch .nav__name {
  color: var(--fg);
  font-family: var(--font-client-mono);
  font-size: var(--type-label);
  font-weight: 700;
  letter-spacing: var(--tracking-label);
}

@media (max-width: 767px) {
  .ol-pitch .nav,
  .ol-pitch .nav.is-stuck {
    inset: var(--space-3) auto auto var(--space-3);
  }

  .ol-pitch .nav__brand {
    padding: var(--space-2);
  }

  .ol-pitch .nav__name {
    display: inline;
  }
}

/* The short dotted tick above the intro belonged to that same grid. With the
   grid gone it floats on its own, so it goes too. */
.ol-pitch .about .shell::after {
  content: none;
}

/* --- 1 / Hero: centred column, GIF between the tagline and the disciplines --
   The cc-tapis layer puts the wordmark left and the mark right. Otto asked for
   the centred sprs composition, so the grid placements are reset here. */
.ol-pitch .hero {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  gap: clamp(1.4rem, 3.2vw, 2.5rem);
}

.ol-pitch .hero__title,
.ol-pitch .hero__sub,
.ol-pitch .hero__mark,
.ol-pitch .hero__meta {
  grid-column: auto;
  grid-row: auto;
  justify-self: center;
}

.ol-pitch .hero__title {
  width: fit-content;
  max-width: 92vw;
  white-space: nowrap;
  margin-inline: auto;
  text-align: center;
  font-size: clamp(2rem, 9vw, 8rem);
  line-height: 0.9;
  letter-spacing: -0.035em;
}

.ol-pitch .hero__sub {
  max-width: 46ch;
  margin-inline: auto;
  text-align: center;
}

.ol-pitch .hero__mark {
  width: clamp(150px, 26vw, 320px);
  max-width: min(80vw, 320px);
  margin-inline: auto;
  aspect-ratio: auto;
  justify-self: center;
}

/* Fashion films are revealed through the animated Nimmersatt caterpillar. */
.ol-pitch .hero__mark.hero-montage {
  position: relative;
  width: min(72vw, 760px);
  max-width: 760px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: transparent;
}

.hero-montage__films {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  -webkit-mask-image: url("../assets/raupe-walk-hd.gif?v=3");
  mask-image: url("../assets/raupe-walk-hd.gif?v=3");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-mode: alpha;
  mask-mode: alpha;
}

.ol-pitch .hero__mark.hero-montage::after {
  content: none;
}

.hero-montage__films > video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  animation: ol-hero-cut 11s steps(1, end) infinite;
}

.hero-montage__films > video:nth-child(2) {
  animation-delay: -8.25s;
}

.hero-montage__films > video:nth-child(3) {
  animation-delay: -5.5s;
}

.hero-montage__films > video:nth-child(4) {
  animation-delay: -2.75s;
}

@keyframes ol-hero-cut {
  0%,
  24.99% {
    opacity: 1;
  }

  25%,
  100% {
    opacity: 0;
  }
}

@media (max-width: 767px) {
  .ol-pitch .hero__title {
    max-width: calc(100vw - (2 * var(--space-4)));
    font-size: clamp(2.25rem, 10.5vw, 2.75rem);
  }

  .ol-pitch .hero__mark.hero-montage {
    width: min(88vw, 520px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-montage__films {
    -webkit-mask-image: url("../assets/raupe-walk-hd-static.png");
    mask-image: url("../assets/raupe-walk-hd-static.png");
  }

  .ol-pitch .hero__mark.hero-montage::after {
    display: none;
  }

  .hero-montage__films > video {
    animation: none;
    opacity: 0;
  }

  .hero-montage__films > video:first-child {
    opacity: 1;
  }
}

.ol-pitch .hero__meta {
  justify-content: center;
}

/* --- 2 / "What we delivered": one number per row, read across the page ------
   Otto: "make it sound bigger or list horizontally." Each line is a full-width
   row: oversized figure, the deliverable, and the detail that qualifies it. */
.ol-delivered {
  margin-top: clamp(2.5rem, 5vw, 4rem);
  border-top: 1px dotted var(--client-line);
}

.ol-delivered__row {
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, 1fr) minmax(0, 0.9fr);
  align-items: baseline;
  column-gap: clamp(1.5rem, 4vw, 4rem);
  row-gap: 0.35rem;
  padding: clamp(1.1rem, 2.4vw, 1.9rem) 0;
  border-bottom: 1px dotted var(--client-line);
}

.ol-delivered__num {
  font-family: var(--font-client-display);
  font-weight: 700;
  font-size: clamp(2.6rem, 7.5vw, 6.5rem);
  line-height: 0.82;
  letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums;
}

.ol-delivered__name {
  font-family: var(--font-client-display);
  font-weight: 700;
  font-size: clamp(1.1rem, 2.4vw, 2rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
}

.ol-delivered__note {
  max-width: 40ch;
  color: var(--ink);
  font-size: clamp(0.72rem, 0.95vw, 0.86rem);
  font-weight: var(--w-read);
  line-height: 1.6;
}

@media (max-width: 860px) {
  .ol-delivered__row {
    grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  }
  .ol-delivered__note {
    grid-column: 2;
    max-width: none;
  }
}

/* --- 3 / Project index tiles ------------------------------------------------
   Used three times: the other Fashion Week work, the index® references, and the
   event recaps. One tile per project, image on top, metadata underneath. */
.ol-projects {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: 1px;
  margin-top: clamp(1.6rem, 3vw, 2.4rem);
  border: 1px dotted var(--client-line);
  background: var(--client-line);
}

.ol-project {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--bg);
}

.ol-project__media {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: #ededea;
}

.ol-project__media :is(img, video) {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-ui) var(--ease-spring);
}

.ol-project:hover .ol-project__media :is(img, video) {
  transform: scale(1.03);
}

/* Recap tiles that open a full-video lightbox signal it with the zoom cursor. */
.ol-project__media video[data-zoom] {
  cursor: zoom-in;
}

.ol-project__body {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: var(--client-row-pad);
}

.ol-project__num {
  font-family: var(--font-client-mono);
  font-size: 0.55rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}

.ol-project__name {
  font-family: var(--font-client-display);
  font-size: clamp(1.05rem, 1.9vw, 1.5rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.02em;
}

.ol-project__meta {
  font-family: var(--font-client-mono);
  font-size: 0.56rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --- 6 / Concept table --------------------------------------------------
   client-otto.css forces every .conceptbody into single full-width rows. The
   Case section wants exactly that, but Index and Recaps keep the cc-tapis
   five-column table, so it is restored per section. */
@media (min-width: 980px) {
  .ol-pitch .conceptbody--table {
    grid-template-columns: repeat(5, minmax(0, 1fr)) !important;
  }
}

/* --- 7 / Type: cc-tapis only, never the SPRS pitch's -----------------------
   client-otto.css (the layer behind nimmersatt-x-sprs.surge.sh) forces every
   heading to Poynter OS Display. That face does not belong here; headings run
   on the cc-tapis display face, Nimbus Sans Round.

   The HERO WORDMARK is the deliberate exception: it keeps Rock 3D, the
   hand-drawn Nimmersatt face, which is what Otto annotated. That comes from
   `.otto-pitch .hero__title`, so this file leaves the hero alone. */
body.ol-pitch h2,
body.ol-pitch h3,
body.ol-pitch .otto-cubebox__label strong {
  font-family: var(--font-client-display) !important;
}

/* The ASCII closing inherits its font from the h2 above, and any proportional
   face collapses the block. It needs a real monospace. */
.ol-pitch .closing__line--ascii,
.ol-pitch .closing__line--ascii .ascii-art {
  font-family: "Apercu Mono", "Martian Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace !important;
}

/* --- 9 / Offered services: two equal rows ----------------------------------
   Eight services, four per row on desktop, so the two rows are the same
   length. */
@media (min-width: 900px) {
  .ol-pitch .about__services {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    justify-content: initial;
  }
}

/* --- 10 / Case body: one column, sub-blocks stacked ------------------------
   client-otto.css splits each block into "tag | text | text" on wide screens,
   so Setup and Progression sit side by side. Otto wants them under each other. */
@media (min-width: 980px) {
  .ol-pitch .otto-main-film .conceptblock {
    grid-template-columns: minmax(150px, 0.32fr) minmax(0, 1fr);
  }
  .ol-pitch .otto-main-film .conceptblock p {
    grid-column: 2;
  }
}

/* --- 11 / Flipped season block: media right, copy left --------------------- */
.ol-pitch .otto-direction-head--flip .otto-cubebox {
  order: 2;
}
.ol-pitch .otto-direction-head--flip .concept__brief {
  order: 1;
}

/* --- 12 / Client / studio credits inside a season brief -------------------- */
.ol-creditblock {
  margin-top: clamp(1rem, 2vw, 1.5rem);
}
.ol-creditblock + .ol-creditblock {
  margin-top: clamp(0.9rem, 1.8vw, 1.3rem);
}
.ol-creditblock__label {
  display: block;
  margin-bottom: 0.45rem;
  font-family: var(--font-client-mono);
  font-size: 0.55rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}
.ol-creditblock__names {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.9rem;
  list-style: none;
}
.ol-creditblock__names li {
  font-family: var(--font-client-mono);
  font-size: clamp(0.62rem, 0.85vw, 0.74rem);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* --- 13 / Client wall: one uniform black silhouette ------------------------
   Several marks (lululemon, GmbH, index, assembly, ROVO, Jaded) ship as white
   on transparent and vanished on this white ground. brightness(0) flattens
   every logo to the same black, which is also how the live site does it. */
.ol-pitch .clientlist img {
  filter: brightness(0);
  opacity: 0.78;
}

/* Otto asked for the marks to sit bigger. Roughly +55 % over the cc-tapis
   default, with a taller cell so nothing collides. */
.ol-pitch .clientlist li {
  min-height: clamp(110px, 12vw, 165px);
}
.ol-pitch .clientlist img {
  max-width: min(84%, 240px);
  max-height: clamp(44px, 6.4vw, 82px);
}

/* Otto, 04.09.26: "6 logos side by side, 3 rows". The cc-tapis base is an
   auto-fit grid, which reflowed to 5 or 7 across depending on the viewport, so
   this pins the count instead of letting the track width decide it. 18 marks
   divide into 6 x 3 exactly. Six across a phone is 65px per cell, unreadable,
   so it steps to 3 then 2 — the row of six is the desktop instruction. */
.ol-pitch .clientlist {
  grid-template-columns: repeat(6, 1fr);
}

@media (max-width: 899px) {
  .ol-pitch .clientlist { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 559px) {
  .ol-pitch .clientlist { grid-template-columns: repeat(2, 1fr); }
}

/* Clients we hold no mark for run as a plain name row under the wall. */
.ol-clientnames {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.4rem;
  margin-top: clamp(1.1rem, 2.2vw, 1.8rem);
  padding-top: clamp(1rem, 2vw, 1.5rem);
  border-top: 1px dotted var(--client-line);
  list-style: none;
}
.ol-clientnames li {
  font-family: var(--font-client-mono);
  font-size: clamp(0.62rem, 0.85vw, 0.74rem);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
}

/* --- 12b / The crown, inverted, with the crawl lane --------------------------
   The panel goes black with white type, and the bracket row is replaced by a
   column of Nimmersatt marks crawling across it.

   Colour is re-pointed rather than restyled, the same way §16 flips a section:
   --fg carries the meta row's two bold cells and the wordmark, --cc-blue is the
   upstream hover accent (a near-black blue, unreadable here). Only the three
   values cc-tapis hard-codes need overriding by hand. */
.ol-pitch .client-crown {
  --fg: #fafafa;
  --cc-blue: rgba(250, 250, 250, 0.62);
  background: #0d0d0d;
  border-color: rgba(250, 250, 250, 0.16);
  box-shadow: 0 18px 42px rgba(13, 13, 13, 0.42);
  width: min(320px, calc(100vw - (var(--client-edge-pad) * 2)));
}

.ol-pitch .client-crown__meta {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem;
  padding: 0.45rem 0.65rem 0.35rem;
  border-bottom-color: rgba(250, 250, 250, 0.16);
  color: rgba(250, 250, 250, 0.45);
}

.ol-pitch .client-crown__choice {
  color: rgba(250, 250, 250, 0.58);
  font-weight: 600;
  text-align: center;
  transition: color var(--dur-ui) var(--ease-spring);
}

.ol-pitch .client-crown__choice:first-child {
  text-align: left;
}

.ol-pitch .client-crown__choice:last-child {
  text-align: right;
}

.ol-pitch .client-crown__choice:hover,
.ol-pitch .client-crown__choice:focus-visible {
  color: var(--fg);
  outline: none;
}

/* The brackets are gone from the markup; this keeps the rule from applying if a
   sibling deck's markup is ever pasted back in. */
.ol-pitch .client-crown__brackets {
  display: none;
}

/* The crawl lane takes over the row the brackets used to hold, so the panel does
   not grow and this works on the capped mobile crown too. */
.ol-pitch .client-crown__crawl {
  position: relative;
  height: 1.35rem;
  overflow: hidden;
  border-bottom: 1px solid rgba(250, 250, 250, 0.16);
}

@media (max-width: 640px) {
  body.ol-pitch {
    --client-crown-mobile-height: 4rem;
  }

  .ol-pitch .client-crown {
    right: max(1rem, env(safe-area-inset-right));
    left: max(1rem, env(safe-area-inset-left));
    width: auto;
  }

  .ol-pitch .client-crown__meta {
    gap: 0.5rem;
    padding: 0.5rem 0.75rem 0.4rem;
  }

  .ol-pitch .client-crown__crawl {
    height: 1.6rem;
  }
}

/* Each runner spans the lane, so `translateX(100%)` is exactly one lane width:
   travel is lane + mark, with no hard-coded panel width to keep in sync. The
   `from` value is the mark's own width, so it enters off-frame instead of
   popping in.

   ONE duration for all twelve, and the only difference is the start offset. That
   is what keeps the column honest: identical speed means the spacing set by the
   delays never changes, so no mark ever overtakes or overlaps another. Giving
   them individual speeds looks livelier for about five seconds and then they
   bunch into white clumps with empty bar between — the relative drift is roughly
   10px per second even for speeds only 2s apart. */
.ol-pitch .client-crown__runner {
  position: absolute;
  inset: 0;
  display: block;
  animation: olRaupeCrawl 12s linear infinite;
  will-change: transform;
}

.ol-pitch .client-crown__raupe {
  position: absolute;
  left: 0;
  top: 50%;
  height: 0.92rem;
  width: auto;
  transform: translateY(-50%);
}

@keyframes olRaupeCrawl {
  from { transform: translateX(-2.4rem); }   /* mark width */
  to   { transform: translateX(100%); }      /* one lane width */
}

/* Twelve marks, one second apart on a 12s cycle: an even 1/12 of the lane between
   each. Travel is lane + mark, so the pitch is 555/12 ≈ 46px against a 37px mark —
   a ~9px gap that stays constant, at every breakpoint (checked: the narrowest
   panel still leaves ~6px). Nothing here to keep in sync by hand: with the count
   and the duration matching, `-1s` per child is exactly one twelfth. */
.ol-pitch .client-crown__runner:nth-child(1)  { animation-delay:  0s; }
.ol-pitch .client-crown__runner:nth-child(2)  { animation-delay: -1s; }
.ol-pitch .client-crown__runner:nth-child(3)  { animation-delay: -2s; }
.ol-pitch .client-crown__runner:nth-child(4)  { animation-delay: -3s; }
.ol-pitch .client-crown__runner:nth-child(5)  { animation-delay: -4s; }
.ol-pitch .client-crown__runner:nth-child(6)  { animation-delay: -5s; }
.ol-pitch .client-crown__runner:nth-child(7)  { animation-delay: -6s; }
.ol-pitch .client-crown__runner:nth-child(8)  { animation-delay: -7s; }
.ol-pitch .client-crown__runner:nth-child(9)  { animation-delay: -8s; }
.ol-pitch .client-crown__runner:nth-child(10) { animation-delay: -9s; }
.ol-pitch .client-crown__runner:nth-child(11) { animation-delay: -10s; }
.ol-pitch .client-crown__runner:nth-child(12) { animation-delay: -11s; }

/* --- 12c / The panel on narrow screens --------------------------------------
   760px is where client-otto.css turns the crown into a full-width fixed bar, so
   the compact treatment starts there rather than at cc-tapis's 640px — otherwise
   the lane keeps its desktop height inside an already-cramped panel.

   The wordmark row is dropped here. It was being clipped anyway: the panel is
   capped at 4.45rem (71px) while meta + lane + bar need 80px, so the bottom of
   "nimmersatt" was cut off on every phone. It is also redundant — the header
   carries the mark and name, and .backtotop keeps the scroll-to-top affordance.
   With it gone the panel is two clean rows and the height below matches them. */
@media (max-width: 760px) {
  body.ol-pitch {
    --client-crown-mobile-height: 3.1rem;
    --client-crown-mobile-space: calc(
      var(--client-crown-mobile-height) + var(--client-crown-mobile-offset) + 0.5rem
    );
  }

  .ol-pitch .client-crown__bar { display: none; }

  .ol-pitch .client-crown__crawl {
    height: 1.65rem;
    border-bottom: 0;      /* it is the panel's last row now */
  }

  .ol-pitch .client-crown__raupe { height: 0.95rem; }
}

@media (max-width: 640px) and (max-height: 650px) {
  .ol-pitch .client-crown__crawl { height: 1.3rem; }
  .ol-pitch .client-crown__raupe { height: 0.8rem; }
}

/* An animated GIF cannot be paused, so the lane goes rather than sit there
   twitching for someone who asked for less motion. */
@media (prefers-reduced-motion: reduce) {
  .ol-pitch .client-crown__crawl { display: none; }
}

/* --- 13b / Partner studios: three across ------------------------------------
   client-otto.css forces this grid to two columns, which left the third studio
   (poly) orphaned on its own row. The cc-tapis default of three is right here. */
@media (min-width: 720px) {
  .ol-pitch .partners {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* --- 14 / Network note under the partner studios --------------------------- */
.ol-network {
  max-width: 56ch;
  margin-top: clamp(1.1rem, 2.2vw, 1.6rem);
  color: var(--ink);
  font-size: clamp(0.78rem, 1vw, 0.9rem);
  font-weight: var(--w-read);
  line-height: 1.6;
}

/* The Charli XCX block used to sit between the section lead and this label.
   With it gone the two collided, so the label carries its own top space. */
.ol-pitch #recaps .section__index {
  margin-top: clamp(2rem, 4vw, 3.25rem);
}

.ol-pitch #recaps {
  min-height: min(100svh, 960px);
  padding-block: clamp(8rem, 12vw, 12rem);
}

.ol-pitch .visual-frontload__music {
  margin-top: clamp(5rem, 10vw, 10rem);
  padding-top: clamp(4rem, 8vw, 8rem);
}

.ol-pitch .visual-frontload__music .manifesto__line {
  max-width: 12ch;
}

.ol-pitch .visual-frontload__fashion {
  margin-bottom: clamp(5rem, 10vw, 10rem);
}

/* --- 14b / Crew: one row, however many people ------------------------------
   client-otto.css pins #exchange to five columns, so the sixth person (Finnian
   joined as Director) wrapped onto a second row. Column auto-flow puts every
   entry in a single row regardless of headcount, so adding a seventh will not
   break it either. Phones still stack — six across 390px is not a row. */
@media (min-width: 761px) {
  .ol-pitch #exchange .projectteam__crew {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
  }
  /* Names have to survive the narrower cell. */
  .ol-pitch #exchange .artist__name {
    font-size: clamp(0.82rem, 1.25vw, 1.15rem);
    hyphens: none;
  }
  .ol-pitch #exchange .artist__role {
    font-size: clamp(0.5rem, 0.68vw, 0.62rem);
  }
  .ol-pitch #exchange .projectperson {
    padding-inline: clamp(0.7rem, 1.2vw, 1.35rem);
  }
}

/* Phones: client-otto.css puts the crew in two columns, which clips the longest
   label ("Photographer") at 390px. Five short rows stack instead. */
@media (max-width: 760px) {
  .ol-pitch #exchange .projectteam__crew {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* --- 15 / External reference links (Vimeo / YouTube / Instagram) ------------ */
.ol-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1rem;
}
.ol-links a {
  padding: 0.4rem 0.75rem;
  border: 1px dotted var(--client-line);
  font-family: var(--font-client-mono);
  font-size: 0.55rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transition: color var(--dur-ui) var(--ease-spring), border-color var(--dur-ui) var(--ease-spring);
}
.ol-links a:hover,
.ol-links a:focus-visible {
  color: var(--bg);
  background: var(--fg);
  border-color: var(--fg);
}

/* A project tile that links out rather than playing inline. */
.ol-project__link {
  display: flex;
  flex-direction: column;
  height: 100%;
}

/* --- 16 / Stack cards that carry a film -------------------------------------
   Eight of the thirteen index® stills have a cut behind them. The badge is the
   only thing that separates them from a still-only card, so it has to be
   readable over any frame — hence the plate, not just white type. */
.ol-pitch .conceptstack__card.has-film {
  cursor: pointer;
}

/* The tick sits in the very first pixels of the card, so it stays visible even
   when the card is contracted to an 8px sliver — that is how you can tell which
   of the thirteen stills carry a cut before hovering anything. */
.ol-pitch .conceptstack__filmtick {
  position: absolute;
  left: 0;
  bottom: 0;
  z-index: 2;
  width: 8px;
  height: 8px;
  background: #fafafa;
  pointer-events: none;
}

/* --- 16b / Cube tile that holds a linked film -------------------------------
   The cube is a 2x2 grid whose media are direct children, so client-otto.css
   targets them by nth-child. A YouTube film has no <video> to autoplay, it needs
   a still plus a link — which means a wrapper, and the wrapper has to reproduce
   what a video in that cell did: fill it, crop, and tilt away from the cube's
   centre. The per-slot values below mirror the nth-child rules in
   client-otto.css, so a film can sit in any of the three media cells. */
.ol-pitch .otto-cubebox__film {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  background: var(--bg);
  cursor: pointer;
  transform: scale(1.001) rotateX(0) rotateY(0);
  transition: transform 480ms var(--ease-out-expo), filter 300ms var(--ease-spring);
  will-change: transform;
}

.ol-pitch .otto-cubebox__film img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ol-pitch .otto-cubebox--two-media .otto-cubebox__label {
  grid-column: 1 / -1;
}

.ol-pitch .otto-cubebox__film:nth-child(1) { transform-origin: 100% 100%; }
.ol-pitch .otto-cubebox__film:nth-child(2) { transform-origin: 0 100%; }
.ol-pitch .otto-cubebox__film:nth-child(4) { transform-origin: 0 0; }

.ol-pitch .otto-cubebox__film:hover,
.ol-pitch .otto-cubebox__film:focus-visible {
  z-index: 2;
  filter: contrast(1.06) saturate(1.04);
  outline: none;
}

.ol-pitch .otto-cubebox__film:nth-child(1):hover,
.ol-pitch .otto-cubebox__film:nth-child(1):focus-visible {
  transform: scale(1.08) rotateX(5deg) rotateY(-5deg);
}

.ol-pitch .otto-cubebox__film:nth-child(2):hover,
.ol-pitch .otto-cubebox__film:nth-child(2):focus-visible {
  transform: scale(1.08) rotateX(5deg) rotateY(5deg);
}

.ol-pitch .otto-cubebox__film:nth-child(4):hover,
.ol-pitch .otto-cubebox__film:nth-child(4):focus-visible {
  transform: scale(1.08) rotateX(-5deg) rotateY(5deg);
}

@media (prefers-reduced-motion: reduce) {
  .ol-pitch .otto-cubebox__film { transition: none; }
}

.ol-pitch .conceptstack__play,
.ol-pitch .otto-cubebox__play {
  position: absolute;
  left: 0;
  bottom: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.42rem 0.7rem;
  background: #fafafa;
  color: #0d0d0d;
  font-family: var(--font-client-mono);
  font-size: 0.52rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  /* No fade: the plate has to be there the moment the card is open, or a quick
     click reads as "nothing happened". */
  opacity: 0;
  pointer-events: none;
}

/* A font-independent play triangle — no glyph that could fall back to a box. */
.ol-pitch .conceptstack__play::before,
.ol-pitch .otto-cubebox__play::before {
  content: "";
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 0.28rem 0 0.28rem 0.46rem;
  border-color: transparent transparent transparent #0d0d0d;
}

.ol-pitch .conceptstack__card.is-open .conceptstack__play { opacity: 1; }
.ol-pitch .conceptstack__card.is-open .conceptstack__filmtick { opacity: 0; }

/* --- 16c / Runway cards: a loop and a credit inside the deck ----------------
   The Fashion Week shows moved out of the #case block into the deck at the top
   (Otto, 04.09.26). client-cc-tapis.css only sizes `img` inside a card, so the
   <video> needs the identical box, or the loop renders at its intrinsic 560px
   inside a card the accordion has already sized. */
.ol-pitch .conceptstack__card video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: contrast(1.03);
  pointer-events: none;
}

/* Bottom right, because the Play plate owns the bottom left. Hidden in the
   sliver for the same reason the plate is: at 8px it would be a smear. */
.ol-pitch .conceptstack__cap {
  position: absolute;
  right: 0;
  bottom: 0;
  z-index: 3;
  display: grid;
  gap: 0.15rem;
  padding: 0.5rem 0.7rem;
  background: #fafafa;
  color: #0d0d0d;
  text-align: right;
  font-family: var(--font-client-mono);
  opacity: 0;
  pointer-events: none;
}

.ol-pitch .conceptstack__capname {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.ol-pitch .conceptstack__capmeta {
  font-size: 0.52rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #5a5a5a;
}

.ol-pitch .conceptstack__card.is-open .conceptstack__cap { opacity: 1; }

/* The cube tile is always fully visible, so its plate is always on — it is the
   only thing telling you this one tile behaves differently from its neighbours.
   It sits at the top edge, not the bottom: the fixed crown panel occupies the
   lower left of the viewport and swallowed it there. */
.ol-pitch .otto-cubebox__play {
  top: 0;
  bottom: auto;
  opacity: 1;
}

/* --- 17 / Film lightbox ------------------------------------------------------
   Shares the still lightbox's blurred backdrop; only the stage differs, because
   an iframe has no intrinsic size to fit. --film-ar is set per film (the Short
   is 9:16), so the player is never pillarboxed. */
.ol-pitch .cc-lightbox--film {
  --film-ar: 16 / 9;
  background: rgba(9, 9, 9, 0.62);
}

.ol-pitch .cc-lightbox__stage {
  width: min(88vw, calc((100svh - 9rem) * (var(--film-ar))));
  /* --film-max is set per clip. The six runway cuts are 560px sources; blown up
     to the full 1180 they go to mush, so main.js hands them a smaller cap. */
  max-width: min(88vw, var(--film-max, 1180px));
  transform: scale(0.94);
  opacity: 0;
  transition: transform 0.42s var(--ease-out-expo), opacity 0.42s var(--ease-out-expo);
}

.ol-pitch .cc-lightbox--film.is-open .cc-lightbox__stage {
  transform: none;
  opacity: 1;
}

/* The iframe and the local <video> share this: one stage, two possible sources,
   and the visitor cannot tell which one a card used. */
.ol-pitch .cc-lightbox__frame {
  display: block;
  width: 100%;
  aspect-ratio: var(--film-ar);
  border: 0;
  background: #0d0d0d;
  box-shadow: 0 40px 90px rgba(13, 13, 13, 0.45);
}

/* display: block above outranks the UA rule for [hidden], so the stage that is
   not in use has to be switched off explicitly or both would stack. */
.ol-pitch .cc-lightbox__frame[hidden] {
  display: none;
}

.ol-pitch .cc-lightbox__native {
  object-fit: contain;
}

.ol-pitch .cc-lightbox__cap {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.4rem 1.1rem;
  margin-top: 0.75rem;
  font-family: var(--font-client-mono);
  font-size: 0.55rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(250, 250, 250, 0.62);
}

.ol-pitch .cc-lightbox__out {
  color: rgba(250, 250, 250, 0.62);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  transition: color var(--dur-ui) var(--ease-spring);
}

.ol-pitch .cc-lightbox__out:hover,
.ol-pitch .cc-lightbox__out:focus-visible {
  color: var(--on-dark);
}

/* The close control sits on a dark backdrop here, not the blurred page. */
.ol-pitch .cc-lightbox--film .cc-lightbox__close {
  border-color: rgba(250, 250, 250, 0.28);
  background: rgba(9, 9, 9, 0.72);
  color: var(--on-dark);
}

.ol-pitch .cc-lightbox--film .cc-lightbox__close:hover,
.ol-pitch .cc-lightbox--film .cc-lightbox__close:focus-visible {
  background: var(--on-dark);
  color: #0d0d0d;
  border-color: var(--on-dark);
}

@media (max-width: 760px) {
  .ol-pitch .cc-lightbox__stage {
    width: min(94vw, calc((100svh - 7rem) * (var(--film-ar))));
  }
}

/* --- 18 / Contact ledger -----------------------------------------------------
   Otto asked for the closing contacts in the register Radical PR use on their
   own site: three identical blocks, one neutral grotesk at one size, set large
   on black, with the local time next to the name. That face is the deliberate
   exception in this deck — it is a quotation, so it stays a plain grotesk and
   does not borrow the Nimbus display or the mono. */
.ol-pitch .ol-ledger {
  --font-ledger: "Helvetica Neue", Helvetica, Arial, "Liberation Sans", sans-serif;
  margin-top: clamp(2.5rem, 5vw, 4rem);
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2.25rem, 4vw, 3.5rem);
  font-family: var(--font-ledger);
  font-size: clamp(1.05rem, 1.9vw, 1.65rem);
  font-weight: 400;
  letter-spacing: -0.012em;
  line-height: 1.22;
}

@media (min-width: 860px) {
  .ol-pitch .ol-ledger { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.ol-pitch .ol-ledger__head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5em;
}

/* Beats `body.ol-pitch h2, h3 { font-family: var(--font-client-display) }`
   further up — and the city is a span for the same reason. */
.ol-pitch .ol-ledger__city {
  text-transform: uppercase;
  color: var(--on-dark);
}

.ol-pitch .ol-ledger__meta {
  color: rgba(250, 250, 250, 0.42);
  font-variant-numeric: tabular-nums;
}

.ol-pitch .ol-ledger__lines {
  margin-top: 1.15em;
  color: var(--on-dark);
}

.ol-pitch .ol-ledger__coffee-copy {
  max-width: 26ch;
  margin-top: 1.15em;
  color: rgba(250, 250, 250, 0.62);
}

.ol-pitch .ol-ledger__link {
  display: inline-block;
  margin-top: 1.15em;
  color: var(--on-dark);
  text-decoration: underline;
  text-decoration-thickness: from-font;
  text-underline-offset: 0.16em;
  transition: color var(--dur-ui) var(--ease-spring);
}

.ol-pitch .ol-ledger__link:hover,
.ol-pitch .ol-ledger__link:focus-visible {
  color: rgba(250, 250, 250, 0.55);
}

.ol-pitch .ol-ledger__links {
  display: grid;
  justify-items: start;
  gap: 0.5rem;
  margin-top: 1.15em;
}

.ol-pitch .ol-ledger__links .ol-ledger__link {
  margin-top: 0;
}

/* A client mark standing in for a plate we hold no footage for. It deliberately
   does NOT carry .concept__rug-img: that class paints a white background, and
   brightness(0) blackens an element's own background too, which turned the
   plate into a solid black square. */
/* The breathing room around a plate is padding on the link, NOT subtracted from
   max-height. `calc(100% - 4rem)` went negative on a short plate (the mobile
   figure is ~110px tall) and clamped the mark to zero height — the Assembly logo
   loaded and then rendered 0x0. Same reason max-height is a plain 100%. */
.ol-pitch .ol-clientplate {
  max-width: min(70%, 240px);
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: brightness(0);
  opacity: 0.78;
}

/* A photographic client mark (index®) — black on a white ground, so it must NOT
   be flattened with brightness(0) (that blackens its own white background into a
   solid square). It sits as a plate like Assembly, just without the filter. */
.ol-pitch .ol-clientplate--photo {
  filter: none;
  opacity: 1;
  max-width: min(74%, 256px);
  max-height: 100%;
}

/* ============================================================================
   16 / DARK GROUNDS — Ottolinger's own contrast
   Two treatments:
     .ol-dark      a whole section on black, type in white
     .ol-splitdark one panel inside a section on black, the rest stays paper
   Both work by re-pointing the design tokens rather than restyling components,
   so every hairline, label and card that already reads `var(--bg)` /
   `var(--client-line)` / `var(--ink)` follows automatically.
   ========================================================================== */
.ol-pitch .ol-dark,
.ol-pitch .ol-splitdark {
  --bg: #0d0d0d;
  --fg: #fafafa;
  --ink: rgba(250, 250, 250, 0.78);
  --ink-strong: rgba(250, 250, 250, 0.93);
  --muted: rgba(250, 250, 250, 0.56);
  --faint: rgba(250, 250, 250, 0.14);
  --panel: #0d0d0d;
  --client: #fafafa;
  --client-brown: #fafafa;
  --client-line: rgba(250, 250, 250, 0.24);
  background: #0d0d0d;
  color: #fafafa;
}

.ol-pitch .ol-dark {
  border-top-color: rgba(250, 250, 250, 0.24);
}

/* Headings, leads and body copy all sit on --fg / --ink, which the block above
   already flipped. These few carry hard-coded colours upstream. */
.ol-pitch .ol-dark :is(h2, h3, .manifesto__line, .concept__title, .ol-project__name,
                       .ol-delivered__num, .ol-delivered__name, .conceptblock strong),
.ol-pitch .ol-splitdark :is(h3, .concept__title) {
  color: var(--fg);
}

.ol-pitch .ol-dark :is(.section__lead, .conceptblock p, .ol-delivered__note,
                       .concept__premise, .ol-project__meta),
.ol-pitch .ol-splitdark :is(.concept__premise, .concept__style) {
  color: var(--ink);
}

/* Logo wall on black: the marks are flattened to one white silhouette instead
   of one black one. */
.ol-pitch .ol-dark .clientlist img {
  filter: brightness(0) invert(1);
  opacity: 0.86;
}

/* The cube number/name plate. */
.ol-pitch .ol-dark .otto-cubebox__label,
.ol-pitch .ol-splitdark .otto-cubebox__label {
  background: #0d0d0d;
  color: var(--fg);
}

/* External-link chips invert on hover so they stay legible on black. */
.ol-pitch .ol-dark .ol-links a:hover,
.ol-pitch .ol-dark .ol-links a:focus-visible,
.ol-pitch .ol-splitdark .ol-links a:hover,
.ol-pitch .ol-splitdark .ol-links a:focus-visible {
  color: #0d0d0d;
  background: var(--fg);
  border-color: var(--fg);
}

/* Split treatment: only the brief panel of a season block goes black, so each
   block reads as one half image, one half statement. */
.ol-pitch .otto-direction-head .concept__brief.ol-splitdark {
  padding: var(--client-box-pad);
}

@media print {
  .ol-pitch .ol-dark,
  .ol-pitch .ol-splitdark {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
}

@media print {
  .ol-project__media {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
}

/* ============================================================================
   §17 — Intro block: natural wrapping, one measure

   The lead was three hand-set <span> lines forced to break identically at
   every width (`display:block`, and `white-space:nowrap` under 768px). On
   desktop the 48ch override let the block run 1319px wide while each line
   held ~25 characters, so two fifths of the row sat empty. The spans are gone
   from the markup; these rules give the paragraph a measure it can actually
   fill and let the browser balance the rag.
   ========================================================================== */
.ol-pitch .about__lead {
  max-width: 20ch;
  text-wrap: balance;
  hyphens: none;
}

/* The pair of identical --full / --short bodies collapsed into one, so the
   breakpoint toggle that used to hide one of them is no longer needed. */
.ol-pitch .about__body {
  display: grid;
  max-width: 44ch;
}

@media (max-width: 767px) {
  .ol-pitch .about__lead {
    max-width: 16ch;
    font-size: clamp(1.35rem, 7vw, 1.95rem);
  }
}

/* ============================================================================
   19 / Reading flow

   The original typefaces, hierarchy and monochrome language stay intact.
   These final overrides only tune measure, leading and spacing so longer copy
   reads comfortably without changing the deck's visual identity.
   ========================================================================== */
body.ol-pitch {
  --maxw: 1280px;
  --measure: 62ch;
  --gap-section: clamp(4rem, 7vw, 7rem);
  --client-line: rgba(13, 13, 13, 0.12);
  font-weight: 500;
}

.ol-pitch .ol-dark,
.ol-pitch .ol-splitdark {
  --client-line: rgba(250, 250, 250, 0.16);
}

.ol-pitch :is(.manifesto__line, .section__lead, .concept__title, .closing__line) {
  text-wrap: balance;
}

.ol-pitch :is(
  .section__lead,
  .manifesto__body,
  .concept__premise,
  .conceptblock p,
  .ol-delivered__note,
  .ol-network,
  .roster__lead,
  .closing__lead
) {
  max-width: var(--measure);
  font-size: clamp(1rem, 1.05vw, 1.075rem);
  font-weight: var(--w-read);
  line-height: 1.65;
}

.ol-pitch .section__lead {
  margin-top: clamp(0.9rem, 1.8vw, 1.35rem);
}

.ol-pitch .concept__brief {
  align-content: start;
  row-gap: clamp(0.75rem, 1.5vw, 1.25rem);
}

.ol-pitch .ol-project__body {
  gap: 0.5rem;
}

.ol-pitch .ol-project__meta {
  line-height: 1.5;
}

.ol-pitch .pkg__scope,
.ol-pitch .single__scope {
  max-width: 58ch;
  font-size: 1rem;
  font-weight: var(--w-read);
  line-height: 1.55;
}

.ol-pitch .single {
  grid-template-columns: minmax(10rem, 15rem) minmax(0, 58ch) auto;
  column-gap: clamp(1.25rem, 3vw, 2.5rem);
  padding-block: 1.15rem;
}

@media (max-width: 640px) {
  body.ol-pitch {
    --gap-section: 4rem;
  }

  .ol-pitch :is(
    .section__lead,
    .manifesto__body,
    .concept__premise,
    .conceptblock p,
    .ol-delivered__note,
    .ol-network,
    .roster__lead,
    .closing__lead
  ) {
    line-height: 1.6;
  }

  .ol-pitch .single {
    grid-template-columns: minmax(0, 1fr) auto;
    padding-block: 1rem;
  }
}

/* ============================================================================
   20 / Distillation

   Lines no longer carry the hierarchy. Space, scale and the media do. This
   keeps the original monochrome Nimmersatt language while removing the dotted
   frames and repeated UI scaffolding that made the deck feel overbuilt.
   ========================================================================== */
body.ol-pitch {
  --client-line: transparent;
  --faint: transparent;
}

.ol-pitch .ol-dark,
.ol-pitch .ol-splitdark {
  --client-line: transparent;
  --faint: transparent;
}

.ol-pitch :is(
  .nav,
  .section,
  .casefeature,
  .about__servicesblock,
  .about__services li,
  .ol-delivered,
  .ol-delivered__row,
  .ol-projects,
  .ol-tilegrid,
  .otto-direction-head,
  .concept__head,
  .conceptbody,
  .conceptstack__deck,
  .conceptstack__bar,
  .projectteams,
  .projectteam,
  .projectteam__crew,
  .projectperson,
  .partners,
  .partner,
  .clientlist,
  .pricing__packages,
  .pkg__disc,
  .singles,
  .single,
  .ol-clientnames,
  .closing__foot,
  .client-crown,
  .client-crown__meta,
  .client-crown__crawl
) {
  border: 0;
}

.ol-pitch :is(.hero__meta, .section__index)::before,
.ol-pitch .about__services li::after {
  display: none;
}

.ol-pitch .client-crown {
  box-shadow: none;
}

.ol-pitch :is(.ol-tilegrid, .ol-projects) {
  gap: 1.5rem;
  background: transparent;
}

.ol-pitch :is(.pricing__packages, .projectteam__crew, .partners, .clientlist) {
  gap: 2rem;
  background: transparent;
}

.ol-pitch .projectteams {
  gap: 1.5rem;
  background: transparent;
}

.ol-pitch .conceptbody {
  gap: 1rem;
  margin-top: 1rem;
  background: transparent;
}

.ol-pitch .ol-delivered {
  display: grid;
  gap: 1.5rem;
}

.ol-pitch .ol-links a {
  border: 0;
  padding-inline: 0;
}

.ol-pitch :is(.cc-lightbox__close, .reel__back, .reel__nav) {
  border: 0;
}

@media (max-width: 700px) {
  .ol-pitch :is(.ol-tilegrid, .ol-projects, .pricing__packages, .projectteam__crew, .partners, .clientlist) {
    gap: 1rem;
  }
}

/* ============================================================================
   21 / Artist overview

   One quiet list and one shared preview stage replace the compressed row of
   equal tiles. The small local clips play only while a name is hovered or
   focused; clicking still opens the full reel.
   ========================================================================== */
.ol-pitch #exchange {
  padding-block: clamp(6rem, 10vw, 8rem);
}

.ol-pitch .artist-preview-layout {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(3rem, 6vw, 6rem);
  align-items: start;
  margin-top: clamp(4rem, 8vw, 6rem);
}

.ol-pitch .artist-preview__list.projectteams {
  margin: 0;
}

.ol-pitch .artist-preview__list .projectteam {
  display: block;
  background: transparent;
}

.ol-pitch #exchange .artist-preview__list .projectteam__crew {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.ol-pitch #exchange .artist-preview__list .projectperson {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 1rem;
  min-height: 0;
  padding: 1.5rem 0;
  background: transparent;
  transition: opacity 320ms var(--ease-spring), transform 320ms var(--ease-spring);
}

.ol-pitch #exchange .artist-preview__list .projectperson:hover,
.ol-pitch #exchange .artist-preview__list .projectperson:focus-visible,
.ol-pitch #exchange .artist-preview__list .projectperson.is-previewing {
  background: transparent;
  transform: translateX(0.5rem);
  outline: none;
}

.ol-pitch #exchange .artist-preview__list .artist__name {
  font-size: clamp(1.5rem, 2.4vw, 2rem);
  line-height: 1.1;
}

.ol-pitch #exchange .artist-preview__list .artist__role {
  font-size: 0.875rem;
  line-height: 1.5;
}

.ol-pitch .artist-preview__stage {
  position: sticky;
  top: 6rem;
  margin: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(var(--space-3));
  pointer-events: none;
  transition:
    opacity 320ms var(--ease-out-quart),
    transform 320ms var(--ease-out-quart),
    visibility 0s linear 320ms;
}

.ol-pitch .artist-preview-layout.is-preview-active .artist-preview__stage {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition-delay: 0s;
}

.ol-pitch .artist-preview__video {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: var(--panel);
  filter: saturate(0.82) contrast(1.02);
}

.ol-pitch .artist-preview__caption {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1rem;
  font-family: var(--font-client-mono);
}

.ol-pitch .artist-preview__name {
  font-size: 1.25rem;
  font-weight: 700;
}

.ol-pitch .artist-preview__role {
  color: var(--muted);
  font-size: 0.875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.ol-pitch #exchange .roster__partners {
  margin-top: 8rem;
  padding-top: 0;
  border: 0;
}

.ol-pitch #exchange .roster__subhead {
  margin-bottom: 2rem;
}

.ol-pitch #exchange .partners {
  gap: 3rem;
}

.ol-pitch #exchange .partner {
  min-height: 0;
  padding: 0;
  background: transparent;
}

.ol-pitch #exchange .ol-network {
  margin-top: 3rem;
}

@media (max-width: 760px) {
  .ol-pitch #exchange {
    padding-block: 4rem;
  }

  .ol-pitch .artist-preview-layout {
    grid-template-columns: 1fr;
    gap: 2rem;
    margin-top: 4rem;
  }

  .ol-pitch .artist-preview__stage {
    display: none;
    position: static;
    width: 100%;
    margin: 0 0 var(--space-4);
    transform: translateY(var(--space-2));
  }

  .ol-pitch .artist-preview-layout.is-preview-active .artist-preview__stage {
    display: block;
  }

  .ol-pitch .artist-preview__caption {
    display: none;
  }

  .ol-pitch .artist-preview__video {
    aspect-ratio: 16 / 9;
  }

  .ol-pitch #exchange .artist-preview__list .projectperson {
    padding-block: 1.5rem;
  }

  .ol-pitch #exchange .roster__partners {
    margin-top: 6rem;
  }

  .ol-pitch #exchange .partners {
    gap: 2rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ol-pitch #exchange .artist-preview__list .projectperson {
    transition: none;
  }

  .ol-pitch .artist-preview__stage {
    transition: none;
  }
}

/* ============================================================================
   22 / Type, rhythm and restrained depth

   Two working faces stay in charge: Nimbus for statements, Apercu Mono for
   copy and labels. The hand-drawn hero wordmark remains a brand mark rather
   than becoming a third editorial register.
   ========================================================================== */
html:has(> body.ol-pitch) {
  overflow-x: clip;
}

body.ol-pitch {
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 1rem;
  --space-4: 1.5rem;
  --space-5: 2rem;
  --space-6: 3rem;
  --space-7: 4rem;
  --space-8: 6rem;
  --space-9: 8rem;

  --type-display-xl: clamp(3rem, 9vw, 8rem);
  --type-display: clamp(2.25rem, 5vw, 4.75rem);
  --type-heading: clamp(1.5rem, 2.4vw, 2rem);
  --type-body: clamp(1rem, 1.05vw, 1.075rem);
  --type-label: 0.875rem;

  --leading-display: 0.98;
  --leading-heading: 1.1;
  --leading-body: 1.65;
  --tracking-display: -0.035em;
  --tracking-label: 0.12em;

  --gap-section: clamp(6rem, 8vw, 8rem);
  font-family: var(--font-client-mono);
  font-size: var(--type-body);
  line-height: var(--leading-body);
  overflow-x: clip;
}

.ol-pitch .hero__title {
  font-size: var(--type-display-xl);
  letter-spacing: var(--tracking-display);
}

.ol-pitch :is(.manifesto__line, .closing__line) {
  font-family: var(--font-client-display);
  font-size: var(--type-display);
  font-weight: 700;
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
}

.ol-pitch :is(
  .concept__title,
  .ol-project__name,
  .pkg__name,
  .roster__subhead,
  .partner__name,
  .artist__name
) {
  font-family: var(--font-client-display);
  font-size: var(--type-heading);
  line-height: var(--leading-heading);
  letter-spacing: -0.02em;
}

.ol-pitch :is(
  .section__lead,
  .manifesto__body,
  .concept__premise,
  .conceptblock p,
  .ol-delivered__note,
  .ol-network,
  .roster__lead,
  .closing__lead,
  .pkg__scope,
  .single__scope
) {
  font-family: var(--font-client-mono);
  font-size: var(--type-body);
  line-height: var(--leading-body);
}

.ol-pitch :is(
  .section__index,
  .conceptblock__tag,
  .conceptblock__sub,
  .ol-creditblock__label,
  .ol-project__num,
  .ol-project__meta,
  .artist__role,
  .partner__role,
  .about__emailrole,
  .about__serviceslabel,
  .single__price,
  .pkg__price
) {
  font-family: var(--font-client-mono);
  font-size: var(--type-label);
  line-height: 1.5;
  letter-spacing: var(--tracking-label);
}

/* The media is deliberately taller than its clip. GSAP only moves these five
   selected images and films, leaving the text hierarchy completely still. */
@media (min-width: 768px) {
  .motion-on .ol-pitch [data-parallax] {
    overflow: hidden;
  }

  .motion-on .ol-pitch [data-parallax-media] {
    display: block;
    width: 100%;
    height: 112%;
    margin-top: -6%;
    object-fit: cover;
    will-change: transform;
  }
}

@media (max-width: 767px) {
  body.ol-pitch {
    --gap-section: var(--space-7);
    --type-display: clamp(2rem, 10vw, 3rem);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ol-pitch [data-parallax-media] {
    transform: none !important;
    will-change: auto;
  }
}

/* ============================================================================
   23 / Coloured ASCII film mask

   Typography stays in the established Nimmersatt system. Only the fashion film
   becomes coloured ASCII, clipped by the animated caterpillar GIF.
   ========================================================================== */
.ol-pitch .hero--masked-ascii {
  gap: var(--space-5);
}

.ol-pitch .hero-ascii__mask {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}

.ol-pitch .hero-ascii__canvas {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.ol-pitch .hero-montage__films,
.ol-pitch .hero__mark.hero-montage::after {
  transition: opacity 200ms var(--ease-out-quart);
}

.ol-pitch .hero__mark.hero-montage.is-ascii-ready .hero-montage__films,
.ol-pitch .hero__mark.hero-montage.is-ascii-ready::after {
  opacity: 0;
}

.ol-pitch .closing__line.closing__line--ascii {
  width: fit-content;
  max-width: min(100%, 48rem);
  margin-right: auto;
  font-family: var(--font-client-mono) !important;
  font-size: clamp(0.34rem, 0.58vw, 0.6rem) !important;
  font-weight: 500;
  line-height: 0.96 !important;
  letter-spacing: 0.01em !important;
}

.ol-pitch .closing__line--ascii .ascii-art {
  max-width: 100%;
  overflow: visible;
  padding: 0;
  font: inherit;
}

@media (max-width: 767px) {
  .ol-pitch .hero--masked-ascii {
    gap: var(--space-4);
  }

  .ol-pitch .hero--masked-ascii .hero__title {
    font-size: clamp(2rem, 8.5vw, 2.5rem);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ol-pitch .hero-montage__films,
  .ol-pitch .hero__mark.hero-montage::after {
    transition: none;
  }
}

/* ============================================================================
   §23 — Phone cut of the client wall and the recap / music cards
   Emilio, 04.09.26, two notes in one round.
   ========================================================================== */

/* --- 23a / Client wall on a phone -------------------------------------------
   "auf vier Zeilen anpassen, sodass wir mehrere Logos gleichzeitig sehen, aber
   bitte, dass da trotzdem Symmetrie drin ist. Es soll nicht unten links in die
   zwei sein."

   Four rows exactly, which is five marks across: 18 over five columns is
   5 + 5 + 5 + 3. Four across would have been five rows ending in the pair
   bottom left that he called out by name. The remainder of three is centred
   rather than left-aligned, so the block stays symmetric: the grid runs on ten
   half-tracks, every mark spans two, and the third-from-last is pinned to
   track 3, which lands the final three in the middle six tracks.
   The pin is written against a remainder of three. A wall whose count is a
   multiple of five needs the nth-last-child rule deleted with it. */
@media (max-width: 899px) {
  .ol-pitch .clientlist {
    grid-template-columns: repeat(10, 1fr);
  }

  .ol-pitch .clientlist li {
    grid-column: span 2;
  }

  /* Start AND end: `grid-column: span 2` above leaves the end line at auto, so
     overriding only the start would silently shrink this one cell to a single
     track. */
  .ol-pitch .clientlist li:nth-last-child(3) {
    grid-column: 3 / span 2;
  }
}

/* "auf Mobile sind die Logos viel zu groß." The cell was 110px tall for a 44px
   mark, which is why two of them filled a phone screen. Both come down, and the
   mark is allowed a wider share of the narrower cell so it does not also lose
   width. */
@media (max-width: 559px) {
  .ol-pitch .clientlist {
    gap: 0.75rem;
  }

  /* The cc-tapis base pads every cell with --client-row-pad, 15px a side. At a
     59px cell that left 28px for the mark itself, so the padding comes in with
     the cell. */
  .ol-pitch .clientlist li {
    min-height: 58px;
    padding: 0.3rem;
  }

  .ol-pitch .clientlist img {
    max-width: 92%;
    max-height: 26px;
  }
}

/* --- 23b / Recap and music cards on a phone ---------------------------------
   "die drei in einer Zeile ... das Wording drunter ... einfach in einer Zeile
   passt. Dafür kannst du auch gerne eine kleinere Fontgröße benutzen."

   Three across a 390px phone is a ~104px card, and the card body was still
   carrying desktop type: a 24px display name and a 14px label line with 0.16em
   tracking. Both are re-cut here, the row padding comes in so the text keeps
   its width, and the halves of the meta line that the section heading already
   states are dropped, which is what lets the rest sit on one line without
   truncating anything. Desktop is untouched. */
@media (max-width: 700px) {
  .ol-pitch .ol-projects {
    gap: 0.5rem;
  }

  .ol-pitch .ol-project__body {
    gap: 0.2rem;
    padding: 0.5rem 0.15rem 0;
  }

  .ol-pitch .ol-project__name {
    font-size: 0.8rem;
    line-height: 1.15;
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .ol-pitch .ol-project__meta {
    font-size: 0.5rem;
    letter-spacing: 0.06em;
    line-height: 1.4;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* The half already carried by "Event recaps." / "Music videos." above. */
  .ol-pitch .ol-project__meta-lead,
  .ol-pitch .ol-project__meta-tail {
    display: none;
  }
}
