/* ==========================================================================
   Geekett Motion Layer — v1.0
   Depth + motion for the Divi 5 build on geekett.com
   --------------------------------------------------------------------------
   Everything here animates transform / opacity / filter only.
   No width, height, top, left, margin or background-position is animated,
   so nothing in this file can trigger layout or paint thrash.

   Customise from the token block below. You should not need to touch
   anything past section 2 for normal tuning.
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. TOKENS
   Colours are bound to your real Divi global colour IDs, with the hex as a
   fallback so the file still works if a token is ever renamed.
   -------------------------------------------------------------------------- */

:root {
  /* Brand */
  --gk-pink:    var(--gcid-6707f08b-5afb-41d2-9d60-4c775d6dff01, #e91b7a); /* heart   */
  --gk-teal:    #0fb8b0;                                                   /* rocket  */
  --gk-teal-lo: var(--gcid-b696932b-f55c-44cd-bab1-442a3b2b90f6, #d5f6f3); /* tint    */
  --gk-indigo:  var(--gcid-e0630234-1e6b-4bae-8e03-454c9aa55272, #3f2ad1);
  --gk-ink:     var(--gcid-bb7d93b7-745a-4018-99b2-1302f11d177f, #14222a);
  --gk-line:    var(--gcid-03ffa3d1-1b6d-4175-9e36-79d40b511192, #f0c9d8);

  /* Motion — three durations, two curves. That is the whole system. */
  --gk-fast:   180ms;   /* press feedback, focus rings            */
  --gk-base:   420ms;   /* hover states, connector draw           */
  --gk-slow:   720ms;   /* entrance reveals                       */
  --gk-ease:   cubic-bezier(0.22, 1, 0.36, 1);      /* settle, no overshoot */
  --gk-spring: cubic-bezier(0.34, 1.56, 0.64, 1);   /* overshoot, for pops  */

  /* Reveal */
  --gk-reveal-lift: 14px;  /* travel distance. Keep small — big = template-y */
  --gk-reveal-step: 70ms;  /* delay between staggered siblings              */

  /* Float loop */
  --gk-float-amp:  9px;    /* vertical drift                                */
  --gk-float-time: 7.5s;   /* one full loop                                 */

  /* Depth — one shadow ramp, used everywhere, so surfaces stay consistent */
  --gk-shadow-1: 0 1px 2px rgba(20, 34, 42, .05),
                 0 4px 12px -4px rgba(20, 34, 42, .08);
  --gk-shadow-2: 0 2px 4px rgba(20, 34, 42, .06),
                 0 14px 32px -10px rgba(20, 34, 42, .14);
  --gk-shadow-3: 0 3px 6px rgba(20, 34, 42, .07),
                 0 30px 60px -18px rgba(20, 34, 42, .20);

  /* Connector geometry between Process steps */
  --gk-conn-w: 46px;       /* drawable width of one connector               */
  --gk-conn-y: 50%;        /* vertical anchor on the card                   */
}


/* --------------------------------------------------------------------------
   2. GLOBAL SAFETY
   -------------------------------------------------------------------------- */

/* Sideways drift from off-screen reveals must never create a scrollbar. */
.gk-motion-on { overflow-x: clip; }

/* One media query, no exceptions. Reduced motion lands every element in its
   final state instantly — nothing is hidden, nothing loops, nothing moves. */
@media (prefers-reduced-motion: reduce) {
  .gk-reveal,
  .gk-reveal.is-in {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .gk-float,
  .gk-connector__rail,
  .gk-connector__pulse,
  .gk-connector__tip {
    animation: none !important;
    transform: none !important;
    opacity: 1 !important;
  }
  .gk-parallax { transform: none !important; }
  .gk-tilt__inner { transform: none !important; }
  .gk-connector__rail { transform: scaleX(1) !important; }
}


/* --------------------------------------------------------------------------
   3. SCROLL REVEALS (staggered)
   JS adds .gk-reveal + a per-sibling index in --gk-i, then .is-in on entry.
   Transform + opacity only, and will-change is dropped after landing.
   -------------------------------------------------------------------------- */

.gk-reveal {
  opacity: 0;
  transform: translate3d(0, var(--gk-reveal-lift), 0);
  transition:
    opacity   var(--gk-slow) var(--gk-ease),
    transform var(--gk-slow) var(--gk-ease);
  transition-delay: calc(var(--gk-i, 0) * var(--gk-reveal-step));
  will-change: transform, opacity;
}

.gk-reveal.is-in {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* Once it has landed it is a static element again — release the layer. */
.gk-reveal.is-done { will-change: auto; }

/* Variant: cards rise with a whisper of scale so the grid feels assembled
   rather than wiped in. Applied by JS to preset card columns only. */
.gk-reveal--card {
  transform: translate3d(0, var(--gk-reveal-lift), 0) scale(.985);
}
.gk-reveal--card.is-in { transform: translate3d(0, 0, 0) scale(1); }


/* --------------------------------------------------------------------------
   4. FLOATING MEDIA
   A single composite loop. The X and Y phases are deliberately out of sync
   so the path reads as a slow drift, not a metronome.
   -------------------------------------------------------------------------- */

.gk-float {
  animation: gk-drift var(--gk-float-time) ease-in-out infinite;
  animation-delay: var(--gk-float-delay, 0s);
  will-change: transform;
}

@keyframes gk-drift {
  0%   { transform: translate3d(0, 0, 0); }
  25%  { transform: translate3d(3px, calc(var(--gk-float-amp) * -.7), 0); }
  50%  { transform: translate3d(0, calc(var(--gk-float-amp) * -1), 0); }
  75%  { transform: translate3d(-3px, calc(var(--gk-float-amp) * -.35), 0); }
  100% { transform: translate3d(0, 0, 0); }
}

/* The hero media gets a soft cast shadow that breathes with it, so the float
   reads as height off the page rather than a sliding sticker. */
.gk-float--lit {
  filter: drop-shadow(0 26px 34px rgba(20, 34, 42, .16));
  animation-name: gk-drift, gk-drift-shadow;
  animation-duration: var(--gk-float-time), var(--gk-float-time);
  animation-timing-function: ease-in-out, ease-in-out;
  animation-iteration-count: infinite, infinite;
}

@keyframes gk-drift-shadow {
  0%, 100% { filter: drop-shadow(0 22px 28px rgba(20, 34, 42, .18)); }
  50%      { filter: drop-shadow(0 34px 42px rgba(20, 34, 42, .12)); }
}


/* --------------------------------------------------------------------------
   5. GLOWING 3D BUTTONS
   Depth comes from three stacked layers: an inset top highlight, a coloured
   ambient glow, and a hard-edged bottom lip that shortens on press.
   Divi's own button rules carry !important, so the properties we take over
   are reclaimed explicitly. Nothing else is touched.
   -------------------------------------------------------------------------- */

.gk-btn {
  position: relative;
  isolation: isolate;
  border: 0 !important;
  transform: translate3d(0, 0, 0);
  transition:
    transform  var(--gk-fast) var(--gk-spring),
    box-shadow var(--gk-base) var(--gk-ease),
    filter     var(--gk-base) var(--gk-ease) !important;
  will-change: transform;
}

/* Gradient highlight — a light source above the button, not a decorative wash.
   ::before sits under the label; Divi uses ::after for its icon slot. */
.gk-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  z-index: -1;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, .28) 0%,
    rgba(255, 255, 255, .06) 46%,
    rgba(0, 0, 0, .10) 100%
  );
  opacity: .9;
  transition: opacity var(--gk-base) var(--gk-ease);
}

/* Resting elevation: tight contact shadow + the button's own colour bleeding
   out as a low-opacity glow. --gk-glow is set per-variant below. */
.gk-btn {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .34),
    0 1px 1px rgba(20, 34, 42, .12),
    0 6px 14px -6px var(--gk-glow, rgba(15, 184, 176, .55)),
    0 3px 0 -1px var(--gk-lip, rgba(0, 0, 0, .14)) !important;
}

.gk-btn:hover {
  transform: translate3d(0, -2px, 0);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .42),
    0 2px 3px rgba(20, 34, 42, .12),
    0 14px 30px -8px var(--gk-glow, rgba(15, 184, 176, .55)),
    0 0 26px -4px var(--gk-glow, rgba(15, 184, 176, .55)),
    0 5px 0 -1px var(--gk-lip, rgba(0, 0, 0, .14)) !important;
}
.gk-btn:hover::before { opacity: 1; }

/* Press: the button sinks onto its lip. Fast, springy, physical. */
.gk-btn:active {
  transform: translate3d(0, 1px, 0) scale(.975);
  transition-duration: 90ms !important;
  box-shadow:
    inset 0 2px 4px rgba(0, 0, 0, .18),
    0 1px 1px rgba(20, 34, 42, .14),
    0 4px 10px -6px var(--gk-glow, rgba(15, 184, 176, .55)),
    0 1px 0 -1px var(--gk-lip, rgba(0, 0, 0, .14)) !important;
}

/* Keyboard focus is never removed — it is replaced with something better. */
.gk-btn:focus-visible {
  outline: 3px solid var(--gk-indigo);
  outline-offset: 3px;
}

/* Colour variants — JS picks one by sampling the rendered background. */
.gk-btn--teal  { --gk-glow: rgba(15, 184, 176, .58); --gk-lip: #0a8a84; }
.gk-btn--pink  { --gk-glow: rgba(233, 27, 122, .48); --gk-lip: #b01159; }
.gk-btn--ghost { --gk-glow: rgba(20, 34, 42, .18);   --gk-lip: rgba(20,34,42,.12); }


/* --------------------------------------------------------------------------
   6. PROCESS STEP CONNECTORS
   Injected by JS into the gap between step cards. Three parts:
     rail  — dashed track that draws itself in when the band scrolls into view
     pulse — a glow dot that travels the rail, sequenced left to right
     tip   — the arrowhead, pulsing on the same beat
   Desktop runs horizontal; under 980px the row stacks and it runs vertical.
   -------------------------------------------------------------------------- */

.gk-step { position: relative; }

.gk-connector {
  position: absolute;
  left: 100%;
  top: var(--gk-conn-y);
  width: var(--gk-conn-w);
  height: 14px;
  margin-top: -7px;
  transform: translate3d(-50%, 0, 0);
  pointer-events: none;
  z-index: 4;
}

/* The rail. transform-origin left + scaleX is the "drawing" gesture —
   GPU-only, unlike animating width or stroke-dashoffset on an SVG. */
.gk-connector__rail {
  position: absolute;
  inset: 0 10px 0 0;
  top: 50%;
  height: 2px;
  margin-top: -1px;
  border-radius: 2px;
  background-image: linear-gradient(
    90deg,
    var(--gk-teal) 0 6px,
    transparent 6px 12px
  );
  background-size: 12px 2px;
  opacity: .55;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--gk-base) var(--gk-ease);
  transition-delay: calc(var(--gk-i, 0) * 140ms + 220ms);
}

.gk-process.is-in .gk-connector__rail { transform: scaleX(1); }

/* Travelling pulse. Only runs once the band is in view, and each connector
   starts a beat later than the one before it, so the eye is pulled forward. */
.gk-connector__pulse {
  position: absolute;
  top: 50%;
  left: 0;
  width: 7px;
  height: 7px;
  margin-top: -3.5px;
  border-radius: 50%;
  background: var(--gk-teal);
  box-shadow: 0 0 10px 2px rgba(15, 184, 176, .75);
  opacity: 0;
  will-change: transform, opacity;
}

.gk-process.is-in .gk-connector__pulse {
  animation: gk-pulse-travel 2.6s var(--gk-ease) infinite;
  animation-delay: calc(var(--gk-i, 0) * 260ms + 500ms);
}

@keyframes gk-pulse-travel {
  0%        { transform: translate3d(0, 0, 0)   scale(.4); opacity: 0; }
  18%       { opacity: 1; }
  64%       { transform: translate3d(calc(var(--gk-conn-w) - 16px), 0, 0) scale(1); opacity: 1; }
  78%, 100% { transform: translate3d(calc(var(--gk-conn-w) - 16px), 0, 0) scale(.4); opacity: 0; }
}

/* Arrowhead. Chevron built from borders so there is no extra request. */
.gk-connector__tip {
  position: absolute;
  right: 0;
  top: 50%;
  width: 7px;
  height: 7px;
  margin-top: -4px;
  border-top: 2px solid var(--gk-teal);
  border-right: 2px solid var(--gk-teal);
  border-radius: 1px;
  transform: rotate(45deg) scale(.9);
  opacity: 0;
  transition: opacity var(--gk-base) var(--gk-ease);
  transition-delay: calc(var(--gk-i, 0) * 140ms + 520ms);
}

.gk-process.is-in .gk-connector__tip {
  opacity: 1;
  animation: gk-tip-beat 2.6s var(--gk-ease) infinite;
  animation-delay: calc(var(--gk-i, 0) * 260ms + 1.15s);
}

@keyframes gk-tip-beat {
  0%, 44%, 100% { transform: rotate(45deg) scale(.9);  }
  56%           { transform: rotate(45deg) scale(1.28); }
}

/* Stacked layout: the flow turns downward. Same parts, rotated anchor. */
@media (max-width: 980px) {
  .gk-connector {
    left: 50%;
    top: 100%;
    width: 14px;
    height: var(--gk-conn-w);
    margin-top: 0;
    transform: translate3d(-50%, -50%, 0);
  }
  .gk-connector__rail {
    inset: 0 0 10px 0;
    left: 50%;
    top: 0;
    width: 2px;
    height: auto;
    margin: 0 0 0 -1px;
    background-image: linear-gradient(
      180deg,
      var(--gk-teal) 0 6px,
      transparent 6px 12px
    );
    background-size: 2px 12px;
    transform: scaleY(0);
    transform-origin: top center;
  }
  .gk-process.is-in .gk-connector__rail { transform: scaleY(1); }

  .gk-connector__pulse { left: 50%; top: 0; margin: 0 0 0 -3.5px; }
  @keyframes gk-pulse-travel {
    0%        { transform: translate3d(0, 0, 0) scale(.4); opacity: 0; }
    18%       { opacity: 1; }
    64%       { transform: translate3d(0, calc(var(--gk-conn-w) - 16px), 0) scale(1); opacity: 1; }
    78%, 100% { transform: translate3d(0, calc(var(--gk-conn-w) - 16px), 0) scale(.4); opacity: 0; }
  }
  .gk-connector__tip {
    right: auto;
    left: 50%;
    top: auto;
    bottom: 0;
    margin: 0 0 0 -4px;
    transform: rotate(135deg) scale(.9);
  }
  @keyframes gk-tip-beat {
    0%, 44%, 100% { transform: rotate(135deg) scale(.9);  }
    56%           { transform: rotate(135deg) scale(1.28); }
  }
}


/* --------------------------------------------------------------------------
   7. PERSPECTIVE / TILT CARDS
   The outer element owns perspective; only the inner wrapper transforms, so
   the card's own background and border never re-rasterise mid-tilt.
   Pointer-driven values are eased in JS with a critically damped spring.
   -------------------------------------------------------------------------- */

.gk-tilt {
  perspective: 900px;
  transform-style: flat;      /* flat keeps text crisp; 3d blurs it in Safari */
}

.gk-tilt__inner {
  transform:
    rotateX(var(--gk-rx, 0deg))
    rotateY(var(--gk-ry, 0deg))
    translate3d(0, var(--gk-lift, 0px), 0);
  transition: box-shadow var(--gk-base) var(--gk-ease);
  box-shadow: var(--gk-shadow-1);
  border-radius: inherit;
  height: 100%;
}

.gk-tilt.is-active .gk-tilt__inner { box-shadow: var(--gk-shadow-3); }

/* Specular sheen — a soft blob that follows the pointer. It is translated,
   never repainted, so it costs nothing on the compositor. */
.gk-tilt__inner::after {
  content: "";
  position: absolute;
  top: -40%;
  left: -40%;
  width: 90%;
  height: 90%;
  border-radius: 50%;
  background: radial-gradient(
    circle at center,
    rgba(255, 255, 255, .85) 0%,
    rgba(255, 255, 255, 0) 68%
  );
  opacity: 0;
  pointer-events: none;
  transform: translate3d(var(--gk-sx, 0px), var(--gk-sy, 0px), 0);
  transition: opacity var(--gk-base) var(--gk-ease);
  mix-blend-mode: soft-light;
}

.gk-tilt.is-active .gk-tilt__inner::after { opacity: .7; }

/* Touch and coarse pointers get the depth, not the tilt — there is no hover. */
@media (hover: none), (pointer: coarse) {
  .gk-tilt__inner { transform: none !important; }
  .gk-tilt__inner::after { display: none; }
}


/* --------------------------------------------------------------------------
   8. PARALLAX LAYERS
   JS writes --gk-py from a single shared rAF loop. Depth is per-element.
   -------------------------------------------------------------------------- */

.gk-parallax {
  transform: translate3d(0, var(--gk-py, 0px), 0);
  will-change: transform;
}

/* Section-level atmosphere: a soft tinted orb that drifts slower than the
   content above it. Purely a depth cue for the banded page, one per section. */
.gk-aura {
  position: absolute;
  z-index: 0;
  width: min(52vw, 620px);
  aspect-ratio: 1;
  border-radius: 50%;
  filter: blur(70px);
  opacity: .5;
  pointer-events: none;
  transform: translate3d(0, var(--gk-py, 0px), 0);
  will-change: transform;
}

.gk-aura--teal { background: radial-gradient(circle, rgba(15,184,176,.34), transparent 66%); }
.gk-aura--pink { background: radial-gradient(circle, rgba(233,27,122,.22), transparent 66%); }

/* Keep every Divi module above the aura layer. */
.gk-has-aura { position: relative; overflow: hidden; }
.gk-has-aura > .et_pb_row,
.gk-has-aura > .et_pb_row_inner { position: relative; z-index: 1; }

@media (max-width: 780px) {
  /* Blur at this radius is the single most expensive thing on the page.
     Phones get the depth from shadows instead. */
  .gk-aura { display: none; }
}
