/* ============================================================
   Ideal AI — Scroll-driven cinematic layer
   Apple / Scale.com-style pinned, scroll-scrubbed transformation.
   Sits ON TOP of styles.css + demo.css. Purely presentational +
   a few new sections; all motion is GPU-friendly (transform/opacity).

   $0 runtime — self-hosted GSAP + ScrollTrigger + Lenis (public/lib).
   No network/API calls added. Degrades to clean static reveals when
   JS is off, on reduced-motion, or on small phones.
   ============================================================ */

/* ---- root flags toggled by scroll.js once libs are live ---- */
html.has-scrollfx{ scroll-behavior:auto; }            /* Lenis owns scrolling */
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth{scroll-behavior:auto !important}
.lenis.lenis-smooth [data-lenis-prevent]{overscroll-behavior:contain}
.lenis.lenis-stopped{overflow:hidden}

/* The page becomes one connected journey: a fixed gradient field that
   morphs hue/position as you scroll (the "background that MORPHS"). It sits
   behind everything; sections keep their own local blobs on top. */
/* TWO stacked gradient fields. We crossfade between them by OPACITY as the
   page scrolls (compositor-only — no per-frame paint of hue-rotate/filter),
   which morphs the whole page from a cool blue top to a deeper indigo low. */
.scrollfield{position:fixed;inset:0;z-index:-2;pointer-events:none;
  opacity:0;transition:opacity 1s ease;will-change:transform}
html.has-scrollfx .scrollfield{opacity:1}
.scrollfield .sf-a,.scrollfield .sf-b{position:absolute;inset:0;will-change:opacity}
.scrollfield .sf-a{opacity:1;background:
    radial-gradient(60% 50% at 50% 0%,  rgba(0,210,255,.20), transparent 60%),
    radial-gradient(55% 60% at 85% 28%, rgba(0,210,255,.10), transparent 60%)}
/* bottom of the page morphs into a deeper teal-aqua (still aqua family, just
   lower-key) so the scroll journey stays cohesive and cyan-led, not blue. */
.scrollfield .sf-b{opacity:0;background:
    radial-gradient(60% 55% at 18% 30%, rgba(10,150,200,.16), transparent 60%),
    radial-gradient(58% 60% at 80% 80%, rgba(40,200,240,.12), transparent 62%),
    radial-gradient(50% 50% at 50% 110%,rgba(0,210,255,.16), transparent 60%)}
/* a deeper aurora layer for parallax depth (drifts slower) */
.scrollfield .sf-deep{position:absolute;inset:-15%;will-change:transform;
  background:radial-gradient(40% 40% at 30% 20%,rgba(60,220,255,.10),transparent 60%)}

/* keep the existing fixed body wash from doubling up the glow on top */
html.has-scrollfx body{background-attachment:scroll}

/* ============================================================
   1 · PINNED HERO → DEMO TRANSITION
   The hero pins; as you scroll, the headline lifts/fades while the
   live-call card docks (scale + subtle rotate) and the demo section
   emerges underneath — crossfaded by scroll position.
   We wrap the hero + marquee + demo in .scene-hero (added in scroll.js
   only when fx are active, via a JS-built wrapper — but to keep the
   markup untouched we instead pin/transform the existing nodes directly).
   ============================================================ */

/* While fx active, give the hero copy + cue a transform origin and
   will-change so GSAP scrubbing stays on the compositor. */
html.has-scrollfx .hero .container > *{will-change:transform,opacity}
html.has-scrollfx .hero h1{transform-origin:50% 0%}

/* the live-call card gets a transform context for the dock move */
html.has-scrollfx #liveCall{will-change:transform,opacity}

/* a soft vignette that deepens as the hero hands off to the demo,
   so the transition reads as a camera push, not a jump */
.scene-veil{position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:0;
  background:radial-gradient(75% 65% at 50% 42%,transparent 32%,rgba(4,5,8,.6) 80%);
  will-change:opacity}
html.has-scrollfx .scene-veil{display:block}

/* ============================================================
   2 · SCROLL-SCRUBBED 3 A.M. NARRATIVE
   A pinned, full-viewport story whose beats advance with scroll
   position. Three "frames" crossfade as the visitor scrubs.
   Injected as a new <section id="story"> in index.html.
   ============================================================ */
.story{position:relative;padding:0}
.story-pin{position:relative;height:100vh;min-height:620px;display:grid;place-items:center;
  overflow:hidden}
.story-sky{position:absolute;inset:0;z-index:0;
  background:
    radial-gradient(120% 80% at 50% -20%,rgba(0,210,255,.16),transparent 55%),
    linear-gradient(180deg,#070a12,#05060a 70%)}
/* faint clock-hand sweep / drifting stars layer for depth */
.story-stars{position:absolute;inset:0;z-index:0;opacity:.5;
  background-image:
    radial-gradient(1.5px 1.5px at 20% 30%,rgba(180,210,255,.7),transparent),
    radial-gradient(1.5px 1.5px at 70% 60%,rgba(180,210,255,.5),transparent),
    radial-gradient(1px 1px at 40% 80%,rgba(180,210,255,.6),transparent),
    radial-gradient(1px 1px at 85% 25%,rgba(180,210,255,.45),transparent),
    radial-gradient(1.5px 1.5px at 55% 15%,rgba(180,210,255,.55),transparent);
  will-change:transform}
.story-inner{position:relative;z-index:2;width:100%;max-width:980px;padding:0 28px;text-align:center}

.story-eyebrow{font-family:var(--body);font-size:12px;font-weight:600;letter-spacing:.24em;
  text-transform:uppercase;color:var(--blue-2);display:block;margin-bottom:22px;opacity:.9}

/* the stack of beats — each absolutely centered, only one "active" at a time */
.story-beats{position:relative;min-height:clamp(180px,30vh,300px)}
.beat{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:18px;opacity:0;transform:translateY(28px) scale(.98);will-change:transform,opacity;
  pointer-events:none}
.beat .clock{font-family:var(--mono);font-size:clamp(2.4rem,7vw,4.2rem);font-weight:500;letter-spacing:-.02em;
  background:linear-gradient(180deg,#fff,#5fe0ff);-webkit-background-clip:text;background-clip:text;color:transparent;
  line-height:1}
.beat h2{font-size:clamp(1.7rem,4.4vw,3.1rem);max-width:18ch;margin:0}
.beat p{font-size:clamp(1.05rem,2vw,1.25rem);color:var(--ink-2);max-width:42ch;margin:0}
.beat .tagline{font-family:var(--mono);font-size:.82rem;letter-spacing:.14em;text-transform:uppercase}
.beat .tagline.bad{color:#ff9b9b}
.beat .tagline.good{color:var(--green)}
.beat .ring{display:inline-flex;align-items:center;gap:10px;font-family:var(--mono);font-size:.8rem;
  letter-spacing:.12em;text-transform:uppercase;color:var(--blue-2);
  border:1px solid rgba(0,210,255,.35);border-radius:var(--pill);padding:8px 16px;background:rgba(0,210,255,.06)}
.beat .ring::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--blue)}

/* progress rail showing the scrub position through the story */
.story-rail{position:absolute;left:50%;bottom:42px;transform:translateX(-50%);z-index:3;
  display:flex;gap:10px}
.story-rail i{width:32px;height:3px;border-radius:3px;background:rgba(255,255,255,.16);
  transition:background .35s,box-shadow .35s}
.story-rail i.on{background:var(--blue);box-shadow:0 0 14px var(--glow)}

/* ---- NIGHT → DAWN morph (injected by scroll.js; opacity + sun driven by scroll) ----
   A premium, aqua-led sunrise: the sky warms to pale teal and a soft sun climbs the
   horizon as the 3 a.m. story resolves to morning — the reward at the end of the scroll. */
.story-dawn{position:absolute;inset:0;z-index:1;opacity:0;pointer-events:none;overflow:hidden;
  background:linear-gradient(180deg,
    rgba(8,16,28,0) 0%, rgba(12,46,68,.5) 48%, rgba(30,96,120,.78) 76%, rgba(120,196,208,.92) 100%)}
.story-dawn .story-horizon{position:absolute;left:-10%;right:-10%;bottom:0;height:48%;
  background:radial-gradient(120% 150% at 50% 100%, rgba(180,240,247,.6), rgba(80,200,218,.2) 45%, transparent 70%);
  filter:blur(2px)}
.story-dawn .story-sun{position:absolute;left:50%;bottom:13%;width:260px;height:260px;margin-left:-130px;
  border-radius:50%;will-change:transform,opacity;
  background:radial-gradient(circle at 50% 50%,
    rgba(255,253,248,.98), rgba(198,242,250,.85) 26%, rgba(96,212,238,.4) 52%, transparent 72%)}

/* ---- DEMO CARD: depth & dimension (fx only) — a physical object floating in space ---- */
html.has-scrollfx #liveCall{perspective:1100px}
html.has-scrollfx .lc-card{
  box-shadow:0 50px 120px -45px rgba(0,0,0,.85), 0 10px 34px -14px rgba(0,0,0,.6),
             0 0 0 1px rgba(0,210,255,.10), inset 0 1px 0 rgba(255,255,255,.05)}
html.has-scrollfx .livecall.connected .lc-card{
  box-shadow:0 56px 130px -45px rgba(0,176,228,.34), 0 10px 34px -14px rgba(0,0,0,.6),
             0 0 0 1px rgba(0,210,255,.30), inset 0 1px 0 rgba(255,255,255,.06)}

/* ---- nav condense + active-section highlight + button glow (classes set by polish.js) ----
   Not fx-gated: polish.js runs independently of the cinematic layer. */
nav.nav{transition:background .3s ease, backdrop-filter .3s ease, box-shadow .3s ease}
nav.nav.scrolled{background:rgba(8,10,14,.72);
  backdrop-filter:saturate(140%) blur(14px);-webkit-backdrop-filter:saturate(140%) blur(14px);
  box-shadow:0 1px 0 rgba(255,255,255,.06), 0 12px 30px -20px rgba(0,0,0,.85)}
nav.nav .links a:not(.btn){position:relative}
nav.nav .links a:not(.btn).active{color:var(--aqua-2)}
nav.nav .links a:not(.btn).active::after{content:"";position:absolute;left:2px;right:2px;bottom:-6px;height:2px;
  border-radius:2px;background:linear-gradient(90deg,var(--aqua),var(--aqua-2));box-shadow:0 0 10px var(--glow)}
/* aqua hover glow on primary buttons — box-shadow/filter only, so the magnetic transform is free to move */
.btn-primary{transition:box-shadow .3s ease, filter .25s ease}
.btn-primary:hover{box-shadow:0 10px 32px -8px rgba(0,210,255,.55), 0 0 0 1px rgba(0,210,255,.45);filter:brightness(1.06)}

/* ---- CTA attention: a breathing glow "throb" + a periodic sonar ping ----
   Draws the eye to the primary calls-to-action. Built on box-shadow + an
   ::after ring ONLY (no transform on the button), so it never fights the
   magnetic-button JS. Pauses on hover (the hover-glow + magnet take over),
   skips the in-card play/replay buttons, and goes fully still under
   reduced-motion. The ring rides behind the pill and emanates outward. */
@media (prefers-reduced-motion:no-preference){
  .btn-primary:not(.lc-play):not(.lc-replay){position:relative;animation:ctaThrob 2.8s ease-in-out infinite}
  .btn-primary:not(.lc-play):not(.lc-replay)::after{content:"";position:absolute;inset:0;border-radius:inherit;
    z-index:-1;pointer-events:none;box-shadow:0 0 0 1.5px rgba(0,210,255,.55);animation:ctaPing 2.8s ease-out infinite}
  /* the prominent hero/booking CTAs throb a touch stronger; nav stays subtle via the base */
  .btn-primary.btn-lg{animation-duration:2.6s}
  .btn-primary:not(.lc-play):not(.lc-replay):hover{animation:none}
  .btn-primary:not(.lc-play):not(.lc-replay):hover::after{animation:none;opacity:0}
}
@keyframes ctaThrob{
  0%,100%{box-shadow:0 10px 30px -4px rgba(0,210,255,.30)}
  50%{box-shadow:0 14px 48px -2px rgba(0,210,255,.62)}
}
@keyframes ctaPing{
  0%{opacity:.6;transform:scale(1)}
  70%{opacity:0;transform:scale(1.16)}
  100%{opacity:0;transform:scale(1.16)}
}

/* ============================================================
   3 · STICKY "ONE CALL, WIRED TO EVERYTHING" FEATURE-WALK
   Pins the central phone/core while six capabilities reveal one at a
   time as the user scrolls (Apple feature-walk). We REUSE the existing
   #connected hub markup; this only adds the scroll choreography hooks.
   When fx active, the hub's CSS pop-animations are disabled in favour
   of scroll-driven reveals.
   ============================================================ */
html.has-scrollfx #connected .hub .node{animation:none;opacity:0;
  transform:translate(-50%,-50%) scale(.7);
  transition:opacity .5s var(--ease),transform .55s var(--ease),box-shadow .3s,border-color .3s,background .3s}
html.has-scrollfx #connected .hub .node.lit{opacity:1;transform:translate(-50%,-50%) scale(1)}
html.has-scrollfx #connected .hub .node.center{opacity:1;transform:translate(-50%,-50%) scale(1);
  animation:hubpulse 2.8s ease-in-out infinite .2s}
/* spokes draw in with the node they feed */
html.has-scrollfx #connected .hub .spoke{stroke-dasharray:240;stroke-dashoffset:240;
  transition:stroke-dashoffset .7s var(--ease)}
html.has-scrollfx #connected .hub.lit-all .spoke{stroke-dashoffset:0}
/* a little "step counter" caption under the hub during the walk */
html.has-scrollfx #connected .panel.good{will-change:transform}

/* ============================================================
   4 · SECTION REVEAL SEQUENCING (scroll-scrubbed, not just on-enter)
   For non-pinned sections we upgrade the existing .reveal into a
   scrubbed parallax rise. scroll.js tags these with data-sfx.
   ============================================================ */
html.has-scrollfx [data-sfx="rise"]{will-change:transform,opacity}
/* parallax layers — different scroll rates for depth */
html.has-scrollfx [data-parallax]{will-change:transform}

/* the marquee gets a subtle scroll-linked drift on top of its loop */
html.has-scrollfx .marquee{will-change:transform}

/* ============================================================
   Cross-browser / fallback / accessibility
   ============================================================ */

/* If JS/libs never activate (.has-scrollfx absent), NOTHING here changes
   the base layout — the site renders exactly as before with its existing
   IntersectionObserver reveals. The new #story + .scrollfield are styled
   to look intentional even fully static (see below). */

/* Static fallback for the story section when fx are off: show all beats
   stacked, readable, no pinning. */
html:not(.has-scrollfx) .story-pin{height:auto;min-height:0;padding:90px 0;display:block}
html:not(.has-scrollfx) .story-beats{min-height:0;display:flex;flex-direction:column;gap:46px}
html:not(.has-scrollfx) .beat{position:static;opacity:1;transform:none;display:flex}
html:not(.has-scrollfx) .story-rail{display:none}

/* Reduced motion: identical to the no-fx static fallback, plus we never
   pin or scrub even if libs loaded. scroll.js bails before activating, so
   .has-scrollfx is never added — these rules guarantee a clean read. */
@media (prefers-reduced-motion:reduce){
  .scrollfield,.scene-veil{display:none}
  .story-pin{height:auto;min-height:0;padding:90px 0;display:block}
  .story-beats{min-height:0;display:flex;flex-direction:column;gap:46px}
  .beat{position:static;opacity:1;transform:none}
  .story-stars{display:none}
  .story-rail{display:none}
}

/* ---- Mobile: scroll-jacking feels bad on phones ----
   On small screens scroll.js disables Lenis + pinning + scrubbing and we
   fall back to the static story + standard reveals. These rules make the
   static phone layout polished. */
@media (max-width:760px){
  .story-pin{height:auto;min-height:0;padding:80px 0;display:block}
  .story-beats{min-height:0;display:flex;flex-direction:column;gap:40px}
  .beat{position:static;opacity:1;transform:none}
  .story-rail{display:none}
  .story-inner{padding:0 22px}
}
