/* ==========================================================================
   Sphinx Labs — ambient effects layer
   Noise, gradient blooms, glass, border glow, hairline rules.

   Every effect here is painted with a pseudo-element on an element that
   already exists. Nothing in this file requires a decorative <div>, which is
   what keeps the redesign's "don't change the structure" promise literal
   rather than approximate.

   Two rules govern everything below:

   1. No `filter: blur()` for blooms. A 120px blur on a ~900px box repaints on
      every scroll frame and is one of the most expensive effects a browser
      offers. A multi-stop radial-gradient is visually equivalent and free.
   2. Only `transform` and `opacity` animate. Never width, height, top, left,
      filter or box-shadow.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Film grain
   One 128x128 fractal-noise tile, fixed to the viewport so it never scrolls
   with content — grain that moves reads as texture on the elements instead of
   on the screen. `overlay` keeps it invisible in the true blacks and only
   lifts the midtones, which is what stops large dark areas banding.
   -------------------------------------------------------------------------- */

body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: 0.035;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='128' height='128'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   Ambient blooms
   Each major section carries its own light source as a ::before. The blue is
   the demoted brand colour doing the only job it still has: giving the black
   somewhere to fall off to. Lime appears sparingly and only near CTAs, so the
   eye associates the glow with action.
   -------------------------------------------------------------------------- */

#problems,
#solution,
#why-us,
#testimonials,
#how-it-works,
#growth-audit,
#faq {
  position: relative;
  isolation: isolate;
}

#problems::before,
#solution::before,
#why-us::before,
#testimonials::before,
#how-it-works::before,
#growth-audit::before,
#faq::before {
  content: "";
  position: absolute;
  z-index: -1;
  pointer-events: none;
  /* Deliberately wider than the section so the falloff never shows an edge.
     -20% alone only delivers that below 1440px: these sections are .shell, so
     past the cap the overhang stays frozen at 288px while the viewport keeps
     growing, and the bloom gets cut inside the visible area. min() takes
     whichever is wider — -20% at narrow widths (unchanged), the viewport-edge
     breakout beyond the cap — so the box can only ever grow, never shrink. */
  inset-inline: min(-20%, calc(50% - 50vw));
  top: -10%;
  height: 120%;
  /* Fade the horizontal edges rather than ending on them. -10%/120% is not
     enough clearance for the gradients centred near the top: #problems sits at
     18% with a 38% radius, so its box began mid-bloom and ruled a line across
     the full width. Masking here retires every section's glow before its own
     edge, on both sides, whatever each gradient is aimed at. */
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 16%, #000 84%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 16%, #000 84%, transparent);
}

#problems::before {
  background: radial-gradient(
    42% 38% at 78% 18%,
    rgba(7, 78, 135, 0.5),
    transparent 68%
  );
}

#solution::before {
  background: radial-gradient(
    40% 42% at 12% 50%,
    rgba(198, 255, 0, 0.07),
    transparent 66%
  );
}

#why-us::before {
  background: radial-gradient(
    38% 40% at 88% 32%,
    rgba(7, 78, 135, 0.45),
    transparent 66%
  );
}

#testimonials::before {
  background: radial-gradient(
    50% 40% at 50% 50%,
    rgba(7, 78, 135, 0.34),
    transparent 70%
  );
}

#how-it-works::before {
  background: radial-gradient(
    36% 44% at 16% 24%,
    rgba(143, 87, 255, 0.2),
    transparent 66%
  );
}

#growth-audit::before {
  background: radial-gradient(
    40% 44% at 84% 40%,
    rgba(198, 255, 0, 0.075),
    transparent 66%
  );
}

#faq::before {
  background: radial-gradient(
    44% 40% at 20% 20%,
    rgba(7, 78, 135, 0.4),
    transparent 68%
  );
}

/* --------------------------------------------------------------------------
   Glass
   The shared surface treatment for every card on the page.

   `backdrop-filter` is the one genuinely expensive property kept, so it is
   applied only where a card actually sits over imagery or a bloom. Cards on
   flat page background get the same look from the fill alone, at no cost.
   -------------------------------------------------------------------------- */

.u-glass {
  background: var(--glass);
  border: 1px solid var(--hairline);
  box-shadow: var(--shadow-card);
}

/* A 1px inner highlight along the top edge. This is what makes a card read as
   a raised surface rather than a lighter rectangle — real objects catch light
   on their top edge. */
.u-glass-lit {
  position: relative;
}

.u-glass-lit::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.09),
    transparent 40%
  );
  /* Sits above the fill but below the content. */
  z-index: 0;
}

/* --------------------------------------------------------------------------
   Border glow on hover
   An inset radial that fades up under the card's own border. Opacity-only, so
   it composites without repainting.
   -------------------------------------------------------------------------- */

.u-glow {
  position: relative;
}

.u-glow::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s var(--ease-out);
  /* --glow-x/--glow-y let a component move its own light source, so a column
     of cards doesn't read as the same unit repeated. */
  background: radial-gradient(
    60% 70% at var(--glow-x, 50%) var(--glow-y, 0%),
    var(--glow-hue, var(--lime-glow)),
    transparent 70%
  );
}

.u-glow:hover::before,
.u-glow:focus-within::before {
  opacity: 1;
}

/* --------------------------------------------------------------------------
   Animated hairline
   A 1px gradient rule that wipes in from the left when it enters view. Used to
   separate sections without the heaviness of a solid border.
   -------------------------------------------------------------------------- */

.u-rule {
  height: 1px;
  border: 0;
  background: linear-gradient(
    90deg,
    transparent,
    var(--hairline-hi) 18%,
    var(--hairline-hi) 82%,
    transparent
  );
  transform-origin: left center;
}

.js .u-rule[data-animate] {
  transform: scaleX(0);
}

.js .u-rule[data-animate].is-inview {
  transform: scaleX(1);
  transition: transform 0.9s var(--ease-out);
}

/* --------------------------------------------------------------------------
   Custom cursor
   Created by js/motion.js, which only runs for fine pointers with motion
   enabled — so these elements simply never exist otherwise, and no media
   query is needed to hide them.

   The native cursor is deliberately NOT hidden. Replacing it site-wide breaks
   the text I-beam over copy and the pointer over links, trading a real
   affordance for a decorative one. The dot and ring accompany it instead.
   -------------------------------------------------------------------------- */

.cursor-dot,
.cursor-ring {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 10000;
  pointer-events: none;
  border-radius: 50%;
  opacity: 0;
  /* The -50% keeps the element centred on the pointer; JS writes only the
     translate3d, so this must survive as a separate transform property. */
  translate: -50% -50%;
  transition: opacity 0.3s ease;
}

.has-cursor .cursor-dot,
.has-cursor .cursor-ring {
  opacity: 1;
}

.cursor-dot {
  width: 6px;
  height: 6px;
  background: var(--lime);
  box-shadow: 0 0 10px rgba(198, 255, 0, 0.8);
}

.cursor-ring {
  width: 34px;
  height: 34px;
  border: 1px solid rgba(198, 255, 0, 0.45);
  transition: opacity 0.3s ease, width 0.3s var(--ease-out),
    height 0.3s var(--ease-out), background-color 0.3s ease,
    border-color 0.3s ease;
}

.cursor-ring.is-hot {
  width: 52px;
  height: 52px;
  background: rgba(198, 255, 0, 0.1);
  border-color: rgba(198, 255, 0, 0.75);
}

/* --------------------------------------------------------------------------
   Reduced motion
   The blooms and grain are static decoration and stay — they carry no
   movement. Only the hairline wipe is a motion effect, so only it is dropped.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .js .u-rule[data-animate],
  .js .u-rule[data-animate].is-inview {
    transform: none;
    transition: none;
  }

  .u-glow::before {
    transition: none;
  }
}
