/* ============================================================
   Ambient gradient background
   Reading surfaces only: essay, field-notes, photo-essay.

   Two overlapping radial gradients, drifting on non-synchronous
   periods. Must read as a soft atmosphere, not as two visible
   shapes with edges.

   Two design rules that killed the edge banding:
     1. Each gradient layer is 300vw by 300vh, centered on the
        viewport. The rectangular box of the layer sits 100vw /
        100vh offscreen in every direction, so the gradient's
        natural fall-off is what the eye sees, never the box's
        rectangular edge.
     2. The color ramp uses many closely-spaced stops on an
        ease-out curve (roughly 1 - (1 - t)^3). This makes the
        transition from center to transparent look smooth instead
        of the linear two-stop ramp which produces a visible
        terminator ring.

   Hand tune AFTER shipping: if motion is consciously visible,
   drop each center stop's percentage by 1 at a time.
   ============================================================ */

@property --ambient-a-color {
  syntax: "<color>";
  inherits: true;
  initial-value: #2b4563;
}
@property --ambient-b-color {
  syntax: "<color>";
  inherits: true;
  initial-value: #b88a3a;
}

body.almanac-heritage.has-ambient { isolation: isolate; }

.ambient {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
  contain: strict;
  --ambient-a-color: var(--indigo);
  --ambient-b-color: var(--warm);
  transition:
    --ambient-a-color 4s ease,
    --ambient-b-color 4s ease;
}

/* Oversized layers. 300vw × 300vh centered on the viewport so
   the rectangular edge is 100vw / 100vh offscreen in every
   direction. The radial gradient therefore never collides with
   a box edge. */
.ambient__a,
.ambient__b {
  position: absolute;
  inset: -100vh -100vw;
  will-change: transform;
  transform: translateZ(0);
}

/* Multi-stop ease-out ramp. Sampled at t = 0, 0.15, 0.3, 0.45,
   0.6, 0.75, 0.9, with opacity multiplier 1 - (1 - t)^3. This
   approximates a cubic-bezier ease-out and reads as "soft all
   the way out" rather than "colored disk with a ring". */
.ambient__a {
  background: radial-gradient(
    circle 75vmax at 50% 50%,
    color-mix(in srgb, var(--ambient-a-color) 9%,   transparent)  0%,
    color-mix(in srgb, var(--ambient-a-color) 7.0%, transparent) 15%,
    color-mix(in srgb, var(--ambient-a-color) 5.2%, transparent) 30%,
    color-mix(in srgb, var(--ambient-a-color) 3.6%, transparent) 45%,
    color-mix(in srgb, var(--ambient-a-color) 2.3%, transparent) 60%,
    color-mix(in srgb, var(--ambient-a-color) 1.1%, transparent) 75%,
    color-mix(in srgb, var(--ambient-a-color) 0.3%, transparent) 90%,
    transparent 100%
  );
  animation: ambientDriftA 120s linear infinite;
}
.ambient__b {
  background: radial-gradient(
    circle 65vmax at 50% 50%,
    color-mix(in srgb, var(--ambient-b-color) 9%,   transparent)  0%,
    color-mix(in srgb, var(--ambient-b-color) 7.0%, transparent) 15%,
    color-mix(in srgb, var(--ambient-b-color) 5.2%, transparent) 30%,
    color-mix(in srgb, var(--ambient-b-color) 3.6%, transparent) 45%,
    color-mix(in srgb, var(--ambient-b-color) 2.3%, transparent) 60%,
    color-mix(in srgb, var(--ambient-b-color) 1.1%, transparent) 75%,
    color-mix(in srgb, var(--ambient-b-color) 0.3%, transparent) 90%,
    transparent 100%
  );
  animation: ambientDriftB 90s linear infinite;
}

/* Lamplight: 10% center instead of 8%. Night sky eats more signal. */
[data-mode="lamplight"] .ambient__a {
  background: radial-gradient(
    circle 75vmax at 50% 50%,
    color-mix(in srgb, var(--ambient-a-color) 10.5%, transparent)  0%,
    color-mix(in srgb, var(--ambient-a-color)  8.2%, transparent) 15%,
    color-mix(in srgb, var(--ambient-a-color)  6.1%, transparent) 30%,
    color-mix(in srgb, var(--ambient-a-color)  4.2%, transparent) 45%,
    color-mix(in srgb, var(--ambient-a-color)  2.7%, transparent) 60%,
    color-mix(in srgb, var(--ambient-a-color)  1.3%, transparent) 75%,
    color-mix(in srgb, var(--ambient-a-color)  0.4%, transparent) 90%,
    transparent 100%
  );
}
[data-mode="lamplight"] .ambient__b {
  background: radial-gradient(
    circle 65vmax at 50% 50%,
    color-mix(in srgb, var(--ambient-b-color) 10.5%, transparent)  0%,
    color-mix(in srgb, var(--ambient-b-color)  8.2%, transparent) 15%,
    color-mix(in srgb, var(--ambient-b-color)  6.1%, transparent) 30%,
    color-mix(in srgb, var(--ambient-b-color)  4.2%, transparent) 45%,
    color-mix(in srgb, var(--ambient-b-color)  2.7%, transparent) 60%,
    color-mix(in srgb, var(--ambient-b-color)  1.3%, transparent) 75%,
    color-mix(in srgb, var(--ambient-b-color)  0.4%, transparent) 90%,
    transparent 100%
  );
}

/* Drift. Translation bounds are small relative to the 300vw /
   300vh layer, so the rectangular edges never come near the
   viewport. Periods kept at 120s / 90s per spec. */
@keyframes ambientDriftA {
  0%   { transform: translate3d(-22vw, -16vh, 0); }
  25%  { transform: translate3d( 14vw, -14vh, 0); }
  50%  { transform: translate3d( 20vw,  18vh, 0); }
  75%  { transform: translate3d(-10vw,  14vh, 0); }
  100% { transform: translate3d(-22vw, -16vh, 0); }
}
@keyframes ambientDriftB {
  0%   { transform: translate3d( 20vw,  16vh, 0); }
  33%  { transform: translate3d(-14vw,  22vh, 0); }
  66%  { transform: translate3d(-20vw, -12vh, 0); }
  100% { transform: translate3d( 20vw,  16vh, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .ambient__a,
  .ambient__b { animation: none; }
  .ambient__a { transform: translate3d(-22vw, -16vh, 0); }
  .ambient__b { transform: translate3d( 20vw,  16vh, 0); }
}
