/* The waiting mosaic: what there is to look at while a film is gathered and while it is made
   (progress_panel.html, macros.waiting_mosaic). One component, two phases -- "assembling" on the way in, as the
   photos are gathered and put in order, and "flowing" on the way out, as the light runs through what was built.

   It says nothing. No count, no percentage, no stage: a decoration that appeared to report progress would be
   reporting something nobody measured, and the bar beside it is the one place that says how far along the work
   is. So it is aria-hidden and carries no text.

   Only opacity and transform are animated. A box-shadow or a filter on fifty tiles repaints them every frame and
   showed up as jank on a phone; the glow here is a radial gradient inside each tile, which the compositor can
   leave alone once it is painted. The tiles are small and square, and the whole thing is one grid, so a phone
   draws one layer rather than fifty.

   Colours are the theme's own (theme.css): gold and amber warm, violet sparingly, so a tile never competes with
   the text above it. */

.waiting-mosaic {
  display: grid;
  /* Squares of a set size, as many across as the panel holds: twelve stretched columns made each tile a 90px
     bar on a computer, which is a row of dashes and not a mosaic. auto-fill keeps the tile small and lets the
     count follow the width, so the band is a few rows deep on a phone and shallower on a computer -- and its
     height always follows its own tiles, never the panel's, so it cannot push the message or the bar below a
     phone's first screenful. */
  grid-template-columns: repeat(auto-fill, minmax(var(--mosaic-tile-size, 24px), 1fr));
  gap: 5px;
  margin: 0;
}


/* The band belongs to the gathering. A finished or failed film's page has its own content, and while the film is
   made the render screen carries its own band, so a second one here would animate beside it. */
#progress.done > .waiting-area,
#progress.failed > .waiting-area,
#progress.rendering > .waiting-area { display: none; }

/* A flat square, not a soft blob: a radial gradient fading to transparent inside its own tile read as a smudge
   at this size, and twelve smudges in a row are not a mosaic. The light is in the colour and the opacity.

   Each tile has a brightness of its own, dark or light, from its own number (--r, drawn for it when the page was
   rendered): a band where every tile sits at one opacity is a texture, and what is wanted is a sky -- some stars
   brighter than others before anything moves at all. */
.waiting-mosaic span {
  aspect-ratio: 1;
  border-radius: 2px;
  background: var(--mosaic-tile);
  --dim: calc(.05 + var(--r, 40) * .0009);            /* .05 to .14: the tile at rest */
  --lit: calc(.20 + var(--r, 40) * .0022);            /* .20 to .42: the same tile alight */
  opacity: var(--dim);
  will-change: opacity, transform;
}

/* Three warmths, so the band reads as a mosaic rather than a pattern -- and the steps are primes, because the
   count of columns follows the width: every third tile fell in the same columns at twenty-four across and the
   band came out in vertical stripes. Five and eleven divide none of the counts the band is drawn at. The violet
   is the rarest: more of it and the band turns cold and pulls the eye off the text. */
.waiting-mosaic span                  { --mosaic-tile: rgba(224, 164, 77, .85); }   /* amber */
.waiting-mosaic span:nth-child(5n+2)  { --mosaic-tile: rgba(240, 177, 85, .95); }   /* gold */
.waiting-mosaic span:nth-child(11n+7) { --mosaic-tile: rgba(141, 123, 245, .75); }  /* violet */

/* The page is not on the screen (the customer switched app, or the phone locked itself, which a ten-minute wait
   invites): the mosaic's tiles stop breathing until it comes back. 620 tiles a band, each with two infinite
   animations, is a cost a phone pays in battery for nothing while nobody is looking (app-status.js). */
:root.page-away .waiting-mosaic span, :root.page-away .waiting-glow { animation-play-state: paused; }

/* Two things happen at once, and they are two animations because they move two different properties -- the stars
   the opacity, the wave the scale -- so neither overwrites the other and the compositor can keep both off the
   main thread.

   The stars: every tile lights and fades on its own clock, between 2.6 s and 8.7 s, starting at its own point in
   that clock (a negative delay starts an animation part-way through, so nothing waits to begin and no two tiles
   are in step). What makes them random is --r, the tile's own number, not its place in the grid: a band staggered
   by place alone pulses in rows, which reads as a machine and not as a sky.

   The wave: a short swell that passes through the band, delayed by the tile's place (--i), so the crest travels in
   reading order -- and because the tiles are a grid of unknown width, a delay per tile draws the crest as a slant
   across it. The three families below carry three steps and three periods, so three slants of different angles
   cross the band and drift past one another: the direction the band seems to be moving in keeps changing, which
   one wave alone never does. The steps and the periods share no factor, so the three never settle into one. */
.waiting-mosaic[data-phase] span {
  animation: mosaic-star calc(2600ms + var(--r, 40) * 61ms) ease-in-out infinite,
             mosaic-wave 6.4s ease-in-out infinite;
  animation-delay: calc(var(--r, 40) * -83ms), calc(var(--i) * 17ms);
}

.waiting-mosaic[data-phase] span:nth-child(3n+1) {
  animation-duration: calc(2600ms + var(--r, 40) * 61ms), 9.1s;
  animation-delay: calc(var(--r, 40) * -83ms), calc(var(--i) * 29ms);
}

.waiting-mosaic[data-phase] span:nth-child(5n+3) {
  animation-duration: calc(2600ms + var(--r, 40) * 61ms), 13.7s;
  animation-delay: calc(var(--r, 40) * -83ms), calc(var(--i) * 43ms);
}

/* On the way out the band carries a card over it -- the film's title, its bar, the scene being rendered -- and the
   rest state that reads as a sky behind the plain ingress screen disappeared under it. The tiles sit brighter here
   and flash brighter, so the band is still there beside the card rather than a hint of texture. */
.waiting-mosaic[data-phase="flowing"] span {
  --dim: calc(.11 + var(--r, 40) * .0014);           /* .11 to .25: the tile at rest */
  --lit: calc(.34 + var(--r, 40) * .0030);           /* .34 to .64: the same tile alight */
}
:root[data-theme="light"] .waiting-mosaic[data-phase="flowing"] span {
  --dim: calc(.18 + var(--r, 40) * .0016); --lit: calc(.40 + var(--r, 40) * .0024);
}

/* On the way in the tiles arrive first, one after another in reading order, and the sky starts once they are all
   there. On the way out nothing arrives any more: the band is built, and only the stars and the waves are left. */
.waiting-mosaic[data-phase="assembling"] span {
  animation: mosaic-arrive .7s ease-out both,
             mosaic-star calc(2600ms + var(--r, 40) * 61ms) ease-in-out infinite,
             mosaic-wave 6.4s ease-in-out infinite;
  animation-delay: calc(var(--i) * 5ms), calc(1.2s + var(--r, 40) * -83ms), calc(1.2s + var(--i) * 17ms);
}

.waiting-mosaic[data-phase="assembling"] span:nth-child(3n+1) {
  animation-duration: .7s, calc(2600ms + var(--r, 40) * 61ms), 9.1s;
  animation-delay: calc(var(--i) * 5ms), calc(1.2s + var(--r, 40) * -83ms), calc(1.2s + var(--i) * 29ms);
}

.waiting-mosaic[data-phase="assembling"] span:nth-child(5n+3) {
  animation-duration: .7s, calc(2600ms + var(--r, 40) * 61ms), 13.7s;
  animation-delay: calc(var(--i) * 5ms), calc(1.2s + var(--r, 40) * -83ms), calc(1.2s + var(--i) * 43ms);
}

@keyframes mosaic-arrive {
  from { opacity: 0; transform: scale(.55); }
  60%  { opacity: .28; transform: scale(1.06); }
  to   { opacity: var(--dim); transform: scale(1); }
}

/* One star: dark for most of its turn, then a flash and out again. A tile that spends a third of its time lit and
   a third going out is a tile breathing, which at this size is a wash of light over the band; what a sky does is
   nothing, nothing, a sparkle. The flash is a tenth of the turn, so of six hundred tiles a handful are alight at
   any moment and each catches the eye on its own. */
@keyframes mosaic-star {
  0%, 74%, 100% { opacity: var(--dim); }
  80%           { opacity: var(--lit); }
  88%           { opacity: var(--dim); }
}

/* The wave is a swell, not a pulse: a tile is its own size for most of the turn and grows only as the crest
   passes it, so at any moment the band shows a slant of larger tiles and not a general shimmer. */
@keyframes mosaic-wave {
  0%, 64%, 100% { transform: scale(1); }
  82%           { transform: scale(1.45); }
}

/* The mosaic is the screen's background, not an ornament in the middle of it: it fills the whole panel behind
   the words, which on a phone is nearly the whole screen. isolation on #progress is what lets it sit behind --
   the panel is position: relative with no z-index of its own, so a layer at z-index -1 would otherwise fall
   behind the panel's opaque surface and show nothing at all. Only #progress is isolated, never the review
   panel beside it in that rule, whose pages stack their own layers against the step bar's 5. */
#progress { isolation: isolate; }

.waiting-area {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  border-radius: inherit;
  padding: 10px;   /* the grid starts inside the panel's rounded corners, so no tile is cut in half */
}

.waiting-area > .waiting-mosaic { height: 100%; align-content: start; }

/* The veil: the page's own colour over the band, so a line of text never has a lit tile competing with it. The
   mosaic read as a sky of its own with the words lost in it ("hard to read text with mosaic aggressive"); with
   the veil the band is still there and the screen is the words. */
.waiting-area::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--bg);
  opacity: .42;
  pointer-events: none;
}

:root[data-theme="light"] .waiting-area::after { opacity: .5; }

/* The waves. A tile growing by half is a swell nobody sees at 20px and a tenth of an opacity, so what crosses the
   band is light of its own: a soft crest that travels across it, in a slant whose angle keeps changing.

   Two elements, not six hundred: the crest is one gradient on one box, and the whole thing costs two composited
   transforms however many tiles the band is drawn with. The angle is the outer box's rotation and the travel is the
   inner box's slide, because two animations on one element's transform would overwrite one another. The two waves
   turn at different rates and in opposite directions, so the band's apparent direction never settles.

   inset: -60% keeps the box larger than the band at every angle: a rotated box cut to the band's own size shows its
   corners sweeping across as empty wedges. */
.waiting-waves {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  border-radius: inherit;
}

.waiting-wave {
  position: absolute;
  inset: -60%;
  animation: wave-turn 27s ease-in-out infinite;
}

.waiting-wave i {
  position: absolute;
  inset: 0;
  display: block;
  background: linear-gradient(90deg, transparent 0 36%, rgba(240, 177, 85, .09) 50%, transparent 64% 100%);
  animation: wave-run 9.4s linear infinite;
}

.waiting-wave + .waiting-wave { animation-duration: 41s; animation-direction: reverse; }

.waiting-wave + .waiting-wave i {
  background: linear-gradient(90deg, transparent 0 38%, rgba(141, 123, 245, .075) 50%, transparent 62% 100%);
  animation-duration: 14.6s;
}

@keyframes wave-turn {
  0%, 100% { transform: rotate(21deg); }
  50%      { transform: rotate(-29deg); }
}

@keyframes wave-run {
  from { transform: translateX(-85%); }
  to   { transform: translateX(85%); }
}

:root.page-away .waiting-wave, :root.page-away .waiting-wave i { animation-play-state: paused; }

:root[data-theme="light"] .waiting-waves { opacity: .7; }

.waiting-glow {
  position: absolute;
  inset: -10% -14%;
  z-index: 0;
  pointer-events: none;
  /* Both centres sit well inside the box and both fade out before its edges: a gradient centred ON an edge
     leaves colour there, and the box's own straight edge then shows as a seam across the panel. */
  background: radial-gradient(55% 90% at 32% 50%, rgba(240, 177, 85, .08), transparent 62%),
              radial-gradient(45% 80% at 76% 55%, rgba(141, 123, 245, .07), transparent 64%);
  animation: mosaic-ambient 14s ease-in-out infinite;
}

@keyframes mosaic-ambient {
  0%, 100% { opacity: .75; transform: scale(1); }
  50%      { opacity: 1; transform: scale(1.08); }
}

/* The light theme's surfaces are pale: the same opacities there read as dirt on the page rather than light, so
   every tile is lifted by the same amount and keeps the brightness of its own. */
:root[data-theme="light"] .waiting-mosaic span { --dim: calc(.12 + var(--r, 40) * .0011); --lit: calc(.28 + var(--r, 40) * .0018); }
:root[data-theme="light"] .waiting-glow { opacity: .55; }

/* Asked for less motion: the mosaic stays, and stops. It is still a band of warm light under the message, which
   is the point of it -- the tiles keep their own brightnesses, so it is still a sky; nothing moves, pulses or
   sweeps. */
@media (prefers-reduced-motion: reduce) {
  .waiting-mosaic span,
  .waiting-wave,
  .waiting-wave i,
  .waiting-glow {
    animation: none;
  }
  .waiting-waves { display: none; }
  .waiting-mosaic[data-phase] span { opacity: var(--dim); transform: none; }
}

@media (max-width: 480px) {
  .waiting-mosaic { --mosaic-tile-size: 20px; gap: 4px; }
  .waiting-glow { inset: -6% -14%; }
}
