// strikeX — Marketing landing page (v2). Fixed left icon-rail nav + scrolling content.
// Logo scrolls to top; rail items click-scroll to sections and scroll-spy the active one.
// Exposes window.Landing.
const { Logo, Mark, AsciiArt, Button, Badge, Card, Stat, Divider, Input, Switch, Tag } = window.StrikeXDesignSystem_787c16;

const RAIL_W = 244;
const MOBILE_BP = 860;

// Each content section fills at least the viewport, content vertically centered.
const SECTION = { minHeight: "100vh", boxSizing: "border-box", display: "flex", flexDirection: "column", justifyContent: "center" };

function useIsMobile(bp = MOBILE_BP) {
  const q = `(max-width: ${bp}px)`;
  const get = () => typeof window !== "undefined" && window.matchMedia && window.matchMedia(q).matches;
  const [m, setM] = React.useState(get);
  React.useEffect(() => {
    const mq = window.matchMedia(q);
    const on = () => setM(mq.matches);
    mq.addEventListener ? mq.addEventListener("change", on) : mq.addListener(on);
    return () => { mq.removeEventListener ? mq.removeEventListener("change", on) : mq.removeListener(on); };
  }, [q]);
  return m;
}

// Tokenization columns by width: 6 in one line (wide) → 3 → 2 → 1 (narrow).
function useCols() {
  const get = () => {
    if (typeof window === "undefined") return 6;
    const w = window.innerWidth;
    return w >= 1200 ? 6 : w >= 820 ? 3 : w >= 520 ? 2 : 1;
  };
  const [n, setN] = React.useState(get);
  React.useEffect(() => {
    const on = () => setN(get());
    window.addEventListener("resize", on);
    return () => window.removeEventListener("resize", on);
  }, []);
  return n;
}

// Scroll-triggered entrance wrapper. Fires once when the element enters the
// viewport (IntersectionObserver). `variant` picks the motion, `delay` staggers.
const HIDDEN = {
  up:    { opacity: 0, transform: "translateY(34px)" },
  down:  { opacity: 0, transform: "translateY(-30px)" },
  left:  { opacity: 0, transform: "translateX(-40px)" },
  right: { opacity: 0, transform: "translateX(40px)" },
  scale: { opacity: 0, transform: "scale(0.9)" },
  rise:  { opacity: 0, transform: "translateY(46px) scale(0.97)" },
  blur:  { opacity: 0, filter: "blur(12px)", transform: "translateY(14px)" },
  fade:  { opacity: 0 },
  clip:  { opacity: 0, clipPath: "inset(0 100% 0 0)", transform: "translateX(-12px)" },
};
const SHOWN = { opacity: 1, transform: "none", filter: "none", clipPath: "inset(0 0 0 0)" };

function Reveal({ children, variant = "up", delay = 0, duration = 760, once = true, style, ...rest }) {
  const reduce = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  const ref = React.useRef(null);
  const [shown, setShown] = React.useState(reduce);
  React.useEffect(() => {
    if (reduce) return;
    const el = ref.current;
    if (!el) return;
    let raf = 0;
    const cleanup = () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
    };
    const check = () => {
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight || document.documentElement.clientHeight;
      const visible = r.top < vh * 0.9 && r.bottom > 0;
      if (visible) { setShown(true); if (once) cleanup(); }
      else if (!once) setShown(false);
    };
    const onScroll = () => { cancelAnimationFrame(raf); raf = requestAnimationFrame(check); };
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    check();
    return cleanup;
  }, [reduce, once]);
  const ease = "cubic-bezier(0.22, 1, 0.36, 1)";
  return (
    <div ref={ref} style={{
      transition: `opacity ${duration}ms ${ease} ${delay}ms, transform ${duration}ms ${ease} ${delay}ms, filter ${duration}ms ${ease} ${delay}ms, clip-path ${duration}ms ${ease} ${delay}ms`,
      willChange: "opacity, transform",
      ...(shown ? SHOWN : (HIDDEN[variant] || HIDDEN.up)),
      ...style,
    }} {...rest}>{children}</div>
  );
}

// Small dot-matrix glyphs (evoke the reference's dotted icons)
const ICONS = {
  about:    "· · ·\n· ● ·\n· · ·",
  token:    "●\n· ●\n· · ●",
  strategy: "·   ·\n  ●  \n·   ·",
  print:    "● ● ●\n·   ·\n● ● ●",
  contact:  "·   ·\n· ● ·\n·   ·",
};

// Sections that participate in scroll-spy + click-scroll
const SECTIONS = [
  { id: "about-us",     label: "About Us",     icon: "about" },
  { id: "blueprint",    label: "Blueprint",    icon: "print" },
  { id: "tokenization", label: "Tokenization", icon: "token" },
  { id: "strategy",     label: "Strategy",     icon: "strategy" },
  { id: "contact",      label: "Contact Us",   icon: "contact" },
];

function RailCell({ item, active, onClick, delay = 0, entered = true, mobile = false }) {
  const [hover, setHover] = React.useState(false);
  const on = active || hover;
  const ease = "cubic-bezier(0.22, 1, 0.36, 1)";
  return (
    <button
      onClick={onClick}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        flex: mobile ? "none" : 1, textAlign: "left", cursor: "pointer", border: "none",
        background: active ? "var(--gray-50)" : hover ? "var(--gray-50)" : "transparent",
        ...(mobile
          ? {
              borderLeft: "1px solid var(--border)",
              borderBottom: `2px solid ${active ? "var(--blue-500)" : "transparent"}`,
              padding: "0 18px", height: "100%",
              display: "flex", alignItems: "center", whiteSpace: "nowrap",
            }
          : {
              minHeight: 96, borderTop: "1px solid var(--border)",
              borderLeft: `2px solid ${active ? "var(--blue-500)" : "transparent"}`,
              padding: "22px 22px 0", display: "flex", flexDirection: "column", gap: 14,
            }),
        opacity: entered ? 1 : 0,
        transform: entered ? "none" : (mobile ? "translateY(-14px)" : "translateX(-24px)"),
        transition: `background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), opacity 620ms ${ease} ${delay}ms, transform 620ms ${ease} ${delay}ms`,
      }}
    >
      {!mobile && (
        <pre aria-hidden="true" style={{ margin: 0, fontFamily: "var(--font-mono)", fontSize: 9, lineHeight: 1.25, letterSpacing: "1px", color: on ? "var(--blue-500)" : "var(--gray-400)" }}>{ICONS[item.icon]}</pre>
      )}
      <span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-xs)", letterSpacing: "var(--tracking-wide)", textTransform: "uppercase", color: on ? "var(--gray-900)" : "var(--text-muted)" }}>{item.label}</span>
    </button>
  );
}

function Rail({ active, onNav, onTop, mobile = false }) {
  const reduce = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  const [entered, setEntered] = React.useState(reduce);
  React.useEffect(() => {
    if (reduce) return;
    let r2;
    const r1 = requestAnimationFrame(() => { r2 = requestAnimationFrame(() => setEntered(true)); });
    return () => { cancelAnimationFrame(r1); if (r2) cancelAnimationFrame(r2); };
  }, [reduce]);
  const ease = "cubic-bezier(0.22, 1, 0.36, 1)";
  // Rail cells slide in first (staggered); the LOGO enters dead last, only after
  // every other first-paint element has finished — a clean scale/fade, NO shine.
  const cellBase = 220, cellStep = 110;
  const logoDelay = 1750;

  const asideStyle = mobile
    ? {
        position: "sticky", top: 0, left: 0, right: 0, zIndex: 40, height: 64,
        width: "100%", minWidth: "100vw",
        background: "var(--surface-card)", borderBottom: "1px solid var(--border)",
        display: "flex", flexDirection: "row", alignItems: "stretch",
      }
    : {
        position: "fixed", top: 0, left: 0, bottom: 0, width: RAIL_W, zIndex: 30,
        background: "var(--surface-card)", borderRight: "1px solid var(--border)",
        display: "flex", flexDirection: "column",
      };

  const logoBtnStyle = mobile
    ? {
        border: "none", background: "none", cursor: "pointer", padding: "0 20px", flex: "none",
        display: "flex", alignItems: "center",
        opacity: entered ? 1 : 0, transform: entered ? "none" : "scale(0.82)", transformOrigin: "left center",
        transition: `opacity 620ms ${ease} ${logoDelay}ms, transform 620ms ${ease} ${logoDelay}ms`,
      }
    : {
        border: "none", background: "none", cursor: "pointer", padding: "26px 22px 22px", textAlign: "left",
        opacity: entered ? 1 : 0, transform: entered ? "none" : "scale(0.82)", transformOrigin: "left center",
        transition: `opacity 620ms ${ease} ${logoDelay}ms, transform 620ms ${ease} ${logoDelay}ms`,
      };

  return (
    <aside style={asideStyle}>
      <button onClick={onTop} title="Back to top" style={logoBtnStyle}>
        <Logo size={mobile ? "sm" : "md"} />
      </button>
      <nav style={{ flex: 1, display: "flex", flexDirection: mobile ? "row" : "column", overflowX: mobile ? "auto" : "visible" }}>
        {SECTIONS.map((s, i) => <RailCell key={s.id} item={s} active={active === s.id} onClick={() => onNav(s.id)} delay={cellBase + i * cellStep} entered={entered} mobile={mobile} />)}
      </nav>
    </aside>
  );
}

function StatLine({ k, v }) {
  return (
    <div style={{ display: "flex", justifyContent: "space-between", gap: 40, whiteSpace: "nowrap" }}>
      <span style={{ color: "var(--text-muted)" }}>{k}</span>
      <span style={{ color: "var(--text-strong)" }}>{v}</span>
    </div>
  );
}

// Build one set of orthogonal grid lines. `grown` drives the spawn animation,
// `color` lets us draw a faint base layer and a brighter hover layer.
function gridLines({ cols, rows, grown, jitter, color }) {
  const ease = "cubic-bezier(0.22, 1, 0.36, 1)";
  const out = [];
  for (let i = 1; i < cols; i++) {
    const delay = (cols / 2 - Math.abs(i - cols / 2)) * 95 + jitter["v" + i];
    out.push(
      <div key={"v" + i} style={{
        position: "absolute", top: 0, bottom: 0, left: `${(i / cols) * 100}%`, width: 1,
        background: color, transformOrigin: "center",
        transform: `scaleY(${grown ? 1 : 0})`,
        transition: `transform 820ms ${ease} ${delay}ms`,
      }} />
    );
  }
  for (let j = 1; j < rows; j++) {
    const delay = (rows / 2 - Math.abs(j - rows / 2)) * 110 + jitter["h" + j];
    out.push(
      <div key={"h" + j} style={{
        position: "absolute", left: 0, right: 0, top: `${(j / rows) * 100}%`, height: 1,
        background: color, transformOrigin: "center",
        transform: `scaleX(${grown ? 1 : 0})`,
        transition: `transform 820ms ${ease} ${delay}ms`,
      }} />
    );
  }
  return out;
}

// Animated orthogonal grid — lines spawn outer→inner with per-line jitter, and a
// cursor-following radial spotlight (eased, lags toward the cursor) intensifies
// the lines beneath the mouse.
function GridField({ cols = 15, rows = 9, radius = 220, baseColor = "var(--gray-300)", glowColor = "var(--blue-400)", baseOpacity = 0.7 }) {
  const reduce = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  const [grown, setGrown] = React.useState(reduce);
  const rootRef = React.useRef(null);
  const overlayRef = React.useRef(null);
  const target = React.useRef({ x: -9999, y: -9999, on: false });
  const cur = React.useRef({ x: -9999, y: -9999, a: 0 });

  React.useEffect(() => {
    if (reduce) return;
    let r2;
    const r1 = requestAnimationFrame(() => { r2 = requestAnimationFrame(() => setGrown(true)); });
    return () => { cancelAnimationFrame(r1); if (r2) cancelAnimationFrame(r2); };
  }, [reduce]);

  React.useEffect(() => {
    const onMove = (e) => {
      const el = rootRef.current;
      if (!el) return;
      const r = el.getBoundingClientRect();
      const x = e.clientX - r.left, y = e.clientY - r.top;
      const inside = x >= 0 && y >= 0 && x <= r.width && y <= r.height;
      target.current = { x, y, on: inside };
      // seed current position on first entry so the spotlight doesn't sweep in from a corner
      if (inside && cur.current.x < -9000) { cur.current.x = x; cur.current.y = y; }
    };
    window.addEventListener("mousemove", onMove, { passive: true });

    let raf;
    const tick = () => {
      const t = target.current, c = cur.current, o = overlayRef.current;
      const kPos = 0.10;   // lower = more lag / longer transition
      const kFade = 0.12;
      c.x += (t.x - c.x) * kPos;
      c.y += (t.y - c.y) * kPos;
      c.a += ((t.on ? 1 : 0) - c.a) * kFade;
      if (o) {
        const mask = `radial-gradient(circle ${radius}px at ${c.x.toFixed(1)}px ${c.y.toFixed(1)}px, rgba(0,0,0,1) 0%, rgba(0,0,0,0.5) 50%, rgba(0,0,0,0) 100%)`;
        o.style.webkitMaskImage = mask;
        o.style.maskImage = mask;
        o.style.opacity = c.a.toFixed(3);
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => { window.removeEventListener("mousemove", onMove); cancelAnimationFrame(raf); };
  }, [radius]);

  const jitter = React.useMemo(() => {
    const f = {};
    for (let i = 1; i < cols; i++) f["v" + i] = Math.random() * 130;
    for (let j = 1; j < rows; j++) f["h" + j] = Math.random() * 130;
    return f;
  }, [cols, rows]);

  return (
    <div ref={rootRef} aria-hidden="true" style={{ position: "absolute", inset: 0, pointerEvents: "none" }}>
      {/* faint base grid */}
      <div style={{ position: "absolute", inset: 0, opacity: baseOpacity }}>
        {gridLines({ cols, rows, grown, jitter, color: baseColor })}
      </div>
      {/* brighter cobalt grid, revealed only under the eased cursor spotlight */}
      <div ref={overlayRef} style={{ position: "absolute", inset: 0, opacity: 0, willChange: "mask-image, opacity" }}>
        {gridLines({ cols, rows, grown, jitter, color: glowColor })}
      </div>
    </div>
  );
}

function Hero() {
  return (
    <section id="top" style={{ position: "relative", minHeight: "100vh", padding: "40px 56px 80px", display: "flex", flexDirection: "column", overflow: "hidden", scrollMarginTop: 0 }}>
      {/* animated orthogonal wire grid */}
      <GridField />
      <div aria-hidden="true" style={{ position: "absolute", top: "30%", right: "7%", pointerEvents: "none" }}><Mark size={300} color="accent" strokeWidth={7} animate duration={5.2} /></div>

      {/* top bar: stats terminal + book a demo */}
      <div style={{ position: "relative", display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 24, flexWrap: "wrap" }}>
        <div style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-sm)", letterSpacing: "0.04em", display: "flex", flexDirection: "column", gap: 6, minWidth: 280, flex: "1 1 280px" }}>
          <Reveal variant="left" delay={120}><StatLine k="ASSETS TOKENIZED" v="$1.2B" /></Reveal>
          <Reveal variant="left" delay={210}><StatLine k="ACTIVE MANDATES" v="48" /></Reveal>
          <Reveal variant="left" delay={300}><StatLine k="AVG SETTLEMENT" v="4M 12S" /></Reveal>
          <Reveal variant="left" delay={390}><StatLine k="STATUS" v={<span style={{ color: "var(--sage-500)" }}>OPERATIONAL</span>} /></Reveal>
        </div>
        <Reveal variant="scale" delay={260} duration={820}>
          <BookDemoButton />
        </Reveal>
      </div>

      {/* headline pinned lower-left like the reference */}
      <div style={{ position: "relative", marginTop: "auto", maxWidth: 820 }}>
        <Reveal variant="rise" delay={120} duration={900}>
          <h1 style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: "clamp(56px, 8vw, 104px)", lineHeight: 0.96, letterSpacing: "-0.04em", color: "var(--gray-900)", margin: 0 }}>
            Real-world value,<br /><span style={{ color: "var(--blue-500)" }}>tokenized.</span>
          </h1>
        </Reveal>
        <Reveal variant="up" delay={340}>
          <p style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-md)", color: "var(--text-muted)", lineHeight: 1.6, maxWidth: 500, marginTop: 26 }}>
            strikeX turns institutional assets — private credit, real estate, treasuries — into compliant, on-chain instruments. Settlement in minutes, fully auditable, end to end.
          </p>
        </Reveal>
        <Reveal variant="up" delay={480}>
          <div style={{ display: "flex", gap: 12, marginTop: 30 }}>
            <Button variant="accent" size="lg" iconRight="→">Request access</Button>
            <Button variant="secondary" size="lg">Book a walkthrough</Button>
          </div>
        </Reveal>
      </div>
    </section>
  );
}

function SectionHead({ index, kicker, title, sub, onDark = false }) {
  return (
    <div style={{ maxWidth: 720 }}>
      <Reveal variant="clip" duration={680}>
        <span style={{ display: "inline-block", fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", letterSpacing: "var(--tracking-label)", textTransform: "uppercase", color: onDark ? "var(--blue-300)" : "var(--blue-600)" }}>[ {index} ] {kicker}</span>
      </Reveal>
      <Reveal variant="up" delay={120} duration={820}>
        <h2 style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: "clamp(34px, 4.5vw, 56px)", letterSpacing: "-0.03em", color: onDark ? "var(--gray-100)" : "var(--gray-900)", margin: "16px 0 0", lineHeight: 1.02 }}>{title}</h2>
      </Reveal>
      {sub && (
        <Reveal variant="up" delay={240}>
          <p style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-sm)", color: onDark ? "var(--gray-400)" : "var(--text-muted)", lineHeight: 1.6, marginTop: 18 }}>{sub}</p>
        </Reveal>
      )}
    </div>
  );
}

function AboutUs() {
  return (
    <section id="about-us" style={{ ...SECTION, padding: "96px 56px", borderTop: "1px solid var(--border)", scrollMarginTop: 0 }}>
      <SectionHead index="01" kicker="About Us" title="Built for institutional precision." sub="strikeX is a small, exacting team building the rails for real-world asset tokenization — compliant by construction, transparent by default, and fast enough to settle while the call is still live." />
      <div style={{ display: "flex", gap: 64, flexWrap: "wrap", marginTop: 56, borderTop: "1px solid var(--border)", paddingTop: 40 }}>
        <Reveal variant="rise" delay={0}><Stat label="Assets tokenized" value="$1.2B" delta="+38% QoQ" trend="up" /></Reveal>
        <Reveal variant="rise" delay={110}><Stat label="Active mandates" value="48" delta="+6" trend="up" /></Reveal>
        <Reveal variant="rise" delay={220}><Stat label="Jurisdictions" value="7" /></Reveal>
        <Reveal variant="rise" delay={330}><Stat label="Avg settlement" value="<5m" delta="-31%" trend="up" /></Reveal>
      </div>
    </section>
  );
}

// Preview dimensions (300×300 placeholder + copy). Used to keep the card on-screen.
const PREVIEW_W = 340;
const PREVIEW_H = 392;

// One tokenization cell. Idle it's a flat bordered card; on hover its left edge
// thickens into the instrument's Product Palette color (tokens/product-palettes.css),
// and a preview card tracks the cursor — entering (fade + scale toward the pointer)
// and exiting (fade + scale away) — carrying a 300×300 image placeholder + copy.
function TokenCell({ it, i }) {
  // Only the enter/leave toggle lives in React state (fires twice per hover). Pointer
  // tracking writes the preview's position straight to the DOM via refs, coalesced with
  // requestAnimationFrame — so moving the cursor triggers ZERO React re-renders. That's
  // the fix for the lag: re-rendering the 300×300 card on every mousemove is what janks.
  const [hover, setHover] = React.useState(false);
  const posRef = React.useRef(null);     // outer node — moved imperatively
  const sideRef = React.useRef("right"); // last flip side (read at enter/exit render)
  const frame = React.useRef(0);
  const next = React.useRef(null);

  const flush = () => {
    frame.current = 0;
    const p = next.current, el = posRef.current;
    if (p && el) el.style.transform = `translate3d(${p.x}px, ${p.y}px, 0)`;
  };
  const track = (e) => {
    const side = e.clientX + 22 + PREVIEW_W > window.innerWidth - 8 ? "left" : "right";
    sideRef.current = side;
    next.current = {
      x: side === "right" ? e.clientX + 22 : e.clientX - 22 - PREVIEW_W,
      // vertically center on the pointer, but keep the whole card within the viewport
      y: Math.min(Math.max(e.clientY, PREVIEW_H / 2 + 8), window.innerHeight - PREVIEW_H / 2 - 8),
    };
    if (!frame.current) frame.current = requestAnimationFrame(flush);
  };
  React.useEffect(() => () => { if (frame.current) cancelAnimationFrame(frame.current); }, []);

  // Portal to <body>: the preview escapes every ancestor's overflow + stacking context,
  // so nothing can clip or bury it. The outer node owns the (imperative, fixed) position;
  // the inner node owns the eased enter/exit — only opacity + scale are transitioned.
  const preview = (
    <div ref={posRef} aria-hidden="true" style={{
      position: "fixed", left: 0, top: 0, width: PREVIEW_W,
      pointerEvents: "none", zIndex: 1000, willChange: "transform",
    }}>
      <div style={{
        transformOrigin: sideRef.current === "left" ? "right center" : "left center",
        transform: `translateY(-50%) scale(${hover ? 1 : 0.9})`,
        opacity: hover ? 1 : 0, willChange: "opacity, transform",
        background: "var(--surface-card)", border: "1px solid var(--border)",
        borderTop: `3px solid ${it.c}`, borderRadius: "var(--radius-lg)",
        boxShadow: "var(--shadow-lg)", padding: 20,
        transition: "opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out)",
      }}>
        {/* instrument payoff diagram (assets/sc), contained inside a 300×300 frame */}
        <div style={{ width: 300, height: 300, background: "var(--surface-card)", border: "1px solid var(--border-faint)", borderRadius: "var(--radius-md)", overflow: "hidden", display: "flex", alignItems: "center", justifyContent: "center" }}>
          <img src={it.img} alt={`${it.t} payoff diagram`} draggable="false" style={{ width: "100%", height: "100%", objectFit: "contain", display: "block" }} />
        </div>
        <div style={{ marginTop: 14, display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 10 }}>
          <span style={{ fontFamily: "var(--font-mono)", fontWeight: 600, fontSize: "var(--text-sm)", letterSpacing: "0.02em", color: it.c }}>{it.t}</span>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", color: "var(--text-faint)" }}>{it.n}</span>
        </div>
        <p style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-xs)", color: "var(--text-muted)", lineHeight: 1.55, margin: "6px 0 0" }}>{it.d}</p>
      </div>
    </div>
  );

  return (
    <Reveal
      variant="fade"
      delay={i * 110}
      duration={680}
      onMouseEnter={(e) => { track(e); flush(); setHover(true); }}
      onMouseMove={track}
      onMouseLeave={() => setHover(false)}
      style={{
        position: "relative",
        background: "var(--surface-card)",
        borderRight: "1px solid var(--border)",
        borderBottom: "1px solid var(--border)",
        boxSizing: "border-box",
        // raise the hovered cell over its grid neighbors so the themed bar + content
        // shift read cleanly (the preview floats independently, via the portal below)
        zIndex: hover ? 2 : 1,
      }}
    >
      {/* themed left bar — 0px (invisible over the grid line) → thick on hover */}
      <div aria-hidden="true" style={{
        position: "absolute", top: 0, bottom: 0, left: 0,
        width: hover ? 5 : 0, background: it.c,
        transition: "width var(--dur-fast) var(--ease-out)",
      }} />
      <div style={{
        padding: "32px 30px",
        transform: hover ? "translateX(5px)" : "none",
        transition: "transform var(--dur-base) var(--ease-out)",
      }}>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", color: hover ? it.c : "var(--blue-600)", letterSpacing: "var(--tracking-wide)", transition: "color var(--dur-base) var(--ease-out)" }}>{it.n}</span>
        <h3 style={{ fontFamily: "var(--font-mono)", fontWeight: 600, fontSize: "var(--text-lg)", color: "var(--gray-900)", margin: "16px 0 10px", letterSpacing: "0.02em" }}>{it.t}</h3>
        <p style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-sm)", color: "var(--text-muted)", lineHeight: 1.6, margin: 0 }}>{it.d}</p>
      </div>
      {ReactDOM.createPortal(preview, document.body)}
    </Reveal>
  );
}

function Tokenization() {
  const cols = useCols();
  const items = [
    { n: "01", t: "CALL_N",   c: "var(--sun-500)",    img: "assets/sc/call_n.png",  d: "Negative-delta call leg. Hedged downside exposure, tokenized and settled on-chain." },
    { n: "02", t: "CALL_P",   c: "var(--flame-500)",  img: "assets/sc/call_p.png",  d: "Positive-delta call leg. Directional upside as a transferable instrument." },
    { n: "03", t: "CALL_NP",  c: "var(--clay-500)",   img: "assets/sc/call_np.png", d: "Delta-neutral call spread. Net premium capture, fully auditable." },
    { n: "04", t: "PUT_N",    c: "var(--azure-500)",  img: "assets/sc/put_n.png",   d: "Negative-delta put leg. Protective downside, compliant by construction." },
    { n: "05", t: "PUT_P",    c: "var(--cobalt-500)", img: "assets/sc/put_p.png",   d: "Positive-delta put leg. Inverse exposure issued to approved investors." },
    { n: "06", t: "PUT_NP",   c: "var(--indigo-500)", img: "assets/sc/put_np.png",  d: "Delta-neutral put spread. Standardized issuance, secondary liquidity built in." },
  ];

  // Pixel-snap the column tracks. With `1fr` the track widths are fractional at most
  // viewport sizes, so the dividers land on sub-pixel boundaries where a 1px line can
  // blur or drop out — and every pixel of resize re-rounds them, which is the jitter.
  // Measure the track and hand the grid an explicit integer-px template (the remainder
  // spread one px at a time across the first columns) so every boundary sits on a whole
  // pixel. Lines stay crisp and only ever shift by a full pixel — they never flicker.
  const wrapRef = React.useRef(null);
  const [tpl, setTpl] = React.useState(null);
  React.useLayoutEffect(() => {
    const el = wrapRef.current;
    if (!el) return;
    const compute = () => {
      const w = Math.round(el.clientWidth);
      const base = Math.floor(w / cols);
      const rem = w - base * cols;
      setTpl(Array.from({ length: cols }, (_, i) => (base + (i < rem ? 1 : 0)) + "px").join(" "));
    };
    compute();
    let ro;
    if (window.ResizeObserver) { ro = new ResizeObserver(compute); ro.observe(el); }
    else window.addEventListener("resize", compute);
    return () => { if (ro) ro.disconnect(); else window.removeEventListener("resize", compute); };
  }, [cols]);

  return (
    <section id="tokenization" style={{ ...SECTION, padding: "96px 56px", borderTop: "1px solid var(--border)", scrollMarginTop: 0 }}>
      <SectionHead index="03" kicker="Tokenization" title="Every instrument, on-chain." />
      {/* Borders are real cell edges, not a gap-bleed: a 1px layout gap showing the
          container background can round to 0 device px and vanish, but a 1px border is
          always painted. Container draws the outer top/left; each cell draws its right +
          bottom — one line per boundary, no doubling. Track widths come from `tpl`
          (integer px, snapped above); `1fr` is only the pre-measure fallback. (6 items
          divide evenly into every column count 1/2/3/6, so the bottom row is full.) */}
      <div ref={wrapRef} style={{ display: "grid", gridTemplateColumns: tpl || `repeat(${cols}, 1fr)`, borderTop: "1px solid var(--border)", borderLeft: "1px solid var(--border)", marginTop: 48 }}>
        {items.map((it, i) => <TokenCell key={it.n} it={it} i={i} />)}
      </div>
    </section>
  );
}

// `diagram` names a window global (CallLadder / PutLadder / CoreLoop) loaded before this
// file — resolved at render time via window[p.diagram]. Calls show the call ladder, puts
// the put ladder, and the Wheel its CC/CSP core loop.
const STRATEGY_PILLARS = [
  { k: "CC",       t: "Covered Call",       d: "Hold the tokenized underlying, write upside calls against it for steady premium income.", diagram: "CallLadder" },
  { k: "CSP",      t: "Cash-Secured Put",   d: "Post collateral, sell puts to acquire the instrument at a discount — or keep the premium.", diagram: "PutLadder" },
  { k: "BCS",      t: "Bull Call Spread",   d: "Defined-risk directional upside: long a lower call, short a higher one.", diagram: "CallLadder" },
  { k: "BPS",      t: "Bull Put Spread",    d: "Collect net credit with capped downside by selling a put spread.", diagram: "PutLadder" },
  { k: "WHEELING", t: "The Wheel",          d: "Cycle cash-secured puts into covered calls — a continuous, compounding premium engine across the full position.", diagram: "CoreLoop" },
];

// Resolve a pillar's diagram (a window global) and render it, or nothing if absent.
function PillarDiagram({ name, style }) {
  const D = name && typeof window !== "undefined" ? window[name] : null;
  return D ? <D style={style} /> : null;
}

const STRAT_EASE = "cubic-bezier(0.65, 0, 0.35, 1)"; // ease-in-out
const STRAT_DUR = 560;     // ms — position/size glide
const STRAT_ROW = 168;     // px — base (1-row) card height
const STRAT_GAP = 14;      // px — gutter between cards
const STRAT_PAD = 24;        // px — card inner padding

// Pack the pillars into a 2-column masonry and return each card's cell.
// The active card claims 3 rows (3× its idle height); the last pillar (the Wheel) always
// spans both columns, so an expanded ladder sits beside the other three stacked cards.
function packStrategy(n, active) {
  const COLS = 2;
  const occ = {};
  const key = (r, c) => r + ":" + c;
  const fits = (r, c, rs, cs) => {
    if (c + cs > COLS) return false;
    for (let dr = 0; dr < rs; dr++) for (let dc = 0; dc < cs; dc++) if (occ[key(r + dr, c + dc)]) return false;
    return true;
  };
  let cr = 0, cc = 0, rows = 0;
  const cells = [];
  for (let i = 0; i < n; i++) {
    const isLast = i === n - 1;
    const cs = isLast ? 2 : 1;
    const rs = i === active ? 3 : 1;
    let r = cr, c = cc;
    while (true) {                      // walk forward (never backward) to the first fit
      if (c + cs > COLS) { c = 0; r++; continue; }
      if (fits(r, c, rs, cs)) break;
      c++;
    }
    for (let dr = 0; dr < rs; dr++) for (let dc = 0; dc < cs; dc++) occ[key(r + dr, c + dc)] = true;
    cells.push({ r, c, rs, cs });
    rows = Math.max(rows, r + rs);
    cc = c + cs; cr = r;               // advance the auto-placement cursor
    if (cc >= COLS) { cc = 0; cr = r + 1; }
  }
  return { cells, rows };
}

// One strategy card — absolutely positioned so its move + resize can be eased.
// `box` is the pixel rect for its current cell; `animate` gates the glide so the
// first paint lands in place without sliding in from the corner.
function StrategyCard({ p, i, n, active, box, animate, onOpen }) {
  const num = String(i + 1).padStart(2, "0");
  const glide = animate
    ? `transform ${STRAT_DUR}ms ${STRAT_EASE}, width ${STRAT_DUR}ms ${STRAT_EASE}, height ${STRAT_DUR}ms ${STRAT_EASE}, border-color 320ms ${STRAT_EASE}, background 320ms ${STRAT_EASE}`
    : `border-color 320ms ${STRAT_EASE}, background 320ms ${STRAT_EASE}`;
  return (
    <div
      onMouseEnter={onOpen}
      onFocus={onOpen}
      tabIndex={0}
      role="button"
      aria-expanded={active}
      style={{
        position: "absolute", top: 0, left: 0,
        width: box.w, height: box.h, transform: `translate(${box.x}px, ${box.y}px)`,
        minWidth: 0, overflow: "hidden", cursor: "pointer", boxSizing: "border-box",
        background: "var(--surface-card)",
        border: `1px solid ${active ? "var(--blue-500)" : "var(--border)"}`,
        borderRadius: "var(--radius-lg)", outline: "none", padding: STRAT_PAD,
        display: "flex", flexDirection: "column",
        transition: glide, willChange: "transform, width, height",
      }}
    >
      <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 14 }}>
        <Mark size={22} color="accent" strokeWidth={9} />
        <span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fontWeight: 600, letterSpacing: "var(--tracking-label)", textTransform: "uppercase", color: "var(--blue-600)" }}>[ {p.k} ]</span>
        <span style={{ marginLeft: "auto", fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", letterSpacing: "var(--tracking-label)", color: "var(--text-faint)" }}>{num} / {String(n).padStart(2, "0")}</span>
      </div>
      <h3 style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: "var(--text-xl)", color: "var(--gray-900)", margin: 0, letterSpacing: "-0.02em" }}>{p.t}</h3>
      <p style={{
        fontFamily: "var(--font-mono)", fontSize: "var(--text-sm)", color: "var(--text-muted)", lineHeight: 1.65, margin: "10px 0 0",
        display: "-webkit-box", WebkitBoxOrient: "vertical", WebkitLineClamp: active ? 8 : 2, overflow: "hidden",
      }}>{p.d}</p>
      {/* Diagram centers in the space below the text in the expanded (3-row) card. */}
      {p.diagram && active && (
        <div style={{ flex: 1, minHeight: 0, display: "flex", alignItems: "center", justifyContent: "center", marginTop: 16 }}>
          <PillarDiagram name={p.diagram} />
        </div>
      )}
    </div>
  );
}

function Strategy() {
  const pillars = STRATEGY_PILLARS;
  const n = pillars.length;
  const mobile = useIsMobile(760);
  const reduce = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  // -1 = nothing hovered → idle layout [1,2][3,4][5-wide]. Hover expands a card to 3 rows
  // (3× its idle height); the rest glide to their new cells. Leaving the grid returns to idle.
  const [active, setActive] = React.useState(-1);
  const wrapRef = React.useRef(null);
  const [w, setW] = React.useState(0);
  const [animate, setAnimate] = React.useState(false);

  // Measure the track width (cards are placed in px, so we need it to lay them out).
  React.useLayoutEffect(() => {
    if (mobile) return;
    const el = wrapRef.current;
    if (!el) return;
    const measure = () => setW(el.clientWidth);
    measure();
    let ro;
    if (window.ResizeObserver) { ro = new ResizeObserver(measure); ro.observe(el); }
    else window.addEventListener("resize", measure);
    return () => { if (ro) ro.disconnect(); else window.removeEventListener("resize", measure); };
  }, [mobile]);

  // Enable the glide one frame after first paint so the initial layout snaps in.
  React.useEffect(() => {
    if (mobile || reduce) return;
    const r = requestAnimationFrame(() => setAnimate(true));
    return () => cancelAnimationFrame(r);
  }, [mobile, reduce]);

  const { cells, rows } = packStrategy(n, active);
  const colW = w > 0 ? (w - STRAT_GAP) / 2 : 0;
  const rect = (cell) => ({
    x: cell.c * (colW + STRAT_GAP),
    y: cell.r * (STRAT_ROW + STRAT_GAP),
    w: cell.cs * colW + (cell.cs - 1) * STRAT_GAP,
    h: cell.rs * STRAT_ROW + (cell.rs - 1) * STRAT_GAP,
  });
  const boxes = cells.map(rect);
  const trackH = rows * (STRAT_ROW + STRAT_GAP) - STRAT_GAP;

  return (
    <section id="strategy" style={{ ...SECTION, padding: "96px 56px", borderTop: "1px solid var(--border)", scrollMarginTop: 0 }}>
      <SectionHead index="04" kicker="Strategy" title="A strategy built on rails." />
      {mobile ? (
        <div style={{ display: "grid", gridTemplateColumns: "1fr", gap: 14, marginTop: 48 }}>
          {pillars.map((p, i) => (
            <Reveal key={p.k} variant="rise" delay={i * 110} duration={760}>
            <Card padding="lg">
              <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 16 }}>
                <Mark size={22} color="accent" strokeWidth={9} />
                <span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", fontWeight: 600, letterSpacing: "var(--tracking-label)", textTransform: "uppercase", color: "var(--blue-600)" }}>[ {p.k} ]</span>
              </div>
              <h3 style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: "var(--text-xl)", color: "var(--gray-900)", margin: "0 0 12px", letterSpacing: "-0.02em" }}>{p.t}</h3>
              <p style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-sm)", color: "var(--text-muted)", lineHeight: 1.65, margin: 0 }}>{p.d}</p>
              <PillarDiagram name={p.diagram} style={{ marginTop: 18 }} />
            </Card>
            </Reveal>
          ))}
        </div>
      ) : (
        <Reveal variant="up" delay={120} duration={820}>
          <div
            ref={wrapRef}
            onMouseLeave={() => setActive(-1)}
            style={{ position: "relative", marginTop: 48, height: trackH, transition: animate ? `height ${STRAT_DUR}ms ${STRAT_EASE}` : "none" }}
          >
            {pillars.map((p, i) => (
              <StrategyCard key={p.k} p={p} i={i} n={n} active={active === i} box={boxes[i]} animate={animate} onOpen={() => setActive(i)} />
            ))}
          </div>
        </Reveal>
      )}
    </section>
  );
}

function Blueprint() {
  const steps = [
    { n: "01", t: "Originate", d: "Source and underwrite the underlying real-world asset." },
    { n: "02", t: "Structure", d: "Wrap it in a compliant legal + token framework." },
    { n: "03", t: "Issue", d: "Mint on-chain instruments to approved investors." },
    { n: "04", t: "Settle", d: "Trade and settle in minutes — fully auditable." },
  ];
  return (
    <section id="blueprint" style={{ ...SECTION, padding: "96px 56px", background: "var(--gray-900)", scrollMarginTop: 0 }}>
      <SectionHead index="02" kicker="Blueprint" title="From asset to instrument." sub="One repeatable pipeline takes a real-world asset all the way to a tradeable, settled on-chain instrument." onDark />
      <div>
        {/* WheelGraph stagger-fades its own parts on scroll-into-view; the caption
            rides the same reveal as the final item, so no outer Reveal here. */}
        <window.WheelGraph caption={
          <span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", letterSpacing: "var(--tracking-label)", textTransform: "uppercase", color: "var(--blue-300)" }}>The wheel state machine</span>
        } />
      </div>
    </section>
  );
}

// Primary "Book a demo" CTA — logo above the label, opens a mailto to DEMO_EMAIL.
// Shared by the hero and the footer so the two stay identical.
function BookDemoButton() {
  const [hover, setHover] = React.useState(false);
  const bookDemo = () => {
    const email = (window.ENV || {}).DEMO_EMAIL;
    if (email) window.location.href = "mailto:" + email;
  };
  return (
    <button
      onClick={bookDemo}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        background: hover ? "var(--blue-600)" : "var(--blue-500)", color: "var(--white)",
        border: "none", cursor: "pointer",
        borderRadius: "var(--radius-md)", padding: "26px 40px", minWidth: 280, textAlign: "left",
        fontFamily: "var(--font-mono)", fontSize: "var(--text-sm)", letterSpacing: "var(--tracking-label)", textTransform: "uppercase",
        transition: "background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out)",
        transform: hover ? "translateY(-1px)" : "none",
      }}
    >
      <span style={{ display: "block", marginBottom: 40 }}><Mark size={20} color="invert" strokeWidth={10} /></span>
      Book a demo
    </button>
  );
}

// Footer nav link with a subtle hover: text brightens, nudges right, arrow fades in.
function FooterLink({ href, onClick, external, children }) {
  const [hover, setHover] = React.useState(false);
  return (
    <a
      href={href}
      onClick={onClick}
      target={external ? "_blank" : undefined}
      rel={external ? "noopener noreferrer" : undefined}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        display: "inline-flex", alignItems: "center", gap: 6,
        fontFamily: "var(--font-mono)", fontSize: "var(--text-xs)",
        color: hover ? "var(--white)" : "var(--gray-300)",
        textDecoration: "none",
        transition: "color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out)",
        transform: hover ? "translateX(3px)" : "none",
      }}
    >
      {children}
      <span aria-hidden="true" style={{ opacity: hover ? 1 : 0, transition: "opacity var(--dur-fast) var(--ease-out)" }}>→</span>
    </a>
  );
}

function Contact() {
  const mobile = useIsMobile();
  const E = window.ENV || {};
  // Footer Menu links scroll smoothly to their section instead of jumping.
  const onJump = (e, id) => {
    e.preventDefault();
    const el = document.getElementById(id);
    if (el) window.scrollTo({ top: el.offsetTop - (mobile ? 64 : 0), behavior: "smooth" });
  };
  // Menu = in-page sections (smooth scroll); Resources/Legal URLs come from .env.
  const cols = [
    { h: "Menu", l: SECTIONS.map((s) => ({ t: s.label, href: "#" + s.id, jump: s.id })) },
    { h: "Resources", l: [
      { t: "Docs", href: E.LINK_DOCS || "#", external: true },
      { t: "Whitepaper", href: E.LINK_WHITEPAPER || "#", external: true },
      { t: "GitHub", href: E.LINK_GITHUB || "#", external: true },
      { t: "X", href: E.LINK_X || "#", external: true },
    ] },
    { h: "Legal", l: [
      { t: "Privacy", href: E.LINK_PRIVACY || "#", external: true },
      { t: "Terms", href: E.LINK_TERMS || "#", external: true },
      { t: "SOC 2", href: E.LINK_SOC2 || "#", external: true },
      { t: "Disclosures", href: E.LINK_DISCLOSURES || "#", external: true },
    ] },
  ];
  return (
    <section id="contact" style={{ ...SECTION, position: "relative", overflow: "hidden", padding: "96px 56px 64px", background: "var(--gray-900)", scrollMarginTop: 0 }}>
      {/* same animated wire grid as the hero, tuned for a dark surface */}
      <GridField baseColor="var(--gray-700)" glowColor="var(--blue-400)" baseOpacity={0.9} />
      <div style={{ position: "relative" }}>
        <SectionHead index="05" kicker="Contact Us" title="Let's talk." sub="Tell us about your mandate. We'll get back within one business day." onDark />
        <Reveal variant="up" delay={120}>
          <div style={{ marginTop: 28 }}>
            <BookDemoButton />
          </div>
        </Reveal>
        <div style={{ display: "flex", gap: 56, flexWrap: "wrap", marginTop: 88 }}>
          {cols.map((c, i) => (
            <Reveal key={c.h} variant="up" delay={i * 110}>
            <div>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", letterSpacing: "var(--tracking-label)", textTransform: "uppercase", color: "var(--gray-400)", marginBottom: 14 }}>{c.h}</div>
              <ul style={{ listStyle: "none", padding: 0, margin: 0, display: "flex", flexDirection: "column", gap: 9 }}>
                {c.l.map((x) => <li key={x.t}><FooterLink href={x.href} external={x.external} onClick={x.jump ? (e) => onJump(e, x.jump) : undefined}>{x.t}</FooterLink></li>)}
              </ul>
            </div>
            </Reveal>
          ))}
        </div>
        <div style={{ marginTop: 80, display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 12 }}>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", color: "var(--gray-500)" }}>© 2026 strikeX, Inc.</span>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 8, fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", letterSpacing: "var(--tracking-label)", textTransform: "uppercase", color: "var(--gray-500)" }}>
            <span style={{ width: 7, height: 7, borderRadius: "50%", background: "var(--sage-500)" }} />
            All systems operational
          </span>
        </div>
      </div>
    </section>
  );
}

function Landing() {
  const [active, setActive] = React.useState("");
  const mobile = useIsMobile();
  const onNav = (id) => {
    const el = document.getElementById(id);
    if (el) window.scrollTo({ top: el.offsetTop - (mobile ? 64 : 0), behavior: "smooth" });
  };
  const onTop = () => window.scrollTo({ top: 0, behavior: "smooth" });
  React.useEffect(() => {
    const onScroll = () => {
      const y = window.scrollY + 160;
      let cur = "";
      for (const s of SECTIONS) {
        const el = document.getElementById(s.id);
        if (el && el.offsetTop <= y) cur = s.id;
      }
      setActive(cur);
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return (
    <div style={{ background: "var(--bg-page)", minHeight: "100vh" }}>
      <Rail active={active} onNav={onNav} onTop={onTop} mobile={mobile} />
      <main style={{ marginLeft: mobile ? 0 : RAIL_W }}>
        <Hero /><AboutUs /><Blueprint /><Tokenization /><Strategy /><Contact />
      </main>
    </div>
  );
}

window.Landing = Landing;
