/* The brand band: the 3D mark and the six worlds.

   The mark render ships with its own ground already flattened to exactly
   --mint by scripts/make-mark-3d.py, and this band paints --mint behind it, so
   the square edge of a 1400 px image sitting on a full width band cannot be
   found at any width. Nothing here keys, masks or feathers the image.

   Geometry is four lengths declared once on the band and read by everything
   else: --stage-w and --stage-h are the box the composition lives in, --mark
   is the render, --tile is one world. The ring is an ellipse of --rx by --ry
   around the centre, and each tile carries the cosine and sine of its own
   angle as --x and --y, so one transform places all six and one pair of
   lengths resizes the whole ring. The angles are not evenly spaced: an even
   six reads as a clock face, and every tile clears the mark's box by at least
   13 px at every width the band is drawn at.

   Motion is transform and opacity only. Entrances use the site's --ease, the
   loops use --ease-bob, which is the symmetric one, because a loop that eases
   out hard on both halves reads as a twitch. */

.markband {
  --stage-w: min(980px, 88vw);
  --stage-h: min(620px, 46vw);
  --mark: min(430px, 30vw);
  --tile: min(112px, 8vw);
  --rx: calc(var(--stage-w) * .40);
  --ry: calc(var(--stage-h) * .50);
  --bob: 5px;
  --ease-bob: cubic-bezier(.45, 0, .55, 1);
  background: var(--mint);
  padding: 76px 0 68px;
  overflow: hidden;
}

.markband-stage {
  position: relative;
  width: var(--stage-w);
  height: var(--stage-h);
  margin: 0 auto;
}

/* the parallax layer: the mark leans away from the pointer, the tiles lean
   into it, which is what reads as depth rather than as a sliding picture */
.markband-mark {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--mark);
  height: var(--mark);
  margin: calc(var(--mark) / -2) 0 0 calc(var(--mark) / -2);
  transform: translate(calc(var(--mx, 0px) * -.35), calc(var(--my, 0px) * -.35));
  transition: transform 900ms var(--ease);
}

.markband-mark picture { display: block; }

.markband-mark img {
  display: block;
  width: 100%;
  height: auto;
  animation: markband-float 6s var(--ease-bob) infinite;
}

/* The face lights the ground under it in the render already. This is that
   light, breathing. It is screen blended so it brightens the mint without
   tinting the white tubes, and it sits inside the mark's own box, which is a
   stacking context, so it can never bleed onto the caption. */
.markband-glow {
  position: absolute;
  left: 67%;
  top: 66%;
  width: 62%;
  height: 62%;
  margin: -31% 0 0 -31%;
  z-index: 1;
  border-radius: 50%;
  pointer-events: none;
  mix-blend-mode: screen;
  background: radial-gradient(closest-side, var(--lime) 0%, rgba(142, 227, 3, .55) 42%, rgba(142, 227, 3, 0) 72%);
  animation: markband-glow 6s var(--ease-bob) infinite;
}

.markband-ring {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.markband-tile {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--tile);
  height: var(--tile);
  margin: calc(var(--tile) / -2) 0 0 calc(var(--tile) / -2);
  transform: translate(
    calc(var(--x) * var(--rx) + var(--mx, 0px)),
    calc(var(--y) * var(--ry) + var(--my, 0px))
  );
  transition: transform 900ms var(--ease);
}

/* Two animations on one property: the entrance fills forwards and the hover
   has no fill, so during its delay the entrance still governs and the moment
   the delay is up the later one in the list takes over. */
.markband-tile-in {
  display: block;
  width: 100%;
  height: 100%;
  animation:
    markband-in 700ms var(--ease) var(--in) both,
    markband-hover var(--bob-t) var(--ease-bob) calc(var(--in) + 700ms) infinite;
}

.markband-tile img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 14px;
  box-shadow: 0 2px 5px rgba(15, 25, 20, .10), 0 18px 34px -16px rgba(15, 25, 20, .42);
  transition: transform 900ms var(--ease), box-shadow 900ms var(--ease);
}

.markband-tile.is-front { z-index: 3; }

.markband-tile.is-front img {
  transform: scale(1.16);
  box-shadow: 0 3px 8px rgba(15, 25, 20, .12), 0 26px 48px -18px rgba(15, 25, 20, .52);
}

/* a loose ring: cosine and sine of six angles that are not a clock face */
.markband-tile:nth-child(1) { --x: .92; --y: -.40; --in: 200ms; --bob-t: 7.2s; }
.markband-tile:nth-child(2) { --x: .99; --y: .22; --in: 280ms; --bob-t: 8.4s; }
.markband-tile:nth-child(3) { --x: .16; --y: .99; --in: 360ms; --bob-t: 6.6s; }
.markband-tile:nth-child(4) { --x: -.86; --y: .56; --in: 440ms; --bob-t: 9.1s; }
.markband-tile:nth-child(5) { --x: -.98; --y: -.16; --in: 520ms; --bob-t: 7.8s; }
.markband-tile:nth-child(6) { --x: -.22; --y: -.98; --in: 600ms; --bob-t: 8.8s; }

/* the lowest tile hangs half its own height below the stage box */
.markband-cap {
  margin: calc(var(--tile) / 2 + 30px) auto 0;
  max-width: 34ch;
  text-align: center;
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink-2);
}

@keyframes markband-float {
  0%, 100% { transform: translateY(-3px) rotate(-1deg); }
  50% { transform: translateY(3px) rotate(1deg); }
}

@keyframes markband-glow {
  0%, 100% { opacity: .16; transform: scale(.94); }
  50% { opacity: .34; transform: scale(1.06); }
}

/* out from behind the face: the start negates the ring offset its own list
   item carries, so the tile is literally at the centre of the mark */
@keyframes markband-in {
  from {
    opacity: 0;
    transform: translate(calc(var(--x) * var(--rx) * -1), calc(var(--y) * var(--ry) * -1)) scale(.28);
  }
  to {
    opacity: 1;
    transform: translate(0, 0) scale(1);
  }
}

@keyframes markband-hover {
  0%, 100% { transform: translateY(calc(var(--bob) * -1)); }
  50% { transform: translateY(var(--bob)); }
}

/* Held at the first frame until the band is on screen, and held again when it
   leaves. Both classes are set by assets/brand-band.js, and the paused rule is
   qualified by the class the script adds to the band, so with no script at all
   the composition simply runs and settles on load. */
.markband-js:not(.is-in) .markband-tile-in,
.markband.is-off .markband-tile-in,
.markband.is-off .markband-mark img,
.markband.is-off .markband-glow {
  animation-play-state: paused;
}

@media (max-width: 760px) {
  .markband {
    --stage-w: 92vw;
    --stage-h: 108vw;
    --mark: 50vw;
    --tile: 13.5vw;
    --rx: calc(var(--stage-w) * .46);
    --ry: calc(var(--stage-h) * .47);
    --bob: 4px;
    padding: 56px 0 44px;
  }
  .markband-cap { margin-top: calc(var(--tile) / 2 + 20px); font-size: 14px; }
}

@media (prefers-reduced-motion: reduce) {
  .markband-mark img,
  .markband-glow,
  .markband-tile-in {
    animation: none;
  }
  .markband-mark,
  .markband-tile,
  .markband-tile img {
    transition: none;
  }
  .markband-tile-in { opacity: 1; transform: none; }
  .markband-glow { opacity: .26; }
}

/* ------------------------------------------------------------ /animation --

   The same composition at 1920 x 1080, choreographed once over ten seconds and
   ending settled. Nothing here is triggered by script: every animation starts
   with the document, so scripts/export-animation.mjs can pause the page and
   ask for the state at any second and get the same frame every time. */

.animpage {
  margin: 0;
  background: var(--mint);
  overflow: hidden;
}

.markband-full {
  width: 100vw;
  min-height: 100vh;
  padding: 0 0 56px;
  display: grid;
  grid-template-rows: 1fr auto;
  align-items: center;
  justify-items: center;
}

.markband-full .markband-stage { margin: 0; }

/* The two cuts that get rendered. Anything narrower is not a frame size, it is
   somebody opening the page on a phone, and there the band's own responsive
   geometry above is left to handle it. */
@media (min-width: 1340px) {
  .markband-full {
    --stage-w: 1280px;
    --stage-h: 740px;
    --mark: 560px;
    --tile: 130px;
    --rx: calc(var(--stage-w) * .43);
    --ry: calc(var(--stage-h) * .50);
    --bob: 6px;
  }
}

@media (max-aspect-ratio: 1 / 1) and (min-width: 1000px) {
  .markband-full {
    --stage-w: 1000px;
    --stage-h: 700px;
    --mark: 460px;
    --tile: 108px;
    --rx: calc(var(--stage-w) * .43);
    --ry: calc(var(--stage-h) * .50);
    --bob: 6px;
  }
}

/* the mark holds the first frame, so it is on screen at zero and only settles
   its scale, and the whole stage drifts up as the wordmark arrives */
.markband-full .markband-mark img {
  animation:
    markband-settle 2600ms var(--ease) both,
    markband-float 6s var(--ease-bob) 2600ms infinite;
}

.markband-full .markband-tile-in {
  animation:
    markband-in 900ms var(--ease) var(--in-full) both,
    markband-hover var(--bob-t) var(--ease-bob) calc(var(--in-full) + 900ms) infinite;
}

.markband-full .markband-tile:nth-child(1) { --in-full: 1600ms; }
.markband-full .markband-tile:nth-child(2) { --in-full: 2000ms; }
.markband-full .markband-tile:nth-child(3) { --in-full: 2400ms; }
.markband-full .markband-tile:nth-child(4) { --in-full: 2800ms; }
.markband-full .markband-tile:nth-child(5) { --in-full: 3200ms; }
.markband-full .markband-tile:nth-child(6) { --in-full: 3600ms; }

.markband-full .markband-tile.is-front img {
  animation: markband-front 2400ms var(--ease) 7000ms both;
}

.animword {
  text-align: center;
  animation: markband-word 1400ms var(--ease) 7200ms both;
}

.animword b {
  display: block;
  font-size: min(76px, 13vw);
  font-weight: 600;
  letter-spacing: -.03em;
  line-height: 1;
  color: var(--ink);
}

.animword span {
  display: block;
  margin-top: 14px;
  padding: 0 16px;
  font-size: min(24px, 4.6vw);
  color: var(--ink-2);
}

@keyframes markband-settle {
  from { transform: scale(.92); }
  to { transform: scale(1); }
}

/* the static is-front rule would put the heavier shadow on from frame zero, so
   the shadow is carried by the keyframes too and arrives with the scale */
@keyframes markband-front {
  from {
    transform: scale(1);
    box-shadow: 0 2px 5px rgba(15, 25, 20, .10), 0 18px 34px -16px rgba(15, 25, 20, .42);
  }
  to {
    transform: scale(1.16);
    box-shadow: 0 3px 8px rgba(15, 25, 20, .12), 0 26px 48px -18px rgba(15, 25, 20, .52);
  }
}

@keyframes markband-word {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: translateY(0); }
}
