/* KuduDoc v6 — the continuous sky.
   ONE fixed background for the whole page: six phase fields (plus two bridge fields used only
   mid-crossfade) crossfaded by opacity, with a static grain baked in; the strand ribbon (a dawn
   render and an ember render of one geometry); and the drifting mark bubbles. sky.js builds the children inside <div class="sky" id="sky" aria-hidden="true">
   and writes only opacity and transform. Needs tokens.css first.

   Stack (bottom to top): phases (+ two bridges) · ribbon · bubbles. Page content must sit above
   it (position: relative; z-index: var(--z-content)) and sections carry NO backgrounds.

   Phase will-change is only set on layers sky.js marks .is-live (the current section's
   neighbourhood): every composited full-viewport layer costs ~20 MB of GPU memory at 2x, even at
   opacity 0. The ribbon is always composited: its screen-blended strands are costly to rasterise,
   so it is rasterised once at load and only ever transformed and faded after that. */

.sky {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;               /* the large viewport on phones: no gap when the URL bar hides */
  z-index: var(--z-sky, 0);
  overflow: hidden;
  pointer-events: none;
  contain: strict;
  background: var(--navy-950, #06162a);
  /* static film grain, rendered once as an image and baked into the dark phases (so it adds no
     layer of its own): dithers the dark gradients against banding */
  --sky-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='g' x='0' y='0'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .085 -.032'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23g)'/%3E%3C/svg%3E") 0 0 / 220px 220px;
}

/* ---------------------------------------------------------------- phases */
.sky__phase {
  position: absolute;
  inset: 0;
  opacity: 0;
}
.sky__phase.is-live { will-change: opacity; }
.sky__phase--dawn { opacity: 1; }

/* dawn — a sunrise, not a flat navy: deep navy crown, saturated blue welling up from below,
   a restrained amber/peach horizon glow low on the right. */
.sky__phase--dawn {
  background:
    var(--sky-grain),
    radial-gradient(30% 15% at 96% 103%, rgba(255, 179, 71, .92) 0%, rgba(255, 205, 130, .62) 34%, rgba(255, 240, 222, .26) 66%, rgba(255, 240, 222, 0) 100%),
    radial-gradient(64% 36% at 92% 106%, rgba(191, 227, 255, .5) 0%, rgba(79, 179, 255, .34) 42%, rgba(79, 179, 255, 0) 100%),
    radial-gradient(110% 72% at 80% 112%, rgba(0, 107, 203, .92) 0%, rgba(0, 94, 181, .62) 34%, rgba(0, 78, 153, .22) 62%, rgba(0, 78, 153, 0) 84%),
    radial-gradient(70% 60% at 100% 30%, rgba(0, 78, 153, .38) 0%, rgba(0, 78, 153, 0) 80%),
    radial-gradient(80% 64% at 0% 0%, rgba(6, 22, 42, .95) 0%, rgba(6, 22, 42, 0) 76%),
    linear-gradient(180deg, #06162a 0%, #0a2340 26%, #0d2b50 50%, #083f7c 78%, #004e99 100%);
}

/* morning — deeper to brighter blue, still dark enough for white text. The sun a little higher:
   the dawn horizon warmth stays low on the right, which also lets morning hand over to the
   ember bloom warm-to-warm instead of blue-into-orange (which reads mauve). */
.sky__phase--morning {
  background:
    var(--sky-grain),
    radial-gradient(34% 18% at 94% 104%, rgba(255, 179, 71, .78) 0%, rgba(255, 205, 130, .48) 36%, rgba(255, 240, 222, .16) 68%, rgba(255, 240, 222, 0) 100%),
    radial-gradient(70% 55% at 88% 96%, rgba(79, 179, 255, .30) 0%, rgba(79, 179, 255, 0) 80%),
    radial-gradient(80% 60% at 0% 0%, rgba(6, 22, 42, .75) 0%, rgba(6, 22, 42, 0) 74%),
    linear-gradient(180deg, #0a2340 0%, #073a70 38%, #004e99 68%, #0761b8 100%);
}

/* ember — the one warm moment. Navy base, a big ember bloom low on the right with a hot amber
   heart; the upper-left third stays dark navy for the white text column. */
.sky__phase--ember {
  background:
    var(--sky-grain),
    radial-gradient(24% 22% at 84% 93%, rgba(255, 247, 232, .6) 0%, rgba(255, 214, 150, .42) 36%, rgba(255, 179, 71, 0) 100%),
    radial-gradient(52% 50% at 84% 98%, rgba(255, 179, 71, .94) 0%, rgba(255, 118, 43, .9) 26%, rgba(255, 77, 43, .84) 42%, rgba(70, 18, 12, .74) 54%, rgba(8, 14, 28, .6) 68%, rgba(8, 14, 28, 0) 100%),
    radial-gradient(64% 58% at 0% 0%, rgba(6, 22, 42, .92) 0%, rgba(6, 22, 42, 0) 78%),
    linear-gradient(180deg, #06162a 0%, #0a2340 44%, #0c2542 100%);
}

/* day — warm light ground, a faint sky haze top-left, faint peach warmth bottom-right. */
.sky__phase--day {
  background:
    radial-gradient(70% 60% at 0% 0%, rgba(227, 242, 255, .95) 0%, rgba(227, 242, 255, 0) 72%),
    radial-gradient(60% 50% at 100% 100%, rgba(255, 220, 198, .55) 0%, rgba(255, 240, 230, .30) 40%, rgba(255, 240, 230, 0) 76%),
    linear-gradient(180deg, #f6f5f1 0%, #f8f5ef 60%, #f8f3ec 100%);
}

/* calm — a calmer, slightly cooler light ground. */
.sky__phase--calm {
  background:
    radial-gradient(80% 60% at 100% 0%, rgba(238, 246, 255, .85) 0%, rgba(238, 246, 255, 0) 70%),
    linear-gradient(180deg, #f6f7f9 0%, #f7f6f3 55%, #f8f5ef 100%);
}

/* dusk — the bookend: navy with a low amber/ember horizon glowing along the very bottom. */
.sky__phase--dusk {
  background:
    var(--sky-grain),
    linear-gradient(0deg, rgba(255, 179, 71, .30) 0, rgba(255, 179, 71, 0) 3.5%),
    radial-gradient(70% 16% at 50% 100%, rgba(255, 247, 232, .30) 0%, rgba(255, 179, 71, .22) 40%, rgba(255, 179, 71, 0) 100%),
    radial-gradient(90% 34% at 56% 104%, rgba(255, 179, 71, .44) 0%, rgba(255, 118, 43, .26) 36%, rgba(255, 77, 43, .10) 64%, rgba(255, 77, 43, 0) 100%),
    radial-gradient(120% 60% at 50% 108%, rgba(0, 78, 153, .55) 0%, rgba(0, 78, 153, 0) 76%),
    linear-gradient(180deg, #06162a 0%, #0a2340 34%, #102d49 72%, #173a5c 100%);
}

/* bridges — never a section's phase; each takes the middle of one kind of crossfade.
   twilight: dark↔light (ember→day, calm→dusk). The sky brightens through a blue-and-gold
   sunrise, or dims through a sunset, instead of mixing navy and cream into slate grey. */
.sky__phase--twilight {
  background:
    radial-gradient(70% 46% at 84% 104%, rgba(255, 179, 71, .8) 0%, rgba(255, 220, 198, .5) 40%, rgba(255, 220, 198, 0) 82%),
    linear-gradient(180deg, #1a64b4 0%, #3f96e2 36%, #93cbf6 68%, #ffe6cc 100%);
}

/* kindle: cool dark↔ember (sign→seal). Blue under the ember bloom's red rim reads mauve;
   this carries the change through navy and a gold horizon, with no red over blue. */
.sky__phase--kindle {
  background:
    var(--sky-grain),
    radial-gradient(36% 22% at 86% 102%, rgba(255, 226, 170, .9) 0%, rgba(255, 179, 71, .72) 34%, rgba(255, 179, 71, 0) 100%),
    radial-gradient(64% 44% at 84% 106%, rgba(255, 179, 71, .5) 0%, rgba(255, 179, 71, .16) 46%, rgba(255, 179, 71, 0) 78%),
    radial-gradient(80% 64% at 0% 0%, rgba(6, 22, 42, .9) 0%, rgba(6, 22, 42, 0) 76%),
    linear-gradient(180deg, #06162a 0%, #0a2340 42%, #0b2d52 100%);
}

/* ---------------------------------------------------------------- ribbon */
.sky__ribbon {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  will-change: transform, opacity;   /* always composited: rasterised once, never re-rastered */
}
.sky__strands {
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  overflow: hidden;
  will-change: opacity;
}
.sky__strands--ember { opacity: 0; }
/* overlapping strands add light rather than cover each other */
.sky__strands .s { mix-blend-mode: screen; }

/* ---------------------------------------------------------------- bubbles */
.sky__bubbles {
  position: absolute;
  inset: 0;
}
.sky__bubble {
  position: absolute;
  left: var(--x);
  top: calc(100% + 20px);                    /* born just below the viewport */
  width: var(--sz);
  height: var(--sz);
  will-change: transform, opacity;           /* parallax and phase opacity, written by sky.js */
}
.sky__rise,
.sky__sway {
  position: absolute;
  inset: 0;
  will-change: transform;
}
/* The one loop on the page: a slow rise through the viewport plus a gentle sway. Each bubble
   carries a twin one travel-length below it, so the loop point and the parallax wrap both
   happen out of sight — no bubble ever pops. */
.sky__rise { animation: kd-sky-rise 60s linear infinite; }
.sky__sway { animation: kd-sky-sway 11s var(--ease-io, ease-in-out) infinite alternate; }
@keyframes kd-sky-rise {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, calc(-100vh - 180px), 0); }
}
@keyframes kd-sky-sway {
  from { transform: translate3d(calc(var(--a, 14px) * -1), 0, 0) rotate(-5deg); }
  to   { transform: translate3d(var(--a, 14px), 0, 0) rotate(5deg); }
}

/* A soap bubble, not a glass panel: clear interior, thin luminous rim, a specular highlight
   upper-left, a faint secondary reflection lower-right, and sky/cream/amber iridescence
   confined to the rim. No backdrop-filter. */
.sky__orb {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background:
    radial-gradient(24% 11% at 66% 83%, rgba(255, 247, 232, .42) 0%, rgba(255, 247, 232, 0) 100%),
    radial-gradient(circle at 50% 50%, rgba(79, 179, 255, 0) 56%, rgba(79, 179, 255, .10) 74%, rgba(79, 179, 255, .26) 90%, rgba(191, 227, 255, .42) 100%);
  box-shadow:
    inset 0 0 0 1px rgba(79, 179, 255, .62),
    inset 0 0 0 2px rgba(255, 247, 232, .16),
    inset 3px 4px 10px rgba(255, 247, 232, .16),
    inset -4px -6px 14px rgba(255, 179, 71, .16);
}
.sky__orb--twin { top: calc(100vh + 180px); }
.sky__orb::before {                          /* specular highlight */
  content: '';
  position: absolute;
  left: 17%;
  top: 11%;
  width: 32%;
  height: 19%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 255, 255, .95) 0%, rgba(255, 255, 255, .5) 42%, rgba(255, 255, 255, 0) 100%);
  transform: rotate(-36deg);
}
.sky__orb::after {                           /* thin-film iridescence on the rim only */
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(from 200deg, rgba(79, 179, 255, .50), rgba(255, 247, 232, .40), rgba(255, 179, 71, .42), rgba(191, 227, 255, .30), rgba(79, 179, 255, .50));
  -webkit-mask-image: radial-gradient(circle closest-side, transparent 72%, #000 96%, #000 100%);
          mask-image: radial-gradient(circle closest-side, transparent 72%, #000 96%, #000 100%);
  opacity: .8;
}
.sky__orb img {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 52%;
  height: auto;
  transform: translate(-50%, -50%);
  opacity: .92;
}

/* phones: fewer, smaller bubbles, pushed to the edges */
@media (max-width: 700px) {
  .sky__bubble {
    left: var(--xm);
    width: calc(var(--sz) * .6);
    height: calc(var(--sz) * .6);
  }
  .sky__bubble:nth-child(n+8) { display: none; }
}

/* reduced motion: no drift, no sway, no parallax (sky.js skips it); each bubble rests at the
   point its loop would start from, and the phases still crossfade. */
@media (prefers-reduced-motion: reduce) {
  .sky__rise {
    animation: none;
    transform: translate3d(0, calc((100vh + 180px) * var(--p, .5) * -1), 0);
  }
  .sky__sway { animation: none; }
  .sky__rise,
  .sky__sway { will-change: auto; }
  .sky__bubble { will-change: opacity; }
}
