// cinematic.jsx — Apple-grade award-winning sections
// Services (scroll-pinned cinema) · Expertise (scroll-reactive marquee)
// Specializations (sticky editorial) · Contact (mesh + form)

const {
  motion: cm, AnimatePresence: CAP, useScroll: cuScroll, useTransform: cuTransform,
  useMotionValue: cuMV, useSpring: cuSpring, useInView: cuInView, useMotionValueEvent: cuMVE,
} = window.framerMotion || window.Motion || {};
const {
  IconStack: CIconStack, IconChain: CIconChain, IconPhone: CIconPhone,
  IconCloud: CIconCloud, IconGrid: CIconGrid, IconShield: CIconShield,
  IconArrow: CIconArrow, IconMail: CIconMail, IconPin: CIconPin,
  Reveal: CReveal, SplitText: CSplitText, MagneticLink: CMagneticLink, Aurora: CAurora,
} = window;

/* ═══════════════════════════════════════════════════════════════════
   01 · SERVICES — "Six disciplines" scroll-pinned cinema
   ───────────────────────────────────────────────────────────────── */

const DISCIPLINES = [
  { kicker: "01",
    title: "Full-Stack",
    subtitle: "Development",
    line: "End-to-end engineering — architected backends, crafted interfaces, delivered as one system.",
    meta: ["Next.js", "Node", "Postgres", "tRPC"],
    visual: "orbit" },
  { kicker: "02",
    title: "Cloud",
    subtitle: "Infrastructure",
    line: "Scalable architectures on AWS and GCP with CI/CD, observability, and zero-touch ops.",
    meta: ["AWS", "GCP", "Kubernetes", "Terraform"],
    visual: "grid" },
  { kicker: "03",
    title: "Blockchain",
    subtitle: "Protocols",
    line: "Smart contracts, DeFi rails, and Web3 integrations — secure, audited, gas-aware.",
    meta: ["Solidity", "Solana", "Hardhat", "Foundry"],
    visual: "mesh" },
  { kicker: "04",
    title: "Mobile",
    subtitle: "Apps",
    line: "Native-feeling cross-platform apps that earn daily use, not just downloads.",
    meta: ["React Native", "Expo", "Swift", "Kotlin"],
    visual: "signal" },
  { kicker: "05",
    title: "Modern",
    subtitle: "Web Design",
    line: "High-performance marketing and product sites that convert, rank, and feel alive.",
    meta: ["React", "Astro", "Framer", "Motion"],
    visual: "wave" },
  { kicker: "06",
    title: "Security",
    subtitle: "& Auditing",
    line: "Comprehensive audits, pentests, and hardening — done before the world can find it.",
    meta: ["OWASP", "SOC 2", "ZK", "Fuzzing"],
    visual: "shield" },
];

function ServicesCinema() {
  const ref = React.useRef(null);
  const { scrollYProgress } = cuScroll({ target: ref, offset: ["start start", "end end"] });
  // Use smoothed progress for everything
  const smooth = cuSpring(scrollYProgress, { stiffness: 90, damping: 22, mass: 0.4 });

  const [active, setActive] = React.useState(0);
  React.useEffect(() => {
    const unsub = smooth.on("change", (v) => {
      const n = DISCIPLINES.length;
      const idx = Math.min(n - 1, Math.max(0, Math.floor(v * n * 0.9999)));
      setActive((prev) => (prev === idx ? prev : idx));
    });
    return () => unsub();
  }, [smooth]);

  const bgHue = cuTransform(smooth, [0, 1], [210, 285]);
  const bgColor = cuTransform(bgHue, (h) => `radial-gradient(1200px 800px at 70% 30%, hsla(${h}, 70%, 40%, 0.22), transparent 60%), radial-gradient(900px 700px at 20% 80%, hsla(${h + 40}, 70%, 40%, 0.18), transparent 60%), #05070a`);

  return (
    <section id="services" ref={ref} className="cs" style={{ height: `${DISCIPLINES.length * 100}vh` }}>
      <cm.div className="cs-sticky" style={{ background: bgColor }}>
        <div className="cs-rails">
          <span>GriffinMind Labs / Services</span>
          <span>{String(active + 1).padStart(2, "0")} / {String(DISCIPLINES.length).padStart(2, "0")}</span>
        </div>

        {/* Stage */}
        <div className="cs-stage">
          <div className="cs-visual-col">
            <CAP mode="popLayout">
              <cm.div
                key={active}
                className="cs-visual"
                initial={{ opacity: 0, scale: 0.92, filter: "blur(12px)" }}
                animate={{ opacity: 1, scale: 1, filter: "blur(0px)" }}
                exit={{ opacity: 0, scale: 1.06, filter: "blur(12px)" }}
                transition={{ duration: 0.8, ease: [0.2, 0.8, 0.2, 1] }}
              >
                <CinemaVisual kind={DISCIPLINES[active].visual}/>
              </cm.div>
            </CAP>
          </div>

          <div className="cs-type-col">
            <div className="cs-eyebrow">
              <span className="cs-eyebrow-dot"/>
              01 · Services — Six disciplines, one studio
            </div>

            <h2 className="cs-display">
              <CAP mode="popLayout">
                <cm.span
                  key={`t-${active}`}
                  className="cs-display-row"
                  initial={{ opacity: 0, y: 60, filter: "blur(14px)" }}
                  animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
                  exit={{ opacity: 0, y: -30, filter: "blur(10px)" }}
                  transition={{ duration: 0.75, ease: [0.2, 0.8, 0.2, 1] }}
                >
                  {DISCIPLINES[active].title}
                </cm.span>
              </CAP>
              <CAP mode="popLayout">
                <cm.span
                  key={`s-${active}`}
                  className="cs-display-row cs-display-row--serif"
                  initial={{ opacity: 0, y: 60, filter: "blur(14px)" }}
                  animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
                  exit={{ opacity: 0, y: -30, filter: "blur(10px)" }}
                  transition={{ duration: 0.75, delay: 0.08, ease: [0.2, 0.8, 0.2, 1] }}
                >
                  {DISCIPLINES[active].subtitle}
                </cm.span>
              </CAP>
            </h2>

            <CAP mode="popLayout">
              <cm.p
                key={`l-${active}`}
                className="cs-line"
                initial={{ opacity: 0, y: 18 }}
                animate={{ opacity: 1, y: 0 }}
                exit={{ opacity: 0, y: -12 }}
                transition={{ duration: 0.6, delay: 0.12 }}
              >
                {DISCIPLINES[active].line}
              </cm.p>
            </CAP>

            <CAP mode="popLayout">
              <cm.ul
                key={`m-${active}`}
                className="cs-meta"
                initial={{ opacity: 0 }}
                animate={{ opacity: 1 }}
                exit={{ opacity: 0 }}
                transition={{ duration: 0.5, delay: 0.18 }}
              >
                {DISCIPLINES[active].meta.map((x, i) => (
                  <cm.li
                    key={x}
                    initial={{ opacity: 0, y: 8 }}
                    animate={{ opacity: 1, y: 0 }}
                    transition={{ delay: 0.2 + i * 0.04 }}
                  >{x}</cm.li>
                ))}
              </cm.ul>
            </CAP>

            <div className="cs-counter" aria-hidden="true">
              <span className="cs-counter-n">{String(active + 1).padStart(2, "0")}</span>
              <span className="cs-counter-t">/ 06 disciplines</span>
            </div>
          </div>
        </div>

      </cm.div>
    </section>
  );
}

function CinemaVisual({ kind }) {
  if (kind === "orbit") return (
    <svg viewBox="-120 -120 240 240" className="cv">
      <defs>
        <radialGradient id="cv-g-orbit" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="var(--accent)" stopOpacity="0.9"/>
          <stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/>
        </radialGradient>
      </defs>
      <circle r="8" fill="url(#cv-g-orbit)"/>
      {[30, 55, 85, 110].map((r, i) => (
        <cm.g key={r} animate={{ rotate: 360 }} transition={{ duration: 26 + i * 6, repeat: Infinity, ease: "linear" }} style={{ transformOrigin: "center" }}>
          <circle r={r} fill="none" stroke="var(--accent)" strokeWidth="0.6" strokeOpacity={0.45 - i * 0.08} strokeDasharray={i % 2 === 0 ? "2 4" : "none"}/>
          <circle cx={r} cy="0" r={2.4 - i * 0.3} fill="var(--accent)" opacity={0.9 - i * 0.15}/>
        </cm.g>
      ))}
      <circle r="115" fill="none" stroke="var(--accent)" strokeWidth="0.3" strokeOpacity="0.2"/>
    </svg>
  );
  if (kind === "mesh") return (
    <svg viewBox="-120 -120 240 240" className="cv">
      {Array.from({ length: 14 }).map((_, i) => {
        const a = (i / 14) * Math.PI * 2;
        const r = 80 + (i % 3) * 12;
        const x = Math.cos(a) * r, y = Math.sin(a) * r;
        return <cm.circle key={i} cx={x} cy={y} r="2.5" fill="var(--accent)"
          animate={{ opacity: [0.3, 1, 0.3] }} transition={{ duration: 3, delay: i * 0.15, repeat: Infinity }}/>;
      })}
      {Array.from({ length: 14 }).map((_, i) => {
        const a1 = (i / 14) * Math.PI * 2;
        const a2 = ((i + 5) / 14) * Math.PI * 2;
        const r = 80 + (i % 3) * 12;
        return <cm.line key={`l${i}`} x1={Math.cos(a1) * r} y1={Math.sin(a1) * r}
          x2={Math.cos(a2) * r} y2={Math.sin(a2) * r}
          stroke="var(--accent)" strokeWidth="0.5" strokeOpacity="0.3"
          animate={{ pathLength: [0, 1, 0], opacity: [0, 0.5, 0] }}
          transition={{ duration: 4, delay: i * 0.2, repeat: Infinity }}/>;
      })}
      <circle r="4" fill="var(--accent)"/>
    </svg>
  );
  if (kind === "signal") return (
    <div className="cv cv--signal">
      {Array.from({ length: 32 }).map((_, i) => (
        <cm.span key={i} className="cv-bar"
          animate={{ scaleY: [0.2, 1, 0.4, 0.9, 0.25] }}
          transition={{ duration: 2.4, delay: i * 0.04, repeat: Infinity, ease: "easeInOut" }}/>
      ))}
    </div>
  );
  if (kind === "grid") return (
    <svg viewBox="-120 -120 240 240" className="cv">
      <defs>
        <pattern id="cv-grid" width="12" height="12" patternUnits="userSpaceOnUse">
          <path d="M0 12 L12 12 M12 0 L12 12" stroke="var(--accent)" strokeOpacity="0.25" strokeWidth="0.4"/>
        </pattern>
      </defs>
      <rect x="-120" y="-120" width="240" height="240" fill="url(#cv-grid)"/>
      {[40, 70, 100].map((r, i) => (
        <cm.circle key={r} cx="0" cy="0" r={r} fill="none" stroke="var(--accent)" strokeWidth="1"
          animate={{ r: [r - 10, r + 20, r - 10], opacity: [0.6, 0, 0.6] }}
          transition={{ duration: 4, delay: i * 0.8, repeat: Infinity }}/>
      ))}
      <circle cx="0" cy="0" r="6" fill="var(--accent)"/>
    </svg>
  );
  if (kind === "wave") return (
    <svg viewBox="-120 -120 240 240" className="cv">
      {[0, 1, 2, 3, 4].map((i) => (
        <cm.path key={i}
          d={`M-110 0 Q -55 ${-40 + i * 5} 0 0 T 110 0`}
          fill="none" stroke="var(--accent)" strokeWidth="0.8" strokeOpacity={0.7 - i * 0.1}
          animate={{ d: [
            `M-110 0 Q -55 ${-40 + i * 5} 0 0 T 110 0`,
            `M-110 0 Q -55 ${40 - i * 5} 0 0 T 110 0`,
            `M-110 0 Q -55 ${-40 + i * 5} 0 0 T 110 0`,
          ] }}
          transition={{ duration: 4 + i * 0.4, repeat: Infinity, ease: "easeInOut" }}/>
      ))}
    </svg>
  );
  if (kind === "shield") return (
    <svg viewBox="-120 -120 240 240" className="cv">
      {[0, 1, 2, 3].map((i) => (
        <cm.polygon key={i}
          points="0,-100 86,-50 86,50 0,100 -86,50 -86,-50"
          fill="none" stroke="var(--accent)" strokeWidth={1.2 - i * 0.2} strokeOpacity={0.6 - i * 0.12}
          animate={{ scale: [1 - i * 0.05, 1.08 - i * 0.05, 1 - i * 0.05], rotate: i % 2 ? 0 : [0, 60, 0] }}
          transition={{ duration: 5, delay: i * 0.3, repeat: Infinity, ease: "easeInOut" }}
          style={{ transformOrigin: "center" }}/>
      ))}
      <cm.circle r="10" fill="var(--accent)"
        animate={{ opacity: [0.6, 1, 0.6], r: [8, 12, 8] }}
        transition={{ duration: 2, repeat: Infinity }}/>
    </svg>
  );
  return null;
}

/* ═══════════════════════════════════════════════════════════════════
   02 · EXPERTISE — Kinetic category showcase + orbital constellation
   ───────────────────────────────────────────────────────────────── */

const EXPERTISE = [
  { id: "infra",     label: "Infrastructure", kicker: "The foundation",
    blurb: "Reproducible environments, zero-touch deploys, and observability that answers questions before they're asked.",
    techs: [
      { name: "AWS",             note: "Workhorse cloud" },
      { name: "Google Cloud",    short: "GCP",       note: "Data · ML" },
      { name: "Kubernetes",      short: "K8s",       note: "Container orchestration" },
      { name: "Docker",          note: "Immutable images" },
      { name: "Terraform",       note: "Infra as code" },
      { name: "GitHub Actions",  short: "Actions",   note: "CI/CD pipelines" },
      { name: "Cloudflare",      note: "Edge · workers" },
      { name: "OpenTelemetry",   short: "OTel",      note: "Distributed tracing" },
    ]},
  { id: "backend",   label: "Backend",        kicker: "The engine",
    blurb: "Durable services with sensible defaults. Tracing, types, and migration discipline — not prayer-driven deploys.",
    techs: [
      { name: "Node.js",     note: "Event-driven" },
      { name: "Python",      note: "FastAPI · ML" },
      { name: "Go",          note: "High-throughput" },
      { name: "Rust",        note: "Zero-cost safety" },
      { name: "PostgreSQL",  short: "Postgres",   note: "Source of truth" },
      { name: "Redis",       note: "Queues · cache" },
      { name: "GraphQL",     note: "Schema-first APIs" },
      { name: "Prisma",      note: "Typed ORM" },
    ]},
  { id: "blockchain", label: "Blockchain",    kicker: "The ledger",
    blurb: "Protocols and primitives on-chain — with gas discipline, audit-ready code, and adversarial thinking baked in.",
    techs: [
      { name: "Solidity",      note: "EVM smart contracts" },
      { name: "Solana",        note: "High-TPS chain" },
      { name: "Foundry",       note: "Fuzz-first testing" },
      { name: "Hardhat",       note: "Dev environment" },
      { name: "ethers.js",     note: "Client-side web3" },
      { name: "The Graph",     note: "On-chain indexing" },
      { name: "IPFS",          note: "Content addressing" },
      { name: "WalletConnect", short: "WC",       note: "Wallet bridges" },
    ]},
  { id: "frontend",  label: "Frontend",       kicker: "The surface",
    blurb: "Interfaces that feel immediate and earn daily use. Typography, motion, and pixel-level craft.",
    techs: [
      { name: "React",         note: "Composable UI" },
      { name: "TypeScript",    note: "Typed end-to-end" },
      { name: "Next.js",       note: "App Router · RSC" },
      { name: "Astro",         note: "Content-first" },
      { name: "Tailwind CSS",  short: "Tailwind",  note: "Design system" },
      { name: "Framer Motion", short: "Framer", note: "Choreography" },
      { name: "Three.js",      note: "WebGL scenes" },
      { name: "GSAP",          note: "Scroll timelines" },
    ]},
  { id: "mobile",    label: "Mobile",         kicker: "The pocket",
    blurb: "Apps that feel native on both platforms, survive bad networks, and get better every release.",
    techs: [
      { name: "React Native", short: "RN",     note: "Cross-platform core" },
      { name: "Expo",         note: "Tooling · OTA updates" },
      { name: "Swift",        note: "Native iOS polish" },
      { name: "Kotlin",       note: "Modern Android" },
      { name: "Flutter",      note: "Widget-driven UI" },
      { name: "SwiftUI",      note: "Declarative iOS" },
      { name: "Jetpack",      note: "Android libraries" },
      { name: "MapKit",       note: "Location · maps" },
    ]},
];

function ExpertiseWall() {
  const [active, setActive] = React.useState(0);
  const [hover, setHover] = React.useState(null); // hovered tech index
  const intervalRef = React.useRef(null);

  // Auto-advance, pause on interaction
  const [paused, setPaused] = React.useState(false);
  React.useEffect(() => {
    if (paused) return;
    intervalRef.current = setInterval(() => {
      setActive((i) => (i + 1) % EXPERTISE.length);
    }, 2000);
    return () => clearInterval(intervalRef.current);
  }, [paused]);

  const chapter = EXPERTISE[active];

  return (
    <section id="expertise" className="ex">
      {/* backdrop */}
      <div className="ex-bg">
        <div className="ex-bg-grid"/>
        <cm.div className="ex-bg-glow"
          animate={{ opacity: [0.35, 0.55, 0.35] }}
          transition={{ duration: 6, repeat: Infinity, ease: "easeInOut" }}/>
      </div>

      <div className="ex-head">
        <CReveal>
          <div className="cs-eyebrow">
            <span className="cs-eyebrow-dot"/>
            02 · Expertise
          </div>
        </CReveal>
        <CReveal delay={0.08}>
          <h2 className="ex-title">
            <span>A toolkit,</span>
            <span className="ex-title--serif">refined by practice.</span>
          </h2>
        </CReveal>
        <CReveal delay={0.16}>
          <p className="ex-lede">
            Five disciplines. Forty tools in daily rotation. Every one picked because
            it survives real production, not because it trends on the timeline.
          </p>
        </CReveal>
      </div>

      <div className="ex-stage">
        {/* LEFT: kinetic type */}
        <div className="ex-left">
          <div className="ex-kicker" aria-hidden="true">
            <CAP mode="popLayout">
              <cm.span key={chapter.id + "-k"}
                initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -20 }}
                transition={{ duration: 0.5 }}>
                {String(active + 1).padStart(2, "0")} — {chapter.kicker}
              </cm.span>
            </CAP>
          </div>

          <h3 className="ex-category">
            <CAP mode="popLayout">
              <cm.span key={chapter.id}
                className="ex-category-inner"
                initial={{ opacity: 0, y: 80, filter: "blur(16px)" }}
                animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
                exit={{ opacity: 0, y: -60, filter: "blur(14px)" }}
                transition={{ duration: 0.85, ease: [0.2, 0.8, 0.2, 1] }}>
                {chapter.label}
              </cm.span>
            </CAP>
          </h3>

          <div className="ex-blurb">
            <CAP mode="popLayout">
              <cm.p key={chapter.id + "-b"}
                initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0 }}
                transition={{ duration: 0.5, delay: 0.1 }}>
                {chapter.blurb}
              </cm.p>
            </CAP>
          </div>

          <div className="ex-tabs" role="tablist">
            {EXPERTISE.map((c, i) => (
              <button key={c.id} type="button"
                className={`ex-tab ${i === active ? "on" : ""}`}
                onClick={() => setActive(i)}>
                <span className="ex-tab-n">{String(i + 1).padStart(2, "0")}</span>
                <span className="ex-tab-l">{c.label}</span>
                <span className="ex-tab-b"/>
              </button>
            ))}
          </div>

          <div className="ex-auto">
            <cm.span className="ex-auto-bar"
              key={chapter.id + "-bar-" + paused}
              initial={{ scaleX: 0 }}
              animate={{ scaleX: paused ? 0 : 1 }}
              transition={{ duration: paused ? 0 : 2, ease: "linear" }}/>
            <span className="ex-auto-t">{paused ? "Paused" : "Auto-advancing"}</span>
          </div>
        </div>

        {/* RIGHT: constellation */}
        <div className="ex-right" onMouseEnter={() => setPaused(true)} onMouseLeave={() => setPaused(false)}>
          <ExpertiseConstellation chapter={chapter} hover={hover} setHover={setHover}/>
          <div className="ex-list">
            <CAP mode="popLayout">
              <cm.ul key={chapter.id + "-l"}
                initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
                transition={{ duration: 0.3 }}>
                {chapter.techs.map((t, i) => (
                  <cm.li key={t.name}
                    className={`ex-item ${hover === i ? "hot" : ""}`}
                    onMouseEnter={() => setHover(i)}
                    onMouseLeave={() => setHover(null)}
                    initial={{ opacity: 0, x: -10 }}
                    animate={{ opacity: 1, x: 0 }}
                    transition={{ delay: i * 0.04, duration: 0.4 }}>
                    <span className="ex-item-n">{String(i + 1).padStart(2, "0")}</span>
                    <span className="ex-item-nm">{t.name}</span>
                    <span className="ex-item-nt">{t.note}</span>
                  </cm.li>
                ))}
              </cm.ul>
            </CAP>
          </div>
        </div>
      </div>
    </section>
  );
}

function ExpertiseConstellation({ chapter, hover, setHover }) {
  const N = chapter.techs.length;
  // Distribute nodes on two rings for depth
  const points = React.useMemo(() => {
    return chapter.techs.map((t, i) => {
      const ring = i % 2;                 // 0 inner, 1 outer
      const r = ring === 0 ? 26 : 42;
      const angleOff = ring === 0 ? 0 : Math.PI / N;
      const a = (i / N) * Math.PI * 2 + angleOff;
      const x = 50 + Math.cos(a) * r;
      const y = 50 + Math.sin(a) * r;
      return { x, y, a, r };
    });
  }, [chapter.id, N]);

  return (
    <div className="ex-consl">
      <svg viewBox="0 0 100 100" className="ex-consl-svg" preserveAspectRatio="xMidYMid meet">
        <defs>
          <radialGradient id="ex-core" cx="50%" cy="50%" r="50%">
            <stop offset="0%" stopColor="var(--accent)" stopOpacity="0.9"/>
            <stop offset="70%" stopColor="var(--accent)" stopOpacity="0.15"/>
            <stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/>
          </radialGradient>
        </defs>

        {/* Orbit rings */}
        <cm.circle cx="50" cy="50" r="26" fill="none" stroke="var(--accent)" strokeOpacity="0.18" strokeWidth="0.25" strokeDasharray="0.6 0.6"
          animate={{ rotate: 360 }} transition={{ duration: 120, repeat: Infinity, ease: "linear" }}
          style={{ transformOrigin: "50% 50%" }}/>
        <cm.circle cx="50" cy="50" r="42" fill="none" stroke="var(--accent)" strokeOpacity="0.12" strokeWidth="0.25" strokeDasharray="1 1"
          animate={{ rotate: -360 }} transition={{ duration: 160, repeat: Infinity, ease: "linear" }}
          style={{ transformOrigin: "50% 50%" }}/>

        {/* Core */}
        <circle cx="50" cy="50" r="15" fill="url(#ex-core)"/>
        <circle cx="50" cy="50" r="1.8" fill="var(--accent)"/>
        <cm.circle cx="50" cy="50" r="3" fill="none" stroke="var(--accent)" strokeWidth="0.3"
          animate={{ r: [2.5, 6, 2.5], opacity: [0.7, 0, 0.7] }}
          transition={{ duration: 3, repeat: Infinity }}/>

        {/* Connections when hovered */}
        <CAP>
          {hover !== null && points[hover] && points.map((p, j) => {
            if (j === hover) return null;
            // Only connect nearby nodes on same/adjacent ring, or sparse others
            const close = (Math.abs(j - hover) % N <= 2) || (Math.abs(j - hover) % N >= N - 2);
            if (!close) return null;
            const a = points[hover];
            return (
              <cm.line key={`c-${hover}-${j}`}
                x1={a.x} y1={a.y} x2={p.x} y2={p.y}
                stroke="var(--accent)" strokeWidth="0.25" strokeOpacity="0.65"
                initial={{ pathLength: 0, opacity: 0 }}
                animate={{ pathLength: 1, opacity: 0.65 }}
                exit={{ opacity: 0 }}
                transition={{ duration: 0.4 }}/>
            );
          })}
        </CAP>

        {/* Nodes */}
        <CAP mode="sync">
          {points.map((p, i) => (
            <cm.g
              key={`${chapter.id}-${i}`}
              initial={{ opacity: 0, scale: 0 }}
              animate={{ opacity: 1, scale: 1 }}
              exit={{ opacity: 0, scale: 0 }}
              transition={{ duration: 0.5, delay: i * 0.04, ease: [0.2, 0.8, 0.2, 1] }}
              style={{ cursor: "pointer" }}
              onMouseEnter={() => setHover(i)}
              onMouseLeave={() => setHover(null)}
            >
              <cm.circle cx={p.x} cy={p.y} r={hover === i ? 2.4 : 1.6}
                fill="var(--accent)"
                animate={{ opacity: hover === null || hover === i ? 1 : 0.35 }}
                transition={{ duration: 0.3 }}/>
              <cm.circle cx={p.x} cy={p.y} r="5" fill="var(--accent)" opacity="0"
                animate={{ opacity: hover === i ? 0.2 : 0 }}/>
              <text x={p.x} y={p.y - 3}
                    textAnchor="middle"
                    fontSize="2.3"
                    fontFamily="var(--font-mono)"
                    fill={hover === i ? "var(--accent)" : "var(--text-dim)"}
                    opacity={hover === null || hover === i ? 1 : 0.4}
                    style={{ transition: "opacity 0.3s, fill 0.3s" }}>
                {chapter.techs[i].short || chapter.techs[i].name}
              </text>
            </cm.g>
          ))}
        </CAP>
      </svg>
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════════════
   03 · SPECIALIZATIONS — Sticky editorial spreads
   ───────────────────────────────────────────────────────────────── */

const CHAPTERS = [
  { n: "01", title: "Infrastructure",
    kicker: "Zero-touch",
    body: "Cloud-native architectures with GitOps deployment, full observability, and fully-reproducible environments — dev, staging, prod.",
    stats: [["IaC", "100% declared"], ["Multi-region", "by default"], ["Observability", "first-class"]],
    art: "infra" },
  { n: "02", title: "Smart Contract Development",
    kicker: "Audited",
    body: "Gas-optimized, formally-reviewed contracts on Ethereum, Solana, and beyond. Every line is a liability until it's proven.",
    stats: [["Audit-first", "delivery"], ["Fuzz-tested", "by default"], ["Gas-aware", "from day one"]],
    art: "contract" },
  { n: "03", title: "Blockchain Applications",
    kicker: "Decentralized",
    body: "DeFi protocols, NFT marketplaces, DAOs, and custom chain deployments — engineered with the assumption that adversaries are already inside.",
    stats: [["Multi-chain", "EVM · Solana"], ["Adversarial", "threat modeling"], ["End-to-end", "wallet to ledger"]],
    art: "chain" },
  { n: "04", title: "Web Platforms",
    kicker: "Scale-ready",
    body: "SaaS platforms, e-commerce systems, and enterprise applications architected for ten times the load you have today.",
    stats: [["Production", "SLOs"], ["Edge-rendered", "where it counts"], ["Horizontal", "scale-out"]],
    art: "web" },
  { n: "05", title: "Mobile Applications",
    kicker: "Native-feel",
    body: "High-performance cross-platform apps that disappear into the device. Users don't notice the framework — they notice the craft.",
    stats: [["iOS · Android", "one codebase"], ["Offline-first", "where it matters"], ["60fps", "the floor"]],
    art: "phone" },
  { n: "06", title: "Full-Stack Solutions",
    kicker: "End-to-end",
    body: "From database schema to shipped UI — one team, one design sensibility, one accountable voice. No handoffs to lose the thread.",
    stats: [["One team", "end-to-end"], ["Tight feedback", "loops"], ["Long-term", "ownership"]],
    art: "stack" },
];

function SpecializationsEditorial() {
  return (
    <section id="specializations" className="se">
      <div className="se-intro">
        <div className="container">
          <CReveal>
            <div className="cs-eyebrow">
              <span className="cs-eyebrow-dot"/>
              03 · Specializations
            </div>
          </CReveal>
          <CReveal delay={0.08}>
            <h2 className="se-title">
              Six disciplines,<br/>
              <span className="se-title--serif">proven in production.</span>
            </h2>
          </CReveal>
        </div>
      </div>

      {CHAPTERS.map((c, i) => (
        <SpecChapter key={c.n} chapter={c} index={i}/>
      ))}
    </section>
  );
}

function SpecChapter({ chapter, index }) {
  const ref = React.useRef(null);
  const { scrollYProgress } = cuScroll({ target: ref, offset: ["start end", "end start"] });
  const numY = cuTransform(scrollYProgress, [0, 1], [60, -60]);
  const numO = cuTransform(scrollYProgress, [0, 0.15, 0.85, 1], [0, 1, 1, 0]);
  const artO = cuTransform(scrollYProgress, [0, 0.3, 0.7, 1], [0, 1, 1, 0]);
  const artY = cuTransform(scrollYProgress, [0, 1], [100, -100]);

  return (
    <div ref={ref} className={`se-ch se-ch--${index % 2 ? "r" : "l"}`}>
      <div className="se-ch-inner container">
        <div className="se-ch-left">
          <cm.div className="se-ch-sticky" style={{ y: numY, opacity: numO }}>
            <div className="se-ch-n">{chapter.n}</div>
            <div className="se-ch-kicker">{chapter.kicker}</div>
            <h3 className="se-ch-title">{chapter.title}</h3>
            <p className="se-ch-body">{chapter.body}</p>
            <dl className="se-ch-stats">
              {chapter.stats.map(([n, l]) => (
                <div key={n} className="se-ch-stat">
                  <dt>{n}</dt><dd>{l}</dd>
                </div>
              ))}
            </dl>
          </cm.div>
        </div>
        <div className="se-ch-right">
          <cm.div className="se-ch-art" style={{ y: artY, opacity: artO }}>
            <SpecArt kind={chapter.art}/>
          </cm.div>
        </div>
      </div>
    </div>
  );
}

/* Validator network — live gossip + block production visualization */
function ValidatorNetworkArt() {
  const W = 400, H = 500, CX = W / 2, CY = H / 2;
  // 14 validator nodes scattered in loose clusters
  const nodes = React.useMemo(() => {
    const seed = [
      [0.22, 0.30], [0.38, 0.18], [0.55, 0.26], [0.72, 0.19],
      [0.85, 0.38], [0.78, 0.58], [0.88, 0.76], [0.66, 0.82],
      [0.48, 0.88], [0.28, 0.80], [0.14, 0.68], [0.18, 0.48],
      [0.42, 0.48], [0.60, 0.58],
    ];
    return seed.map(([u, v], i) => ({
      id: i,
      x: u * W,
      y: v * H,
      size: 1.6 + (i % 3) * 0.4,
      delay: (i * 0.23) % 1.7,
    }));
  }, []);

  // Pairs that exchange packets — curated for visual rhythm
  const edges = React.useMemo(() => {
    const pairs = [
      [12, 0], [12, 2], [12, 4], [12, 10], [12, 8],
      [13, 5], [13, 7], [13, 9], [13, 3],
      [0, 1], [1, 2], [2, 3], [3, 4], [4, 5],
      [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 0],
      [12, 13], [2, 13], [10, 12],
    ];
    return pairs.map(([a, b], i) => ({ a, b, delay: (i * 0.31) % 3.2 }));
  }, []);

  // Rotating block height counter
  const [height, setHeight] = React.useState(23847291);
  React.useEffect(() => {
    const t = setInterval(() => setHeight((h) => h + 1), 1800);
    return () => clearInterval(t);
  }, []);

  // Hash fragments that blink in/out
  const [hashes, setHashes] = React.useState(() => makeHashes());
  React.useEffect(() => {
    const t = setInterval(() => setHashes(makeHashes()), 2600);
    return () => clearInterval(t);
  }, []);

  return (
    <div className="vn">
      <svg viewBox={`0 0 ${W} ${H}`} className="se-art-svg vn-svg">
        <defs>
          <radialGradient id="vn-node-g" cx="50%" cy="50%" r="50%">
            <stop offset="0%" stopColor="var(--accent)" stopOpacity="1"/>
            <stop offset="60%" stopColor="var(--accent)" stopOpacity="0.4"/>
            <stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/>
          </radialGradient>
          <linearGradient id="vn-edge-g" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0%" stopColor="var(--accent)" stopOpacity="0"/>
            <stop offset="50%" stopColor="var(--accent)" stopOpacity="0.7"/>
            <stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/>
          </linearGradient>
          <filter id="vn-glow" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="2"/>
            <feComposite in2="SourceGraphic" operator="over"/>
          </filter>
        </defs>

        {/* Background field of faint points */}
        {Array.from({ length: 36 }).map((_, i) => {
          const x = ((i * 83) % 395) + 2;
          const y = ((i * 151) % 495) + 2;
          return (
            <cm.circle key={`bg-${i}`} cx={x} cy={y} r="0.6" fill="var(--accent)"
              animate={{ opacity: [0.1, 0.35, 0.1] }}
              transition={{ duration: 4 + (i % 3), delay: i * 0.1, repeat: Infinity }}/>
          );
        })}

        {/* Static edge lines (faint) */}
        {edges.map((e, i) => (
          <line key={`el-${i}`}
                x1={nodes[e.a].x} y1={nodes[e.a].y}
                x2={nodes[e.b].x} y2={nodes[e.b].y}
                stroke="var(--accent)" strokeOpacity="0.08" strokeWidth="0.5"/>
        ))}

        {/* Packets traveling along edges */}
        {edges.map((e, i) => {
          const na = nodes[e.a], nb = nodes[e.b];
          return (
            <cm.circle key={`pk-${i}`} r="2" fill="var(--accent)"
              style={{ filter: "drop-shadow(0 0 4px var(--accent))" }}
              initial={{ cx: na.x, cy: na.y, opacity: 0 }}
              animate={{
                cx: [na.x, nb.x, nb.x],
                cy: [na.y, nb.y, nb.y],
                opacity: [0, 1, 0]
              }}
              transition={{
                duration: 1.6,
                delay: e.delay,
                repeat: Infinity,
                repeatDelay: 2.4,
                ease: "easeInOut"
              }}/>
          );
        })}

        {/* Validator nodes */}
        {nodes.map((n, i) => (
          <g key={`n-${i}`}>
            {/* outer glow halo */}
            <cm.circle cx={n.x} cy={n.y} r={n.size * 4}
              fill="url(#vn-node-g)"
              animate={{ opacity: [0.4, 0.9, 0.4], scale: [1, 1.15, 1] }}
              transition={{ duration: 2.4, delay: n.delay, repeat: Infinity, ease: "easeInOut" }}
              style={{ transformOrigin: `${n.x}px ${n.y}px` }}/>
            {/* core dot */}
            <circle cx={n.x} cy={n.y} r={n.size} fill="var(--accent)"/>
            {/* outer ring for a couple key nodes */}
            {(i === 12 || i === 13) && (
              <cm.circle cx={n.x} cy={n.y} r={n.size + 2}
                fill="none" stroke="var(--accent)" strokeWidth="0.4"
                animate={{ r: [n.size + 2, n.size + 10, n.size + 2], opacity: [0.9, 0, 0.9] }}
                transition={{ duration: 2.6, delay: n.delay, repeat: Infinity, ease: "easeOut" }}/>
            )}
          </g>
        ))}

        {/* Block production pulse — sweeping ring from node 12 */}
        <cm.circle cx={nodes[12].x} cy={nodes[12].y} r="6"
          fill="none" stroke="var(--accent)" strokeWidth="0.5" strokeOpacity="0.9"
          animate={{ r: [6, 180], opacity: [0.8, 0] }}
          transition={{ duration: 3, repeat: Infinity, ease: "easeOut" }}/>
      </svg>

      {/* HUD overlay */}
      <div className="vn-hud">
        <div className="vn-hud-row">
          <span className="vn-hud-k">Height</span>
          <span className="vn-hud-v">#{height.toLocaleString()}</span>
        </div>
        <div className="vn-hud-row">
          <span className="vn-hud-k">Leader</span>
          <cm.span className="vn-hud-dot"
            animate={{ opacity: [1, 0.3, 1] }}
            transition={{ duration: 1.2, repeat: Infinity }}/>
          <span className="vn-hud-v">vldr·{hashes[0]?.slice(0, 6)}</span>
        </div>
        <div className="vn-hud-row">
          <span className="vn-hud-k">TPS</span>
          <span className="vn-hud-v vn-hud-v--big">
            <TickingNumber base={2847} variance={180}/>
          </span>
        </div>
      </div>

      {/* Floating hash fragments */}
      <div className="vn-hashes">
        <CAP mode="popLayout">
          {hashes.slice(0, 4).map((h, i) => (
            <cm.span key={`${h}-${i}`}
              className="vn-hash"
              style={{
                left: `${12 + (i * 23) % 74}%`,
                top: `${18 + (i * 31) % 66}%`,
              }}
              initial={{ opacity: 0, y: 6 }}
              animate={{ opacity: [0, 0.7, 0] }}
              exit={{ opacity: 0 }}
              transition={{ duration: 2.4, delay: i * 0.3 }}>
              0x{h}
            </cm.span>
          ))}
        </CAP>
      </div>
    </div>
  );
}

function TickingNumber({ base, variance }) {
  const [n, setN] = React.useState(base);
  React.useEffect(() => {
    const t = setInterval(() => {
      setN(base + Math.floor(Math.random() * variance * 2) - variance);
    }, 900);
    return () => clearInterval(t);
  }, [base, variance]);
  return <span>{n.toLocaleString()}</span>;
}

function makeHashes() {
  const chars = "0123456789abcdef";
  const make = (len) => Array.from({ length: len }, () => chars[Math.floor(Math.random() * 16)]).join("");
  return [make(12), make(10), make(14), make(10), make(12), make(11)];
}

/* ─── Infrastructure: living mesh with traveling packets ─── */
function InfraArt() {
  // Grid geometry — centered inside 400×500 viewBox
  const COLS = 5, ROWS = 4;
  const NODE = 44;
  const STEP_X = 70, STEP_Y = 90;
  const GRID_W = (COLS - 1) * STEP_X + NODE; // 324
  const GRID_H = (ROWS - 1) * STEP_Y + NODE; // 314
  const X0 = (400 - GRID_W) / 2; // 38
  const Y0 = (500 - GRID_H) / 2; // 93

  const nodeX = (c) => X0 + c * STEP_X;
  const nodeY = (r) => Y0 + r * STEP_Y;
  const cx = (c) => nodeX(c) + NODE / 2;
  const cy = (r) => nodeY(r) + NODE / 2;

  // Build edges: each adjacent horizontal and vertical pair
  const edges = React.useMemo(() => {
    const list = [];
    for (let r = 0; r < ROWS; r++) {
      for (let c = 0; c < COLS; c++) {
        if (c < COLS - 1) list.push({ id: `h-${r}-${c}`, dir: "h", x1: nodeX(c) + NODE, y1: cy(r), x2: nodeX(c + 1), y2: cy(r) });
        if (r < ROWS - 1) list.push({ id: `v-${r}-${c}`, dir: "v", x1: cx(c), y1: nodeY(r) + NODE, x2: cx(c), y2: nodeY(r + 1) });
      }
    }
    return list;
    // eslint-disable-next-line
  }, []);

  // A handful of "packets" that hop edges
  const packets = React.useMemo(() => Array.from({ length: 6 }, (_, i) => ({
    id: i,
    delay: i * 0.7,
    duration: 1.6 + (i % 3) * 0.3,
    edgeIdx: (i * 7) % edges.length,
  })), [edges.length]);

  // Pulse wave: nodes light up by diagonal index for a flowing wave
  return (
    <svg viewBox="0 0 400 500" className="se-art-svg" preserveAspectRatio="xMidYMid meet">
      <defs>
        <radialGradient id="infra-node-glow" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="var(--accent)" stopOpacity="0.9"/>
          <stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/>
        </radialGradient>
        <linearGradient id="infra-packet-h" x1="0" x2="1" y1="0" y2="0">
          <stop offset="0%"  stopColor="var(--accent)" stopOpacity="0"/>
          <stop offset="60%" stopColor="var(--accent)" stopOpacity="0.9"/>
          <stop offset="100%" stopColor="#fff" stopOpacity="1"/>
        </linearGradient>
      </defs>

      {/* Static edges (subtle) */}
      <g>
        {edges.map(e => (
          <line key={e.id} x1={e.x1} y1={e.y1} x2={e.x2} y2={e.y2}
            stroke="var(--accent)" strokeOpacity="0.12" strokeWidth="1"/>
        ))}
      </g>

      {/* Nodes */}
      {Array.from({ length: ROWS * COLS }).map((_, i) => {
        const c = i % COLS, r = Math.floor(i / COLS);
        const x = nodeX(c), y = nodeY(r);
        const diag = c + r; // 0..7 — wave index
        const waveDelay = (diag * 0.18) % 2.4;
        return (
          <g key={i}>
            {/* container square */}
            <cm.rect x={x} y={y} width={NODE} height={NODE} rx="7"
              fill="none" stroke="var(--accent)"
              strokeWidth="1.2"
              animate={{ strokeOpacity: [0.25, 0.65, 0.25] }}
              transition={{ duration: 2.4, delay: waveDelay, repeat: Infinity, ease: "easeInOut" }}/>
            {/* faint inner fill on the wave */}
            <cm.rect x={x + 3} y={y + 3} width={NODE - 6} height={NODE - 6} rx="5"
              fill="var(--accent)"
              animate={{ opacity: [0, 0.08, 0] }}
              transition={{ duration: 2.4, delay: waveDelay, repeat: Infinity, ease: "easeInOut" }}/>
            {/* core dot */}
            <cm.circle cx={x + NODE / 2} cy={y + NODE / 2} r="3.5"
              fill="var(--accent)"
              animate={{ opacity: [0.45, 1, 0.45], r: [3, 4.2, 3] }}
              transition={{ duration: 2.4, delay: waveDelay, repeat: Infinity, ease: "easeInOut" }}/>
          </g>
        );
      })}

      {/* Traveling packets along edges */}
      {packets.map(p => {
        const e = edges[p.edgeIdx];
        return (
          <cm.circle key={`p-${p.id}`} r="2.6" fill="#fff"
            initial={{ cx: e.x1, cy: e.y1, opacity: 0 }}
            animate={{
              cx: [e.x1, e.x2],
              cy: [e.y1, e.y2],
              opacity: [0, 1, 1, 0],
            }}
            transition={{
              duration: p.duration,
              delay: p.delay,
              repeat: Infinity,
              repeatDelay: 1.8,
              ease: "linear",
              times: [0, 0.1, 0.9, 1],
            }}
            style={{ filter: "drop-shadow(0 0 4px var(--accent))" }}/>
        );
      })}

      {/* Periodic "deploy" — expanding ring on a random node */}
      {[0, 7, 13, 18].map((idx, k) => {
        const c = idx % COLS, r = Math.floor(idx / COLS);
        return (
          <cm.circle key={`d-${k}`} cx={cx(c)} cy={cy(r)} r="6"
            fill="none" stroke="var(--accent)" strokeWidth="1.5"
            animate={{ r: [6, 34], opacity: [0.9, 0] }}
            transition={{
              duration: 1.8,
              delay: k * 1.6,
              repeat: Infinity,
              repeatDelay: 4.8,
              ease: "easeOut",
            }}/>
        );
      })}
    </svg>
  );
}

function SpecArt({ kind }) {
  if (kind === "chain") return <ValidatorNetworkArt/>;
  if (kind === "contract") return (
    <svg viewBox="0 0 400 500" className="se-art-svg">
      <rect x="60" y="40" width="280" height="420" rx="8" fill="none" stroke="var(--accent)" strokeOpacity="0.3"/>
      {Array.from({ length: 18 }).map((_, i) => (
        <cm.rect key={i} x="80" y={70 + i * 20}
          width={100 + (i * 37) % 180} height="3" rx="1.5" fill="var(--accent)"
          initial={{ opacity: 0, scaleX: 0 }}
          animate={{ opacity: [0, 0.8, 0.4], scaleX: [0, 1, 1] }}
          transition={{ duration: 2, delay: i * 0.08, repeat: Infinity, repeatDelay: 4 }}
          style={{ transformOrigin: "left" }}/>
      ))}
      <cm.circle cx="340" cy="60" r="6" fill="var(--accent)"
        animate={{ opacity: [0.4, 1, 0.4] }} transition={{ duration: 1.5, repeat: Infinity }}/>
    </svg>
  );
  if (kind === "phone") return (
    <svg viewBox="0 0 400 500" className="se-art-svg">
      {/* Phone body: ~9:19.5 aspect, centered. width 220, height 460 */}
      <rect x="90" y="20" width="220" height="460" rx="32" fill="none" stroke="var(--accent)" strokeOpacity="0.7" strokeWidth="2.5"/>
      <rect x="102" y="32" width="196" height="436" rx="22" fill="none" stroke="var(--accent)" strokeOpacity="0.35" strokeWidth="1.5"/>
      {/* Dynamic island / notch */}
      <rect x="175" y="42" width="50" height="10" rx="5" fill="var(--accent)" opacity="0.55"/>
      {/* App grid: 3 cols x 2 rows, icons 44px, gap 16 — fits 196px screen */}
      {Array.from({ length: 6 }).map((_, i) => {
        const col = i % 3;
        const row = Math.floor(i / 3);
        const x = 122 + col * 52;
        const y = 80 + row * 60;
        return (
          <cm.rect key={i} x={x} y={y}
            width="44" height="44" rx="11" fill="var(--accent)"
            animate={{ opacity: [0.45, 0.85, 0.45], scale: [1, 1.06, 1] }}
            transition={{ duration: 2.5, delay: i * 0.2, repeat: Infinity }}
            style={{ transformOrigin: `${x + 22}px ${y + 22}px` }}/>
        );
      })}
      {/* Content lines below the grid */}
      {Array.from({ length: 5 }).map((_, i) => (
        <rect key={`l${i}`} x="122" y={224 + i * 28} width={156 - i * 14} height="7" rx="3.5"
          fill="var(--accent)" opacity={0.55 - i * 0.07}/>
      ))}
      {/* Home indicator */}
      <rect x="160" y="450" width="80" height="4" rx="2" fill="var(--accent)" opacity="0.45"/>
    </svg>
  );
  if (kind === "web") return (
    <svg viewBox="0 0 400 500" className="se-art-svg">
      <rect x="40" y="60" width="320" height="380" rx="10" fill="none" stroke="var(--accent)" strokeOpacity="0.4"/>
      <rect x="40" y="60" width="320" height="34" fill="var(--accent)" opacity="0.08"/>
      <circle cx="58" cy="77" r="4" fill="var(--accent)" opacity="0.5"/>
      <circle cx="72" cy="77" r="4" fill="var(--accent)" opacity="0.35"/>
      <circle cx="86" cy="77" r="4" fill="var(--accent)" opacity="0.25"/>
      <cm.g animate={{ opacity: [0.3, 1, 0.3] }} transition={{ duration: 4, repeat: Infinity }}>
        <rect x="70" y="120" width="260" height="6" rx="3" fill="var(--accent)" opacity="0.7"/>
        <rect x="70" y="140" width="200" height="4" rx="2" fill="var(--accent)" opacity="0.4"/>
      </cm.g>
      {Array.from({ length: 6 }).map((_, i) => (
        <cm.rect key={i} x={70 + (i % 3) * 90} y={180 + Math.floor(i / 3) * 110}
          width="80" height="90" rx="6" fill="none" stroke="var(--accent)" strokeOpacity="0.5"
          initial={{ scaleY: 0 }}
          animate={{ scaleY: [0.8, 1, 0.8] }}
          transition={{ duration: 3, delay: i * 0.3, repeat: Infinity }}
          style={{ transformOrigin: `${70 + (i % 3) * 90 + 40}px ${180 + Math.floor(i / 3) * 110 + 45}px` }}/>
      ))}
    </svg>
  );
  if (kind === "infra") return <InfraArt/>;
  if (kind === "stack") return (
    <svg viewBox="0 0 400 500" className="se-art-svg">
      {Array.from({ length: 6 }).map((_, i) => (
        <cm.g key={i}
          animate={{ x: [0, 4, 0] }}
          transition={{ duration: 3, delay: i * 0.18, repeat: Infinity, ease: "easeInOut" }}>
          <polygon points={`200,${60 + i * 55} 320,${100 + i * 55} 200,${140 + i * 55} 80,${100 + i * 55}`}
            fill="none" stroke="var(--accent)" strokeWidth="1" strokeOpacity={0.7 - i * 0.08}/>
          <polygon points={`200,${60 + i * 55} 320,${100 + i * 55} 200,${140 + i * 55} 80,${100 + i * 55}`}
            fill="var(--accent)" opacity={0.05 + i * 0.01}/>
        </cm.g>
      ))}
    </svg>
  );
  return null;
}

/* ═══════════════════════════════════════════════════════════════════
   04 · CONTACT — Cinematic close with glass form
   ───────────────────────────────────────────────────────────────── */

function ContactCinema() {
  const ref = React.useRef(null);
  const [form, setForm] = React.useState({ name: "", email: "", project: "", message: "" });
  const [sent, setSent] = React.useState(false);
  const mouseX = cuMV(0.5), mouseY = cuMV(0.5);
  const onMouse = (e) => {
    const r = ref.current.getBoundingClientRect();
    mouseX.set((e.clientX - r.left) / r.width);
    mouseY.set((e.clientY - r.top) / r.height);
  };
  const bgX = cuTransform(mouseX, [0, 1], ["30%", "70%"]);
  const bgY = cuTransform(mouseY, [0, 1], ["30%", "70%"]);
  const bg = cuTransform([bgX, bgY], ([x, y]) =>
    `radial-gradient(600px 600px at ${x} ${y}, color-mix(in oklab, var(--accent) 22%, transparent), transparent 60%)`);

  const submit = (e) => {
    e.preventDefault();
    if (!form.email) return;
    setSent(true);
    setTimeout(() => { window.location.href = `mailto:griffinmindlabs@protonmail.com?subject=Project inquiry — ${encodeURIComponent(form.name || "New")}&body=${encodeURIComponent(form.message + "\n\n— " + form.name + " (" + form.email + ")" + (form.project ? " · " + form.project : ""))}`; }, 400);
  };

  return (
    <section id="contact" ref={ref} className="cc" onMouseMove={onMouse}>
      <ContactMesh/>
      <cm.div className="cc-spot" style={{ background: bg }}/>

      <div className="cc-inner container">
        <div className="cc-copy">
          <CReveal>
            <div className="cs-eyebrow">
              <span className="cs-eyebrow-dot"/>
              04 · Contact
            </div>
          </CReveal>
          <CReveal delay={0.08}>
            <h2 className="cc-title">
              <span>Let's build</span>
              <span className="cc-title--serif">something</span>
              <span>extraordinary.</span>
            </h2>
          </CReveal>
          <CReveal delay={0.16}>
            <p className="cc-lede">
              A few sentences about what you're building, who it's for, and what's next is
              usually enough. We'll write back within two business days.
            </p>
          </CReveal>

          <CReveal delay={0.22}>
            <div className="cc-meta">
              <a href="mailto:griffinmindlabs@protonmail.com" className="cc-meta-row">
                <CIconMail/>
                <span>griffinmindlabs@protonmail.com</span>
                <CIconArrow/>
              </a>
              <div className="cc-meta-row cc-meta-row--static">
                <CIconPin/>
                <span>Victoria, BC — remote worldwide</span>
              </div>
            </div>
          </CReveal>
        </div>

        <CReveal delay={0.14} className="cc-form-wrap">
          <form className="cc-form" onSubmit={submit}>
            <div className="cc-form-head">
              <span className="cc-dot"/>
              <span>New inquiry</span>
              <span className="cc-form-id">#{String(Math.floor(Math.random() * 9000) + 1000)}</span>
            </div>
            <Field label="Your name" value={form.name} onChange={(v) => setForm((f) => ({ ...f, name: v }))}/>
            <Field label="Email" type="email" value={form.email} onChange={(v) => setForm((f) => ({ ...f, email: v }))} required/>
            <Field label="Project type"
              value={form.project} onChange={(v) => setForm((f) => ({ ...f, project: v }))}
              placeholder="e.g. Smart contract audit, Native iOS app"/>
            <Field label="What are you building?" value={form.message}
              onChange={(v) => setForm((f) => ({ ...f, message: v }))}
              textarea/>
            <button type="submit" className={`cc-submit ${sent ? "sent" : ""}`}>
              <span className="cc-submit-t">
                <CAP mode="popLayout">
                  {sent ? (
                    <cm.span key="s" initial={{ y: 20, opacity: 0 }} animate={{ y: 0, opacity: 1 }} exit={{ y: -20, opacity: 0 }}>
                      Opening your email…
                    </cm.span>
                  ) : (
                    <cm.span key="d" initial={{ y: 20, opacity: 0 }} animate={{ y: 0, opacity: 1 }} exit={{ y: -20, opacity: 0 }}>
                      Send inquiry
                    </cm.span>
                  )}
                </CAP>
              </span>
              <span className="cc-submit-a"><CIconArrow/></span>
            </button>
          </form>
        </CReveal>
      </div>
    </section>
  );
}

function Field({ label, value, onChange, type = "text", textarea = false, required = false, placeholder = "" }) {
  const [focus, setFocus] = React.useState(false);
  const filled = value && value.length > 0;
  const Tag = textarea ? "textarea" : "input";
  return (
    <label className={`cc-field ${focus ? "on" : ""} ${filled ? "filled" : ""}`}>
      <span className="cc-field-label">{label}{required && <em>*</em>}</span>
      <Tag
        className="cc-field-input"
        type={type}
        value={value}
        placeholder={placeholder}
        required={required}
        rows={textarea ? 4 : undefined}
        onChange={(e) => onChange(e.target.value)}
        onFocus={() => setFocus(true)}
        onBlur={() => setFocus(false)}/>
      <span className="cc-field-underline"/>
    </label>
  );
}

function ContactMesh() {
  return (
    <svg className="cc-mesh" viewBox="0 0 1200 800" preserveAspectRatio="xMidYMid slice">
      <defs>
        <radialGradient id="cc-rg-1" cx="30%" cy="30%" r="50%">
          <stop offset="0%" stopColor="var(--accent)" stopOpacity="0.5"/>
          <stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/>
        </radialGradient>
        <radialGradient id="cc-rg-2" cx="70%" cy="70%" r="50%">
          <stop offset="0%" stopColor="var(--accent-2)" stopOpacity="0.4"/>
          <stop offset="100%" stopColor="var(--accent-2)" stopOpacity="0"/>
        </radialGradient>
      </defs>
      <cm.ellipse cx="360" cy="240" rx="280" ry="180" fill="url(#cc-rg-1)"
        animate={{ cx: [360, 420, 360], cy: [240, 200, 240] }}
        transition={{ duration: 12, repeat: Infinity, ease: "easeInOut" }}/>
      <cm.ellipse cx="840" cy="560" rx="320" ry="200" fill="url(#cc-rg-2)"
        animate={{ cx: [840, 780, 840], cy: [560, 600, 560] }}
        transition={{ duration: 14, repeat: Infinity, ease: "easeInOut" }}/>
      {Array.from({ length: 40 }).map((_, i) => {
        const x = (i * 137) % 1200;
        const y = (i * 211) % 800;
        return <cm.circle key={i} cx={x} cy={y} r="1.2" fill="var(--accent)"
          animate={{ opacity: [0.1, 0.7, 0.1] }}
          transition={{ duration: 4 + (i % 4), delay: (i * 0.1) % 4, repeat: Infinity }}/>;
      })}
    </svg>
  );
}

/* ═══════════════════════════════════════════════════════════════════
   CHROME — Scroll progress + chapter rail
   ───────────────────────────────────────────────────────────────── */

const CHAPTERS_NAV = [
  { id: "home", label: "Intro" },
  { id: "services", label: "Services" },
  { id: "expertise", label: "Expertise" },
  { id: "specializations", label: "Specializations" },
  { id: "contact", label: "Contact" },
];

function ScrollChrome() {
  const { scrollYProgress } = cuScroll();
  const scaleX = cuSpring(scrollYProgress, { stiffness: 120, damping: 28, mass: 0.3 });
  const [active, setActive] = React.useState("home");
  const [visible, setVisible] = React.useState(false);

  React.useEffect(() => {
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => { if (e.isIntersecting) setActive(e.target.id); });
      },
      { rootMargin: "-45% 0px -50% 0px", threshold: 0 }
    );
    CHAPTERS_NAV.forEach(({ id }) => {
      const el = document.getElementById(id);
      if (el) io.observe(el);
    });
    return () => io.disconnect();
  }, []);

  // Show chapter rail only past the hero
  React.useEffect(() => {
    const hero = document.getElementById("home");
    if (!hero) return;
    const io = new IntersectionObserver(
      ([e]) => setVisible(!e.isIntersecting),
      { threshold: 0.2 }
    );
    io.observe(hero);
    return () => io.disconnect();
  }, []);

  return (
    <>
      <cm.div className="chrome-bar" style={{ scaleX }}/>
      <cm.div
        className="chrome-pill"
        initial={{ opacity: 0, y: 20 }}
        animate={{ opacity: visible ? 1 : 0, y: visible ? 0 : 20 }}
        transition={{ duration: 0.5, ease: [0.2, 0.8, 0.2, 1] }}
        style={{ pointerEvents: visible ? "auto" : "none" }}
      >
        {CHAPTERS_NAV.filter((c) => c.id !== "home").map((c, i) => (
          <a key={c.id} href={`#${c.id}`} className={`chrome-pill-i ${active === c.id ? "on" : ""}`}>
            <span className="chrome-pill-n">{String(i + 1).padStart(2, "0")}</span>
            <span className="chrome-pill-l">{c.label}</span>
          </a>
        ))}
      </cm.div>
    </>
  );
}

Object.assign(window, {
  ServicesCinema, ExpertiseWall, SpecializationsEditorial, ContactCinema, ScrollChrome,
});
