/* ============================================================
   SIGNAL DIVE — 3D scroll-motion layer
   Carrying layer = CSS Scroll-Driven Animations + 3D transforms +
   sticky (compositor-sampled by scroll, never rAF). GSAP is extra.
   Everything below is gated: unsupported browsers keep the plain
   IntersectionObserver reveals and read identically.
   ============================================================ */

/* ---- base structure that also works as the fallback ---- */
.void, .cockpit { display: none; }
.svc-scroll { position: relative; }
.svc-track { display: flex; flex-direction: column; gap: 1.25rem; }
.svc-panel {
  position: relative; display: flex; flex-direction: column; justify-content: space-between;
  background: #0a0a0c;
  border: 1px solid rgba(255,255,255,.12); border-radius: var(--r-panel);
  padding: clamp(1.6rem, 3vw, 2.6rem); min-height: 220px; overflow: hidden; text-decoration: none;
  box-shadow: 0 24px 50px -20px rgba(0,0,0,.75);
}
/* Full-bleed media card (the Apple-TV / streaming-tile pattern): the image
   IS the card, edge to edge. The previous version floated an 82%x74% box
   inside the panel, which read as a hard-edged rectangle artefact, and was
   darkened so far it turned to mud. One bottom-up scrim carries the text. */
.svc-panel__bg { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.svc-panel__bg img { width: 100%; height: 100%; object-fit: cover; filter: grayscale(.35) contrast(1.08) brightness(.82); transition: transform 1.2s var(--ease), filter .5s; }
.svc-panel__bg::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(10,10,12,.78) 0%, rgba(10,10,12,.28) 26%, rgba(10,10,12,.86) 74%, #0a0a0c 100%);
}
.svc-panel:hover .svc-panel__bg img { transform: scale(1.05); filter: grayscale(.15) contrast(1.12) brightness(.95); }

.svc-panel__top, .svc-panel__text, .svc-panel__go { position: relative; z-index: 1; }
.svc-panel__top { display: flex; align-items: flex-start; justify-content: space-between; }
.svc-panel__idx { font-family: var(--font-display); font-weight: 700; font-size: clamp(3rem, 6vw, 6rem); line-height: .8; color: transparent; -webkit-text-stroke: 1.5px var(--accent-soft); }
.svc-panel__sku { font-family: var(--font-mono); font-size: .72rem; letter-spacing: .14em; color: var(--accent); }
.svc-panel__icon { display: inline-flex; align-items: center; justify-content: center; width: 46px; height: 46px; border-radius: var(--r-chip); color: var(--accent); }
.svc-panel__icon svg { width: 22px; height: 22px; }
.svc-panel__name { font-family: var(--font-display); font-size: clamp(1.7rem, 3vw, 2.8rem); color: var(--ink); margin-top: 1.2rem; }
.svc-panel__desc { color: var(--ink-dim); margin-top: .7rem; max-width: 42ch; }
.svc-panel__go { margin-top: 1.4rem; font-family: var(--font-mono); font-size: .8rem; letter-spacing: .06em; color: var(--accent); }

/* one-shot glass focus-pull: a surface arrives sharp out of a soft blur.
   Motivated as a state transition — the glass "resolves" into view. */
@keyframes glassFocus { from { opacity: 0; filter: blur(16px); transform: translateY(20px) scale(.97); } to { opacity: 1; filter: blur(0); transform: none; } }

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    /* ---- global void deep-field (3 parallax planes, restrained density) ---- */
    .void { display: block; position: fixed; inset: -18% 0; z-index: 1; pointer-events: none; }
    .void__l { position: absolute; inset: 0; will-change: transform;
      background-image: radial-gradient(circle, var(--accent-soft) 0 1px, transparent 1.6px);
      animation: drift linear both; animation-timeline: scroll(root block); }
    .void__l--a { --dy: -12vh; opacity: .22; background-size: 130px 130px; }
    .void__l--b { --dy: -24vh; opacity: .13; background-size: 220px 220px; }
    .void__l--c { --dy: -38vh; opacity: .08; background-size: 350px 350px; }
    @keyframes drift { to { transform: translate3d(0, var(--dy), 0); } }

    /* ---- cockpit corner brackets ---- */
    .cockpit { display: block; position: fixed; inset: 14px; z-index: 6; pointer-events: none; }
    .cockpit i { position: absolute; width: 22px; height: 22px; border: 1px solid var(--hairline-2);
      animation: breathe linear both; animation-timeline: scroll(root block); }
    .cockpit i:nth-child(1) { top: 0; left: 0; border-right: 0; border-bottom: 0; }
    .cockpit i:nth-child(2) { top: 0; right: 0; border-left: 0; border-bottom: 0; }
    .cockpit i:nth-child(3) { bottom: 0; left: 0; border-right: 0; border-top: 0; }
    .cockpit i:nth-child(4) { bottom: 0; right: 0; border-left: 0; border-top: 0; }
    @keyframes breathe { from { transform: scale(1); opacity: .3; } to { transform: scale(.82); opacity: .65; } }

    /* ---- spine fills by scroll ---- */
    .spine__fill { animation: spineFill linear both; animation-timeline: scroll(root block); }
    @keyframes spineFill { to { transform: scaleY(1); } }

    /* ---- hero canopy: image recedes into Z as you leave the hero ---- */
    .hero { perspective: var(--persp); }
    .hero__canopy-img { animation: heroDolly linear both; animation-timeline: scroll(root block); animation-range: 0 92svh; }
    @keyframes heroDolly { to { transform: perspective(var(--persp)) translateZ(var(--z-recede)) scale(1.1); opacity: .3; } }

    /* ---- marquee lies back and straightens (3D bank) ---- */
    .marquee { perspective: 760px; }
    .marquee__track { animation: scrollx 32s linear infinite, mqBank linear both; animation-timeline: auto, view(); animation-range: normal, entry 0% cover 60%; }
    @keyframes mqBank { from { transform: rotateX(15deg) rotateY(-8deg); } to { transform: rotateX(0) rotateY(0); } }

    /* ---- VOLTAGE TYPE: words ignite as the signal crosses them (line by line,
       robust for any word count — each word ignites on its own view band) ---- */
    .w { color: var(--ink-mute); display: inline-block;
      animation: ignite linear both; animation-timeline: view();
      animation-range: entry 40% cover 52%; }
    @keyframes ignite { to { color: var(--ink); text-shadow: 0 0 22px var(--accent-soft); } }
    .w.hot { animation-name: igniteHot; }
    @keyframes igniteHot { to { color: var(--accent); text-shadow: 0 0 26px var(--accent-glow); } }

    /* ---- SERVICES: pinned horizontal corridor (desktop) ---- */
    @media (min-width: 761px) {
      .svc-scroll { height: 440vh; view-timeline-name: --svc; }
      .svc-pin { position: sticky; top: 0; height: 100svh; overflow: hidden; perspective: var(--persp); display: flex; align-items: center; }
      .svc-track { flex-direction: row; gap: 4vw; padding-inline: 8vw; will-change: transform;
        animation: railX linear both; animation-timeline: --svc; animation-range: contain 0% contain 100%; }
      @keyframes railX { to { transform: translateX(calc(-100% + 84vw)); } }
      .svc-panel { flex: 0 0 clamp(300px, 62vw, 640px); min-height: 62vh; transform-style: preserve-3d;
        animation: panelBank linear both; animation-timeline: view(--svc inline); animation-range: entry 0% exit 100%; }
      @keyframes panelBank { 0% { transform: rotateY(16deg); } 50% { transform: rotateY(0); } 100% { transform: rotateY(-16deg); } }
    }

    /* ---- contact panel + form resolve into focus ---- */
    .contact-grid form, .contact-grid .contact-detail { animation: glassFocus linear both; animation-timeline: view(); animation-range: entry 0% cover 44%; }
    /* a form someone is typing in is never blurred or faded, however little
       the page has scrolled (keyboard focus scrolls only just enough) */
    .contact-grid form:focus-within { animation: none; opacity: 1; filter: none; transform: none; }

    /* ---- CRM proof panel docks in from Z ---- */
    .proofnode { perspective: var(--persp); }
    .proofnode__panel { transform-style: preserve-3d; will-change: transform;
      animation: dock linear both; animation-timeline: view(); animation-range: entry 0% cover 55%; }
    @keyframes dock { from { opacity: 0; transform: rotateY(-14deg) rotateX(8deg) translateZ(-220px); } to { opacity: 1; transform: none; } }

    /* ---- stats: glass tiles hinge up from the floor ---- */
    .stats { perspective: 1100px; }
    .stat { transform-origin: bottom; backface-visibility: hidden;
      animation: hinge linear both; animation-timeline: view(); animation-range: entry 8% cover 34%; }
    .stat:nth-child(2) { animation-range: entry 13% cover 39%; }
    .stat:nth-child(3) { animation-range: entry 18% cover 44%; }
    .stat:nth-child(4) { animation-range: entry 23% cover 49%; }
    @keyframes hinge { from { opacity: 0; transform: perspective(1100px) rotateX(-42deg) translateY(40px); } to { opacity: 1; transform: none; } }

    /* bg-accent images parallax via scroll instead of GSAP */
    .bg-accent img { animation: bgPar linear both; animation-timeline: view(); animation-range: cover 0% cover 100%; }
    @keyframes bgPar { from { transform: translateY(-9%); } to { transform: translateY(9%); } }

    /* ---- how-we-work: each ledger row arrives as it is read ---- */
    .step { animation: stepIn linear both; animation-timeline: view(); animation-range: entry 10% cover 42%; }
    @keyframes stepIn { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: none; } }

    /* ---- CTA: camera pushes into the wall + title ignites ---- */
    .cta-band { perspective: var(--persp); }
    .cta-band__title { animation: ctaPush linear both; animation-timeline: view(); animation-range: cover 0% cover 72%; }
    @keyframes ctaPush { from { transform: scale(.9); } to { transform: scale(1.05); text-shadow: 0 0 30px var(--accent-glow); } }

    /* ---- footer standby line seals ---- */
    .console__standby::before { transform-origin: left; transform: scaleX(0);
      animation: draw linear both; animation-timeline: view(); animation-range: entry 0% entry 92%; }
    @keyframes draw { to { transform: scaleX(1); } }
  }
}

/* ---- SERVICES: each object drifts while its own chapter is read ----
   A named view timeline per chapter, hoisted to .chapters so the stage
   (a sibling column) can read it. Individual transform properties on the
   <img>, so the drift composes with the crossfade transform that lives on
   the wrapper instead of fighting it for the same property. */
@supports (timeline-scope: --a) {
  @media (prefers-reduced-motion: no-preference) {
    .js .chapters { timeline-scope: --c0, --c1, --c2, --c3, --c4, --c5; }
    .js .ch[data-i="0"] { view-timeline-name: --c0; }
    .js .ch[data-i="1"] { view-timeline-name: --c1; }
    .js .ch[data-i="2"] { view-timeline-name: --c2; }
    .js .ch[data-i="3"] { view-timeline-name: --c3; }
    .js .ch[data-i="4"] { view-timeline-name: --c4; }
    .js .ch[data-i="5"] { view-timeline-name: --c5; }
    /* one drift for all six: the object breathes while its chapter is
       read. Five different arbitrary moves read as motion for its own sake. */
    .stage__obj img { animation: driftSwell linear both; animation-range: cover 0% cover 100%; }
    .stage__obj[data-i="0"] img { animation-timeline: --c0; }
    .stage__obj[data-i="1"] img { animation-timeline: --c1; }
    .stage__obj[data-i="2"] img { animation-timeline: --c2; }
    .stage__obj[data-i="3"] img { animation-timeline: --c3; }
    .stage__obj[data-i="4"] img { animation-timeline: --c4; }
    .stage__obj[data-i="5"] img { animation-timeline: --c5; }
    /* phones / no JS: the inline figure breathes on its own view() */
    .ch__media img { animation: driftSwell linear both; animation-timeline: view(); animation-range: cover 0% cover 100%; }
  }
}
@keyframes driftSwell { from { scale: .97; } to { scale: 1.03; } }

/* ---- degrade geometry where scroll-driven is unsupported (Safari/FF) ---- */
@supports not (animation-timeline: view()) {
  .svc-pin { position: static; height: auto; overflow: visible; display: block; }
  .w { color: var(--ink); }
  .w.hot { color: var(--accent); }
}

/* ---- reduced motion: collapse all 3D/scroll motion to flat, readable ---- */
@media (prefers-reduced-motion: reduce) {
  .void, .cockpit { display: none !important; }
  .void__l, .svc-track, .svc-panel, .stat, .step,
  .proofnode__panel, .w, .cta-band__title, .marquee__track,
  .hero__canopy-img, .hero__frame-img, .bg-accent img, .cockpit i, .spine__fill,
  .contact-grid form, .contact-grid .contact-detail {
    animation: none !important; transform: none !important; opacity: 1 !important; filter: none !important;
  }
  .w { color: var(--ink); }
  .w.hot { color: var(--accent); }
  .svc-pin { position: static; height: auto; overflow: visible; }
  .svc-track { flex-direction: column; }
}
