/*
  PROJECT PAGES
  -------------
  A project title and its tagline on one line, then the video(s) — one centred
  column, with the frame navigation around it.

  The tagline moved up onto the title's line on 2026-09-10. It used to sit below
  the video, which on a two-video page left it most of a screen from the title it
  belongs to, reading as an orphan at the foot of the page.

  Two layouts, one stylesheet. A page is single-video by default; adding the
  class `project__videos--two` to the video row puts two side by side at the
  same size, which is what the two-up mockup shows.
*/

:root {
  /* Video width. The mockup has one video at ~32% of the frame width, and the
     two-up puts two of those side by side (~66% with the gap). The clamp keeps
     it sane on very small and very large screens. */
  --video-w: clamp(260px, 32vw, 620px);
  --video-gap: clamp(16px, 2.6vw, 40px);

  /* ASPECT RATIO — set PER VIDEO, not globally.
     The masters are not one shape. Measured from J:\WEBSITE MATT CHING\VIDEOS:
       1.000  Saturdays Spot 1        1920x1920   (square)
       1.333  Saturdays teaser        1920x1440   (4:3)
       1.437  AMD x2, Oofos, Stone Island x2      (open gate)
       1.456  Oakley                  4608x3164
       1.778  Adidas                  1920x1080   (16:9)
     A single value would letterbox or crop five of the nine. Each .project__video
     carries its own --aspect inline; this is only the fallback. */
  --video-aspect: 4448 / 3096;

  --type-project-title: 15px;   /* same as the nav */
  --type-caption: 15px;

  /* The flex gap spaces BOXES, but the eye reads INK. The title is all-caps, so
     its box extends below its ink by the descent the caps never fill — measured
     at 4px for 15px type — while the caption's ink starts flush with its box top.
     Equal gaps therefore look unequal: the title sits further from the video.
     This pushes the caption down by that difference so both read the same.
     Expressed in em so it tracks the type size. Re-measure if the size changes. */
  --caption-ink-offset: 0.267em;
}

.project {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* Keeps the column clear of the frame navigation on all four sides. The side
     items are rotated, so they need horizontal room, not vertical. */
  padding: clamp(72px, 11vh, 130px) clamp(66px, 8vw, 150px);
  box-sizing: border-box;
  gap: clamp(30px, 5vh, 62px);
}

/* THE HEADING WRAPPER DISSOLVES ON ANYTHING BIGGER THAN A PHONE.
   `display: contents` removes this div from the box tree entirely, so its two
   children become flex items of .project directly — exactly as they were before the
   wrapper existed. `order` then puts the caption back below the video, which is the
   desktop layout Matt signed off. The wrapper only becomes a real box on phones,
   where it puts the pair on one line (see the phone block at the foot of this file).
   Markup order stays title / caption / videos either way, which is the sensible
   reading order for a screen reader regardless of how it is painted. */
.project__head {
  display: contents;
}

.project__title  { order: 1; }
.project__videos { order: 2; }
.project__caption { order: 3; }

.project__title {
  margin: 0;
  font-family: "5by7", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: var(--type-project-title);
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.34em;
  text-indent: 0.34em;          /* balances the trailing letter-space — see site.css */
  text-transform: uppercase;
  text-align: center;
  color: var(--fg);
}

.project__videos {
  display: flex;
  gap: var(--video-gap);
  justify-content: center;
  align-items: center;
  width: 100%;
}

.project__video {
  width: var(--video-w);
  max-width: 100%;
  /* TWO aspect ratios per slot, and they can differ:
       --aspect          the video's real shape. Used to size the player.
       --display-aspect  the shape of the hole on the page. Defaults to --aspect.
     Where they differ the video is cropped to fill the hole, exactly like
     object-fit: cover — which an iframe cannot do on its own. Fullscreen ignores
     all of it and plays the video at its own shape. */
  aspect-ratio: var(--display-aspect, var(--aspect, var(--video-aspect)));
  background: #2f2e2f;          /* shows while the player loads, instead of a white flash */
  position: relative;
  overflow: hidden;
}

/* The iframe and the placeholder still both fill the slot exactly, so swapping
   one for the other cannot change the layout. */
.project__video > iframe,
.project__video > img {
  position: absolute;
  border: 0;
  display: block;
}

/* Images crop themselves. */
.project__video > img {
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Iframes cannot. The player letterboxes the video to whatever box it is given, so
   to crop instead of bar, the iframe is made big enough that the video covers the
   hole and is then clipped by the slot's overflow: hidden. --cover-w / --cover-h are
   worked out per slot; both are 100% wherever the two aspects match, which is most
   of them. */
.project__video > iframe {
  left: 50%;
  /* Vertical anchor is configurable because of the control bar. Bunny puts its
     controls along the bottom of the player and offers no way to hide them —
     ?controls=false is ignored. So on a slot that crops vertically, centring the
     iframe clips the control bar clean off, taking the fullscreen button with it.
     Anchoring the bottom edge instead keeps the whole bar in view and moves the
     entire crop to the top. --cover-anchor is 'center' by default (no crop, so it
     does not matter) and 'bottom' on slots that crop. */
  top: var(--cover-top, 50%);
  bottom: var(--cover-bottom, auto);
  transform: translate(-50%, var(--cover-shift, -50%));
  width: var(--cover-w, 100%);
  height: var(--cover-h, 100%);
}

/* CONTAIN variant — the opposite of the crop above.
   The slot takes the site's usual shape so the page furniture lines up with every
   other project, but the video keeps its own. It sits centred inside, at its real
   aspect, with the leftover space filled by the PAGE colour rather than the
   player's black — so it reads as a smaller video, not a letterboxed one.
   Nothing is cropped and every control stays reachable.
   Used on Adidas, the only 16:9 file in the set. */
.project__video--contain {
  background: var(--bg);
}

.project__video--contain > iframe,
.project__video--contain > .video-play {
  inset: auto;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  height: auto;
  aspect-ratio: var(--aspect);
}

/* Bottom-anchored variant, for vertically cropped slots. */
.project__video--anchor-bottom > iframe {
  --cover-top: auto;
  --cover-bottom: 0;
  --cover-shift: 0;
}

/* Fullscreen must undo the crop — this is the whole point of separating the two
   aspects. The browser sizes a fullscreen element itself; these rules stop the
   cover maths above from fighting it.

   `position: fixed; inset: 0`, NOT `position: static`. Static was wrong: browsers
   put a fullscreen element in the top layer and expect it fixed to the viewport, so
   a static one would be laid out inside the little video slot instead — a
   postage-stamp video on a black screen. Every current browser's built-in stylesheet
   forces fixed positioning with !important, so it never actually surfaced, but the
   rule should not be relying on being overruled. Stating it correctly also cancels
   the base rule's `left: 50%` / `top: 50%`, which do NOT carry !important anywhere. */
.project__video > iframe:fullscreen {
  position: fixed;
  inset: 0;
  transform: none;
  width: 100%;
  height: 100%;
}

.project__caption {
  margin: 0;
  margin-top: var(--caption-ink-offset);   /* see the note by the variable — optical */
  font-family: "5by7", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: var(--type-caption);
  line-height: 1;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  text-align: center;
  color: var(--fg);
}

/* Two-up pairs are matched on HEIGHT, not width.
   Matching width only works while both videos are the same shape. Saturdays pairs a
   1:1 with a 4:3, and at equal width the square would stand a third taller than its
   neighbour. Equal height sits them on a common top and bottom edge, which is what
   reads as a pair; their widths then follow from their own aspect ratios. For the
   pairs that ARE the same shape (AMD, Stone Island) this is identical to before. */
.project__videos--two .project__video {
  height: calc(var(--video-w) / (4448 / 3096));
  width: auto;
  max-width: none;
}

/* Two-up: on a narrow screen side-by-side would make each video useless, so the
   pair stacks and each one takes the width a single video would have had. */
@media (max-width: 860px) {
  .project__videos--two {
    flex-direction: column;
  }
  /* Stacked, so width is the constraint again, not height. */
  .project__videos--two .project__video {
    width: var(--video-w);
    height: auto;
    max-width: 100%;
  }
  .project {
    padding: clamp(64px, 10vh, 110px) clamp(28px, 7vw, 70px);
  }
  :root {
    --video-w: min(84vw, 620px);
  }

  /* THE TAGLINE JOINS THE TITLE THE MOMENT THE VIDEOS STACK.
     This breakpoint is where a two-video page turns into a column, which is exactly
     when a caption underneath stops working: it ends up a whole video away from the
     title it belongs to and reads as an orphan at the foot of the page. Above this
     width the pair is side by side and both are in view at once, so the caption
     stays under the video where it was designed to be.
     Aligned on the BASELINE, not the box: the two carry different tracking and the
     title is all-caps, so matching boxes would sit the ink at different heights.
     flex-wrap, so a longer name in future wraps rather than overflowing.
     No `order` needed — the base rule already sequences title 1 / caption 3, which
     inside this row puts the project name first. */
  .project__head {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: baseline;
    gap: 0.2em 0.6em;
    width: 100%;
  }
  .project__caption {
    margin-top: 0;
  }
}

/* PHONES — TIGHTER TRACKING SO THE HEADING STAYS ON ONE LINE.
   At the full 0.34em the longest pair (STONE ISLAND / 100 Questions) needs about
   325px, which does not fit a 375px screen once the page padding is taken off.
   Pulling the tracking in keeps every pair on one line at the same type size, which
   is much better than shrinking the page's own heading. Measured after: the widest
   is 280px against 319px of available width. */
@media (max-width: 560px) {
  /* Tracking tightens so the pair still fits one line at full type size. At 0.34em
     the longest pair (STONE ISLAND / 100 Questions) needs about 325px, which does
     not fit a 375px screen once the padding is off. Measured after: 266px against
     319px available. Shrinking the page's own heading would be the worse trade. */
  .project__title {
    letter-spacing: 0.15em;
    text-indent: 0.15em;       /* must always equal the tracking — see site.css */
  }
  .project__caption {
    letter-spacing: 0.1em;
    text-indent: 0.1em;
  }
}


/* ---------- Click-to-play ---------- */
/* The resting state of a video slot: our still, our play button, no Bunny chrome.
   The player is only loaded once this is pressed — see js/video.js. */

.video-play {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  display: block;
  overflow: hidden;
}

.video-play img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* A plain white triangle. No circle, no fill, nothing branded.
   Roughly a third of its original size, and flattened: the viewBox is 24x22
   rather than the near-equilateral 24x28, so it reads a little wider than tall. */
.video-play__icon {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: clamp(11px, 1.5vw, 18px);
  height: auto;
  display: block;
  fill: var(--fg);
  /* The stills run from near-black to near-white, so the mark carries its own
     shadow to stay readable on both — same reasoning as the spiral labels. */
  /* Softer than before — at this size a heavy shadow just muddies the mark. */
  filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.5));
  transition: fill 0.2s ease, transform 0.2s ease;
}

.video-play:hover .video-play__icon,
.video-play:focus-visible .video-play__icon {
  fill: var(--link-hover);
  transform: translate(-50%, -50%) scale(1.06);
}

.video-play:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 3px;
}
