/* ============================================================
   film.css — everything /film/ needs and nothing else.

     .frame      the scan primitive: a hairline on page black
     .film-*     the page: margins, intro, the camera beside it
     .strip-*    the row of selected frames
     .lb-*       the lightbox, and the gear in its bar
   ============================================================ */

/* ---------- shared frame primitive ---------------------------------------
   A scan sits on page black with a hairline, never on a dither field —
   same rule the wordmark plate follows. */

.frame {
  display: block;
  position: relative;
  background: var(--bg-0);
  border: 1px solid var(--fg-4);
  overflow: hidden;
  border-bottom: 1px solid var(--fg-4); /* beat the global `a` dotted rule */
}
.frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Scans render slightly cool against the bone foregrounds; pull them back. */
  filter: grayscale(0.12) contrast(1.04);
  transition: filter 160ms ease-in-out, opacity 160ms ease-in-out;
}
a.frame:hover img,
a.frame:focus-visible img {
  filter: grayscale(0) contrast(1.1) brightness(1.06);
}
a.frame:hover,
a.frame:focus-visible {
  border-color: var(--phthalo-bright);
}

/* ============================================================
   THE FILM PAGE — /film/

   `.shell` caps the body at 1400px and centres it, so on a wide viewport there
   is a band of nothing down each side. That band is where the film strips go:
   one canvas per margin, fixed to the viewport edge, running the full height.

   The strip itself never moves — it is fixed, and scrolling does not drag it
   about. What moves is its top fade. `--rail-fade` is the masthead's bottom
   edge in viewport coordinates, written by js/film.js on scroll, and the mask
   ramps from clear to solid over the 70px above it. So while the header is in
   place the strip simply starts underneath it, and as the header leaves the
   strip is drawn out from under it instead of being uncovered all at once.
   Without JavaScript --rail-fade stays 0 and the strip is a plain top fade.

   The gutter only exists above 1400px, so below 1520 the strips are absent and
   the body has the full width to itself.
   ============================================================ */

/* The header row above the body: marker, counts, and nothing on the right. */
.gal-head {
  border-bottom: var(--bd);
  padding: var(--s-5) 0 var(--s-4);
  display: flex;
  align-items: flex-end;
  gap: var(--s-4);
  flex-wrap: wrap;
}
.gal-head__meta {
  display: flex;
  gap: var(--s-4);
  font-size: var(--fs-micro);
  color: var(--fg-3);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}
.gal-head__spacer {
  flex: 1;
}

.film-layout {
  padding: var(--s-6) 0 var(--s-20);
}

.film-rail {
  display: none;
  position: fixed;
  top: 0;
  bottom: 0;
  /* Exactly the space `.shell` leaves over, edge to edge. Percent, not vw:
     the rail is fixed, so 100% is the viewport without the scrollbar, whereas
     100vw includes it and would push the left rail under the content. */
  width: calc((100% - 1400px) / 2);
  z-index: 0;
  pointer-events: none;
}
.film-rail--left {
  left: 0;
}
.film-rail--right {
  right: 0;
}
.film-rail canvas {
  width: 100%;
  max-width: 180px;
  height: 100%;
  margin: 0 auto;
  display: block;
  --rail-fade: 0px;
  -webkit-mask-image: linear-gradient(
    to bottom,
    transparent calc(var(--rail-fade) - 70px),
    #000 calc(var(--rail-fade) + 10px),
    #000 calc(100% - 90px),
    transparent 100%
  );
  mask-image: linear-gradient(
    to bottom,
    transparent calc(var(--rail-fade) - 70px),
    #000 calc(var(--rail-fade) + 10px),
    #000 calc(100% - 90px),
    transparent 100%
  );
}
/* Mirrored, so the two strips lean into the page rather than marching the
   same way down both edges. */
.film-rail--right canvas {
  transform: scaleX(-1);
}

@media (min-width: 1520px) {
  .film-rail {
    display: block;
  }
}

.film-intro {
  padding-bottom: var(--s-8);
  border-bottom: var(--bd);
  margin-bottom: var(--s-8);
}
/* Text left, the camera right — the same split, and the same proportions, as
   the profile and its globe on the root page. */
.film-intro__grid {
  display: grid;
  grid-template-columns: 1.9fr 1fr;
  gap: var(--s-6);
  align-items: center;
}
.film-intro__cam {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
}
.film-intro__cam canvas {
  width: clamp(140px, 20vh, 200px);
  height: clamp(140px, 20vh, 200px);
}
@media (max-width: 900px) {
  .film-intro__grid {
    grid-template-columns: 1fr;
  }
  .film-intro__cam {
    justify-content: flex-start;
  }
  .film-intro__cam canvas {
    width: 130px;
    height: 130px;
  }
}

.film-intro__lead {
  max-width: 74ch;
  margin: var(--s-4) 0 var(--s-4);
}
.film-intro__body {
  max-width: 74ch;
  display: grid;
  gap: var(--s-3);
}
.film-kit {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-6);
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: var(--bd-dashed);
  font-size: var(--fs-micro);
  color: var(--fg-3);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}
.film-kit b {
  color: var(--fg-1);
  font-weight: 600;
}

/* ---------- the selected frames ----------
   Justified rows: each frame's flex basis is its aspect ratio times the target
   row height and its grow is proportional, so a row fills the width and the
   heights only vary a little. Frames keep their own shape — portraits and
   squares stop fighting the grid — and the row height is deliberately modest,
   because at full height a single landscape eats the fold.

   The ::after with an enormous grow stops the last row stretching to fill. */

.strip__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-5);
}
.strip__row::after {
  content: "";
  flex-grow: 999999;
}
.strip__item {
  position: relative;
  display: block;
  height: 220px;
  flex-shrink: 1;
  /* So the gear overlay can drop its words when the frame is too narrow to
     carry them, which a media query cannot know. */
  container-type: inline-size;
}
.strip__item.ar-32 {
  flex-basis: 330px;
  flex-grow: 33;
}
.strip__item.ar-11 {
  flex-basis: 220px;
  flex-grow: 22;
}
.strip__item.ar-23 {
  flex-basis: 147px;
  flex-grow: 15;
}

@media (max-width: 900px) {
  .strip__item {
    height: 170px;
  }
  .strip__item.ar-32 {
    flex-basis: 255px;
  }
  .strip__item.ar-11 {
    flex-basis: 170px;
  }
  .strip__item.ar-23 {
    flex-basis: 113px;
  }
}

/* ============================================================
   LIGHTBOX — used by the sheet and the justified rows
   ============================================================ */

.lb {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(0, 0, 0, 0.94);
  display: none;
  grid-template-rows: 1fr auto;
  padding: var(--s-6);
  gap: var(--s-4);
}
.lb[data-open] {
  display: grid;
}
.lb__stage {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
}
.lb__stage img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border: 1px solid var(--fg-4);
}
/* Gear in the lightbox bar: the camera it was taken on and the cassette it was
   taken on, both live canvases retargeted per frame by js/film.js. */
.lb__gear {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding-right: var(--s-4);
  border-right: var(--bd);
  margin-right: var(--s-2);
}
.lb__body {
  width: 42px;
  height: 42px;
  flex: none;
}
.lb__roll {
  width: 26px;
  height: 45px;
  flex: none;
}
.lb__roll[hidden] {
  display: none;
}
.lb__gear-txt {
  display: flex;
  flex-direction: column;
  gap: 1px;
  line-height: 1.35;
  white-space: nowrap;
}
.lb__gear-txt b {
  color: var(--fg-1);
  font-weight: 600;
  letter-spacing: 0.04em;
}

@media (max-width: 760px) {
  .lb__gear {
    border-right: 0;
    padding-right: 0;
    width: 100%;
  }
}

.lb__bar {
  display: flex;
  align-items: baseline;
  gap: var(--s-4);
  flex-wrap: wrap;
  font-size: var(--fs-micro);
  letter-spacing: var(--tracking-wide);
  color: var(--fg-3);
  border-top: var(--bd);
  padding-top: var(--s-3);
}
.lb__title {
  color: var(--fg-0);
  font-size: var(--fs-tiny);
  letter-spacing: 0.04em;
}
.lb__spacer {
  flex: 1;
}
.lb__btn {
  background: none;
  border: var(--bd);
  color: var(--fg-2);
  font-family: var(--mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--tracking-wide);
  padding: 4px 10px;
  cursor: pointer;
}
.lb__btn:hover,
.lb__btn:focus-visible {
  color: var(--phthalo-vivid);
  border-color: var(--phthalo-bright);
}
