/* backdrop.css -- the page background, shared by the marketing page and the app.

   Modelled on a WebGL "shadow blending" shader: several very large, very soft
   light sources drifting past each other over near-black, with film grain laid
   over the top. The grain is what stops the gradients banding, and it is most
   of why the original reads as a photograph of light rather than as CSS.

   Done with gradients and one SVG noise tile instead of a shader, because a
   WebGL canvas on every page would mean a renderer, a compile step and a
   second thing to keep alive on a laptop. Two fixed divs cost nothing.

   Linked by both landing.html and index.html so the two surfaces cannot drift
   apart. Colour comes from the ember accent alone; the blooms are the same hue
   as the primary button, just enormous and nearly transparent. */

.backdrop,
.backdrop-scrim,
.backdrop-grain {
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
}

/* --- the light ---------------------------------------------------------- */
/* Oversized so the blobs can drift without their edges ever entering frame,
   and centred by the negative offsets. */
.backdrop {
  overflow: hidden;
  background: var(--canvas, #0b0b0d);
}
.backdrop span {
  position: absolute;
  display: block;
  border-radius: 50%;
  /* A soft-edged blob. The stops are close together because a light source
     this large needs a long, slow falloff or it reads as a hard circle. */
  filter: blur(60px);
  will-change: transform;
}

.backdrop .b1 {
  width: 90vw;
  height: 90vw;
  left: 30%;
  top: -10%;
  background: radial-gradient(circle at 50% 50%,
              rgba(226, 96, 58, .375) 0%,
              rgba(226, 96, 58, .15) 38%,
              transparent 68%);
  animation: drift-a 34s ease-in-out infinite alternate;
}
.backdrop .b2 {
  width: 70vw;
  height: 70vw;
  left: 55%;
  top: 35%;
  background: radial-gradient(circle at 50% 50%,
              rgba(255, 138, 99, .275) 0%,
              rgba(255, 138, 99, .10) 40%,
              transparent 70%);
  animation: drift-b 46s ease-in-out infinite alternate;
}
.backdrop .b3 {
  width: 80vw;
  height: 80vw;
  left: -25%;
  top: 20%;
  background: radial-gradient(circle at 50% 50%,
              rgba(226, 96, 58, .20) 0%,
              rgba(226, 96, 58, .06) 42%,
              transparent 72%);
  animation: drift-c 58s ease-in-out infinite alternate;
}

/* Three different periods, none of them multiples of each other, so the
   arrangement never visibly repeats. */
@keyframes drift-a {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(-14%, 10%, 0) scale(1.15); }
}
@keyframes drift-b {
  from { transform: translate3d(0, 0, 0) scale(1.1); }
  to   { transform: translate3d(12%, -14%, 0) scale(.92); }
}
@keyframes drift-c {
  from { transform: translate3d(0, 0, 0) scale(.95); }
  to   { transform: translate3d(18%, -8%, 0) scale(1.2); }
}

/* --- the scrim ---------------------------------------------------------- */
/* Text sits in a centre column; the light is most worth seeing at the edges.
   This puts the canvas colour back over the middle so body copy keeps a dark
   floor, and fades out sideways so the blooms survive where nothing is read.

   It is not decoration, and it is why the blooms above can be as bright as
   they are. Unscrimmed, all three overlapping reach rgb(153,72,49), where
   --ink-muted is 3.7:1 and --ink-subtle 2.1:1: both fail. Dimming the blooms
   alone to fix that needs about a quarter of their strength and leaves nothing
   worth looking at. Capping the composite instead lets them be brighter than
   they started and still measure 4.71:1 at the weakest point. */
.backdrop-scrim {
  z-index: -1;
  /* Never reaches transparent. The backdrop is fixed, so scrolling can put a
     line of small print anywhere in the viewport, and a scrim that fades out
     at the edges would leave a corner where it fails. The floor is .78, which
     measures at 4.71:1 for the weakest ink over the brightest overlap. */
  background: radial-gradient(150% 130% at 50% 42%,
              rgba(11, 11, 13, .90) 0%,
              rgba(11, 11, 13, .84) 48%,
              rgba(11, 11, 13, .78) 100%);
}
@media (prefers-color-scheme: light) {
  .backdrop-scrim {
    background: radial-gradient(150% 130% at 50% 42%,
                rgba(245, 245, 244, .90) 0%,
                rgba(245, 245, 244, .84) 48%,
                rgba(245, 245, 244, .78) 100%);
  }
}

/* --- the grain ---------------------------------------------------------- */
/* fractalNoise from an inline SVG, tiled. This is the texture that makes the
   gradients look like light rather than like a CSS gradient, and it hides the
   banding that large soft gradients produce on 8-bit displays. */
.backdrop-grain {
  /* Same layer as the scrim, and later in the DOM, so it paints over the
     scrim but still behind everything on the page. */
  z-index: -1;
  opacity: .5;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.42'/%3E%3C/svg%3E");
  background-repeat: repeat;
  /* Soft-light keeps the grain in the midtones and off the deep blacks, which
     is where overlay would turn it into visible speckle. */
  mix-blend-mode: soft-light;
}

/* Light mode gets the same arrangement at lower strength: the same amount of
   ember over a near-white page reads as a stain rather than as light. */
@media (prefers-color-scheme: light) {
  .backdrop .b1 { background: radial-gradient(circle at 50% 50%, rgba(226, 96, 58, .16) 0%, rgba(226, 96, 58, .06) 38%, transparent 68%); }
  .backdrop .b2 { background: radial-gradient(circle at 50% 50%, rgba(226, 96, 58, .11) 0%, rgba(226, 96, 58, .04) 40%, transparent 70%); }
  .backdrop .b3 { background: radial-gradient(circle at 50% 50%, rgba(226, 96, 58, .09) 0%, rgba(226, 96, 58, .03) 42%, transparent 72%); }
  .backdrop-grain { opacity: .3; mix-blend-mode: multiply; }
}

/* Drifting light in the corner of the eye is exactly what reduced motion is
   asking not to have. The arrangement stays; only the movement stops. */
@media (prefers-reduced-motion: reduce) {
  .backdrop span { animation: none; }
}
