/* ==========================================================================
   RISHFOTECH — HERO ARC (drawn in CSS) + SCROLL-REACTIVE LIGHT
   --------------------------------------------------------------------------
   Additive. Loads after style.css; nothing existing is edited.

   WHY THE ARTWORK IS REDRAWN
   The original hero used a raster PNG (hero-arc.png) whose bright bloom is
   baked into the pixels. Anything layered over it can only ever add a faint
   wash — the actual light source cannot move, brighten or react, because it
   is part of a fixed image. Rebuilding the arc from gradients makes the light
   itself the animated object, which is what the effect needs.

   It is also lighter: the PNG is 373 KB. This file is a few KB of gradients,
   so the hero paints without waiting on an image download at all.

   STRUCTURE
     .rf-arc                 root — JS writes CSS variables here
       .rf-arc__sky          deep-space vertical wash          (static)
       .rf-arc__light        JS-transformed group
         .rf-arc__bloom      wide atmospheric glow             (CSS keyframes)
         .rf-arc__core       bright apex hotspot               (CSS keyframes)
       .rf-arc__planet       the dark sphere                   (static)
       .rf-arc__rim          thin bright horizon line          (CSS keyframes)

   The planet stays still — it is the ground. Only the light moves over it,
   which is what sells the illusion. JS transforms one wrapper; the keyframes
   live on its children, so the two never fight over `transform`.

   1. Root + variables
   2. Sky
   3. Light group
   4. Planet + rim
   5. Autonomous keyframes
   6. Energy response
   7. Responsive
   8. Reduced motion
   ========================================================================== */

/* ==========================================================================
   1. ROOT + VARIABLES
   --------------------------------------------------------------------------
   Colours below are sampled directly from hero-arc.png, not chosen by eye:

     apex hotspot      rgb(233,255,255)   at 49% x, 67% y
     upper glow        rgb(4,173,246)     60% y
     mid sky           rgb(2,98,200)      50% y
     high sky          rgb(0,41,115)      30% y
     top of frame      rgb(0,17,50)
     planet base       rgb(2,49,130)      100% y
     left/right edges  rgb(0,0,0)         full black vignette

   The palette is cyan-leaning, not blue — R stays near zero while G climbs.
   ========================================================================== */

/* Same specificity as the rule in style.css, but this file loads later, so it
   wins. The PNG is replaced; its base colour is kept underneath. */
.rf-hero .rf-hero__box {
  background-image: none;
  background-color: #000004;
}

/* style.css puts a 34% black veil over the hero (--rf-veil) to keep the
   headline legible against the photo. Drawn light needs less protection than
   a photograph did, and at 34% the glow reads flat, so it is eased here.
   Contrast over the darkest part of the plume stays above 12:1. */
.rf-hero .rf-hero__box::after {
  background: rgba(0, 0, 0, .16);
}

.rf-hero .rf-arc {
  /* Written by JS. Declared here so the hero is correct before the script
     runs — nothing about the artwork depends on JavaScript. */
  --rf-shift: 0px;
  /* scroll-driven drift, px */
  --rf-energy: 0;
  /* scroll intensity, 0..1  */

  /* --- palette, sampled from the original artwork --- */
  --rf-apex: rgb(233, 255, 255);
  --rf-glow: rgb(4, 173, 246);
  --rf-mid: rgb(2, 98, 200);
  --rf-deep: rgb(0, 41, 115);

  /* --- geometry, measured from the original artwork --- */
  --rf-horizon: 67%;
  /* where the bright arc sits          */
  --rf-sphere: 150%;
  /* sphere width; larger = flatter arc */

  position: absolute;
  inset: 0;
  z-index: 1;
  /* above the box background, below .rf-hero__content */
  pointer-events: none;
  overflow: hidden;
  border-radius: inherit;
  background: #000004;
}

/* ==========================================================================
   2. SKY
   An ellipse rather than a linear gradient, because the original falls off
   horizontally as well as vertically — at the bright row the edges are pure
   black while the centre is near-white.
   ========================================================================== */
.rf-hero .rf-arc__sky {
  position: absolute;
  inset: 0;
  background:
    /* tall plume rising from the apex into the sky */
    radial-gradient(ellipse 46% 86% at 50% var(--rf-horizon),
      rgba(170, 240, 255, 1) 0%,
      rgba(40, 195, 252, .85) 12%,
      rgba(6, 150, 235, .62) 26%,
      rgba(2, 95, 195, .40) 44%,
      rgba(0, 52, 138, .30) 64%,
      rgba(0, 26, 76, .14) 80%,
      rgba(0, 10, 32, 0) 96%),
    /* broad low haze hugging the horizon line */
    radial-gradient(ellipse 88% 26% at 50% var(--rf-horizon),
      rgba(30, 170, 245, .62) 0%,
      rgba(3, 105, 200, .30) 38%,
      rgba(0, 35, 100, .10) 62%,
      rgba(0, 10, 32, 0) 82%);
}

/* ==========================================================================
   3. TRAVEL RING — the light rides the curve
   --------------------------------------------------------------------------
   This is the whole idea. The ring is the same circle as the planet, so they
   share a centre. The lights sit at its top edge — exactly on the horizon.
   Rotating the ring therefore sweeps them ALONG the arc, following its
   curvature precisely, with no path maths and no per-frame geometry: one
   `rotate()` on one element.

   A tilt of A degrees moves the light R*sin(A) across, where R is half the
   sphere width — so ~12deg gives a wide, natural sweep.
   ========================================================================== */
.rf-hero .rf-arc__travel {
  position: absolute;
  left: 50%;
  top: var(--rf-horizon);
  width: var(--rf-sphere);
  aspect-ratio: 1/1;
  transform-origin: 50% 50%;
  /* the circle's centre */
  transform: translate3d(-50%, 0, 0) rotate(var(--rf-angle, 0deg));
  animation: rfArcTravel 17s ease-in-out infinite;
  will-change: transform;
}

/* JS takes over: the keyframes are removed so --rf-angle drives the ring.
   Paused keyframes would keep winning over the base rule, so it must be
   `animation:none`, not `animation-play-state:paused`. */
.rf-hero .rf-arc.is-live .rf-arc__travel {
  animation: none;
}

.rf-hero .rf-arc__bloom,
.rf-hero .rf-arc__core {
  position: absolute;
  left: 50%;
  top: 0;
  /* the arc itself */
  border-radius: 50%;
  transform: translate3d(-50%, -50%, 0);
  will-change: transform, opacity;
}

/* Broad cyan bloom sitting on the horizon. */
.rf-hero .rf-arc__bloom {
  width: 58%;
  aspect-ratio: 2.9/1;
  background: radial-gradient(ellipse at center,
      rgba(140, 230, 255, .80) 0%,
      rgba(20, 185, 250, .50) 24%,
      rgba(2, 120, 215, .22) 48%,
      rgba(0, 55, 150, 0) 74%);
  animation: rfArcBloom 15s ease-in-out infinite;
}

/* The near-white hotspot at the apex — sampled at rgb(233,255,255). */
.rf-hero .rf-arc__core {
  width: 22%;
  aspect-ratio: 3.0/1;
  background: radial-gradient(ellipse at center,
      rgba(233, 255, 255, .95) 0%,
      rgba(150, 240, 255, .62) 20%,
      rgba(40, 190, 250, .30) 44%,
      rgba(4, 140, 235, 0) 72%);
  animation: rfArcCore 9.5s ease-in-out infinite;
}

/* ==========================================================================
   4. PLANET + RIM
   A very large circle whose top cap is the only part in view, so the visible
   curve is shallow. Its surface is lit brightest just under the horizon and
   dims downward — matching the sampled fall from rgb(4,173,246) to
   rgb(2,49,130) between 70% and 100% of the frame.
   ========================================================================== */
.rf-hero .rf-arc__planet {
  position: absolute;
  left: 50%;
  top: var(--rf-horizon);
  width: var(--rf-sphere);
  aspect-ratio: 1/1;
  transform: translate3d(-50%, 0, 0);
  border-radius: 50%;
  /* The sphere's lit limb. Sampled targets down the centre of the original:
       just under the rim  rgb(4,166,246)
       80% of frame        rgb(0,123,222)
       bottom of frame     rgb(2,75,168)
     It stays bright, fading to black toward the left and right edges. */
  background:
    radial-gradient(ellipse 34% 30% at 50% 0%,
      rgba(60, 205, 255, .95) 0%,
      rgba(6, 170, 248, .85) 12%,
      rgba(2, 120, 222, .70) 28%,
      rgba(1, 80, 178, .52) 46%,
      rgba(0, 45, 120, .24) 68%,
      rgba(0, 14, 44, 0) 88%),
    radial-gradient(ellipse 52% 44% at 50% 0%,
      rgba(2, 95, 195, .55) 0%,
      rgba(1, 60, 150, .32) 34%,
      rgba(0, 28, 84, .12) 60%,
      rgba(0, 6, 20, 0) 84%),
    #00030A;
}

/* Vignette over the sphere: the lit limb falls away toward the bottom and the
   two lower corners, so the planet reads as curving out of the light rather
   than as a flat blue field.

   Placed on ::after with no z-index, so it paints above the planet (which has
   none) but below the comets and halo (z-index 2) — those stay crisp.

   The stops sit in the top ~14% of the circle because that is all that is on
   screen: the sphere is 150% of the hero's width, so only its top cap shows.
   Percentages further down would fall below the fold and do nothing. */
.rf-hero .rf-arc::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    /* corner falloff, centred on the apex */
    radial-gradient(ellipse 58% 46% at 50% var(--rf-horizon),
      rgba(0, 3, 12, 0) 0%,
      rgba(0, 3, 12, 0) 56%,
      rgba(0, 3, 12, .26) 78%,
      rgba(0, 2, 8, .62) 100%),
    /* floor falloff */
    linear-gradient(180deg,
      rgba(0, 3, 12, 0) 74%,
      rgba(0, 3, 12, .14) 88%,
      rgba(0, 2, 8, .34) 100%);
}

/* The crisp horizon line, sampled at rgb(233,255,255). Its own element so the
   brightness can animate via opacity — animating a box-shadow would repaint. */
.rf-hero .rf-arc__rim {
  position: absolute;
  left: 50%;
  top: var(--rf-horizon);
  width: var(--rf-sphere);
  aspect-ratio: 1/1;
  transform: translate3d(-50%, 0, 0);
  border-radius: 50%;
  border-top: 1.5px solid rgba(233, 255, 255, .95);
  box-shadow: 0 -1px 30px 3px rgba(90, 215, 255, .62);
  animation: rfArcRim 9.5s ease-in-out infinite;
  will-change: opacity;
  /* Fades the line out toward the edges, where the original is pure black.
     The mask is static so it rasterises once; only opacity animates. */
  -webkit-mask-image: radial-gradient(ellipse 40% 34% at 50% 0%,
      #000 0%, rgba(0, 0, 0, .85) 40%, rgba(0, 0, 0, .35) 66%, transparent 88%);
  mask-image: radial-gradient(ellipse 40% 34% at 50% 0%,
      #000 0%, rgba(0, 0, 0, .85) 40%, rgba(0, 0, 0, .35) 66%, transparent 88%);
}

/* ==========================================================================
   5. AUTONOMOUS KEYFRAMES
   Three different periods so the layers never resynchronise and the motion
   never reads as a loop. Only transform and opacity — both composited.
   ========================================================================== */
@keyframes rfArcTravel {

  0%,
  100% {
    transform: translate3d(-50%, 0, 0) rotate(0deg);
  }

  25% {
    transform: translate3d(-50%, 0, 0) rotate(9deg);
  }

  75% {
    transform: translate3d(-50%, 0, 0) rotate(-9deg);
  }
}

@keyframes rfArcCore {

  0%,
  100% {
    transform: translate3d(-50%, -50%, 0) scale(1);
    opacity: .9;
  }

  32% {
    transform: translate3d(-56%, -53%, 0) scale(1.14);
    opacity: 1;
  }

  66% {
    transform: translate3d(-45%, -48%, 0) scale(.92);
    opacity: .8;
  }
}

@keyframes rfArcBloom {

  0%,
  100% {
    transform: translate3d(-50%, -50%, 0) scale(1);
    opacity: .8;
  }

  40% {
    transform: translate3d(-53%, -54%, 0) scale(1.13);
    opacity: 1;
  }

  72% {
    transform: translate3d(-47%, -47%, 0) scale(.95);
    opacity: .72;
  }
}

@keyframes rfArcRim {

  0%,
  100% {
    opacity: .75;
  }

  32% {
    opacity: 1;
  }

  66% {
    opacity: .62;
  }
}

/* ==========================================================================
   6. ENERGY RESPONSE
   Rises while the cursor is steering, so the light reads as being held.
   ========================================================================== */
.rf-hero .rf-arc__rim {
  opacity: calc(.78 + var(--rf-energy, 0) * .22);
}

.rf-hero .rf-arc.is-live .rf-arc__core {
  transform: translate3d(-50%, -50%, 0) scale(calc(1 + var(--rf-energy, 0) * .18));
  animation: none;
}

.rf-hero .rf-arc.is-live .rf-arc__bloom {
  transform: translate3d(-50%, -50%, 0) scale(calc(1 + var(--rf-energy, 0) * .10));
  animation: none;
}

/* ==========================================================================
   7. RESPONSIVE
   ========================================================================== */
@media (max-width:991.98px) {
  .rf-hero .rf-arc {
    --rf-arc-w: 280%;
    --rf-arc-top: 68%;
  }

  .rf-hero .rf-arc__core {
    width: 70%;
  }

  .rf-hero .rf-arc__bloom {
    width: 160%;
  }
}

@media (max-width:767.98px) {
  .rf-hero .rf-arc {
    --rf-arc-w: 360%;
    --rf-arc-top: 70%;
  }

  .rf-hero .rf-arc__core {
    width: 96%;
  }

  .rf-hero .rf-arc__bloom {
    width: 210%;
  }

  /* One fewer large translucent surface to composite on phones. */
  .rf-hero .rf-arc__bloom {
    opacity: .75;
  }
}

/* Set by JS on genuinely low-powered hardware: artwork stays, motion stops. */
.rf-hero .rf-arc.is-static .rf-arc__travel,
.rf-hero .rf-arc.is-static .rf-arc__bloom,
.rf-hero .rf-arc.is-static .rf-arc__core,
.rf-hero .rf-arc.is-static .rf-arc__rim {
  animation: none;
}

/* ==========================================================================
   8. REDUCED MOTION
   The section and all content stay fully visible — only movement stops.
   ========================================================================== */
@media (prefers-reduced-motion:reduce) {
  .rf-hero .rf-arc__travel {
    animation: none;
    transform: translate3d(-50%, 0, 0);
    will-change: auto;
  }

  .rf-hero .rf-arc__bloom,
  .rf-hero .rf-arc__core,
  .rf-hero .rf-arc__rim {
    animation: none;
    will-change: auto;
  }

  .rf-hero .rf-arc__bloom,
  .rf-hero .rf-arc__core {
    transform: translate3d(-50%, -50%, 0);
  }
}

/* ==========================================================================
   9. COMETS
   --------------------------------------------------------------------------
   A bright head with a tail fading out behind it, running left to right along
   the arc and then back again.

   Why a comet and not a row of dots: separate dots read as a dashed line and
   lose the sense of something travelling. A tapered streak reads as motion
   even in a still frame.

   Each comet uses the ring trick: `.rf-comet` is a circle the size of the
   sphere sharing its centre, and the streak is its ::before pinned to the
   ring's top edge. Rotating the ring carries the streak along the curve — and
   because the tangent at the top of a circle is horizontal, the streak stays
   tangent to the arc automatically, with no per-frame maths.

   Cost is low because the painted element is tiny — roughly 190x3px — unlike
   the aurora layer that was tried earlier, which painted a large translucent
   surface and cost about 19fps.

   Per-comet values are inline in the HTML:
     --dur    time for one full round trip
     --delay  negative values start it mid-flight, so the arc is populated on
              the first frame instead of filling up
     --sweep  how far along the curve it travels, each way
     --len    tail length
     --h      streak thickness
   ========================================================================== */
.rf-hero .rf-arc__comets {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  opacity: calc(.85 + var(--rf-energy, 0) * .15);
}

.rf-hero .rf-comet {
  position: absolute;
  left: 50%;
  top: var(--rf-horizon);
  width: var(--rf-sphere);
  aspect-ratio: 1/1;
  transform-origin: 50% 50%;
  /* the circle's centre */
  animation: rfCometRide var(--dur, 5s) cubic-bezier(.45, 0, .55, 1) infinite;
  animation-delay: var(--delay, 0s);
  will-change: transform;
}

/* The streak. The head is at the right-hand end; the tail fades back to
   nothing, so it reads as travelling rather than just sitting there. */
.rf-hero .rf-comet::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  width: var(--len, 160px);
  height: var(--h, 3px);
  border-radius: var(--h, 3px);
  transform: translate(-50%, -50%);
  background: linear-gradient(90deg,
      rgba(90, 205, 255, 0) 0%,
      rgba(110, 215, 255, .18) 38%,
      rgba(165, 235, 255, .55) 68%,
      rgba(225, 250, 255, .95) 90%,
      #ffffff 100%);
  box-shadow:
    0 0 10px 1px rgba(130, 225, 255, .55),
    0 0 24px 5px rgba(40, 175, 250, .28);
  opacity: 0;
  animation: rfCometTurn var(--dur, 5s) cubic-bezier(.45, 0, .55, 1) infinite;
  animation-delay: var(--delay, 0s);
}

/* Out and back in one loop, easing at both ends so the turn feels like a
   real change of direction rather than a bounce. */
@keyframes rfCometRide {

  0%,
  100% {
    transform: translate3d(-50%, 0, 0) rotate(calc(var(--sweep, 28deg) * -1));
  }

  50% {
    transform: translate3d(-50%, 0, 0) rotate(var(--sweep, 28deg));
  }
}

/* The tail has to swap ends on the return leg. The flip is a hard step at
   exactly 50%, which is the instant the comet is stationary at the far end —
   so the swap is never visible. Opacity also dips there, hiding it further. */
@keyframes rfCometTurn {
  0% {
    transform: translate(-50%, -50%) scaleX(1);
    opacity: 0;
  }

  12% {
    transform: translate(-50%, -50%) scaleX(1);
    opacity: 1;
  }

  44% {
    transform: translate(-50%, -50%) scaleX(1);
    opacity: 1;
  }

  49.9% {
    transform: translate(-50%, -50%) scaleX(1);
    opacity: 0;
  }

  50% {
    transform: translate(-50%, -50%) scaleX(-1);
    opacity: 0;
  }

  56% {
    transform: translate(-50%, -50%) scaleX(-1);
    opacity: 1;
  }

  90% {
    transform: translate(-50%, -50%) scaleX(-1);
    opacity: 1;
  }

  100% {
    transform: translate(-50%, -50%) scaleX(-1);
    opacity: 0;
  }
}

@media (max-width:767.98px) {

  /* Two comets instead of three on phones. */
  .rf-hero .rf-comet:nth-child(3) {
    display: none;
  }

  .rf-hero .rf-comet::before {
    width: calc(var(--len, 160px) * .62);
  }
}

.rf-hero .rf-arc.is-static .rf-comet,
.rf-hero .rf-arc.is-static .rf-comet::before {
  animation: none;
  opacity: 0;
}

@media (prefers-reduced-motion:reduce) {
  .rf-hero .rf-comet {
    animation: none;
    will-change: auto;
  }

  .rf-hero .rf-comet::before {
    animation: none;
    opacity: .5;
  }
}

/* ==========================================================================
   10. CURSOR HALO
   --------------------------------------------------------------------------
   A soft bloom that follows the pointer anywhere in the section — including
   the corners, where the arc light cannot reach. It trails slightly behind
   the cursor so it reads as atmosphere responding, not a shape stuck to the
   mouse. Hidden until the pointer arrives.
   ========================================================================== */
.rf-hero .rf-arc__halo {
  position: absolute;
  left: 0;
  top: 0;
  width: 34%;
  aspect-ratio: 1/1;
  margin: -17% 0 0 -17%;
  /* centres it on the cursor */
  border-radius: 50%;
  pointer-events: none;
  z-index: 2;
  opacity: 0;
  transform: translate3d(var(--hx, 0px), var(--hy, 0px), 0) scale(.82);
  background: radial-gradient(circle at center,
      rgba(175, 240, 255, .32) 0%,
      rgba(70, 195, 252, .17) 26%,
      rgba(12, 125, 225, .07) 50%,
      rgba(2, 60, 160, 0) 74%);
  transition: opacity .5s ease;
  will-change: transform, opacity;
}

.rf-hero .rf-arc.is-live .rf-arc__halo {
  opacity: calc(.72 + var(--rf-energy, 0) * .28);
  transform: translate3d(var(--hx, 0px), var(--hy, 0px), 0) scale(calc(.82 + var(--rf-energy, 0) * .18));
}

@media (max-width:991.98px) {
  .rf-hero .rf-arc__aurora span {
    width: 100%;
    height: 46%;
  }
}

@media (max-width:767.98px) {

  /* Two shafts instead of five: fewer composited layers, same impression. */
  .rf-hero .rf-arc__aurora span:nth-child(2) {
    display: none;
  }

  .rf-hero .rf-arc__aurora span {
    width: 120%;
  }
}

.rf-hero .rf-arc.is-static .rf-arc__aurora span {
  animation: none;
}

@media (prefers-reduced-motion:reduce) {
  .rf-hero .rf-arc__aurora span {
    animation: none;
    will-change: auto;
  }

  .rf-hero .rf-arc__halo {
    display: none;
  }
}