/* Ben Krueger: main site. Quiet frame, photographs first. */

:root {
  --bg: #fff;
  --fg: rgba(0, 0, 0, 0.85);
  --fg-soft: #5c5a55;
  --fg-faint: #9a978f;
  --rule: rgba(20, 20, 20, 0.12);
  --accent: #c24a2c;
  /* ben-krueger.com is set in Neue Haas Grotesk Text. Cargo's copy can't be served from
     another site, so this falls through to Helvetica Neue, its direct descendant, until a
     web licence is added (drop the files in src/static/fonts and a @font-face here). */
  --sans: 'Neue Haas Grotesk Text', 'Neue Haas Grotesk', 'NHaasGroteskTXPro-55Rg', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --mono: var(--sans);
  --nav-w: max(20vw, 15.5rem);
  --gutter: clamp(16px, 2.4vw, 32px);
  color-scheme: light;
}

* { box-sizing: border-box; }

/* Cargo scales the root size with the viewport: 15.55px at 1440 wide. */
html { -webkit-text-size-adjust: 100%; font-size: clamp(14px, 1.08vw, 19px); }

.site-body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 500 1rem/1.4 var(--sans);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

a { color: inherit; }
img { max-width: 100%; height: auto; }

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

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.skip {
  position: fixed;
  left: 12px;
  top: -60px;
  z-index: 100;
  padding: 10px 14px;
  background: var(--fg);
  color: var(--bg);
  border-radius: 6px;
}
.skip:focus { top: 12px; }

/* ---------- nav: the left-hand column from the Cargo site ---------- */

.site-nav {
  position: fixed;
  inset: 0 auto auto 0;
  z-index: 50;
  padding: 0.4rem 2.3rem 1rem 0.85rem;
  display: flex;
  flex-direction: column;
  font-size: 1rem;
  line-height: 1.4;
  font-weight: 500;
  color: #000;
}

.site-name {
  font-weight: 700;
  text-transform: uppercase;
  text-decoration: none;
}

.nav-panel { display: flex; flex-direction: column; gap: 1.4em; margin-top: 0; }
.nav-panel > .nav-group:first-child { margin-top: 0; }
.nav-group { display: flex; flex-direction: column; align-items: flex-start; }

.nav-label,
.nav-panel .nav-strong {
  font-size: 11px;
  line-height: 1.3;
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}

.nav-label { color: rgba(0, 0, 0, 0.85); opacity: 0.3; }

/* 365, the calendar of daily photographs: a small outlined folder tab standing on its
   own hairline, the same line drawing as the archive's drawers. */
.nav-365 { display: inline-flex; align-items: flex-end; margin-top: 0.3em; text-decoration: none; }
.nav-365::before,
.nav-365::after { content: ''; width: 0.45em; border-bottom: 1px solid currentColor; }
.nav-365::after { width: 1.4em; }
.nav-365 span {
  padding: 0.12em 0.6em 0.08em;
  border: 1px solid currentColor;
  border-bottom: 0;
  border-radius: 5px 5px 0 0;
  font-size: 11px;
  line-height: 1.45;
  font-weight: 700;
  letter-spacing: 0.3px;
  font-variant-numeric: tabular-nums;
}
.nav-panel a { text-decoration: none; color: #000; }

/* As on Cargo: the menu stays out of the photographs' way until you reach for it. */
@media (min-width: 861px) and (hover: hover) {
  .nav-panel a { opacity: 0; transition: opacity 0.35s cubic-bezier(.2, .8, .2, 1); }
  .site-nav:hover .nav-panel a,
  .site-nav:focus-within .nav-panel a { opacity: 0.3; }
  .site-nav:hover .nav-panel a:hover,
  .site-nav .nav-panel a:focus-visible,
  .nav-panel a[aria-current='page'],
  .nav-panel .nav-strong,
  .nav-panel .nav-365 { opacity: 1 !important; }
}

.nav-toggle,
.mobile-menu { display: none; }

/* The BK mark (traced from the logo, see mark.svg). Its 11-unit gaps are under a pixel
   at this size, so it is drawn with geometric precision rather than snapped. */
.mark {
  display: block;
  width: 30px;
  height: auto;
  aspect-ratio: 467 / 365;
  fill: currentColor;
  shape-rendering: geometricPrecision;
}

/* Desktop: as on Cargo, the mark sits small in the bottom-right corner and leads home.
   It turns a quarter-step when you reach for it. */
.brandmark {
  position: fixed;
  right: 15px;
  bottom: 15px;
  z-index: 45;
  color: #000;
  transition: rotate 0.5s cubic-bezier(.3, 1.4, .5, 1);
}
.brandmark .mark { width: 28px; }
.brandmark:hover { rotate: -8deg; }

.site-main {
  margin-left: var(--nav-w);
  min-height: 100svh;
  padding: var(--gutter);
}

.is-home .site-main { margin: 0; padding: 0; }

/* ---------- phones and narrow windows: Cargo's mobile menu ----------
   Measured from ben-krueger.com at 390px: no bar and no wordmark, just the BK mark in
   the top-right corner. It opens a full-screen sheet of white at 95% over the page:
   16px type at 1.4, section names in bold, their pages indented 28px, groups 28px
   apart, the page you're on at 20%, and a thin 50px × to close. Cargo snaps it open;
   here it comes up in a short fade with the links settling in after it. */

@media (max-width: 1080px) {
  .site-nav {
    position: fixed;
    inset: 0 0 auto auto;
    padding: 0;
    display: block;
  }
  .site-name,
  .nav-panel { display: none; }

  .brandmark { display: none; }

  /* One button, two marks. Opening, the BK turns a quarter and folds away into the
     middle while the × draws out from that same middle, turning in after it; closing
     runs it back. Both share the turn, so it reads as one mark becoming the other. */
  .nav-toggle {
    --turn: 0.52s cubic-bezier(.2, .8, .2, 1);
    position: fixed;
    top: max(7px, env(safe-area-inset-top));
    right: max(10px, env(safe-area-inset-right));
    z-index: 80;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    margin-top: -3px;
    padding: 0;
    border: 0;
    background: none;
    color: #000;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .nav-toggle > * { grid-area: 1 / 1; }
  .nav-toggle .mark {
    transition: rotate var(--turn), scale var(--turn), opacity 0.3s ease 0.06s;
  }
  /* Same scale as the mark: 30px for 467 units. */
  .mark-x {
    width: calc(300 / 467 * 30px);
    height: auto;
    aspect-ratio: 300 / 401.8;
    fill: currentColor;
    shape-rendering: geometricPrecision;
    overflow: visible;
    rotate: -90deg;
    scale: 0.6;
    opacity: 0;
    transition: rotate var(--turn), scale var(--turn), opacity 0.16s;
  }
  .mark-x path {
    transform-box: view-box;
    transform-origin: 150px 150px;
    transition: translate 0.24s cubic-bezier(.4, 0, 1, 1), scale 0.24s cubic-bezier(.4, 0, 1, 1);
  }
  /* Folded: the whole ribbon is drawn in to a point, the halves wait inside it. */
  .mark-x-b { scale: 0.2; }
  .mark-x-a1 { translate: 40px 40px; }
  .mark-x-a2 { translate: -40px -40px; }

  .has-menu .nav-toggle .mark { rotate: 90deg; scale: 0.2; opacity: 0; transition: rotate var(--turn), scale var(--turn), opacity 0.2s; }
  .has-menu .mark-x { rotate: 0deg; scale: 1; opacity: 1; transition: rotate var(--turn), scale var(--turn), opacity 0.2s ease 0.06s; }
  .has-menu .mark-x path { transition: translate 0.44s cubic-bezier(.2, .8, .2, 1) 0.1s, scale 0.44s cubic-bezier(.2, .8, .2, 1) 0.06s; }
  .has-menu .mark-x-b { scale: 1; }
  .has-menu .mark-x-a1, .has-menu .mark-x-a2 { translate: 0 0; }

  /* The menu always fits the screen: its rows (--rows, counted by the build: links plus 2
     labels) and 3 group gaps share the visible height, so each row grows on tall phones
     and shrinks on short ones. */
  .mobile-menu {
    --pad-top: max(12px, env(safe-area-inset-top));
    --pad-bottom: max(24px, env(safe-area-inset-bottom));
    --row: clamp(30px, calc((100dvh - var(--pad-top) - var(--pad-bottom)) / (var(--rows, 14) + 1.8)), 48px);
    position: fixed;
    inset: 0;
    z-index: 70;
    display: flex;
    flex-direction: column;
    gap: calc(var(--row) * 0.6);
    height: 100dvh;
    padding: var(--pad-top) 20px var(--pad-bottom) max(20px, env(safe-area-inset-left));
    overflow-y: auto; /* only past the 30px floor, e.g. a phone on its side */
    overscroll-behavior: contain;
    background: rgba(255, 255, 255, 0.95);
    color: #000;
    font: 600 clamp(17px, calc(var(--row) * 0.56), 24px)/1.2 var(--sans);
    letter-spacing: -0.015em;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.22s cubic-bezier(.2, .8, .2, 1), visibility 0s 0.22s;
  }
  .mobile-menu.is-open { opacity: 1; visibility: visible; transition-delay: 0s; }

  .mobile-menu-group { display: flex; flex-direction: column; align-items: stretch; }
  .mobile-menu-label { font-weight: 800; pointer-events: none; }
  .mobile-menu-label ~ a { margin-left: 32px; }
  /* Every row is one --row tall; the whole row is the touch target. */
  .mobile-menu a,
  .mobile-menu-label {
    display: flex;
    align-items: center;
    height: var(--row);
    flex: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .mobile-menu a {
    color: #000;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
  }
  /* The first row clears the close button. */
  .mobile-menu-group:first-child a { margin-right: 44px; }
  .mobile-menu a[aria-current='page'] { opacity: 0.2; }
  /* The 365 tab at menu size: the tab and its hairline share one height so they meet. */
  .mobile-menu a.nav-365 { margin-top: 0; }
  .mobile-menu .nav-365 span,
  .mobile-menu .nav-365::before,
  .mobile-menu .nav-365::after { box-sizing: border-box; height: 1.55em; }
  .mobile-menu .nav-365 span { display: inline-flex; align-items: center; padding: 0 0.5em; font-size: inherit; font-weight: 800; letter-spacing: 0; line-height: 1; }

  .mobile-menu-group {
    translate: 0 6px;
    opacity: 0;
    transition: translate 0.45s cubic-bezier(.2, .8, .2, 1), opacity 0.3s;
  }
  .mobile-menu.is-open .mobile-menu-group { translate: 0 0; opacity: 1; }
  .mobile-menu.is-open .mobile-menu-group:nth-of-type(2) { transition-delay: 30ms; }
  .mobile-menu.is-open .mobile-menu-group:nth-of-type(3) { transition-delay: 60ms; }
  .mobile-menu.is-open .mobile-menu-group:nth-of-type(4) { transition-delay: 90ms; }
  .mobile-menu.is-open .mobile-menu-group:nth-of-type(5) { transition-delay: 120ms; }


  .has-menu, .has-menu body { overflow: hidden; }

  .site-main { margin-left: 0; padding: 52px 16px 16px; }
}

/* ---------- home: the Cargo backdrop ---------- */

/* Measured from the live Cargo page: the backdrop fills the right 80% of the window
   and each photo is contained about 7.5vw in from its edges. */
.backdrop {
  position: fixed;
  inset: 0 0 0 20%;
  background: #fff;
}

.backdrop-slide {
  position: absolute;
  inset: 7.5vw;
  width: calc(100% - 15vw);
  height: calc(100% - 15vw);
  object-fit: contain;
  visibility: hidden;
}

@media (max-width: 1080px) {
  .backdrop { inset: 44px 0 0; }
  .backdrop-slide { inset: 16px; width: calc(100% - 32px); height: calc(100% - 32px); }
}

.backdrop-slide.is-on { visibility: visible; }
/* For the one frame in which both photographs are up, the newer one sits on top as a
   white sheet, so the old one can't show in its margins. */
.backdrop-slide.is-top { z-index: 1; background: var(--bg); }

/* ---------- series viewer ----------
   The photographs get the whole stage. The frame counter and the title sit together in
   the empty foot of the nav column (above the photo on narrow screens), and the
   introduction is a plate set in type that takes its place in the sequence. */

.series { position: relative; display: flex; flex-direction: column; height: calc(100svh - 2 * var(--gutter)); min-height: 420px; }

.page-title {
  margin: 0;
  font-size: 2.2rem;
  line-height: 1.2;
  font-weight: 400;
}

.series-meta {
  position: fixed;
  left: 0.85rem;
  bottom: var(--gutter);
  z-index: 40;
  width: calc(var(--nav-w) - 0.85rem - var(--gutter));
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  color: #000;
}

.series-count {
  display: flex;
  align-items: baseline;
  gap: 0.35em;
  margin: 0;
  font-size: 11px;
  line-height: 1.3;
  font-weight: 700;
  letter-spacing: 0.3px;
  font-variant-numeric: tabular-nums;
}
.series-count-now { min-width: 2ch; }
.series-count-of { opacity: 0.3; }

.series-title {
  margin: 0.15rem 0 0.9rem;
  font-size: 1rem;
  line-height: 1.25;
  font-weight: 500;
  text-wrap: balance;
}

/* On desktop the nav already lights the current series, so the title here is for
   screen readers only; phones, with the menu tucked away, still show it. */
@media (min-width: 1081px) {
  .series-title {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .series-count { margin-bottom: 0.9rem; }
}

.series-mode {
  padding: 0.45rem 0.85rem;
  border: 1px solid #000;
  border-radius: 999px;
  background: none;
  font: 700 11px/1 var(--sans);
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: #000;
  cursor: pointer;
  transition: background-color 0.2s, color 0.2s;
}
.series-mode:hover,
.series-mode[aria-pressed='true'] { background: #000; color: #fff; }

.series-stage {
  position: relative;
  flex: 1;
  min-height: 0;
  user-select: none;
  -webkit-user-select: none;
  touch-action: pan-y;
  overflow: hidden;
}

.series-frame {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  margin: 0;
  opacity: 0;
  visibility: hidden;
  /* Each frame is a whole white sheet, not just its photograph. The arriving sheet
     dissolves in over the leaving one, which stays put underneath until it is fully
     covered and then drops out. So the change is a true crossfade of one picture into
     the next: the stage never dips to white, and the old photograph never shows in the
     margins of a new one with a different shape. */
  background: var(--bg);
  transition: opacity 0s 0.42s, visibility 0s 0.42s;
}

/* On a phone a frame that leaves goes at once: the strip motion (or the plain fade-in
   of the next frame) carries the change, and nothing lingers in the letterbox. */
@media (hover: none) {
  .series-frame:not(.is-on) { transition: none; }
}

.series-frame.is-on {
  z-index: 1;
  opacity: 1;
  visibility: visible;
  transition: opacity 0.42s cubic-bezier(.2, .8, .2, 1);
}

.series-frame img {
  flex: 1;
  min-height: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: left center;
}

.series-frame figcaption {
  min-height: 1.5em;
  padding-top: 1rem;
  font: 500 0.65rem/1 var(--sans);
  letter-spacing: 0.015rem;
  text-transform: uppercase;
  color: #000;
  opacity: 0.75;
}

/* The introduction plate: the size and place of a 3:2 photograph, filled flat with a
   paper tone (or ink), the text set as large as it will go. --fit comes from the build,
   from the length of the text. */

.series-plate {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  container: plate / size;
}

.series-plate-card {
  --paper: #efede8;
  --ink: #111;
  width: min(100cqw, 150cqh);
  height: min(100cqh, 66.667cqw);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 1.5rem;
  padding: clamp(18px, 4.4cqmin, 64px);
  background: var(--paper);
  color: var(--ink);
  container-type: inline-size;
  overflow: hidden;
}

.is-ink .series-plate-card { background: var(--ink); color: #f4f2ee; }

.series-plate-title {
  margin: 0;
  font-size: 11px;
  line-height: 1.3;
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  opacity: 0.45;
}

.series-plate-text {
  max-width: 30em;
  font-size: max(15px, calc(var(--fit) * 1cqi));
  line-height: 1.12;
  font-weight: 500;
  letter-spacing: -0.018em;
  hanging-punctuation: first;
  overflow-y: auto;
  scrollbar-width: none;
}
.series-plate-text p { margin: 0; }
.series-plate-text p + p { margin-top: 1.12em; }

/* A tall stage (phones, narrow windows) gets an upright plate, so the type can stay big. */
@container plate (aspect-ratio < 1.15) {
  .series-plate-card {
    width: min(100cqw, 80cqh);
    height: min(100cqh, 125cqw);
  }
  .series-plate-text { font-size: max(15px, calc(var(--fit) * 1.3cqi)); }
}

/* Click either half to turn; the cursor says which way. */
.series-hit {
  position: absolute;
  z-index: 2;
  -webkit-tap-highlight-color: transparent;
  top: 0;
  bottom: 40px;
  width: 50%;
  border: 0;
  background: none;
  padding: 0;
}

.series-hit--prev { left: 0; cursor: w-resize; }
.series-hit--next { right: 0; cursor: e-resize; }

.series.is-index { height: auto; overflow: clip; }

.series-index {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(46%, 150px), 1fr));
  gap: 28px 18px;
  align-items: end;
  margin: 0;
  padding: 0;
  list-style: none;
}

.series-index button {
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  text-align: left;
  font: 700 10.5px var(--sans);
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: var(--fg-faint);
}

.series-index img,
.series-index-plate {
  width: 100%;
  height: auto;
  transition: opacity 0.2s, translate 0.3s cubic-bezier(.2,.8,.2,1);
}

.series-index-plate {
  display: block;
  aspect-ratio: 3 / 2;
  padding: 9%;
  background: #efede8;
  color: #111;
  overflow: hidden;
}
.series-index-plate span {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  overflow: hidden;
  font: 500 11px/1.15 var(--sans);
  letter-spacing: -0.01em;
  text-transform: none;
}
.is-ink .series-index-plate { background: #111; color: #f4f2ee; }

.series-index button:hover img,
.series-index button:hover .series-index-plate { translate: 0 -3px; }
.series-index button:hover > span:last-child { color: var(--fg); }

/* While the index is open the stage steps out of the way but keeps its size (frozen by
   the script in --stage-w / --stage-h). Taking it out of layout altogether collapsed the
   plate's container to nothing, and iOS Safari then repainted the introduction plate
   only in patches when it came back: black bars behind the text, white elsewhere. */
.series.is-index .series-stage {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--stage-w, 100%);
  height: var(--stage-h, 0);
  flex: none;
  opacity: 0;
  pointer-events: none;
}

@media (max-width: 1080px) {
  .series { height: calc(100svh - 52px - 16px); min-height: 420px; }
  .series.is-index { height: auto; overflow: clip; }
  .series-meta {
    position: static;
    width: auto;
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    column-gap: 16px;
    margin-bottom: 12px;
  }
  .series-count { grid-column: 1; grid-row: 1; }
  .series-title { grid-column: 1; grid-row: 2; margin: 0.1rem 0 0; font-size: 15px; }
  .series-mode { grid-column: 2; grid-row: 1 / span 2; }
  /* The photograph and its caption sit together in the middle of the stage, so a wide
     frame on a tall phone doesn't leave a well of white under it. */
  .series-frame { justify-content: center; }
  .series-frame img { flex: 0 1 auto; height: auto; max-height: calc(100% - 2.5rem); object-position: center; }
  .series-frame figcaption { padding-top: 0.75rem; }
  .series-plate { align-items: center; }
}

/* ---------- covers (section indexes) ---------- */

.covers .page-title { margin-bottom: 28px; }

.cover-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
  gap: 40px 24px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.cover { display: grid; gap: 4px; text-decoration: none; }

.cover img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  margin-bottom: 8px;
  transition: filter 0.3s, scale 0.6s cubic-bezier(.2,.8,.2,1);
}

.cover:hover img { scale: 1.015; }
.cover-title { font-weight: 500; font-size: 17px; }
.cover-meta { font: 500 11px var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--fg-faint); }
.cover--film img { aspect-ratio: 16 / 9; }

/* ---------- info ---------- */

.info {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1fr);
  gap: clamp(28px, 5vw, 80px);
  align-items: start;
  max-width: 1200px;
}

.info-portrait { margin: 0; position: sticky; top: var(--gutter); }
.info-portrait img { width: 100%; height: auto; display: block; }
.info-portrait figcaption { margin-top: 8px; font: 400 11px var(--mono); color: var(--fg-faint); letter-spacing: 0.06em; }

.info-text { font-size: clamp(18px, 1.6vw, 23px); line-height: 1.45; font-weight: 450; max-width: 34em; }
.info-text p { margin: 0 0 1em; }
.info-text a { text-decoration-thickness: 1px; text-underline-offset: 3px; }
.info-links { font: 500 12px var(--mono); letter-spacing: 0.1em; text-transform: uppercase; display: flex; gap: 22px; align-items: baseline; flex-wrap: wrap; }
.info-copy {
  font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit;
  background: none; border: 0; padding: 0; cursor: pointer;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px;
}

/* "Say hi and holler@ben-krueger.com", which reads aloud as "holler at Ben Krueger".
   The address is set a size up from the bio. Each character that differs between the
   written and spoken versions is a slot holding both; on hover (and once, when it first
   comes into view) the slots roll over in a ripple and the address becomes the sentence. */
.info-holler {
  margin: 1.6em 0 1.1em !important;
  font-size: 1.5em; line-height: 1.2; font-weight: 400; letter-spacing: -0.01em;
}
/* Two lines, so the address can change length without reflowing the sentence. */
.holler-lead { display: block; color: var(--fg-soft); }
.holler {
  white-space: nowrap; text-decoration: none;
  /* A drawn underline: text-decoration would skip the slots. */
  background: linear-gradient(currentColor, currentColor) 0 100% / 100% 1px no-repeat;
  padding-bottom: 2px;
}
.hm > span:not(.on) { display: none; }
.holler.is-ready .hm {
  display: inline-grid; vertical-align: bottom; overflow: hidden; white-space: pre;
  transition: width 0.55s cubic-bezier(.3, 1.25, .4, 1) var(--d, 0s);
}
/* Layers wait below the line; the showing one sits on it; the one leaving rises out. */
.holler.is-ready .hm > span {
  display: block; grid-area: 1 / 1; transform: translateY(105%); opacity: 0;
  transition: transform 0.55s cubic-bezier(.3, 1.25, .4, 1) var(--d, 0s), opacity 0.3s ease var(--d, 0s);
}
.holler.is-ready .hm > span.on { transform: none; opacity: 1; }
.holler.is-ready .hm > span.up { transform: translateY(-105%); opacity: 0; }
.holler.is-ready .hm > span.reset { transition: none; }

@media (max-width: 640px) {
  .info-holler { font-size: 1.32em; }
}

@media (max-width: 1080px) {
  .info { grid-template-columns: 1fr; }
  .info-portrait { position: static; max-width: 420px; }
}

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

.film { max-width: 1280px; }

.film-player {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #000;
  overflow: hidden;
}

.film-player iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

.film-poster {
  position: absolute;
  inset: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.film-poster img { width: 100%; height: 100%; object-fit: cover; display: block; transition: opacity 0.3s, scale 0.8s cubic-bezier(.2,.8,.2,1); }
.film-poster:hover img { opacity: 0.88; scale: 1.01; }

.film-play {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 76px;
  height: 76px;
  translate: -50% -50%;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.92);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
  transition: scale 0.25s cubic-bezier(.2,.8,.2,1);
}

.film-play::after {
  content: '';
  position: absolute;
  left: 53%;
  top: 50%;
  translate: -50% -50%;
  border-style: solid;
  border-width: 11px 0 11px 18px;
  border-color: transparent transparent transparent var(--fg);
}

.film-poster:hover .film-play { scale: 1.08; }

.film-head { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; margin: 22px 0 18px; }
.film-head h1 { margin: 0; font-size: 2.2rem; font-weight: 400; line-height: 1.2; }
.film-heading { margin: 0; font: 400 12px var(--mono); letter-spacing: 0.06em; color: var(--fg-soft); }

.film-body { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: clamp(24px, 5vw, 72px); }
.film-lede { margin: 0; font-size: clamp(17px, 1.5vw, 21px); line-height: 1.5; font-weight: 450; }
.film-lede p { margin: 0 0 1em; }
.film-lede p:last-child { margin-bottom: 0; }
.film-credits { font-size: 13px; line-height: 1.6; color: var(--fg-soft); }
.film-credits p { margin: 0 0 0.6em; }
.film-credits .credit-role { margin: 1.2em 0 0.2em; font: 500 10.5px var(--mono); letter-spacing: 0.14em; color: var(--fg-faint); }
.film-credits .credit-block { margin-bottom: 1em; }

.film-stills { columns: 2 320px; column-gap: 20px; margin-top: 56px; }
.film-stills figure { margin: 0 0 20px; break-inside: avoid; }
.film-stills img { display: block; width: 100%; height: auto; }
/* Captions match the series pages: small uppercase sans, softened. */
.film-stills figcaption { margin-top: 0.75rem; font: 500 0.65rem/1.3 var(--sans); letter-spacing: 0.015rem; text-transform: uppercase; color: #000; opacity: 0.75; }

.film-next { margin-top: 64px; padding-top: 18px; border-top: 1px solid var(--rule); }
.film-next a { display: flex; flex-direction: column; gap: 4px; text-decoration: none; font-size: clamp(20px, 2vw, 28px); font-weight: 500; }
.film-next span { font: 500 10.5px var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--fg-faint); }

@media (max-width: 1080px) {
  .film-body { grid-template-columns: 1fr; }
}

.not-found { min-height: 70svh; display: grid; place-content: center; text-align: center; }
.not-found h1 { font-weight: 500; font-size: clamp(28px, 4vw, 48px); margin: 0 0 12px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}
.series-index[hidden] { display: none; }

/* ---------- page transitions ----------
   Same-origin page loads cross-fade with a short rise; the header holds still. */

@view-transition { navigation: auto; }

::view-transition-old(root) { animation: 160ms cubic-bezier(.4, 0, 1, 1) both vt-out; }
::view-transition-new(root) { animation: 480ms cubic-bezier(.2, .8, .2, 1) 40ms both vt-in; }
::view-transition-group(chrome) { animation-duration: 0s; }

@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; translate: 0 10px; } }

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}
.site-nav { view-transition-name: chrome; }

/* A film's own website, e.g. PARACHUTE. */
.film-site {
  display: inline-flex;
  gap: 6px;
  margin-top: 10px;
  padding: 0.5rem 1rem;
  border: 1px solid #000;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  text-decoration: none;
  color: #000;
  transition: background-color 0.2s, color 0.2s;
}
.film-site:hover { background: #000; color: #fff; }
.film-site-credit { margin: 0; font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.015rem; opacity: 0.75; }

/* ---------- landscape lightbox ----------
   A phone turned on its side shows the series alone: each photograph as large as the
   screen allows, on black, its caption beneath, swiped one to the next. */

.lb {
  position: fixed;
  inset: 0;
  z-index: 200;
  overflow: hidden;
  background: #000;
  color: #fff;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  opacity: 0;
  transition: opacity 0.32s cubic-bezier(.2, .8, .2, 1);
}
.lb.is-in { opacity: 1; }
.lb[hidden] { display: none; }
.lb:focus { outline: none; }

.lb-track {
  display: flex;
  height: 100%;
  will-change: transform;
}

.lb-slide {
  flex: 0 0 100%;
  height: 100%;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding:
    max(8px, env(safe-area-inset-top))
    max(16px, env(safe-area-inset-right))
    max(8px, env(safe-area-inset-bottom))
    max(16px, env(safe-area-inset-left));
}

.lb-slide img {
  flex: 0 0 auto;
  width: 100%;
  height: calc(100% - 26px);
  object-fit: contain;
  scale: 0.985;
  transition: scale 0.5s cubic-bezier(.2, .8, .2, 1);
  pointer-events: none;
}
.lb.is-in .lb-slide img { scale: 1; }

.lb-slide figcaption {
  min-height: 14px;
  font: 500 0.65rem/1.2 var(--sans);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-align: center;
  color: rgba(255, 255, 255, 0.62);
}

.has-lb, .has-lb body { overflow: hidden; }
.has-lb .site-nav, .has-lb .site-main { visibility: hidden; }

/* Only the gestures we handle: no double-tap zoom anywhere. */
html { touch-action: manipulation; }

/* Photos are for looking at: no long-press save sheet, no dragging them off the page. */
img,
video,
.series-frame { -webkit-touch-callout: none; -webkit-user-drag: none; user-select: none; -webkit-user-select: none; }

/* AVIF photos come wrapped in <picture>; it must not change layout. */
picture { display: contents; }
