/* Marketing-site effects (2026-11): border beam, hero grid beams.
   Loaded by the homepage, /pricing (built from the homepage markup) and
   /runtime-guard. Marketing pages only; the dashboard never loads this.

   Performance contract, the reason for every choice below:
   - Only transform and opacity animate, so the compositor runs the motion and
     nothing repaints per frame. The beam ports the approved mockup
     (linkedin-videos/ui-refresh-mockup.html), which spun a registered
     --beam angle inside a conic-gradient: that repaints every frame. Here the
     gradient is static and its layer rotates instead.
   - The rotating layer is a square that must cover the element's diagonal, so
     it is only used on small/medium boxes (hero CTA, featured price card).
     Wide boxes use .fx-beam--edges: two thin comets that slide along the top
     and bottom edges, a few KB of layer instead of a full-width square.
   - static/js/page/fx.js pauses everything while it is off screen.
   - prefers-reduced-motion: no motion at all; the beam stays as a faint static
     ring so the emphasis is still there.
   No colours outside the RedLens navy / red / blue palette. */

/* -- Border beam ------------------------------------------------------------ */
.fx-beam-host{position:relative;isolation:isolate}
.fx-beam{position:absolute;inset:0;border-radius:inherit;pointer-events:none;overflow:hidden;
  padding:1.5px;z-index:1;
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask-composite:exclude}
.fx-beam::before{content:"";position:absolute;left:50%;top:50%;width:var(--fx-beam-size,160%);aspect-ratio:1;
  translate:-50% -50%;
  background:conic-gradient(from 0deg,transparent 0 62%,rgba(75,139,255,.0) 64%,rgba(75,139,255,.85) 78%,#F55050 88%,rgba(245,80,80,0) 94%,transparent 100%);
  animation:fxBeamSpin var(--fx-beam-dur,5.5s) linear infinite}
@keyframes fxBeamSpin{to{transform:rotate(1turn)}}
/* The CTA is wide and short: 160% of its width covers its diagonal. The price
   card is tall: size the square from its height instead. */
.fx-beam--tall::before{width:auto;height:150%}

/* Wide boxes: comets on the top and bottom edges. Each comet layer is the box's
   width x 2px; translate moves it a full width per pass. */
.fx-beam--edges{padding:0;-webkit-mask:none;mask:none}
.fx-beam--edges::before,.fx-beam--edges::after{content:"";position:absolute;left:0;width:100%;height:1.5px;aspect-ratio:auto;
  top:0;translate:none;
  background:linear-gradient(90deg,transparent 0 30%,rgba(75,139,255,.9) 46%,#F55050 52%,transparent 66% 100%);
  animation:fxComet var(--fx-beam-dur,7s) linear infinite}
.fx-beam--edges::after{top:auto;bottom:0;animation-direction:reverse;animation-delay:calc(var(--fx-beam-dur,7s) / -2)}
@keyframes fxComet{from{transform:translateX(-100%)}to{transform:translateX(100%)}}

/* -- Hero grid beams ----------------------------------------------------------
   Light streaks travelling along the hero's existing 64px grid (.hero-mesh),
   positioned on its lines so they read as signals on a circuit. Static
   circuit nodes sit on grid intersections; the RedLens mark is the hub. */
/* Inside .hero-mesh-grid, so it drifts with the grid and fades with its mask.
   Everything sits in the right half (the attack-schema graphic's side), never
   behind the headline or copy: --c is the hero's centre snapped down to a grid
   line, so every beam, node and the hub stays on the 64px lines at any width. */
.fx-grid{position:absolute;inset:0;pointer-events:none;--c:round(down,50%,64px)}
.fx-grid i{position:absolute;display:block;opacity:0}
.fx-grid .v{top:0;width:1px;height:140px;margin-left:-.5px;
  background:linear-gradient(180deg,transparent,rgba(75,139,255,.75) 70%,#F55050);
  animation:fxDown 7s linear infinite}
.fx-grid .h{height:1px;width:160px;margin-top:-.5px;left:var(--c);top:calc(64px * 4);
  background:linear-gradient(90deg,transparent,rgba(75,139,255,.7) 70%,#F55050);
  animation:fxRight 9s linear infinite;animation-delay:-3s}
.fx-grid .v:nth-of-type(1){left:calc(var(--c) + 64px * 2);animation-delay:-1s}
.fx-grid .v:nth-of-type(2){left:calc(var(--c) + 64px * 5);animation-delay:-4.5s;animation-duration:8.5s}
.fx-grid .v:nth-of-type(3){left:calc(var(--c) + 64px * 8);animation-delay:-2.5s;animation-duration:9s}
@keyframes fxDown{0%{transform:translateY(-140px);opacity:0}10%{opacity:1}85%{opacity:1}100%{transform:translateY(100vh);opacity:0}}
@keyframes fxRight{0%{transform:translateX(-160px);opacity:0}10%{opacity:1}85%{opacity:1}100%{transform:translateX(50vw);opacity:0}}
/* Circuit nodes on intersections the beams pass through: one painted layer,
   never animated. */
.fx-grid::before{content:"";position:absolute;inset:0;
  background-image:
    radial-gradient(circle at calc(var(--c) + 64px * 2) calc(64px * 4),rgba(75,139,255,.55) 0 2px,transparent 3px),
    radial-gradient(circle at calc(var(--c) + 64px * 5) calc(64px * 4),rgba(245,80,80,.55) 0 2px,transparent 3px),
    radial-gradient(circle at calc(var(--c) + 64px * 8) calc(64px * 4),rgba(75,139,255,.45) 0 2px,transparent 3px),
    radial-gradient(circle at calc(var(--c) + 64px * 5) calc(64px * 11),rgba(75,139,255,.4) 0 1.5px,transparent 2.5px),
    radial-gradient(circle at calc(var(--c) + 64px * 2) calc(64px * 13),rgba(75,139,255,.35) 0 1.5px,transparent 2.5px)}
/* The RedLens mark as the circuit's hub, at the foot of the third trace. */
.fx-grid .fx-hub{position:absolute;left:calc(var(--c) + 64px * 8 - 14px);top:calc(64px * 13 - 14px);width:28px;height:28px;
  opacity:.55;border-radius:7px;box-shadow:0 0 0 1px rgba(245,80,80,.25)}
/* Single-column hero: the copy spans the width, so no beams, nodes or hub. */
@media (max-width:1099px){.fx-grid{display:none}}

/* Paused off screen (fx.js) and in background tabs. */
.fx-paused .fx-beam::before,.fx-paused .fx-beam::after,.fx-paused .fx-grid i,
.fx-beam-host.fx-paused .fx-beam::before,.fx-beam-host.fx-paused .fx-beam::after{animation-play-state:paused}

@media (prefers-reduced-motion:reduce){
  .fx-beam::before,.fx-beam::after,.fx-grid i{animation:none!important}
  .fx-beam::before{opacity:.35}
  .fx-beam--edges::before,.fx-beam--edges::after{transform:none;opacity:.35}
  .fx-grid i{display:none}
}
@supports not ((mask-composite:exclude) or (-webkit-mask-composite:xor)){
  .fx-beam:not(.fx-beam--edges){display:none}
}
