:root {
  --cream: #F5F4ED;
  --oxblood: #6A1500;
  --black: #050505;

  /* Driven by JS. --s: continuous video shrink, --p: colour flip, --q: scatter */
  --s: 0;
  --p: 0;
  --q: 0;

  /* Light page from the start (no black phase). Text starts cream over the
     full-bleed video and the nav quickly flips to oxblood as the cream bg shows
     through (driven in main.js). */
  --nav-color: var(--cream);
  --page-bg: var(--cream);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: auto; }

body {
  background: var(--page-bg);
  color: var(--oxblood);
  font-family: "neue-haas-grotesk-display", "Neue Haas Grotesk Display Pro",
               "Helvetica Neue", Arial, sans-serif;
  font-size: 0.8125rem; /* 13px */
  font-feature-settings: "kern" 1;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* ======================= NAV ======================= */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
  padding: 44px 50px 0;
  color: var(--nav-color);
  mix-blend-mode: normal;
}

.nav__logo { display: inline-block; line-height: 0; color: var(--nav-color); }
.nav__logo svg { width: 47px; height: auto; display: block; }
.nav__logo svg path { fill: currentColor; transition: fill .1s linear; }

.nav__center {
  grid-column: 2;
  display: flex;
  align-items: center;
  gap: 10px;
  justify-self: center;
  padding-top: 4px;
  font-family: "neue-haas-grotesk-display", "Neue Haas Grotesk Display Pro",
               "Helvetica Neue", Arial, sans-serif;
  font-size: 0.75rem; /* 12px */
  line-height: 1.09;
  text-transform: uppercase;
  white-space: nowrap;
}
.nav__eyebrow { font-weight: 700; }
.nav__rule { width: 16px; height: 1px; background: currentColor; display: inline-block; }
.nav__date { font-weight: 700; }
.nav__venue {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  font-weight: 500;
}

.nav__menu {
  grid-column: 3;
  justify-self: end;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  font-family: "neue-haas-grotesk-display", "Neue Haas Grotesk Display Pro",
               "Helvetica Neue", Arial, sans-serif;
  font-size: 0.8125rem; /* 13px */
  line-height: 0.9;
  font-weight: 700;
  text-transform: uppercase;
}
.nav__menu a { color: inherit; text-decoration: none; transition: opacity .2s ease; }
.nav__menu a:hover { opacity: .55; }

/* ======================= HERO ======================= */
/* Tall stage: phase 1 = full-bleed -> card, phase 2 = clips scatter around it */
.hero { position: relative; height: 260vh; }

.hero__sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

/* One continuous shrink driven by --s (full-bleed -> final card). Radius fades
   in with --p so the rounding appears as the background flips to cream. */
.hero__media {
  --w: calc(100vw - (100vw - 46vw) * var(--s));
  --h: calc(100vh - (100vh - 58vh) * var(--s));
  --r: calc(20px * var(--p));
  position: relative;
  z-index: 10;
  width: var(--w);
  height: var(--h);
  border-radius: var(--r);
  overflow: hidden;
  transform: translateY(var(--mshift, 0px)); /* light exit rise, driven by JS */
  will-change: width, height, transform;
}

.hero__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* turns black & white as it scatters (frame 3) */
  filter: grayscale(var(--q));
}

/* Scattered clips (small, no blur) revealed around the same hero video in phase 2.
   Depth (0..1) drives size, stacking and parallax speed only. */
.clip {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  aspect-ratio: 3 / 4;
  border-radius: 3px;
  overflow: hidden;
  opacity: 0; /* JS reveals + parallaxes in phase 2 */
  /* far clips behind the hero video, near clips in front */
  z-index: calc(4 + 30 * var(--depth));
  transform: translate(-50%, -50%) translateY(var(--shift, 0px));
  will-change: transform, opacity;
  box-shadow: 0 12px 26px rgba(10, 4, 0, calc(.14 * var(--depth)));
}
.clip video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.hero__caption {
  position: absolute;
  /* Above the video (z-index:10) so the text is actually visible, not painted
     behind it. Position, alignment and colour are all driven by JS across the
     hero scroll (the CAP_* knobs in main.js): it starts bottom-left over the
     full-bleed video, left-aligned and cream (matching Web Design/1.jpg), and
     lands centred just below the resolved card, centre-aligned and oxblood, at
     the first snap stop. It then rides the SAME --mshift as the video, so the
     two leave together instead of the text fading out first. */
  left: var(--cap-x, 12.8%);
  top: var(--cap-y, 81%);
  max-width: 320px;
  z-index: 20;
  transform: translate(var(--cap-tx, 0%), -50%) translateY(var(--mshift, 0px));
  text-align: var(--cap-align, left);
  color: var(--cap-color, var(--cream));
  font-weight: 700;
  font-size: 14px;
  line-height: 1.14;
  text-transform: uppercase;
  pointer-events: none;
  will-change: transform, color;
}

/* Each line is its own row, as drawn. Without this the spans run inline and
   re-wrap to the block width, collapsing the three lines into two. */
.hero__cap-line { display: block; }

.hero__scrollcue {
  position: absolute;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  opacity: var(--p);
  transition: opacity .2s ease;
}
.hero__pill {
  display: block;
  width: 34px;
  height: 6px;
  border-radius: 6px;
  background: var(--oxblood);
  opacity: .5;
}

/* ======================= WORKS / PROJECTS SLIDER ======================= */
.works {
  position: relative;
  min-height: 100vh;
  background: var(--cream);
  color: var(--oxblood);
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
  padding: 8vh 0 0;
  /* Pull the section up into the hero's sticky trailing so the resolved video
     card hands off directly to the projects instead of scrolling through an
     empty viewport first.
       hero is 260vh, so its scroll range is 160vh
       stop 1 (video resolved) = HERO_STOP 0.42 x 160vh = 67.2vh
       this margin puts .works at 260 - 91 = 169vh
     which is 1.8vh below the fold at stop 1 (just out of sight) and means the
     projects start rising the moment you scroll off it. Anything less negative
     re-opens a band of empty cream between the two. */
  margin-top: -91vh;
}

.works__viewport {
  position: relative;
  width: 100%;
  height: 34vh;
}

/* All projects sit across the screen as a centered strip. The active project is
   always re-ordered into the middle slot (see main.js), with the rest wrapping
   out symmetrically on either side. */
.works__track {
  position: absolute;
  inset: 0;
}

/* Each item is absolutely centred, then pushed to its slot with an animated
   translateX (--x) driven by main.js. Because every slide shares the same
   origin and only its transform changes, a change of active makes the whole row
   glide one slot instead of snapping. --sc grows the centre item. */
.work {
  position: absolute;
  left: 50%;
  top: 50%;
  /* Height is definite; aspect-ratio derives the width so the 4:5 source is
     never cropped. Size changes come from --sc so they never reflow. */
  height: 15vh;
  width: auto;
  aspect-ratio: 4 / 5;
  cursor: pointer;
  transform: translate(-50%, -50%) translateX(var(--x, 0px)) scale(var(--sc, 1));
  transform-origin: center center;
  transition:
    transform 1.6s cubic-bezier(.33, 0, .2, 1),
    opacity 1.3s cubic-bezier(.33, 0, .2, 1),
    filter 1.6s cubic-bezier(.33, 0, .2, 1);
  will-change: transform, opacity, filter;
}
.work img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: 10px;
  box-shadow: 2px 5px 5px rgba(20, 6, 0, .12);
}

/* Edge gradients fading the outer projects into the cream bg. Sit ABOVE the
   slides (which JS gives z-index up to 20) so the fade actually covers them;
   stay below the nav (z-index 50). */
.works__fade {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 26vw;
  pointer-events: none;
  z-index: 30;
}
.works__fade--left {
  left: 0;
  background: linear-gradient(90deg, var(--cream) 30%, rgba(245, 244, 237, 0) 100%);
}
.works__fade--right {
  right: 0;
  background: linear-gradient(270deg, var(--cream) 30%, rgba(245, 244, 237, 0) 100%);
}

/* Center caption under the active slide */
.works__caption {
  text-align: center;
  margin-top: 3.5vh;
  text-transform: uppercase;
  font-size: 0.75rem;
  line-height: 1.5;
  min-height: 5.5em;
  transition: opacity .5s ease;
}
.works__caption .wc-title { font-weight: 700; margin-bottom: 1.2em; }
.works__caption .wc-line { display: block; font-weight: 500; }
.works__caption.is-fading { opacity: 0; }

/* Bottom-left index. A 2-column grid so every year aligns in its own column,
   independent of name length. Bold throughout; the active row is full oxblood
   while the rest are a muted tint. */
.works__index {
  position: absolute;
  left: 50px;
  bottom: 44px;
  list-style: none;
  display: grid;
  grid-template-columns: auto auto;
  column-gap: 2.4em;
  row-gap: 0.12em;
  font-size: 0.8125rem; /* 13px */
  line-height: 1.15;
  font-weight: 700;
  text-transform: uppercase;
}
/* Each row's name + year become cells of the shared grid so columns align. */
.works__index li { display: contents; cursor: pointer; }
.works__index .wi-name,
.works__index .wi-year {
  color: var(--oxblood);
  opacity: .38;
  transition: opacity .4s ease;
}
.works__index li:hover .wi-name,
.works__index li:hover .wi-year { opacity: .6; }
.works__index li.is-active .wi-name,
.works__index li.is-active .wi-year { opacity: 1; }

/* ======================= ABOUT / STUDIO ======================= */
/* One full panel, laid out per Web Design/6.jpg: portrait + credit links on the
   left, statement + justified bio on the right, footer centred at the bottom.
   Both columns hang off the same 50px gutters the nav uses; the gap down the
   middle is intentional dead space. */
.about {
  position: relative;
  min-height: 100vh;
  background: var(--cream);
  color: var(--oxblood);
  display: flex;
  flex-direction: column;
  /* Top padding keeps the statement clear of the fixed nav, which runs to about
     118px (44px offset + five 13px rows). The px floor matters on short screens:
     8vh alone is only 72px at 900px tall, which the nav would overlap.
     The side gutters live on the children, not here, so .footer can carry its
     own and stay self-contained on pages that have no .about wrapper. */
  padding: max(130px, 8vh) 0 0;
}

.about__inner {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: 6vw;
  /* "safe" centres only while there is room; once the copy is taller than the
     panel it falls back to start-alignment instead of overflowing upward behind
     the nav. */
  align-content: safe center;
  padding: 0 50px;
}

/* LEFT: the credit links tuck against the portrait's bottom-right corner.
   align-self keeps the column at its content height so the portrait tops out
   level with the statement opposite it, rather than being stretched and pushed
   to the bottom of the row. */
.about__left {
  align-self: start;
  display: flex;
  align-items: flex-end;
  gap: 30px;
}

/* Height is definite and aspect-ratio derives the width, so the 2:3 source
   (bio.jpg is 734x1100) is never cropped or stretched. */
.about__portrait {
  flex: none;
  height: 39vh;
  width: auto;
  aspect-ratio: 2 / 3;
}
.about__portrait img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: 10px; /* matches the works slider images */
}

.about__links {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.6em;
  padding-bottom: 0.25em;
}
.about__link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
}
.about__link-icon { display: inline-flex; line-height: 0; }
/* The rule sits under the label only, clear of the arrow icon, as drawn. */
.about__link-text {
  font-size: 0.8rem; /* set explicitly, not fluid like the rest of the panel */
  font-weight: 700;
  text-transform: uppercase;
  white-space: nowrap;
  border-bottom: 1px solid currentColor;
  padding-bottom: 3px;
}

/* RIGHT: statement and bio share the right gutter; the bio runs in a narrower
   measure than the statement above it. */
.about__right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}
/* Type in this panel is fluid rather than fixed px. The design frame is drawn at
   a 2048px viewport, so each size is expressed as the vw it occupies there (e.g.
   the statement is 28px at 2048 = 1.37vw) and clamped so it stays readable on
   small screens and keeps growing on large ones. Pinning these to px made the
   whole panel read ~11% small on a 2272px display. */
.about__title {
  text-align: right;
  font-weight: 500;
  font-size: 1.9rem; /* set explicitly, not fluid like the rest of the panel */
  line-height: 1.22;
  letter-spacing: -0.01em;
  margin-bottom: 3.2vh;
}
.about__bio {
  width: 74%;
  font-weight: 500;
  font-size: 15px; /* set explicitly, not fluid like the rest of the panel */
  line-height: 1.2;
  text-align: justify;
}
.about__bio p + p { margin-top: 1.1em; }

/* ======================= COLLECTION PAGE ======================= */
/* Per Web Design/Frame 94.jpg. Two column widths, both centred and both taken
   from the 2048px design frame: the caption row is wider (1602/2048) than the
   image grid (1326/2048) so the medium and year hang outside the plates. */
.collection {
  --grid-w: 64.75%;
  --head-w: 78.2%;
  /* 15px at the 2048px design width. Must be a LENGTH, not a percentage: a
     percentage row-gap resolves against the grid's own (auto) height, which is
     circular and silently corrupts the auto row heights. */
  --gap: 0.73vw;
  /* Top clears the fixed nav (~130px); bottom is the 207px gap to the footer
     rule in the design, as a share of the 2048px frame. */
  padding: 160px 0 10.1%;
}

/* Pages that are cream from the very top need the nav in oxblood immediately.
   index.html leaves this alone: there main.js drives --nav-color from cream to
   oxblood as the hero video resolves. */
body.page-cream { --nav-color: var(--oxblood); }

.collection__head {
  width: var(--head-w);
  margin: 0 auto 33px;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 4vw;
}
.collection__medium,
.collection__meta {
  flex: none;
  font-size: 1rem; /* 16px */
  font-weight: 500;
  line-height: 1.09;
  color: rgba(106, 21, 0, 0.64);
}
.collection__meta { text-align: right; }
.collection__title {
  flex: 1;
  text-align: center;
  font-size: 1.5rem; /* 24px */
  font-weight: 400;
  line-height: 1.09;
  color: var(--oxblood);
}

.collection__grid {
  width: var(--grid-w);
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--gap);
}

/* A plate is the oxblood mat. The photo sits centred on it at its NATURAL
   aspect ratio (never cropped): only its height is set, as a share of the mat,
   and the width follows from the image itself. --ih is the one knob per row. */
.plate {
  --ih: 78%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--oxblood);
  border-radius: 10px;
  aspect-ratio: 1;
  overflow: hidden;
}
.plate img {
  height: var(--ih);
  width: auto;
  display: block;
  border-radius: 10px;
}

/* Full-bleed rows span both columns. */
.plate--full { grid-column: 1 / -1; }

/* Row 1: no mat at all, the photo IS the plate, at its own 1.702 ratio. */
.plate--bare {
  background: none;
  border-radius: 0;
  aspect-ratio: auto;
}
.plate--bare img {
  width: 100%;
  height: auto;
}

/* Row 3: wide mat, 1326x794 in the design. */
.plate--wide {
  aspect-ratio: 1326 / 794;
  --ih: 77.2%;
}

/* Row 2 photos sit smaller on their mats than row 4's. */
.plate--inset { --ih: 76.6%; }
.plate--roomy { --ih: 80.4%; }

/* ============ FOOTER (bottom of the about/studio panel) ============ */
/* Self-contained: carries its own gutters and its own positioning context, so
   it drops into any page (about panel, collection page) without needing a
   wrapper. Markup lives in footer.js — edit it there, not per page. */
.footer {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 0 50px 6vh;
}

/* Sits between the brand mark and the contact block, which is its DOM order, so
   it just flows normally. */
.footer__rule {
  width: 26.7%;
  height: 1px;
  background: currentColor;
  opacity: .5;
  margin-top: 2.4vh;
}

.footer__brand { display: flex; align-items: center; gap: 14px; }
/* logo.svg is authored in oxblood, so it needs no recolouring here. */
.footer__logo {
  width: 47px;
  height: 23px;
  background: url(assets/logo.svg) no-repeat center / contain;
}
.footer__divider { width: 1px; height: 22px; background: currentColor; opacity: .55; }
.footer__ig { color: inherit; display: inline-flex; transition: opacity .2s ease; }
.footer__ig:hover { opacity: .6; }

.footer__label {
  margin-top: 2.6vh;
  font-size: 0.8125rem; /* 13px, matching the nav menu items */
  font-weight: 700;
  text-transform: uppercase;
}
.footer__email {
  margin-top: 0.55em;
  color: inherit;
  font-weight: 600;
  font-size: 0.85rem; /* set explicitly, not fluid like the rest of the panel */
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Credits sit in the panel's bottom-right corner, outside the centred stack. */
.footer__meta {
  position: absolute;
  right: 50px;
  bottom: 3vh;
  display: flex;
  gap: 2.6em;
  font-size: 11px; /* set explicitly, not fluid like the rest of the panel */
  font-weight: 700;
  text-transform: uppercase;
}

@media (max-width: 720px) {
  .nav { padding: 22px 22px 0; grid-template-columns: 1fr auto; }
  .nav__center { display: none; }
  .nav__menu { grid-column: 2; }
  .hero__media { --w: calc(100vw - (100vw - 88vw) * var(--p)); }
  .hero__caption { font-size: 12px; max-width: 74vw; }

  /* About stacks: portrait, then its links, then statement + bio full width.
     Nothing is justified at this measure — the word gaps get ugly. */
  .about { padding: 0; }
  .about__inner {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 4vh;
    padding: 14vh 22px 6vh;
  }
  .footer { padding: 0 22px 6vh; }

  /* Collection: single column, full-bleed within the 22px gutters. The caption
     row stacks so the long medium/location strings stop colliding. */
  .collection { --grid-w: auto; --head-w: auto; padding: 120px 0 14%; }
  .collection__head {
    margin: 0 22px 22px;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
  .collection__title { text-align: left; font-size: 1.25rem; }
  .collection__meta { text-align: left; }
  .collection__grid { margin: 0 22px; grid-template-columns: minmax(0, 1fr); gap: 10px; }
  /* One column means every plate is already full width. */
  .plate--full { grid-column: auto; }
  .about__left { flex-direction: column; align-items: flex-start; gap: 18px; }
  .about__portrait { height: 34vh; }
  .about__links { padding-bottom: 0; }
  .about__right { align-items: stretch; }
  .about__title { text-align: left; font-size: 18px; margin-bottom: 2.4vh; }
  .about__bio { width: 100%; text-align: left; }

  .footer__rule { width: 70%; }
  .footer__meta {
    position: static;
    justify-content: center;
    margin-top: 3vh;
    gap: 1.6em;
  }
}
