/* =============================================================
   Animated offshore scene
   Markup: includes/partials/hero-scene.php

   The scene runs on a single 0→1 dial, --kg-mix: 0 is a clear calm day,
   1 is a storm at night. motion.js writes raw scroll progress through the
   band into --kg-p and everything below interpolates from it, so the scene
   moves continuously from day to night as the section is scrolled rather
   than flipping between two states.

   Why the tokens are declared on .kg-scene and not :root: an unregistered
   custom property is substituted at computed-value time on the element it is
   declared on. Declaring these on :root would resolve var(--kg-mix) against
   the root's value and inherit a fixed colour downward, ignoring the local
   dial. Declared here, they resolve per scene against the inherited --kg-mix.

   All motion is CSS-only and is switched off under prefers-reduced-motion.
   ============================================================= */

:root {
  /* ---- Day palette ---- */
  --d-sky-1: #3f7fc4;  --d-sky-2: #8fbde6;  --d-sky-3: #d9e9f6;
  --d-sea-1: #3d78ab;  --d-sea-2: #16375c;
  --d-wave-far: #4a85b8; --d-wave-mid: #34699b; --d-wave-near: #23527f; --d-wave-fore: #163a5e;
  --d-orb: #fff6d8;    --d-orb-glow: #ffe9a3;
  --d-cloud: rgba(255,255,255,.82); --d-cloud-low: rgba(255,255,255,.6);
  --d-haze: rgba(255,255,255,.55);
  --d-rig: #142a4b;    --d-rig-line: #1d3a63;
  --d-rain: rgba(255,255,255,.35);

  /* ---- Night palette ---- */
  --n-sky-1: #03060f;  --n-sky-2: #0a1428;  --n-sky-3: #182842;
  --n-sea-1: #0e1e38;  --n-sea-2: #02060e;
  --n-wave-far: #35597e; --n-wave-mid: #1e3c5c; --n-wave-near: #0f2540; --n-wave-fore: #050f1d;
  --n-orb: #e8eeff;    --n-orb-glow: #9fb8e8;
  --n-cloud: rgba(13,24,44,.92); --n-cloud-low: rgba(9,17,33,.85);
  --n-haze: rgba(20,34,60,.7);
  --n-rig: #060d1c;    --n-rig-line: #0d1930;
  --n-rain: rgba(170,195,235,.5);

  /* Scroll progress (0-1), written by motion.js. */
  --kg-p: 0;
  /* In a dark page a fully bright scene at the top of the band reads as a
     hole punched in the layout, so night mode starts the dial part-way in. */
  --kg-mix-floor: 0;
}
:root[data-theme="dark"] { --kg-mix-floor: .22; }

/* ===== Stage ===== */
.kg-scene {
  position: absolute; inset: 0; z-index: 0; overflow: hidden;

  --kg-mix: calc(var(--kg-mix-floor) + (1 - var(--kg-mix-floor)) * var(--kg-p));
  --mixpct: calc(var(--kg-mix) * 100%);

  --kg-sky-1: color-mix(in srgb, var(--d-sky-1), var(--n-sky-1) var(--mixpct));
  --kg-sky-2: color-mix(in srgb, var(--d-sky-2), var(--n-sky-2) var(--mixpct));
  --kg-sky-3: color-mix(in srgb, var(--d-sky-3), var(--n-sky-3) var(--mixpct));
  --kg-sea-1: color-mix(in srgb, var(--d-sea-1), var(--n-sea-1) var(--mixpct));
  --kg-sea-2: color-mix(in srgb, var(--d-sea-2), var(--n-sea-2) var(--mixpct));
  --kg-wave-far:  color-mix(in srgb, var(--d-wave-far),  var(--n-wave-far)  var(--mixpct));
  --kg-wave-mid:  color-mix(in srgb, var(--d-wave-mid),  var(--n-wave-mid)  var(--mixpct));
  --kg-wave-near: color-mix(in srgb, var(--d-wave-near), var(--n-wave-near) var(--mixpct));
  --kg-wave-fore: color-mix(in srgb, var(--d-wave-fore), var(--n-wave-fore) var(--mixpct));
  --kg-orb:       color-mix(in srgb, var(--d-orb),       var(--n-orb)       var(--mixpct));
  --kg-orb-glow:  color-mix(in srgb, var(--d-orb-glow),  var(--n-orb-glow)  var(--mixpct));
  --kg-cloud:     color-mix(in srgb, var(--d-cloud),     var(--n-cloud)     var(--mixpct));
  --kg-cloud-low: color-mix(in srgb, var(--d-cloud-low), var(--n-cloud-low) var(--mixpct));
  --kg-haze:      color-mix(in srgb, var(--d-haze),      var(--n-haze)      var(--mixpct));
  --kg-rig:       color-mix(in srgb, var(--d-rig),       var(--n-rig)       var(--mixpct));
  --kg-rig-line:  color-mix(in srgb, var(--d-rig-line),  var(--n-rig-line)  var(--mixpct));
  --kg-rain:      color-mix(in srgb, var(--d-rain),      var(--n-rain)      var(--mixpct));
  --kg-light: #ffd88a;

  /* Numeric dials interpolate directly off the same value. */
  --kg-star-opacity:    var(--kg-mix);
  --kg-bird-opacity:    calc(.55 - .55 * var(--kg-mix));
  --kg-rain-opacity:    calc(.42 * var(--kg-mix));
  --kg-light-opacity:   calc(.28 + .72 * var(--kg-mix));
  --kg-window-opacity:  calc(.12 + .73 * var(--kg-mix));
  --kg-flame-opacity:   calc(.9 + .1 * var(--kg-mix));
  --kg-crater-opacity:  calc(.16 * var(--kg-mix));
  --kg-orb-track-opacity: calc(.5 + .05 * var(--kg-mix));
  --kg-lightning-opacity: var(--kg-mix);
  --kg-calm-opacity:  calc(1 - var(--kg-mix));
  --kg-storm-opacity: var(--kg-mix);

  /* Scrim over the scene, also interpolated. */
  --kg-scrim-a:    calc(.46 + .22 * var(--kg-mix));
  --kg-scrim-b:    calc(.24 + .20 * var(--kg-mix));
  --kg-scrim-base: calc(.42 + .13 * var(--kg-mix));

  background: var(--kg-sky-2);
}
.kg-scene-svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* Wave loop speeds are deliberately NOT interpolated. animation-duration is
   recomputed on every custom-property change, which restarts the loop and
   makes the sea stutter on every scroll frame. One speed, both ends. */
.kg-scene {
  --kg-w-far: 38s; --kg-w-mid: 27s; --kg-w-near: 18s; --kg-w-fore: 12s;
  --kg-bob: 5s;
}

/* Scrim — a real element with an explicit z-index, never a pseudo-element
   sandwiched between absolutely-positioned siblings. Deliberately light at
   the day end: the panel over it is a solid tinted-glass surface that already
   carries its own text contrast. */
.kg-scene-scrim {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    linear-gradient(100deg,
      rgba(2,7,20,var(--kg-scrim-a)) 0%,
      rgba(2,7,20,var(--kg-scrim-b)) 34%,
      rgba(2,7,20,0) 62%),
    linear-gradient(180deg,
      rgba(0,6,20,0) 58%,
      rgba(0,6,20,var(--kg-scrim-base)) 100%);
}

/* ===== Sky bodies ===== */
.kg-stars circle { fill: #fff; opacity: var(--kg-star-opacity); }
.kg-stars circle:nth-child(3n)   { animation: kg-twinkle 4.5s ease-in-out infinite; }
.kg-stars circle:nth-child(4n+1) { animation: kg-twinkle 6.5s ease-in-out infinite .8s; }
@keyframes kg-twinkle { 0%,100% { opacity: var(--kg-star-opacity); } 50% { opacity: calc(var(--kg-star-opacity) * .25); } }

.kg-orb { fill: var(--kg-orb); }
.kg-moon-craters circle { fill: #7d93bd; opacity: var(--kg-crater-opacity); }
.kg-orb-glow { animation: kg-breathe 9s ease-in-out infinite; transform-origin: 1196px 214px; }
.kg-orb-track { opacity: var(--kg-orb-track-opacity); }
@keyframes kg-breathe { 0%,100% { transform: scale(1); opacity: .9; } 50% { transform: scale(1.09); opacity: 1; } }

.kg-cloud ellipse { fill: var(--kg-cloud); }
.kg-cloud--low ellipse { fill: var(--kg-cloud-low); }
.kg-clouds--slow { animation: kg-drift 150s linear infinite; }
.kg-clouds--fast { animation: kg-drift 92s linear infinite; }
@keyframes kg-drift { from { transform: translateX(0); } to { transform: translateX(-1600px); } }

.kg-birds { opacity: var(--kg-bird-opacity); animation: kg-fly 58s linear infinite; }
.kg-bird { fill: none; stroke: #1b3050; stroke-width: 2.2; stroke-linecap: round; }
@keyframes kg-fly { from { transform: translate(-120px, 20px); } to { transform: translate(1720px, -60px); } }

.kg-haze { fill: var(--kg-haze); }

/* ===== Sea =====
   Two complete sets of wave geometry sit in the DOM, one calm and one storm,
   cross-faded by the dial. Storm is genuinely choppier geometry — a
   shorter-period cross-swell stacked on the main swell — rather than the calm
   swell stretched vertically, which only ever produced tall smooth waves. It
   also keeps the sea off any transform, so its shape does not depend on how a
   renderer resolves transform-origin. */
.kg-calm  { opacity: var(--kg-calm-opacity); }
.kg-storm { opacity: var(--kg-storm-opacity); }

.kg-wave--far  { fill: var(--kg-wave-far);  animation: kg-roll var(--kg-w-far) linear infinite; }
.kg-wave--mid  { fill: var(--kg-wave-mid);  animation: kg-roll var(--kg-w-mid) linear infinite; }
.kg-wave--near { fill: var(--kg-wave-near); animation: kg-roll var(--kg-w-near) linear infinite; }
.kg-wave--fore { fill: var(--kg-wave-fore); animation: kg-roll var(--kg-w-fore) linear infinite; }
/* Paths are 3200 wide (2x the viewBox) so this lands exactly on the repeat.
   `translate`, not `transform`, so any transform on the element survives. */
@keyframes kg-roll { from { translate: 0 0; } to { translate: -1600px 0; } }

/* ===== Structures =====
   Every transform-origin here is in viewBox coordinates, so each transformed
   node needs transform-box: view-box — without it the origin resolves against
   the node's own bounding box and the element flies off. */
.kg-orb-glow, .kg-rig, .kg-flame, .kg-flare-glow, .kg-vessel-inner { transform-box: view-box; }

.kg-rig-solid, .kg-far-vessel path, .kg-far-vessel rect { fill: var(--kg-rig); }
.kg-rig-jacket path, .kg-rig-derrick path, .kg-rig-crane path, .kg-rig-line {
  fill: none; stroke: var(--kg-rig-line); stroke-width: 3; stroke-linecap: round;
}
.kg-rig-jacket path:first-child { stroke-width: 6; }
.kg-rig-derrick path { stroke-width: 2.6; }
.kg-heli-ring { fill: none; stroke: var(--kg-light); stroke-width: 2; opacity: var(--kg-light-opacity); }
.kg-rig { animation: kg-rig-sway calc(var(--kg-bob) * 2.4) ease-in-out infinite; transform-origin: 1190px 680px; }
@keyframes kg-rig-sway { 0%,100% { transform: rotate(0deg) translateY(0); } 50% { transform: rotate(.14deg) translateY(2px); } }

.kg-rig-lights circle, .kg-vessel-lights circle { fill: var(--kg-light); opacity: var(--kg-light-opacity); }
/* Accommodation windows: barely there by day, clearly lit at night. */
.kg-rig-windows rect { fill: var(--kg-light); opacity: var(--kg-window-opacity); }
.kg-rig-lights circle { filter: drop-shadow(0 0 7px var(--kg-light)); }
.kg-beacon { animation: kg-beacon 2.6s ease-in-out infinite; }
@keyframes kg-beacon { 0%,72%,100% { opacity: calc(var(--kg-light-opacity) * .25); } 84% { opacity: var(--kg-light-opacity); } }

.kg-flame { fill: #ff9d3d; opacity: var(--kg-flame-opacity); transform-origin: 1472px 366px; animation: kg-flicker 1.5s ease-in-out infinite; }
.kg-flare-glow { opacity: var(--kg-flame-opacity); animation: kg-breathe 2.9s ease-in-out infinite; transform-origin: 1472px 352px; }
@keyframes kg-flicker {
  0%,100% { transform: scale(1) skewX(0deg); }
  30%     { transform: scale(1.16, .92) skewX(-5deg); }
  60%     { transform: scale(.92, 1.14) skewX(4deg); }
}

.kg-vessel-inner { animation: kg-bob var(--kg-bob) ease-in-out infinite; transform-origin: 110px 60px; }
@keyframes kg-bob {
  0%,100% { transform: translateY(0) rotate(-.7deg); }
  50%     { transform: translateY(7px) rotate(.9deg); }
}
.kg-far-vessel path, .kg-far-vessel rect { opacity: .55; }

/* ===== Weather ===== */
.kg-rain { opacity: var(--kg-rain-opacity); animation: kg-rainfall .55s linear infinite; }
@keyframes kg-rainfall { from { transform: translate(0,0); } to { transform: translate(-21px, 86px); } }

.kg-lightning { fill: #cfe0ff; opacity: 0; animation: kg-strike 11s linear infinite; }
@keyframes kg-strike {
  0%, 6.9%   { opacity: 0; }
  7%         { opacity: calc(var(--kg-lightning-opacity) * .5); }
  7.6%       { opacity: 0; }
  8.2%       { opacity: calc(var(--kg-lightning-opacity) * .28); }
  9.4%, 100% { opacity: 0; }
}

/* ===== Reduced motion =====
   The scroll dial is a colour change, not movement, so it stays. Only the
   looping animations are held on a still, fully-composed frame. */
@media (prefers-reduced-motion: reduce) {
  .kg-scene-svg *, .kg-scene-svg { animation: none !important; }
  .kg-rain, .kg-lightning { opacity: 0 !important; }
}

/* No JS: the dial never moves, so show a clear day rather than nothing. */
.no-js .kg-scene { --kg-p: 0; }
