/* ============================================================
   Round 12 - item 4: the case-study layer.

   The layer is opened from two shells (the homepage and films.html) that share
   no stylesheet, which is how it ended up styled in the old site's type system
   - Archivo Black headings and IBM Plex Mono chrome - while everything around
   it moved to Playfair and Helvetica. One sheet, loaded by both, owns it now.

   Load this last on both routes: it deliberately out-ranks legacy-bridge.css
   (which raises the site nav above the layer) and styles.css.
   ============================================================ */

/* ---- The layer owns the screen ------------------------------------------
   legacy-bridge.css gives the open state `z-index: 150` on the site nav -
   above the layer's 140 - which is why a case study opened with the full site
   header still painted across the top of it, the CTA colliding with the close
   control. Two headers stacked above the fold was most of what made these
   pages read as broken. The header stands down completely. */
body.project-open .site-nav.site-nav,
body.project-open .floating-logo {
  z-index: 1;
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
  transition: opacity 220ms ease, visibility 0s linear 220ms;
}

body.project-open .project-layer {
  z-index: 200;
}

/* ---- Close ---------------------------------------------------------------
   It was 11px of monospace tucked under the nav CTA. It is a control now. */
body.project-open .project-close.project-close {
  position: fixed;
  top: clamp(1rem, 2.2vw, 1.9rem);
  right: clamp(1rem, 2.2vw, 1.9rem);
  z-index: 210;
  display: inline-flex;
  gap: 0.6rem;
  align-items: center;
  height: auto;
  padding: 0.7rem 1.1rem;
  border: 1px solid rgba(244, 241, 235, 0.28);
  border-radius: 999px;
  background: rgba(6, 7, 10, 0.72);
  backdrop-filter: blur(16px) saturate(120%);
  -webkit-backdrop-filter: blur(16px) saturate(120%);
  color: #f4f1eb;
  font-family: Helvetica, Arial, sans-serif;
  font-size: 0.63rem;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  transition: background-color 220ms cubic-bezier(0.16, 1, 0.3, 1), border-color 220ms ease;
}
body.project-open .project-close.project-close:hover,
body.project-open .project-close.project-close:focus-visible {
  border-color: rgba(244, 241, 235, 0.6);
  background: rgba(244, 241, 235, 0.14);
  color: #f4f1eb;
}
body.project-open .project-close.project-close::after {
  width: 8px;
  height: 8px;
}

/* ---- Above the fold: the hero, and one identity block ------------------- */
.project-layer .project-hero {
  /* Tall enough that the first gallery head cannot peek under the fold at a
     900px-tall viewport: 94dvh plus the body's own top padding clears it. */
  height: 94dvh;
  min-height: 32rem;
  margin-top: 0;
}

/* One reading floor, weighted to the bottom third where the identity sits. */
.project-layer .project-hero::after {
  background: linear-gradient(
    to top,
    rgba(5, 6, 10, 0.9) 0%,
    rgba(5, 6, 10, 0.52) 22%,
    rgba(5, 6, 10, 0.08) 46%,
    transparent 62%
  );
}

.project-layer .project-hero-title {
  right: auto;
  bottom: clamp(2.4rem, 6vh, 5rem);
  left: clamp(1.4rem, 5vw, 4.5rem);
  max-width: min(92vw, 60rem);
}

.project-layer .project-hero-name {
  font-family: "Playfair Display", Georgia, serif;
  font-size: clamp(2.9rem, 7.4vw, 7.4rem);
  font-weight: 400;
  letter-spacing: -0.03em;
  line-height: 0.96;
  text-transform: none;
}

/* The one quiet line. Same label treatment the rest of the site uses. */
.project-layer .project-hero-context {
  margin: 1rem 0 0;
  color: rgba(244, 241, 235, 0.66);
  font-family: Helvetica, Arial, sans-serif;
  font-size: 0.63rem;
  font-weight: 400;
  letter-spacing: 0.18em;
  line-height: 1.5;
  text-transform: uppercase;
}

/* Nothing else is allowed above the fold. */
.project-layer .project-hero-client {
  display: none;
}

/* ---- The galleries ------------------------------------------------------ */
.project-layer .project-body {
  padding-top: clamp(3.5rem, 6vw, 6rem);
}

.project-layer .project-block-head {
  align-items: baseline;
  padding-inline: clamp(0.2rem, 1vw, 0.8rem);
  padding-bottom: 0.9rem;
}

.project-layer .project-block-head h2 {
  font-family: "Playfair Display", Georgia, serif;
  font-size: clamp(1.5rem, 2.4vw, 2.2rem);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1;
  text-transform: none;
}

.project-layer .project-block-head .section-label {
  color: rgba(244, 241, 235, 0.55);
  font-family: Helvetica, Arial, sans-serif;
  font-size: 0.63rem;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* 9/1 polish (Giovani: "the play buttons look off"). The play button is a
   grid with two children - the 64px disc and the caption - and its two auto
   rows split the frame in half, so the disc centred in the TOP half (56px
   above the frame's centre on a 16:9 tile, 115px on a 9:16) and the caption
   in the bottom half. Both leave the flow: the disc sits on the frame's true
   centre, its hover scale composed onto the same transform; the caption is a
   label along the bottom edge, inside the button's own scrim. The caption
   also leaves the layer's Helvetica for the site's label grammar - Plex Mono
   on uniform.css's --u-label / --u-track, the theater meta line's voice -
   one step under full ink with the sheet's own soft shadow so it stays
   legible over a bright poster. It wraps to two lines on a narrow tile
   rather than clip. */
.project-layer .project-video-play span {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) scale(1);
}

.project-layer .project-video-play:hover span {
  transform: translate(-50%, -50%) scale(1.06);
}

.project-layer .project-video-play small {
  position: absolute;
  right: 0.8rem;
  bottom: clamp(0.8rem, 1.5vw, 1.2rem);
  left: 0.8rem;
  margin: 0;
  color: var(--u-ink-2);
  /* the page's own label voice: .campaign-meta beside these tiles resolves
     to --int-body, and definitive-interior.css keeps Plex Mono out of the
     interior system on purpose - the tile speaks like its neighbours */
  font-family: var(--int-body, Helvetica, Arial, sans-serif);
  font-size: var(--u-label);
  font-weight: 400;
  letter-spacing: var(--u-track);
  line-height: 1.4;
  text-align: center;
  text-shadow: 0 2px 14px rgb(0 0 0 / 0.6);
  text-transform: uppercase;
  text-wrap: balance;
}

/* ---- More work ----------------------------------------------------------
   Five real projects with their real poster frames, in place of one enormous
   next-project plate. Clicking swaps the layer through the existing hash
   routing; the layer's own scroll resets to the top. */
.project-layer .project-more {
  padding: clamp(3.5rem, 7vw, 7rem) clamp(1.4rem, 5vw, 4.5rem) clamp(4rem, 8vw, 8rem);
  border-top: 1px solid rgba(244, 241, 235, 0.1);
}

.project-layer .project-more-head {
  margin-bottom: clamp(1.4rem, 2.6vw, 2.4rem);
}

.project-layer .project-more-head h2 {
  margin: 0;
  color: #f4f1eb;
  font-family: "Playfair Display", Georgia, serif;
  font-size: clamp(1.8rem, 3.4vw, 3.2rem);
  font-weight: 400;
  letter-spacing: -0.025em;
  line-height: 1;
  text-transform: none;
}

.project-layer .project-more-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: clamp(0.6rem, 1.1vw, 1.1rem);
}

.project-layer .project-more-card {
  display: block;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.project-layer .project-more-media {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 0.35rem;
  background: #0b0c0f;
}

.project-layer .project-more-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 900ms cubic-bezier(0.16, 1, 0.3, 1), opacity 320ms ease;
  opacity: 0.86;
}

.project-layer .project-more-card:hover .project-more-media img,
.project-layer .project-more-card:focus-visible .project-more-media img {
  opacity: 1;
  transform: scale(1.04);
}

.project-layer .project-more-name {
  display: block;
  margin-top: 0.7rem;
  color: rgba(244, 241, 235, 0.78);
  font-family: Helvetica, Arial, sans-serif;
  font-size: 0.63rem;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  transition: color 200ms ease;
}

.project-layer .project-more-card:hover .project-more-name,
.project-layer .project-more-card:focus-visible .project-more-name {
  color: #f4f1eb;
}

@media (max-width: 1100px) {
  .project-layer .project-more-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 720px) {
  .project-layer .project-hero { height: 82dvh; }
  .project-layer .project-more-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  body.project-open .project-close.project-close {
    padding: 0.6rem 0.9rem;
    font-size: 0.58rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .project-layer .project-more-media img { transition: opacity 160ms linear; }
  .project-layer .project-more-card:hover .project-more-media img { transform: none; }
}

/* ============================================================
   Round 13 - item 8: the layer zooms open, it does not arrive.

   The open/close geometry is in script.js (initProjects -> flip): the layer is
   scaled down by the clicked element's width and translated so the case
   study's above-the-fold lands centred on whatever was clicked, then released
   to identity. What belongs here is the timing. 440ms was tuned for a
   crossfade-ish arrival; a real zoom out of a small card needs the extra beat,
   and the film theater's expand (620ms, cubic-bezier(0.16,1,0.3,1)) is the
   reference the rest of the site is already using. Same easing, one notch
   quicker because the layer travels less far than a card does.

   The easing is heavily front-loaded, so opacity riding the same curve is
   effectively opaque by a third of the way in - the layer never sits
   half-transparent over the page while it grows.
   ============================================================ */
:root {
  --layer-dur: 560ms;
}

/* ============================================================
   ROUND 16 - Workstream B item 4. The layer on a phone.

   Measured opening from films.html on a 6x-throttled 390x844
   emulation, one scripted scroll of `.project-scroll` top to
   bottom (1529 ms of scrolling): 1768 ms of main-thread task
   time, 1676 ms of raster and 698 ms of image decode. The main
   thread was oversubscribed for the whole gesture, which is
   what "stutters" is.
   ============================================================ */

/* Item 1: the layer's headers centre with everything else at this width. The
   hero identity was pinned to the left margin, the block heads space-betweened
   a label against a title across 390px, and the More-work names hung left
   under centred tiles. Same axis as the route behind it now. */
@media (max-width: 700px) {
  .project-layer .project-hero-title {
    right: clamp(1.4rem, 5vw, 4.5rem);
    left: clamp(1.4rem, 5vw, 4.5rem);
    max-width: none;
    text-align: center;
  }

  .project-layer .project-block-head {
    flex-direction: column;
    align-items: center;
    gap: 0.35rem;
    text-align: center;
  }

  .project-layer .project-more-head,
  .project-layer .project-more-head h2,
  .project-layer .project-more-name { text-align: center; }

  /* The close pill is `position: fixed` over a scrolling layer, so its blur is
     a compositing pass on every frame of every scroll for the sake of a 2rem
     chip. Opaque instead - it sits over the layer's own near-black anyway. */
  body.project-open .project-close.project-close {
    background: rgba(6, 7, 10, 0.92);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  /* `content-visibility` on the five More-work posters was tried here and
     taken out again: image decode across the layer's full scroll measured
     743ms with it and 669-714ms without, i.e. it deferred nothing worth
     having, and the longest-task numbers moved with machine load rather than
     with the property. Nothing ships in this sheet that could not be shown to
     earn its place. */
}

/* Item B5 inside the layer. Two handoffs live here and both were
   cross-dissolves: the hero picture into the gallery ground, and the More-work
   posters into the cloned footer's star field, which rises 22rem above the
   footer's top edge and landed on them. Same three stages as the routes - the
   picture resolves to the ground colour on its own, a beat of black, then the
   field. The footer's own dead-zone mask comes from definitive-interior.css,
   which the layer inherits because the clone keeps the footer's class names. */
.project-layer .project-hero::after {
  background: linear-gradient(
    to top,
    #050505 0%,
    #050505 7%,
    rgba(5, 5, 5, 0.9) 16%,
    rgba(5, 5, 5, 0.52) 34%,
    rgba(5, 5, 5, 0.08) 52%,
    transparent 66%
  );
}

.project-layer .project-more {
  position: relative;
  /* No rule between the work and the closing grid: Round 14's principle holds
     inside the layer too, and the scrim below is what separates them now. */
  border-top: 0;
}

.project-layer .project-more::after {
  position: absolute;
  z-index: 2;
  right: 0;
  bottom: 0;
  left: 0;
  height: clamp(4rem, 8vw, 8rem);
  content: "";
  pointer-events: none;
  /* The layer's ground is #050505, not the document's #06070a - a scrim that
     resolved to the route's colour would leave a faintly lighter panel under
     the closing grid. It resolves to the ground it is actually sitting on. */
  background: linear-gradient(to bottom, rgba(5, 5, 5, 0) 0%, #050505 64%, #050505 100%);
}

/* ---- r89: the brand page loses its banner (Kyle at 56:23) ----
   The identity is a compact head now; the films grid is the first thing
   on the page, photography follows. The hero-film plumbing above stays
   for the day the banner is asked back - with no [data-hero-film] frame
   in the DOM it simply never runs. */
.project-layer .project-hero.is-compact {
  height: auto;
  min-height: 0;
  /* 9/1 polish (Giovani: the name sits too high in its band). The band runs
     from the fixed header's bottom edge - the interior header is a 5rem box
     (definitive-interior.css) - to the first block head. Measured before at
     1440x900: 28px of black above the name, 106px below, because the top
     pad was a 12vh clamp, the bottom a 2.2vh one, and the body's own 6vw
     lead-in stacked under that. One measure now, above and below: the
     layer's gallery lead-in, clamp(3.5rem, 6vw, 6rem), which the body no
     longer adds on top (next rule) - so the band reads even at every
     viewport height and width. */
  padding: calc(5rem + clamp(3.5rem, 6vw, 6rem)) clamp(1.4rem, 5vw, 4.5rem) clamp(3.5rem, 6vw, 6rem);
}
/* The compact head owns the space down to the first gallery. Sibling-scoped:
   the banner hero and the photo-only route keep .project-body's own lead-in. */
.project-layer .project-hero.is-compact + .project-body {
  padding-top: 0;
}
.project-layer .project-hero.is-compact::after { content: none; }
.project-layer .project-hero.is-compact .project-hero-title {
  position: static;
  max-width: min(92vw, 60rem);
}
.project-layer .project-hero.is-compact .project-hero-name {
  font-size: clamp(2.4rem, 5vw, 4.6rem);
  /* Optical centre, not box centre: Playfair's tall ascenders sit the glyph
     mass ~0.03em below the line box's middle (measured 2.3px at 72px), so the
     name rides that much high. A relative offset - no layout, no transform. */
  position: relative;
  top: -0.03em;
}

/* ---- r90l: the brand page opens on the brand's LIGHT — the lockup
   centred, a quiet bloom behind it, no count line. ---- */
.project-layer .project-hero.is-compact {
  position: relative;
  display: grid;
  place-items: center;
  text-align: center;
}
.project-layer .project-hero.is-compact::before { content: none; }
.project-layer .project-hero.is-compact .project-hero-title.is-mark {
  position: static;
  left: auto;
  right: auto;
  bottom: auto;
  margin: 0 auto;
  max-width: min(92vw, 60rem);
  text-align: center;
}
.project-layer .project-hero.is-compact .project-hero-lockup {
  display: block;
  margin: 0 auto;
  width: auto;
  height: auto;
  max-width: min(20rem, 64vw);
  max-height: 6.5rem;
}
.project-layer .project-hero.is-compact .project-hero-context { display: none; }

/* ---- 8/31: the More Work dual marquee (Giovani). Two counter-scrolling
   rows carrying every other partner; -50% translate over doubled sets
   loops seamlessly; hover pauses the row under the pointer; tiles carry
   the white lockup over the cover and the same hover preview loop as the
   wall. Reduced motion: static scrollable strips. ---- */
.project-layer .project-more-rows { display: grid; gap: 14px; overflow: hidden; }
/* 9/1 (Giovani): the CSS animation is retired - initMoreDrift in script.js
   drives the rows now (slow drift, hover eases to quarter speed, drag and
   horizontal swipe scrub). Static without the engine (reduced motion /
   coarse pointers, which keep native overflow scrolling below). */
.project-layer .project-more-row { display: flex; gap: 14px; width: max-content; will-change: transform; }
.project-layer .project-more-set { display: flex; gap: 14px; padding-right: 14px; }
.project-layer .project-more-rows .project-more-card { position: relative; flex: 0 0 auto; width: clamp(220px, 24vw, 320px); }
.project-layer .project-more-rows .project-more-media { position: relative; display: block; aspect-ratio: 16 / 9; overflow: hidden; }
.project-layer .project-more-rows .project-more-media img { width: 100%; height: 100%; object-fit: cover; }
.project-layer .project-more-rows .project-more-media .campaign-video { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; opacity: 0; transition: opacity 320ms ease; pointer-events: none; }
.project-layer .project-more-rows .project-more-card.is-preview-ready .campaign-video { opacity: 1; }
.project-layer .project-more-lockup { position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none; transition: opacity 300ms ease; }
.project-layer .project-more-card.is-preview-ready .project-more-lockup { opacity: 0; }
.project-layer .project-more-lockup img { max-width: calc(56% * var(--lk, 1)); max-height: calc(38% * var(--lk, 1)); object-fit: contain; filter: drop-shadow(0 2px 10px rgb(0 0 0 / 0.45)); }
@media (prefers-reduced-motion: reduce) {
  .project-layer .project-more-rows { overflow-x: auto; }
  .project-layer .project-more-row { animation: none; }
}


/* 9/1 (Giovani): a layer photo is a door - it lifts a breath under the
   hand, and the click opens the viewer below. */
.project-layer .project-media.is-photo { overflow: hidden; cursor: pointer; }
.project-layer .project-media.is-photo img {
  transition: transform 640ms cubic-bezier(0.22, 1, 0.36, 1), filter 420ms ease;
}
.project-layer .project-media.is-photo:hover img,
.project-layer .project-media.is-photo:focus-visible img { transform: scale(1.035); filter: brightness(1.06); }

/* ---- the photo viewer: nothing on it but the frame. The layer stays
   visible behind a deep blur that rises at the same pace the photo eases
   toward the viewport. Arrows are the film rail's own circles. ---- */
.kls-pv {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100dvh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  display: grid;
  place-items: center;
  overflow: hidden;
}
.kls-pv::backdrop {
  background: rgb(6 7 10 / 0.3);
  -webkit-backdrop-filter: blur(0px);
  backdrop-filter: blur(0px);
  transition: background 560ms ease, backdrop-filter 560ms cubic-bezier(0.22, 1, 0.36, 1), -webkit-backdrop-filter 560ms cubic-bezier(0.22, 1, 0.36, 1);
}
.kls-pv.is-open::backdrop {
  background: rgb(6 7 10 / 0.58);
  -webkit-backdrop-filter: blur(26px);
  backdrop-filter: blur(26px);
}
.kls-pv-img {
  max-width: min(92vw, 112rem);
  max-height: 86dvh;
  object-fit: contain;
  opacity: 0;
  transform: scale(0.9) translateY(2.5%);
  transition: transform 560ms cubic-bezier(0.22, 1, 0.36, 1), opacity 420ms ease;
  box-shadow: 0 3rem 9rem rgb(0 0 0 / 0.55);
  touch-action: pan-y;
}
.kls-pv.is-open .kls-pv-img { opacity: 1; transform: none; }
.kls-pv-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 3.6rem;
  height: 3.6rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: rgb(244 241 235 / 0.85);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  filter: drop-shadow(0 2px 12px rgb(0 0 0 / 0.65));
  transition: color 200ms ease, transform 320ms cubic-bezier(0.22, 0.61, 0.21, 1), opacity 200ms ease;
}
.kls-pv-nav.is-prev { left: clamp(0.7rem, 2.6vw, 2.2rem); }
.kls-pv-nav.is-next { right: clamp(0.7rem, 2.6vw, 2.2rem); }
.kls-pv-nav.is-prev:hover, .kls-pv-nav.is-prev:focus-visible { color: #fff; transform: translateY(-50%) translateX(-4px); }
.kls-pv-nav.is-next:hover, .kls-pv-nav.is-next:focus-visible { color: #fff; transform: translateY(-50%) translateX(4px); }
.kls-pv-x {
  position: absolute;
  top: clamp(0.9rem, 3vh, 1.8rem);
  right: clamp(0.9rem, 3vw, 2.2rem);
  display: grid;
  place-items: center;
  width: 2.8rem;
  height: 2.8rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: rgb(244 241 235 / 0.8);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  filter: drop-shadow(0 2px 10px rgb(0 0 0 / 0.65));
  transition: color 200ms ease, transform 260ms ease;
}
.kls-pv-x:hover, .kls-pv-x:focus-visible { color: #fff; transform: rotate(90deg); }
@media (max-width: 760px) {
  .kls-pv-nav { display: none; } /* the thumb swipes; arrows are desktop chrome */
  .kls-pv-img { max-width: 96vw; }
}
@media (prefers-reduced-motion: reduce) {
  .kls-pv::backdrop, .kls-pv-img { transition: none; }
  .kls-pv-img { opacity: 1; transform: none; }
  .kls-pv::backdrop { background: rgb(6 7 10 / 0.82); }
}

/* 9/1 (Giovani: "some of them are too low"): in the drifting rows a brand
   without a lockup file printed its NAME under the tile while lockups sat
   centered on it - two anatomies in one rail. Names overlay centered too,
   and fade the same way when the film wakes. */
.project-layer .project-more-rows .project-more-name {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  margin: 0;
  padding: 0 0.8rem;
  text-align: center;
  color: rgb(244 241 235 / 0.92);
  text-shadow: 0 2px 14px rgb(0 0 0 / 0.6);
  pointer-events: none;
  transition: opacity 300ms ease;
}
.project-layer .project-more-rows .project-more-card { position: relative; }
.project-layer .project-more-rows .project-more-card.is-preview-ready .project-more-name { opacity: 0; }
