/* SPDX-License-Identifier: LicenseRef-Proprietary */
/* The story of the landing page, built by homepage.js: the scenes of Jack (S1), of Reaper deleting
   Creeper (S2) and of Shelly (S3), and the comic panel (S4). Without motion, or where the browser has
   no scroll-driven animations, every scene stands one below the other on its rest frame with all of
   its text. Where it has them, a scene is pinned to the screen while its tall section scrolls past, and
   the scroll moves it both ways: nothing plays by itself except the talk of Shelly, which lasts under
   two seconds. */

/* --- Scenes --- */

.showcase {
  padding: var(--space-24) 0 var(--space-56);
  overflow-x: clip;
}
.scene-pin {
  --layout-gap: var(--space-48);
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  align-items: center;
  gap: var(--layout-gap);
  padding: var(--space-32) 0;
}
.scene-copy { justify-items: start; }
.scene-copy h2 { font: var(--font-h3); }
.scene-copy p { max-width: var(--measure-text); font: var(--font-lead); color: var(--text-2); }
.scene-copy .years { color: var(--text); font: var(--font-20)/var(--leading-130) var(--pixel); }

/* The room on the scene sets the size of the characters: twice --sprite-size on a large scene, that
   size on a medium one and half of it on a small one. */
.scene { height: var(--height-scene); container-type: size; }
.cast { --size: var(--cast-s); --share: 1; --width: calc(var(--size) * var(--share)); position: relative; }
@container (width >= 340px) and (height >= 300px) {
  .cast { --size: var(--cast-m); }
}
@container (width >= 512px) and (height >= 640px) {
  .cast { --size: var(--cast-l); }
}

/* The characters stand side by side in the middle. */
.cast-row {
  position: absolute;
  inset-inline: 0;
  bottom: 14%;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: var(--space-24);
}

/* The screen of the Creeper line: a dark box with scanlines, in the purple of Jack, drawn in CSS. */
.crt {
  position: absolute;
  inset: var(--space-16) var(--space-16) auto;
  padding: var(--space-12) var(--space-16);
  border: var(--border-2) solid var(--line-strong);
  border-radius: var(--radius-8);
  background:
    repeating-linear-gradient(var(--black-a40) 0 var(--space-1), transparent var(--space-1) var(--space-3)),
    var(--black);
  color: var(--jack-purple-bright);
  font: var(--font-12)/var(--leading-160) var(--pixel);
  text-shadow: 0 0 var(--space-6) currentcolor;
}

/* Stacked in one place: the two poses of Shelly in S3, which are never on screen together, and Shelly
   and Jack in S2 while the scroll deletes Jack. Without a scroll-driven scene they stand side by side. */
.shelly-poses { display: grid; place-items: end center; }
.shelly-poses > * { grid-area: 1 / 1; }
.shelly-spin, .light-fade { display: none; }

/* --- Comic panel --- */

/* Thick outlines and a dot raster in the green of Shelly. Shelly stands at the left edge, with a frame
   as wide as --width, and the bubble beside him points at him. What Shelly says is a sentence, so it
   shows in the sans font: the pixel font is only for short labels. */
.comic {
  --width: var(--comic-cast);
  display: grid;
  grid-template-columns: calc(var(--width) * 0.92) minmax(0, var(--measure-bubble));
  align-items: end;
  min-height: calc(var(--width) * 1.1);
  margin-top: var(--space-32);
  padding: var(--space-24) var(--space-24) 0 0;
  overflow: hidden;
  border: var(--comic-border) solid var(--text);
  border-radius: var(--radius);
  background: var(--comic-raster), var(--stage);
}
.comic-walk, .comic-talk { grid-area: 1 / 1; width: var(--width); }
.comic .character { width: var(--width); }
.comic-walk { display: none; }
.comic-bubble {
  position: relative;
  grid-area: 1 / 2;
  align-self: start;
  padding: var(--space-12) var(--space-16);
  border: var(--border-3) solid var(--text);
  border-radius: var(--radius-18);
  background: var(--surface);
  box-shadow: var(--shadow-comic);
  color: var(--text);
  font: var(--font-bubble);
}
.comic-bubble::before {
  content: "";
  position: absolute;
  bottom: var(--space-16);
  left: var(--bubble-tail-offset);
  width: var(--size-bubble-tail);
  height: var(--size-bubble-tail);
  border-bottom: var(--border-3) solid var(--text);
  border-left: var(--border-3) solid var(--text);
  background: var(--surface);
  rotate: 45deg;
}

/* --- Phone --- */

@media (width <= 760px) {
  .scene-pin { grid-template-columns: 1fr; --layout-gap: var(--space-24); }
  .scene { height: var(--height-scene-phone); }
  .comic { --width: var(--comic-cast-phone); padding: var(--space-16) var(--space-16) 0 0; }
  .comic-bubble { font: var(--font-bubble-phone); }
}

/* --- Scenes pinned to the screen, moved by the scroll --- */

/* Each scene is a tall section with a view timeline, --scene, of the time in which it fills the screen.
   Its content is pinned below the header for that time, and the scroll runs every animation of the scene
   from 0% to 100% of it and back. The numbers of steps are the frames of the strips and the rows that
   Reaper deletes. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    :root:not([data-motion="reduce"]) {
      .scene-tall {
        view-timeline: --scene block;
        height: var(--length-scene);
      }
      .scene-pin {
        position: sticky;
        top: var(--header-height, var(--space-72));
        height: calc(100svh - var(--header-height, var(--space-72)));
        padding: 0;
      }

      /* S1: Jack plays his frames as the scroll moves on, and the Creeper line types itself character by
         character. */
      .scene-jack .character-sprite-once img {
        animation: sprite-scrub steps(var(--frames), jump-none) both;
        animation-timeline: --scene;
        animation-range: contain 0% contain 70%;
      }
      .crt span {
        animation: fade-in var(--ease-linear) both;
        animation-timeline: --scene;
        animation-range: contain calc(var(--i) * 70% / var(--chars)) contain calc((var(--i) + 1) * 70% / var(--chars));
      }

      /* S2: the scroll deletes Jack row by row from the top, and the green light of Shelly rises behind
         him. */
      .scene-reaper .cast-row { display: grid; place-items: end center; }
      .scene-reaper .cast-row > * { grid-area: 1 / 1; }
      .reaper-jack {
        animation: delete-rows steps(32) both;
        animation-timeline: --scene;
        animation-range: contain 20% contain 80%;
      }
      .light-fade {
        display: block;
        animation: fade-in var(--ease-linear) both;
        animation-timeline: --scene;
        animation-range: contain 20% contain 80%;
      }

      /* S3: Shelly turns around once, then his shell spins once and he rests in it. */
      .shelly-turn {
        animation: fade-out var(--ease-linear) both;
        animation-timeline: --scene;
        animation-range: contain 49% contain 50%;
      }
      .shelly-spin {
        display: block;
        animation: fade-in var(--ease-linear) both;
        animation-timeline: --scene;
        animation-range: contain 49% contain 50%;
      }
      .shelly-turn img {
        animation: sprite-scrub steps(var(--frames), jump-none) both;
        animation-timeline: --scene;
        animation-range: contain 5% contain 45%;
      }
      .shelly-spin img {
        animation: sprite-scrub steps(var(--frames), jump-none) both;
        animation-timeline: --scene;
        animation-range: contain 55% contain 95%;
      }

      /* S4: Shelly walks in while the panel comes up the screen, in three rounds of his frames, each of
         which moves him on by a quarter of his frame. He stops where he stands without motion, and the
         talk and the bubble show once the panel is fully on screen. */
      .comic { view-timeline: --comic block; }
      .comic-walk {
        display: block;
        animation: comic-walk-in var(--ease-linear) both, fade-out var(--ease-linear) both;
        animation-timeline: --comic, --comic;
        animation-range: entry 0% entry 100%, entry 99% entry 100%;
      }
      .comic-walk img {
        animation: sprite-frames steps(var(--frames)) 3 both;
        animation-timeline: --comic;
        animation-range: entry 0% entry 100%;
      }
      .comic-talk, .comic-bubble {
        animation: fade-in var(--ease-linear) both;
        animation-timeline: --comic;
        animation-range: entry 99% entry 100%;
      }
    }
  }

  /* Once the panel is whole on screen, whether or not the browser follows the scroll, Shelly talks
     once and rests pointing. */
  :root:not([data-motion="reduce"]) .comic.playing .comic-talk img {
    animation: sprite-frames calc(var(--frames) * var(--art-frame-time)) steps(var(--frames)) backwards;
  }
}
@keyframes sprite-scrub {
  from { transform: none; }
  to { transform: translateX(calc(-100% * (var(--frames) - 1) / var(--frames))); }
}
@keyframes fade-in { from { opacity: 0; } }
@keyframes fade-out { to { opacity: 0; } }
@keyframes delete-rows { from { clip-path: inset(0); } to { clip-path: inset(100% 0 0 0); } }
@keyframes comic-walk-in { from { transform: translateX(-75%); } }

/* --- Phone, pinned --- */

@media (width <= 760px) and (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    :root:not([data-motion="reduce"]) {
      .scene-tall { height: var(--length-scene-phone); }
      .scene-pin { --layout-gap: var(--space-16); align-content: start; padding-top: var(--space-8); }
      .scene { height: var(--height-scene-pinned-phone); }
      .scene-copy p { font: var(--font-body); }
    }
  }
}
