/* ==========================================================================
   CLARITASK — KORE EFFECT LAYER
   Ported from new_kore_website/assets/css/core.css (its "Animation engine"
   section) and layout.css (header states), adapted to Claritask's markup.

   Everything here is gated on html.js-anim, which js/kore-fx.js sets. Without
   JavaScript nothing is hidden, so the page still reads.

   The hooks: .reveal (+ --left/--right/--zoom/--blur/--fade, delay via --rd),
   .stagger, [data-split], [data-count], [data-parallax], [data-tilt],
   [data-spotlight], .k-marquee, .k-lift, .k-orbs, .k-grid-bg, .k-progress.
   ========================================================================== */

:root {
  --fx-ease: cubic-bezier(0.22, 1, 0.36, 1);
  /* Entrance curve: a long, gentle decelerate with no overshoot, so arrivals
     across the whole site share one feel. */
  --fx-ease-out: cubic-bezier(0.16, 0.84, 0.3, 1);
  --fx-t: 0.32s;
  --header-h: 72px;
  --sticky-top: var(--header-h);
}
body.is-header-hidden {
  --sticky-top: 0px;
}

/* --------------------------------------------------------------------------
   1 · Scroll reveal, the workhorse
   Longer durations on a soft decelerate read as smooth; the generous overlap
   between neighbouring elements is what keeps it from also feeling slow.
   -------------------------------------------------------------------------- */
.js-anim .reveal {
  opacity: 0;
  transform: translate3d(0, 28px, 0);
  transition:
    opacity 0.62s var(--fx-ease-out),
    transform 0.68s var(--fx-ease-out);
  /* Per-element delays are authored inline as --rd. Scaling them here keeps
     the sequence in proportion when the pace is retuned, rather than editing
     the value on every element. */
  transition-delay: calc(var(--rd, 0ms) * 0.62);
  will-change: opacity, transform;
}
.js-anim .reveal--left {
  transform: translate3d(-42px, 0, 0);
}
.js-anim .reveal--right {
  transform: translate3d(42px, 0, 0);
}
.js-anim .reveal--zoom {
  transform: scale(0.95);
}
.js-anim .reveal--blur {
  filter: blur(10px);
  transition:
    opacity 0.62s var(--fx-ease-out),
    transform 0.68s var(--fx-ease-out),
    filter 0.62s var(--fx-ease-out);
}
.js-anim .reveal--fade {
  transform: none;
}
.js-anim .reveal.is-in {
  opacity: 1;
  transform: none;
  filter: none;
}

/* --------------------------------------------------------------------------
   2 · Stagger children
   An animation rather than a transition on purpose: a transition has to leave
   "transform: none" on the finished state, and that outranks any
   .card:hover { transform: ... }, which silently kills every card lift in a
   grid. JS adds .is-done once the sequence has played, dropping the animation
   so hover styles have nothing to fight.
   -------------------------------------------------------------------------- */
.js-anim .stagger > * {
  opacity: 0;
}
.js-anim .stagger.is-in > * {
  animation: fxStaggerIn 0.58s var(--fx-ease-out) both;
}
@keyframes fxStaggerIn {
  from {
    opacity: 0;
    transform: translate3d(0, 22px, 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.js-anim .stagger.is-done > * {
  animation: none;
  opacity: 1;
}
.js-anim .stagger.is-in > *:nth-child(1) {
  animation-delay: 0.02s;
}
.js-anim .stagger.is-in > *:nth-child(2) {
  animation-delay: 0.07s;
}
.js-anim .stagger.is-in > *:nth-child(3) {
  animation-delay: 0.12s;
}
.js-anim .stagger.is-in > *:nth-child(4) {
  animation-delay: 0.17s;
}
.js-anim .stagger.is-in > *:nth-child(5) {
  animation-delay: 0.22s;
}
.js-anim .stagger.is-in > *:nth-child(6) {
  animation-delay: 0.27s;
}
.js-anim .stagger.is-in > *:nth-child(7) {
  animation-delay: 0.32s;
}
.js-anim .stagger.is-in > *:nth-child(8) {
  animation-delay: 0.37s;
}
.js-anim .stagger.is-in > *:nth-child(9) {
  animation-delay: 0.42s;
}
.js-anim .stagger.is-in > *:nth-child(10) {
  animation-delay: 0.47s;
}
.js-anim .stagger.is-in > *:nth-child(11) {
  animation-delay: 0.52s;
}
.js-anim .stagger.is-in > *:nth-child(12) {
  animation-delay: 0.57s;
}

/* --------------------------------------------------------------------------
   3 · Split-text headlines: words rise out of a mask
   The step between words is short enough that a long headline lands as one
   movement rather than a visible queue.
   -------------------------------------------------------------------------- */
.js-anim [data-split] .word {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-bottom: 0.08em;
}
.js-anim [data-split] .word > span {
  display: inline-block;
  transform: translate3d(0, 110%, 0) rotate(2.5deg);
  opacity: 0.001;
  transition:
    transform 0.66s var(--fx-ease-out),
    opacity 0.46s var(--fx-ease-out);
  transition-delay: calc(50ms + var(--i) * 30ms);
}
.js-anim [data-split].is-in .word > span {
  transform: none;
  opacity: 1;
}

/* --------------------------------------------------------------------------
   4 · Counters land with a subtle pop
   -------------------------------------------------------------------------- */
.js-anim [data-count].is-in {
  animation: fxCountPop 0.7s var(--fx-ease) both;
}
@keyframes fxCountPop {
  0% {
    transform: scale(0.9);
    opacity: 0.4;
  }
  100% {
    transform: none;
    opacity: 1;
  }
}

/* --------------------------------------------------------------------------
   5 · Pointer effects
   -------------------------------------------------------------------------- */
[data-tilt] {
  transform-style: preserve-3d;
  transition: transform 0.5s var(--fx-ease);
  transform: perspective(1100px) rotateX(var(--rx, 0deg))
    rotateY(var(--ry, 0deg));
}
[data-tilt].is-tilting {
  transition: transform 0.12s linear;
}

/* A soft light follows the cursor across a card. */
[data-spotlight] {
  position: relative;
}
[data-spotlight]::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  border-radius: inherit;
  transition: opacity 0.4s var(--fx-ease);
  background: radial-gradient(
    420px circle at var(--sx, 50%) var(--sy, 50%),
    color-mix(in srgb, var(--ct-viz) 14%, transparent),
    transparent 62%
  );
}
[data-spotlight]:hover::before {
  opacity: 1;
}
[data-spotlight] > * {
  position: relative;
  z-index: 1;
}

[data-parallax] {
  will-change: transform;
  transform: translate3d(0, var(--py, 0px), 0);
}

/* --------------------------------------------------------------------------
   6 · Shared card lift
   Separation on this site comes from borders rather than shadows, so the lift
   is a move plus a border that picks up the brand colour.
   -------------------------------------------------------------------------- */
.k-lift {
  transition:
    transform var(--fx-t) var(--fx-ease),
    border-color var(--fx-t) var(--fx-ease);
}
.k-lift:hover {
  transform: translateY(-6px);
  border-color: color-mix(in srgb, var(--ct-viz) 34%, var(--ct-border));
}

/* --------------------------------------------------------------------------
   7 · Marquee: JS clones the track so the loop is seamless
   -------------------------------------------------------------------------- */
.k-marquee {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent,
    #000 8%,
    #000 92%,
    transparent
  );
  mask-image: linear-gradient(
    90deg,
    transparent,
    #000 8%,
    #000 92%,
    transparent
  );
}
.k-marquee__track {
  display: flex;
  align-items: center;
  gap: 68px;
  width: max-content;
  animation: fxMarquee var(--dur, 46s) linear infinite;
}
.k-marquee:hover .k-marquee__track {
  animation-play-state: paused;
}
@keyframes fxMarquee {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(-50%, 0, 0);
  }
}

/* --------------------------------------------------------------------------
   8 · Decorative background fields
   -------------------------------------------------------------------------- */
/* The blobs are a fixed 420-620px but the sections hosting them are not, so
   overflow:hidden alone would cut one through its bright middle, and a clipped
   blur has a hard edge that reads as a grey rectangle. Masking the layer fades
   every blob out before it reaches an edge, whatever the section's height. */
.k-orbs {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
  -webkit-mask-image: radial-gradient(
    118% 96% at 50% 42%,
    #000 38%,
    transparent 88%
  );
  mask-image: radial-gradient(118% 96% at 50% 42%, #000 38%, transparent 88%);
}
.k-orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.5;
  will-change: transform;
  animation: fxOrbDrift 22s ease-in-out infinite alternate;
}
.k-orb--a {
  width: 520px;
  height: 520px;
  top: -180px;
  left: -120px;
  background: radial-gradient(circle, rgba(0, 180, 229, 0.34), transparent 70%);
}
.k-orb--b {
  width: 620px;
  height: 620px;
  top: 60px;
  right: -220px;
  background: radial-gradient(circle, rgba(0, 37, 116, 0.22), transparent 70%);
  animation-delay: -7s;
}
.k-orb--c {
  width: 420px;
  height: 420px;
  bottom: -160px;
  left: 34%;
  background: radial-gradient(circle, rgba(245, 166, 35, 0.18), transparent 70%);
  animation-delay: -13s;
}
@keyframes fxOrbDrift {
  0% {
    transform: translate3d(0, 0, 0) scale(1);
  }
  50% {
    transform: translate3d(40px, -30px, 0) scale(1.08);
  }
  100% {
    transform: translate3d(-30px, 26px, 0) scale(0.96);
  }
}

.k-grid-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image:
    linear-gradient(to right, rgba(11, 21, 36, 0.045) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(11, 21, 36, 0.045) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(
    ellipse 80% 60% at 50% 0%,
    #000 20%,
    transparent 78%
  );
  mask-image: radial-gradient(
    ellipse 80% 60% at 50% 0%,
    #000 20%,
    transparent 78%
  );
}

/* --------------------------------------------------------------------------
   9 · Scroll progress bar
   -------------------------------------------------------------------------- */
.k-progress {
  position: fixed;
  inset: 0 0 auto 0;
  height: 3px;
  z-index: 1200;
  pointer-events: none;
  background: transparent;
}
.k-progress__bar {
  display: block;
  height: 100%;
  width: 100%;
  transform: scaleX(var(--p, 0));
  transform-origin: 0 50%;
  background: linear-gradient(
    90deg,
    var(--ct-primary),
    var(--ct-viz) 70%,
    var(--ct-accent)
  );
}

/* --------------------------------------------------------------------------
   10 · Header: stuck, and out of the way on the way down
   -------------------------------------------------------------------------- */
.header {
  border-bottom: 1px solid transparent;
  background: rgba(255, 255, 255, 0.72);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  backdrop-filter: saturate(180%) blur(18px);
  transition:
    background-color var(--fx-t) var(--fx-ease),
    border-color var(--fx-t) var(--fx-ease),
    transform 0.45s var(--fx-ease);
}
.header.is-stuck {
  background: rgba(255, 255, 255, 0.94);
  border-bottom-color: var(--ct-border);
}
.header.is-hidden {
  transform: translateY(-102%);
}
/* An open drawer pins the header back in place: sliding it away with a menu
   hanging off it leaves the menu floating. */
.header.is-open {
  transform: none;
  background: #fff;
  border-bottom-color: var(--ct-border);
}

/* --------------------------------------------------------------------------
   11 · Hero entrance choreography
   Every hero arrives as one sequence rather than several independent fades.
   The device stage gets the longest, softest travel: scaling a large mock
   reads as soft focus, so it rises instead.
   -------------------------------------------------------------------------- */
.js-anim .clx-herostage.reveal,
.js-anim .clx-devices.reveal {
  transition-duration: 0.86s, 0.92s;
  transition-delay: 180ms;
}
.js-anim .clx-herostage.reveal:not(.is-in),
.js-anim .clx-devices.reveal:not(.is-in) {
  transform: translate3d(0, 52px, 0) scale(0.99);
}
.js-anim .clx-hero__inner .reveal {
  transition-duration: 0.66s, 0.7s;
}
/* Eyebrows lead the sequence with a shorter travel. */
.js-anim .clx-eyebrow.reveal {
  transition-duration: 0.5s;
}
.js-anim .clx-eyebrow.reveal:not(.is-in) {
  transform: translate3d(0, 14px, 0);
}
/* Floating chips fade in after the stage they sit on has arrived. Opacity
   only: these already run an idle float, and a transform entrance would
   fight it. */
.js-anim .clx-fxchip {
  opacity: 0;
  transition: opacity 0.58s var(--fx-ease-out);
}
.js-anim .clx-herostage.is-in .clx-fxchip {
  opacity: 1;
}
.js-anim .clx-herostage.is-in .clx-fxchip:nth-of-type(1) {
  transition-delay: 0.85s;
}
.js-anim .clx-herostage.is-in .clx-fxchip:nth-of-type(2) {
  transition-delay: 1s;
}
.js-anim .clx-herostage.is-in .clx-fxchip:nth-of-type(3) {
  transition-delay: 1.15s;
}

/* --------------------------------------------------------------------------
   12 · Reduced motion
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .js-anim .reveal,
  .js-anim .stagger > *,
  .js-anim [data-split] .word > span,
  .js-anim .clx-fxchip {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
    animation: none !important;
  }
  .k-orb,
  .k-marquee__track {
    animation: none !important;
  }
  .header {
    transition: none;
  }
}
