/* ========================================================================
   HERO. Only the hero component itself. The side bars + overlays live in
   css/sidebars.css (loaded by js/sidebars.js on every page).
   ======================================================================== */

@font-face {
  font-family: 'Galatea';
  src: url('./galatea-regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  /* --hero-img is intentionally NOT defined here. Each page sets its own
     via inline <style> so the shared hero component doesn't force one image
     on every page. See index.html, about/index.html, studio/index.html. */

  --bars: 12;
  --bar-stagger: 70ms;
  --bar-duration: 1100ms;
  --bar-ease: cubic-bezier(0.22, 1, 0.36, 1);

  --intro-delay: 0ms;
  --intro-total: 3400ms;
  --bars-start: 0ms;
  --bars-hold: 500ms;
  --bars-fadeout: 1000ms;

  --ink: #0f1a2e;
  --ink-soft: #2a3651;
  --paper: #ffffff;
}

*,
*::before,
*::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
}

html {
  scroll-snap-type: y proximity;
}

body { background: #ececec; }

main.hero {
  position: relative;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: #ececec;
  color: var(--ink);
  font-family: 'Galatea', 'Times New Roman', serif;
  font-size: 16px;
  font-weight: 400;
  letter-spacing: normal;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  isolation: isolate;
  scroll-snap-align: start;
  /* Same 3-column grid as disciplines. Photo/visual lives in col 1,
     headline + blurb in cols 2–3. */
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-items: center;
  gap: clamp(16px, 2.5vw, 48px);
  padding: clamp(32px, 7vh, 80px) clamp(24px, 5vw, 64px);
}

/* ============ BARS (desktop collage) ============ */
.hero__bars {
  position: absolute;
  inset: 0;
  display: flex;
  z-index: 1;
  pointer-events: none;
}

/* Every bar is a full-size copy of the same image, clipped to its own column,
   instead of a column-wide box painting a shifted slice. Slicing by
   background-position makes each bar round its own raster, so the collage shows
   hairline gaps or overlaps at widths that don't divide evenly. Here all bars
   share one identical paint, so the seams can't drift. The extra 0.5px on the
   right edge overlaps the next bar with pixels that are identical anyway, which
   kills the antialiased seam of the clip itself. */
.hero__bar {
  position: absolute;
  inset: 0;
  background-image: var(--hero-img);
  background-repeat: no-repeat;
  background-size: 100% auto;
  background-position: center;
  clip-path: inset(
    0
    calc(100% - 100% * ((var(--i) + 1) / var(--bars)) - 0.5px)
    0
    calc(100% * (var(--i) / var(--bars)))
  );
  transform: translateY(-110%);
  opacity: 0;
  will-change: transform, opacity;
  animation:
    heroBarIn var(--bar-duration) var(--bar-ease) forwards,
    heroBarsFadeOut var(--bars-fadeout) ease-out forwards;
  animation-delay:
    calc(var(--bars-start) + var(--i) * var(--bar-stagger)),
    calc(var(--bars-start) + (var(--bars) - 1) * var(--bar-stagger) + var(--bar-duration) + var(--bars-hold));
}

@keyframes heroBarIn {
  0%   { transform: translateY(-110%); opacity: 0; }
  40%  { opacity: 1; }
  100% { transform: translateY(0); opacity: 1; }
}

@keyframes heroBarsFadeOut {
  from { opacity: 1; }
  to   { opacity: 0; }
}

/* ============ HERO VIDEO (visual element) ============
   Decorative layer absolutely positioned inside the hero. Lives BEHIND the
   headline (lower z-index) and extends behind the start of its two lines
   ("I turn" / "clarity"). Reveal timed to the hero reveal so it never
   covers the intro animation. */
.hero__video {
  position: absolute;
  top: 50%;
  left: clamp(16px, 3vw, 40px);
  translate: 0 -50%;
  width: clamp(460px, 66vw, 1040px);
  height: auto;
  max-height: 88vh;
  object-fit: contain;
  z-index: 0;
  opacity: 0;
  animation: heroPhotoIn 900ms var(--bar-ease) forwards;
  animation-delay: calc(var(--side-delay, 3400ms) + 200ms);
  pointer-events: none;
  background: transparent;
}

@keyframes heroPhotoIn {
  from { opacity: 0; transform: scale(1.015); }
  to   { opacity: 1; transform: scale(1); }
}

/* ============ INTRO: BIG CENTERED NAME ============ */
.hero__intro-name {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 7;
  padding: 0 2rem;
  font-weight: 400;
  font-size: clamp(1.8rem, 7.5vw, 7.5rem);
  letter-spacing: -0.01em;
  color: var(--ink);
  text-align: center;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  animation: heroIntroName var(--intro-total) cubic-bezier(0.76, 0, 0.24, 1) var(--intro-delay) forwards;
}

@keyframes heroIntroName {
  0%   { opacity: 0; transform: translateY(10px); }
  15%  { opacity: 1; transform: translateY(0); }
  70%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(0); }
}

/* ============ HEADLINE + BLURB ============
   Content lives in cols 2 and 3. Dark Galatea stays dark, legibility over
   the mixed-brightness video is handled with mix-blend-mode: luminosity so
   the text borrows the backdrop's hue/sat while keeping its own low
   lightness. Reads over bright and dark zones without a halo or panel. */
.hero__content {
  grid-column: 2 / span 2;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(20px, 4vh, 40px);
  min-width: 0;
  padding-right: clamp(0px, 2vw, 32px);
}

.hero__headline {
  position: relative;
  z-index: 10;
  margin: 0;
  font-weight: 400;
  font-size: clamp(2.6rem, 7.6vw, 8rem);
  line-height: 0.98;
  letter-spacing: -0.02em;
  color: #ffffff;
  mix-blend-mode: difference;
  max-width: 20ch;
  opacity: 0;
  transform: translateY(10px);
  animation: heroHeadlineIn 900ms var(--bar-ease) forwards;
  animation-delay: calc(var(--side-delay, 3400ms) + 400ms);
}

@keyframes heroHeadlineIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

.hero__blurb {
  position: absolute;
  bottom: 100px;
  right: clamp(24px, 5vw, 64px);
  z-index: 10;
  margin: 0;
  max-width: 36ch;
  font-family: 'Galatea', 'Times New Roman', serif;
  font-size: 16px;
  line-height: 1.55;
  color: var(--ink);
  mix-blend-mode: luminosity;
  opacity: 0;
  transform: translateY(10px);
  animation: heroBlurbIn 900ms var(--bar-ease) forwards;
  animation-delay: calc(var(--side-delay, 3400ms) + 600ms);
}

@keyframes heroBlurbIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ============ MOBILE ============ */
@media (max-width: 820px) {
  :root {
    --bars: 6;
    /* Horizontal focal point of the intro collage once it gets cropped to
       portrait. 50% keeps whatever the source centers on; pages whose subject
       sits off-centre override it (see index.html). */
    --hero-focus: 50%;
  }

  main.hero {
    grid-template-columns: 1fr;
    padding: 20px;
    align-items: stretch;
    gap: 0;
  }

  /* The intro collage takes the whole screen. A 16:9 source can't fill a
     portrait viewport without cropping, and cropping is right here: the
     collage is the opening beat, not the piece itself. */
  .hero__bar {
    background-size: cover;
    background-position: var(--hero-focus) center;
  }

  /* Video fills the whole hero viewport, behind the headline. translate and
     max-height have to be unset explicitly: the base rule centers the video
     with translate: 0 -50% and caps it at 88vh, and both survive into this
     override, which otherwise leaves the video shifted up by half its height. */
  .hero__video {
    top: 0;
    left: 0;
    translate: none;
    width: 100%;
    height: 100%;
    max-height: none;
    object-fit: cover;
  }

  /* Flat dark scrim over the video, no gradient, so the whole hero reads at
     one single contrast and the type can be light anywhere on it. Scoped to
     heroes that actually have a video: /about/ keeps its light treatment,
     since there the art is the intro collage and the type lands on flat
     #ececec. Sits above the video and the bars (z-index 0 and 1) and below
     .hero__content (z-index 3).

     It belongs to the video, not to the intro, so it fades in on the same
     delay as the video. The intro collage and the big centered name play
     over the bare art and are already gone by the time the scrim lands. */
  .hero:has(.hero__video)::after {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(15, 26, 46, 0.45);
    z-index: 2;
    pointer-events: none;
    opacity: 0;
    animation: heroScrimIn 900ms var(--bar-ease) forwards;
    animation-delay: calc(var(--side-delay, 3400ms) + 200ms);
  }

  @keyframes heroScrimIn {
    from { opacity: 0; }
    to   { opacity: 1; }
  }

  /* 9vw made the full name wider than the viewport minus its own padding at
     375px, so it ran edge to edge. */
  .hero__intro-name {
    font-size: clamp(1.2rem, 7.4vw, 2.6rem);
  }

  @keyframes heroIntroName {
    0%   { opacity: 0; transform: translate(0, 10px); }
    15%  { opacity: 1; transform: translate(0, 0); }
    70%  { opacity: 1; transform: translate(0, 0); }
    100% { opacity: 0; transform: translate(0, 0); }
  }

  .hero__content {
    grid-column: 1;
    grid-row: 1;
    z-index: 3;
    justify-content: flex-end;
    padding: 20px;
    gap: 16px;
  }

  /* No blend on mobile. .hero__content above takes a z-index, and as a grid
     item that creates a stacking context, so mix-blend-mode has no backdrop
     to blend against and the declared color is literally what paints. Dark
     ink is the default, for /about/, whose hero type lands on flat #ececec
     once the intro collage is gone. Heroes with a full-bleed video flip to
     light type, because the dark scrim above is what they sit on. */
  .hero__headline {
    max-width: none;
    font-size: clamp(2.4rem, 9vw, 4rem);
    color: var(--ink);
  }

  .hero__blurb {
    position: static;
    bottom: auto;
    right: auto;
    align-self: flex-start;
    max-width: none;
    color: var(--ink-soft);
  }

  .hero:has(.hero__video) .hero__headline { color: var(--paper); }
  .hero:has(.hero__video) .hero__blurb { color: rgba(255, 255, 255, 0.88); }
}

/* ============ REDUCED MOTION ============ */
@media (prefers-reduced-motion: reduce) {
  .hero__headline,
  .hero__blurb {
    animation: none !important;
    opacity: 1 !important;
  }
  .hero__intro-name { display: none; }
  .hero__bar { display: none !important; }
  .hero__headline { transform: translateY(-50%) !important; }
}

@media (prefers-reduced-motion: reduce) and (max-width: 820px) {
  .hero__headline { transform: none !important; }
}
