/*
 * Scroll Film page.
 *
 * The film plays on a STAGE: a pinned, full-screen panel painted one colour.
 * The footage arrives with its backdrop already lifted away, so the product
 * stands on the stage itself, and words can sit behind it (the back layer),
 * in front of it (the front layer) or beside it.
 *
 * Where the product lands on screen is worked out here, in CSS, from numbers
 * the build writes: the frame's shape (--A) and the box the product fills
 * across the whole film (--ul --ut --ur --ub, fractions of the frame). The
 * frame is scaled so that box fills the stage, and each beat's words are
 * placed against the box the product fills during that beat (--bl --bt --br
 * --bb). film.js draws into the same .fit box, so the picture and the words
 * cannot disagree.
 */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: auto; }
body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
img, video, canvas { display: block; max-width: 100%; }
h1, h2, h3, p, ul { margin: 0; padding: 0; }
ul { list-style: none; }
a { color: inherit; }

:root {
  --gutter: 24px;
  --bar-h: 64px;
  --m: 1;
  --ease: cubic-bezier(0.215, 0.61, 0.355, 1);
}
@media (prefers-reduced-motion: reduce) { :root { --m: 0; } }

.display {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  text-transform: var(--display-case);
  letter-spacing: var(--display-track);
  line-height: 1;
}
.eyebrow { font-size: 12px; font-weight: 600; letter-spacing: 0.18em; text-transform: uppercase; color: var(--ink-soft); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 12px 28px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background 240ms var(--ease), color 240ms var(--ease), border-color 240ms var(--ease);
}
.btn:hover { background: transparent; color: var(--accent); }
.btn:focus-visible, a:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
.text-link { font-size: 13px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; text-underline-offset: 4px; }

/* Top bar: painted the colour of whatever is beneath it (film.js), so it
   melts into the stage and still never lets words collide with it. */
.bar {
  position: fixed;
  inset: 0 0 auto;
  z-index: 50;
  height: var(--bar-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gutter);
  padding: 0 var(--gutter);
  background: var(--bar-bg, var(--ground));
  color: var(--ink);
  border-bottom: 1px solid color-mix(in srgb, currentColor 14%, transparent);
}
.bar[data-on-dark] { color: var(--on-dark); }
.bar-brand { display: inline-flex; align-items: center; font-weight: 600; letter-spacing: 0.08em; text-decoration: none; }
.bar-brand img { height: 28px; width: auto; }
.bar-link { font-size: 13px; font-weight: 600; letter-spacing: 0.08em; text-decoration: none; }

/* ------------------------------------------------------------ the stage */
.scene {
  position: relative;
  height: var(--h);
  --p: 0;
  --edge: max(var(--gutter), 3vw);
  /* The area the film's product box is fitted into. */
  --area-t: calc(var(--bar-h) + 4svh);
  --area-h: calc(100svh - var(--area-t) - 4svh);
  --area-w: calc(100vw - 2 * var(--edge));
  --uw: calc(var(--ur) - var(--ul));
  --uh: calc(var(--ub) - var(--ut));
  /* The whole frame, as large as fits, but never blown up past 1.4x the size
     that would just cover the screen: past that the footage turns soft. */
  --fw: min(var(--area-w) / var(--uw), var(--area-h) * var(--A) / var(--uh), 1.4 * max(100vw, 100svh * var(--A)));
  --fh: calc(var(--fw) / var(--A));
  --fx: calc(50vw - (var(--ul) + var(--uw) / 2) * var(--fw));
  --fy: calc(var(--area-t) + var(--area-h) / 2 - (var(--ut) + var(--uh) / 2) * var(--fh));
}
.frame {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  background: var(--stage);
  color: var(--on-stage);
}
.frame .eyebrow, .frame .lede, .frame .sub { color: var(--on-stage-soft); }
.frame .btn { background: var(--stage-accent); border-color: var(--stage-accent); color: var(--on-stage-accent); }
.frame .btn:hover { background: transparent; color: var(--stage-accent); }
.art { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.fit { position: absolute; left: var(--fx); top: var(--fy); width: var(--fw); height: var(--fh); }
.poster { width: 100%; height: 100%; }
/* The poster is the scene until the first frame is drawn, then steps aside:
   both are see-through, so leaving it would show through the film. */
.art[data-live] .poster { visibility: hidden; }
.film { position: absolute; inset: 0; width: 100%; height: 100%; }
/* Kept in the document: some browsers stop decoding a display:none video. */
.film-src { position: absolute; width: 2px; height: 2px; opacity: 0; pointer-events: none; }

/* A beat is a set of words shown over its own stretch of --p; --q is the
   beat's own 0 to 1, which drives its motion. --x0 --x1 --y0 --y1 are the
   edges of the product during the beat, in px from the stage's corner. */
.beat {
  --q: clamp(0, (var(--p) - var(--in)) / (var(--out) - var(--in)), 1);
  --x0: calc(var(--fx) + var(--bl) * var(--fw));
  --x1: calc(var(--fx) + var(--br) * var(--fw));
  --y0: calc(var(--fy) + var(--bt) * var(--fh));
  --y1: calc(var(--fy) + var(--bb) * var(--fh));
  --ym: calc((var(--y0) + var(--y1)) / 2);
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: calc(clamp(0, (var(--p) - var(--in)) / 0.025, 1) * clamp(0, (var(--out) - var(--p)) / 0.025, 1));
  pointer-events: none;
}
.beat[data-layer="front"] { z-index: 2; }
.beat[data-on] a { pointer-events: auto; }
.anchor { position: absolute; left: 0; width: 1px; height: 1px; }

/* ------------------------------------------------------------ placement
   Every set of words is a .block, placed by data-at (computers) and
   data-at-phone (phones). The build picks each from the room the product
   leaves during that beat. */
.block {
  position: absolute;
  display: grid;
  align-content: start;
  gap: 16px;
  transform: translate(var(--mx, 0px), calc(var(--cy, 0%) + var(--my, 0px)));
}
@media (min-width: 768px) {
  .block[data-at="left"], .block[data-at="left-low"] {
    left: var(--edge);
    right: calc(100vw - var(--x0) + 3vw);
    justify-items: end;
    text-align: right;
  }
  .block[data-at="right"] { left: calc(var(--x1) + 3vw); right: var(--edge); }
  .block[data-at="left"], .block[data-at="right"] { top: var(--ym); --cy: -50%; }
  /* Beside the product's lower half, so it stays clear of a word behind it. */
  .block[data-at="left-low"] { bottom: calc(100svh - var(--y1)); }
  .block[data-at="top"] { left: var(--edge); right: var(--edge); top: calc(var(--bar-h) + 3svh); }
  .block[data-at="under"] { left: var(--edge); right: var(--edge); top: calc(var(--bar-h) + 3svh + var(--under, 0px)); }
  .block[data-at="bottom"] { left: var(--edge); right: var(--edge); bottom: 4svh; align-content: end; }
  .block[data-at="behind"] { left: 0; right: 0; top: var(--ym); --cy: -50%; justify-items: center; text-align: center; }
  .block[data-at="split"] { display: contents; }
  .block[data-at="left-low"] .cta-row, .block[data-at="left"] .cta-row { justify-content: flex-end; }
}

/* Hero: the brand, huge, behind the product, and a short line with the
   main button. film.js sizes the big words to the width of the stage. */
.giant {
  margin: 0;
  white-space: nowrap;
  font-family: var(--font-display);
  font-weight: var(--giant-weight);
  text-transform: var(--display-case);
  letter-spacing: var(--giant-track);
  line-height: 0.9;
  font-size: min(calc((100vw - 2 * var(--edge)) / var(--chars) / 0.66), 30svh);
  --my: calc(var(--q) * -6svh * var(--m));
}
.giant span { display: inline-block; }
@media (min-width: 768px) { .giant[data-at="behind"] { padding-inline: var(--edge); } }
@media (max-width: 767px) { .giant[data-at-phone="behind"] { padding-inline: var(--gutter); } }
.copy { max-width: 27rem; }
.lede { font-size: 16px; }
.cta-row { display: flex; flex-wrap: wrap; align-items: center; gap: 24px; margin-top: 8px; }

/* Statement: up to three short lines, sliding in one after another. */
.statement .line {
  --l: clamp(0, (var(--q) - var(--i) * 0.16) / 0.3, 1);
  font-size: clamp(1.8rem, 3.6vw, 4rem);
  opacity: var(--l);
  --mx: calc((1 - var(--l)) * var(--dir, -1) * 8vw * var(--m));
  transform: translateX(var(--mx));
}
.statement { gap: 0.3em; }
@media (min-width: 768px) {
  /* Lines either side of the product, down its height. */
  .statement[data-at="split"] .line {
    position: absolute;
    top: calc(var(--y0) + (var(--i) + 0.5) / var(--n) * (var(--y1) - var(--y0)));
    transform: translate(var(--mx), -50%);
  }
  .statement[data-at="split"] .line:nth-child(odd) { left: var(--edge); right: calc(100vw - var(--x0) + 3vw); text-align: right; }
  .statement[data-at="split"] .line:nth-child(even) { left: calc(var(--x1) + 3vw); right: var(--edge); --dir: 1; }
}

/* Above or below a product that fills the stage, words run wide and short. */
@media (min-width: 768px) {
  .statement:is([data-at="top"], [data-at="bottom"], [data-at="under"]) {
    display: flex;
    flex-wrap: wrap;
    gap: 0.1em 0.5em;
  }
  .statement:is([data-at="top"], [data-at="bottom"], [data-at="under"]) .line {
    font-size: clamp(1.6rem, 3.2vw, 3.6rem);
    transform: translateY(calc((1 - var(--l)) * 1.2rem * var(--m)));
  }
  .story:is([data-at="top"], [data-at="bottom"]) { max-width: 62rem; gap: 10px; }
  .story:is([data-at="top"], [data-at="bottom"]) p:last-child { font-size: clamp(1.1rem, 1.6vw, 1.5rem); }
  .headline:is([data-at="top"], [data-at="bottom"]) {
    max-width: none;
    grid-template-columns: auto minmax(0, 26rem);
    align-items: end;
    gap: 10px 48px;
  }
  .headline:is([data-at="top"], [data-at="bottom"]) .eyebrow { grid-column: 1 / -1; }
  .headline:is([data-at="top"], [data-at="bottom"]) .display { font-size: clamp(2rem, 4.2vw, 4.6rem); }
  .lists:is([data-at="top"], [data-at="bottom"], [data-at="under"]) .list { display: flex; flex-wrap: wrap; gap: 10px 40px; }
}

/* Story: a short paragraph, drifting. */
.story { max-width: 30rem; --my: calc((var(--q) - 0.5) * -8svh * var(--m)); }
.story p:last-child { font-size: clamp(1.15rem, 1.7vw, 1.6rem); line-height: 1.4; }

/* Headline: a big line and a small one, rising into place. */
.headline { max-width: 40rem; --my: calc((1 - var(--q)) * 8svh * var(--m)); }
.headline .display { font-size: clamp(2.2rem, 4.6vw, 5.4rem); line-height: 0.95; }
.headline .sub { max-width: 30ch; opacity: clamp(0, var(--q) * 3 - 0.4, 1); }

/* List: a big heading, and the items around the product. */
.list-title { font-size: clamp(2rem, 6vw, 7rem); --my: calc((1 - var(--q)) * 6svh * var(--m)); }
.list-title[data-at="top"], .list-title[data-at="bottom"] { font-size: clamp(1.8rem, 3.4vw, 3.6rem); }
.lists { display: flex; flex-wrap: wrap; gap: 20px 56px; }
.list { display: grid; gap: 16px; align-content: start; }
.list li {
  --l: clamp(0, (var(--q) - 0.1 - var(--i) * 0.06) / 0.16, 1);
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 14px;
  opacity: var(--l);
  transform: translateY(calc((1 - var(--l)) * 14px * var(--m)));
}
.tick { width: 22px; height: 1px; background: currentColor; flex: none; }
@media (min-width: 768px) {
  .lists[data-at="split"] .list { position: absolute; top: var(--ym); transform: translateY(-50%); }
  .lists[data-at="split"] .list[data-side="left"] { right: calc(100vw - var(--x0) + 3vw); text-align: right; }
  .lists[data-at="split"] .list[data-side="left"] li { flex-direction: row-reverse; }
  .lists[data-at="split"] .list[data-side="right"] { left: calc(var(--x1) + 3vw); }
}

/* --------------------------------------------------------- after the film */
.section { padding: 96px var(--gutter); }
.shell { max-width: 1200px; margin-inline: auto; }
.section-head { display: grid; gap: 12px; max-width: 40rem; margin-bottom: 48px; }
.section-title { font-size: clamp(2rem, 4vw, 3.4rem); }

/* Product shots on white drop straight onto a light ground. On a dark one
   they sit on their own white cards instead. */
.products-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 48px 32px; }
.product { display: grid; align-content: start; gap: 8px; }
.product-frame { display: block; aspect-ratio: 4 / 5; mix-blend-mode: multiply; overflow: hidden; }
body[data-ground="dark"] .product-frame { mix-blend-mode: normal; background: #fff; }
.product-frame img { width: 100%; height: 100%; object-fit: cover; }
.product-name { font-weight: 600; }
.product-sub, .product-price { font-size: 14px; color: var(--ink-soft); }
.product .btn { margin-top: 8px; width: 100%; }

.closing { background: var(--dark); color: var(--on-dark); text-align: center; }
.closing .section-title { margin-bottom: 16px; }
.closing p { color: var(--on-dark); max-width: 36rem; margin: 0 auto 32px; }
.closing .btn { background: var(--on-dark); color: var(--dark); border-color: var(--on-dark); }
.closing .btn:hover { background: transparent; color: var(--on-dark); }

.foot {
  background: var(--dark);
  color: var(--on-dark);
  padding: 32px var(--gutter);
  border-top: 1px solid color-mix(in srgb, var(--on-dark) 20%, transparent);
  font-size: 13px;
}
.foot .shell { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 16px; }
.foot-links { display: flex; flex-wrap: wrap; gap: 20px; }

/* Floating CTA: the opposite of whatever ground is behind it. */
.float-cta {
  position: fixed;
  right: 32px;
  bottom: 32px;
  z-index: 40;
  opacity: 0;
  transform: translateY(16px);
  pointer-events: none;
  transition: opacity 280ms var(--ease), transform 280ms var(--ease);
}
.float-cta[data-shown] { opacity: 1; transform: none; pointer-events: auto; }
.float-cta .btn { background: var(--ink); color: var(--ground); border-color: var(--ink); }
.float-cta[data-on-dark] .btn { background: var(--on-dark); color: var(--dark); border-color: var(--on-dark); }
.float-cta .btn:hover { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
@media (prefers-reduced-motion: reduce) { .float-cta { transition: none; } }

/* ----------------------------------------------------------------- phones
   The picture is a 4:5 box the width of the phone, set low on the stage, its
   frames already framed round the product. Words live in the band above it,
   which never moves, so nothing on the stage moves except the film. */
@media (max-width: 767px) {
  :root { --bar-h: 56px; --gutter: 16px; }
  body { font-size: 16px; }
  .scene {
    /* The strip the floating button takes along the bottom. */
    --stage-foot: calc(16px + env(safe-area-inset-bottom) + 48px + 8px);
    --pw: min(100vw, (100svh - var(--bar-h) - var(--stage-foot) - 8svh) * var(--pa));
    --ph: calc(var(--pw) / var(--pa));
    /* Low on the stage: the product's lowest point just clears the button. */
    --py: max(calc(var(--bar-h) - var(--put) * var(--ph)), calc(100svh - var(--stage-foot) - 1svh - var(--pub) * var(--ph)));
  }
  .fit { left: calc((100vw - var(--pw)) / 2); top: var(--py); width: var(--pw); height: var(--ph); }
  .beat {
    --x0: calc((100vw - var(--pw)) / 2 + var(--pl) * var(--pw));
    --x1: calc((100vw - var(--pw)) / 2 + var(--pr) * var(--pw));
    --y0: calc(var(--py) + var(--pt) * var(--ph));
    --y1: calc(var(--py) + var(--pb) * var(--ph));
  }
  .block { left: var(--gutter); right: var(--gutter); gap: 12px; --cy: 0%; }
  .block[data-at-phone="top"] { top: calc(var(--bar-h) + 3svh); }
  .block[data-at-phone="under"] { top: calc(var(--bar-h) + 3svh + var(--under, 0px)); }
  .block[data-at-phone="bottom"] { bottom: calc(var(--stage-foot) + 1svh); align-content: end; }
  .block[data-at-phone="behind"] { left: 0; right: 0; top: var(--ym); --cy: -50%; justify-items: center; text-align: center; }

  .giant { font-size: min(calc((100vw - 2 * var(--gutter)) / var(--chars) / 0.66), 22svh); }
  /* Up in the band, nothing drifts: it would slide under the bar or into the words below. */
  .giant[data-at-phone="top"], .list-title { --my: 0px; }
  .statement .line { transform: translateY(calc((1 - var(--l)) * 0.8rem * var(--m))); }
  .copy .lede { font-size: 14px; line-height: 1.5; }
  .cta-row { margin-top: 0; gap: 20px; }
  .statement { font-size: clamp(1.3rem, 6.4vw, 1.9rem); }
  .statement .line { font-size: inherit; }
  .story p:last-child { font-size: 1.05rem; }
  .story, .headline { --my: calc((1 - var(--q)) * 3svh * var(--m)); }
  .headline .display { font-size: clamp(1.7rem, 8.4vw, 2.4rem); }
  .headline .sub { font-size: 15px; }
  .list-title, .list-title[data-at="top"] { font-size: clamp(1.6rem, 8vw, 2.4rem); }
  .lists { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
  .list { gap: 6px; }
  .list li { font-size: 12px; align-items: baseline; gap: 8px; }
  .tick { width: 10px; }

  .section { padding: 64px var(--gutter); }
  .products-grid { grid-template-columns: 1fr 1fr; gap: 40px 20px; }

  .float-cta { left: var(--gutter); right: var(--gutter); bottom: calc(16px + env(safe-area-inset-bottom)); }
  .float-cta .btn { width: 100%; }
}
