/* ============================================================
   Liza — hero section

   The plate is a blossom meadow under an open sky, with two
   characters sitting low and roughly symmetrical about the
   middle. That decides the layout: the copy goes in the centre,
   in the gap the composition already leaves between them, and
   the type is dark on a light plate rather than the other way
   round.

   Measured over the whole loop (luma /255, worst frame):

     centre band  x 0.28-0.72  y 0.15-0.47   never below 183
     x 0.19-0.81  (same rows)                never below 183
     left edge    x 0.00-0.12                down to 76
     right edge   x 0.88-1.00                down to 103

   So the copy column is capped to the middle 62% and nothing
   under it needs a scrim: ink at #16202B on luma 183 is 8.1:1,
   which is past AA for body text, never mind a headline. The
   edges, where the blossom and the leaves come in, are exactly
   where no text goes.

   The clip is a boomerang — it plays forward, then back — so
   the loop point is a real frame step instead of the jump the
   raw plate cut on (mean absolute difference 2.35 to 0.17).
   ============================================================ */

:root {
  --ink:      #16202B;   /* the plate's burnt-in nav read #131B24; lifted a little */
  --ink-soft: #3E4C5B;
  --mute:     #5A6875;
  --sky:      #8DCDF7;   /* sampled at the top of the sky */
  --sky-pale: #DCF0FD;   /* the page's own ground, off the same ramp */
  --cream:    #E7C79A;   /* the near character */
  --rose:     #C4527A;   /* the blossom, taken down until it holds on sky */
  --hair:     rgba(22, 32, 43, .14);

  --display: "Fraunces", Georgia, "Times New Roman", serif;
  --body:    "Nunito", "Helvetica Neue", Arial, sans-serif;
  --gutter:  clamp(1.5rem, 5vw, 5rem);
  --ease:    cubic-bezier(.22, .61, .36, 1);
}

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

html, body { margin: 0; }

body {
  background: var(--sky-pale);
  color: var(--ink);
  font-family: var(--body);
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }

:focus-visible { outline: 2px solid var(--rose); outline-offset: 4px; }

/* ---------- stage ---------- */

.hero {
  position: relative;
  min-height: 100svh;
  overflow: hidden;
  display: grid;
  grid-template-rows: auto 1fr;
  padding: 0 var(--gutter) clamp(2rem, 6vh, 4rem);
}

.hero__media {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* Far enough back that a couple of degrees reads as a lean and not a flip. */
  perspective: 1800px;
}

/* The plate leans toward the pointer. The characters cannot be turned on their
   own — they are single moulded shapes in the footage with no edge clean enough
   to cut along — so the stage turns instead, which with the eyes following
   reads as the pair noticing you.

   The 3% scale is the cost of the lean: perspective pulls the far corner in by
   a few pixels, and this keeps plate under the whole frame. It magnifies about
   the centre, which is also where the copy is, so the growth happens out at the
   blossom rather than under the words. */
.hero__stage {
  position: absolute;
  inset: 0;
  transform: scale(1.03);
  will-change: transform;
}

.hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The cast is symmetrical about the middle — one character at 33% of the
     plate's width, one at 68% — so unlike a plate with its subject to one side
     this one is cropped evenly and stays centred at every viewport shape. */
  object-position: center;
  display: block;
}

/* ---------- the character's eyes ----------
   Not an overlay on the footage — the plate has no eyes left in it. These are
   the eyes, two marks a few pixels across sitting exactly where the painted
   ones were, free to look wherever the pointer is. script.js writes each one's
   position and size straight into the transform, because both change every
   video frame as the character bobs.

   The far character is left alone: its eyes are drawn shut for the whole loop,
   so there is nothing in there to replace. */

.eyes {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  contain: strict;
}

.eye {
  position: absolute;
  top: 0;
  left: 0;
  /* A fixed 100px box scaled by the transform: the dots change size as the
     character moves toward the camera, and scaling never costs a layout. */
  width: 100px;
  height: 100px;
  margin: -50px 0 0 -50px;
  border-radius: 50%;
  /* Flat, like the painted ones — this character has no highlight in its eyes.
     The ramp over the last sixth of the radius is the anti-aliasing the
     original had; script.js knows about it and sizes the box to match. */
  background: radial-gradient(circle at 50% 50%,
                              var(--ink) 84%, rgba(22, 32, 43, 0) 100%);
  opacity: 0;
  will-change: transform;
}

.eye[data-on] { opacity: 1; }

/* ---------- top bar ---------- */

.topbar {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: clamp(1.3rem, 3.2vh, 2.1rem);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.15rem, 1.5vw, 1.4rem);
  letter-spacing: -.015em;
}

/* The mark is the near character's face, which is the thing the whole plate is
   built around. Three boxes rather than an SVG: at this size it is a dome with
   two dots, which CSS draws on its own, and it keeps the moving parts plain
   elements. The proportions match favicon.svg. */
.brand__face {
  position: relative;
  display: block;
  width: 26px;
  height: 22px;
  flex: none;
  border-radius: 50% 50% 46% 46%;
  background: var(--cream);
  box-shadow: inset 0 -3px 6px rgba(22, 32, 43, .08);
}

/* Both eyes follow the pointer — script.js writes --px/--py in the range -1..1
   and the translate below scales that to the pixel and a half a face this size
   can spend without the dots sliding off it. */
.brand__eye {
  position: absolute;
  top: 7px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--ink);
  transform: translate(calc(var(--px, 0) * 1.5px), calc(var(--py, 0) * 1.5px));
  transition: transform .12s linear;
}
.brand__eye:first-child { left: 6px; }
.brand__eye:last-child  { right: 6px; }

.brand__word { white-space: nowrap; }

/* ---------- nav ---------- */

.nav {
  display: flex;
  align-items: center;
  gap: clamp(1.1rem, 2.4vw, 2.1rem);
}

.nav__link,
.nav__cta {
  font-size: .88rem;
  font-weight: 600;
  letter-spacing: .01em;
  white-space: nowrap;
}

.nav__link {
  color: var(--ink-soft);
  padding-bottom: 3px;
  border-bottom: 1.5px solid transparent;
  transition: color .3s var(--ease), border-color .3s var(--ease);
}
.nav__link:hover, .nav__link:focus-visible {
  color: var(--ink);
  border-color: var(--rose);
}

/* The one nav item that crosses the leaves in the top right corner, so it
   brings its own ground the way a button does rather than sitting on a scrim.
   Dark, because on a plate this bright a filled dark pill is the only thing
   that still reads as a button at every frame of the loop. */
.nav__cta {
  display: inline-flex;
  align-items: center;
  min-height: 38px;
  padding: .55rem 1.15rem;
  border-radius: 999px;
  background: var(--ink);
  color: #FFF;
  transition: background .3s var(--ease), transform .3s var(--ease);
}
.nav__cta:hover, .nav__cta:focus-visible {
  background: var(--rose);
}

/* ---------- burger (narrow only) ---------- */

.burger {
  display: none;
  width: 44px;
  height: 44px;
  margin-right: -10px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
}
.burger span {
  display: block;
  width: 22px;
  height: 2px;
  margin: 5px auto;
  background: currentColor;
  border-radius: 2px;
  transition: transform .3s var(--ease);
}
.burger[aria-expanded="true"] span:first-child { transform: translateY(3.5px) rotate(45deg); }
.burger[aria-expanded="true"] span:last-child  { transform: translateY(-3.5px) rotate(-45deg); }

/* ---------- copy ---------- */

.hero__copy {
  position: relative;
  z-index: 1;
  align-self: center;
  /* The horizon runs across the plate at about 58% of its height, and the two
     characters sit just under it. Centring in the row would drop the button
     onto the grass, so the block is lifted by the difference. */
  margin-block-end: clamp(2rem, 14vh, 9rem);
  margin-inline: auto;
  text-align: center;
  /* The measured light column is the middle 62% of the plate; cover crops the
     sides before it crops anything else, so the cap is on the plate's width
     rather than the viewport's. */
  max-width: min(46rem, 62vw);
}

.eyebrow {
  margin: 0 0 clamp(.7rem, 1.6vh, 1.1rem);
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--rose);
}

.title {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2.4rem, 5.6vw, 4.6rem);
  line-height: 1.04;
  letter-spacing: -.025em;
}

.title__line { display: block; }

/* ---------- button ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: .8rem;
  min-height: 50px;          /* tap-target floor at every size below, too */
  margin-top: clamp(1.5rem, 3.4vh, 2.4rem);
  padding: .95rem 1.8rem;
  border-radius: 999px;
  background: var(--ink);
  color: #FFF;
  font-size: .95rem;
  font-weight: 700;
  transition: background .3s var(--ease), transform .3s var(--ease);
}
.btn__arrow { width: 22px; height: 11px; flex: none; }

.btn:hover, .btn:focus-visible {
  background: var(--rose);
  transform: translateY(-2px);
}

/* ============================================================
   Narrow and portrait: cover on a 16:9 plate crops a phone down
   to one character's cheek, so the footage becomes a band that
   holds the whole frame and the copy sits on the page's own
   sky below it.
   ============================================================ */

@media (max-width: 900px),
       (max-width: 1200px) and (orientation: portrait) {

  .hero {
    grid-template-rows: auto auto 1fr;
    padding-inline: 0;
    row-gap: clamp(1.2rem, 3vh, 2rem);
  }

  .topbar, .hero__copy { padding-inline: var(--gutter); }

  .topbar { order: -1; }     /* the wordmark stays above the band */

  /* No lean in the band: it is sized to hold the frame exactly, and a lean
     would push the corners out past it. */
  .hero__stage { transform: none; }

  .hero__media {
    position: relative;
    inset: auto;
    width: 100%;
    /* Squarer than the plate, so cover trims the sides to the middle 75% —
       x 0.13 to 0.88. That is chosen, not inherited: the two characters sit at
       0.33 and 0.68 of the plate's width, so both keep their room, and what
       goes is the blossom and the leaf tips in the corners, which are the one
       part of the frame nothing depends on. Giving the band the plate's own
       16:9 instead would crop nothing at all, but on a phone it comes out
       barely a quarter of the screen tall and the hero reads as a header with
       a strip of wallpaper under it. */
    aspect-ratio: 4 / 3;
    max-height: 42svh;
    -webkit-mask-image: linear-gradient(to bottom, #000 82%, transparent 100%);
            mask-image: linear-gradient(to bottom, #000 82%, transparent 100%);
  }

  .burger { display: block; position: relative; z-index: 4; }

  .nav {
    position: fixed;
    inset: 0;
    z-index: 3;
    flex-direction: column;
    justify-content: center;
    gap: 1.6rem;
    /* only while the menu is open, and it replaces the view rather than
       tinting it — the footage never sits under a permanent scrim, and at
       anything short of opaque the headline ghosts through the links */
    background: var(--sky-pale);
    opacity: 0;
    visibility: hidden;
    transition: opacity .3s var(--ease), visibility .3s var(--ease);
  }
  .nav[data-open] { opacity: 1; visibility: visible; }

  .nav__link, .nav__cta { font-size: 1.05rem; }
  .nav__cta { min-height: 46px; padding: .8rem 1.6rem; }

  /* Centred in what the band leaves rather than pushed to the top of it: the
     copy is shorter than the row on every phone we fit, and starting it high
     parks all the slack under the button. */
  .hero__copy {
    align-self: center;
    margin-block-end: 0;
    max-width: none;
  }

  .title { font-size: clamp(2.2rem, 9vw, 3.2rem); }
  .btn   { width: 100%; justify-content: center; }
}

/* ============================================================
   Upright phones and tablets: a plate of their own. It was shot
   tall, 720x1280, so it goes back to being the backdrop — full
   bleed, no band — and the copy moves up onto the sky.

   Measured over the loop (luma /255, worst frame, middle 80%):

     sky      y 0.09-0.44   never below 123, mean 200
     grass    y 0.65-1.00   down to 2 — the characters' shadows

   The two characters sit at 0.21 and 0.78 of the plate's width,
   0.71 of its height, so the copy takes the sky above them and
   the grass stays clear. Ink on the worst sky frame is 3.9:1,
   which is past AA for type this large; the average frame is
   well over 8.
   ============================================================ */

@media (max-width: 1200px) and (orientation: portrait) {

  .hero {
    grid-template-rows: auto 1fr;
    row-gap: 0;
  }

  .hero__media {
    position: absolute;
    inset: 0;
    width: auto;
    aspect-ratio: auto;
    max-height: none;
    -webkit-mask-image: none;
            mask-image: none;
  }

  .hero__copy {
    align-self: start;
    padding-top: clamp(1.2rem, 7svh, 4.5rem);
  }

  .title { font-size: clamp(2.3rem, 10.5vw, 4.2rem); }
  .btn   { width: auto; }
}

/* ---------- small phones ---------- */

@media (max-width: 380px) {
  .hero__media { min-height: 22svh; }
  .title   { font-size: clamp(2rem, 9.2vw, 2.4rem); }
  .eyebrow { font-size: .74rem; }
}

/* ---------- short viewports (phone held sideways) ----------
   Wider than 16:9, so a stacked band does not fit — go back to the overlay
   and let the copy sit on the sky again. */

@media (max-height: 560px) and (min-width: 561px) {
  .hero {
    grid-template-rows: auto 1fr;
    padding-inline: var(--gutter);
    row-gap: 0;
  }

  .topbar { order: 0; }
  .topbar, .hero__copy { padding-inline: 0; }

  /* undo the band: it is a backdrop again, so every constraint the narrow
     rules put on the media has to come back off */
  .hero__media {
    position: absolute;
    inset: 0;
    width: auto;
    aspect-ratio: auto;
    max-height: none;
    -webkit-mask-image: none;
            mask-image: none;
  }

  .hero__copy {
    align-self: center;
    margin-block-end: clamp(1rem, 8vh, 3rem);
    max-width: min(34rem, 62vw);
  }

  .title { font-size: clamp(1.8rem, 5vw, 2.6rem); }
  .btn   { width: auto; margin-top: 1.1rem; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: .01ms !important; }
  .brand__eye  { transform: none; }   /* the face holds still */
  .hero__stage { transform: none; }   /* and the stage does not lean */
}
