// HERO: mobile-first editorial cover
// Mobile:   single column, receipt below CTAs
// Tablet:   5+3 two-column, receipt right
// Desktop:  1+8+3 twelve-col asymmetric with vertical rail

// HeroFunnel: same editorial waveform as before, with a subtle funnel pinch
// at center (roadmap neck): noise in wide left, resolves to signal right.
function HeroFunnel() {
  const canvasRef = React.useRef(null);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;

    const reduce =
      typeof window.matchMedia === "function" &&
      window.matchMedia("(prefers-reduced-motion: reduce)").matches;

    let W = 0, H = 0, dpr = 1;
    let raf = 0;
    let running = false;
    let startT = 0;

    const NECK = 0.5;

    function smoothstep(a, b, x) {
      const t = Math.min(1, Math.max(0, (x - a) / (b - a)));
      return t * t * (3 - 2 * t);
    }

    // Subtle pinch at roadmap neck: felt, not drawn as funnel walls.
    function funnelScale(xN) {
      const dist = Math.abs(xN - NECK) / NECK;
      return 0.88 + 0.12 * smoothstep(0, 1, dist);
    }

    function cohAt(xN) { return smoothstep(0.34, 0.64, xN); }

    // Soft fade at canvas edges so noise/signal never hard-clips.
    function edgeFade(xN) {
      const left = smoothstep(0, 0.12, xN);
      const right = 1 - smoothstep(0.88, 1, xN);
      return left * right;
    }

    const seeds = new Float32Array(2048);
    for (let i = 0; i < seeds.length; i++) seeds[i] = Math.random() * 2 - 1;

    const parts = [];
    for (let i = 0; i < 64; i++) {
      const r = Math.random();
      parts.push({ x: r * r * 0.7, y: Math.random(), s: Math.random() * 2 + 0.6, ph: Math.random() * 6.28 });
    }

    function resize() {
      const rect = canvas.getBoundingClientRect();
      W = Math.max(1, Math.round(rect.width));
      H = Math.max(1, Math.round(rect.height));
      dpr = Math.min(window.devicePixelRatio || 1, 2);
      canvas.width = Math.round(W * dpr);
      canvas.height = Math.round(H * dpr);
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      if (!running || reduce) frame(0);
    }

    function signalAt(xN, t) {
      const env = Math.sin(xN * Math.PI);
      const a = Math.sin(xN * Math.PI * 6 + t * 1.05);
      const b = Math.sin(xN * Math.PI * 13 - t * 0.7) * 0.36;
      const c = Math.sin(xN * Math.PI * 2.5 + t * 0.45) * 0.55;
      return ((a + b + c) / 2) * env;
    }

    function frame(t) {
      ctx.clearRect(0, 0, W, H);
      if (W < 2 || H < 2) return;

      const mid = H * 0.5;
      const breathe = 0.82 + 0.18 * Math.sin(t * 0.6);
      const amp = H * 0.15 * breathe;
      const fillFloor = mid + amp * 1.35;
      const step = Math.max(2, Math.round(W / 560));

      for (let i = 0; i < parts.length; i++) {
        const p = parts[i];
        const edge = edgeFade(p.x);
        const fade = (1 - cohAt(p.x)) * edge;
        if (fade <= 0.02) continue;
        const jx = reduce ? 0 : Math.sin(t * 2 + p.ph) * 6 * edge;
        const jy = reduce ? 0 : Math.cos(t * 2.4 + p.ph) * 8 * edge;
        const px = p.x * W + jx;
        const spread = funnelScale(p.x) * H * 0.42 * edge;
        const py = mid + (p.y - 0.5) * spread + jy;
        const coh = cohAt(p.x);
        const a = (0.14 + coh * 0.1) * fade;
        if (coh < 0.35) {
          ctx.fillStyle = "rgba(192,57,43," + a.toFixed(3) + ")";
        } else {
          const mix = (coh - 0.35) / 0.65;
          const r = Math.round(192 + (212 - 192) * mix);
          const g = Math.round(57 + (166 - 57) * mix);
          const b = Math.round(43 + (74 - 43) * mix);
          ctx.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a.toFixed(3) + ")";
        }
        ctx.fillRect(px, py, p.s, p.s);
      }

      const pts = [];
      for (let x = 0; x <= W; x += step) {
        const xN = x / W;
        const edge = edgeFade(xN);
        const coh = cohAt(xN);
        const si = Math.min(seeds.length - 1, Math.floor(xN * (seeds.length - 1)));
        const sig = signalAt(xN, t);
        const jitter = reduce ? seeds[si] : seeds[si] * 0.7 + Math.sin(xN * 140 + t * 7.5) * 0.5;
        const v = (sig * coh + jitter * (1 - coh)) * edge;
        pts.push(x, mid - v * amp * funnelScale(xN));
      }

      const stroke = ctx.createLinearGradient(0, 0, W, 0);
      stroke.addColorStop(0.00, "rgba(192,57,43,0)");
      stroke.addColorStop(0.08, "rgba(192,57,43,0.75)");
      stroke.addColorStop(0.34, "rgba(192,57,43,0.82)");
      stroke.addColorStop(0.50, "rgba(176,86,52,0.78)");
      stroke.addColorStop(0.62, "rgba(212,166,74,0.88)");
      stroke.addColorStop(0.92, "rgba(232,200,120,0.95)");
      stroke.addColorStop(1.00, "rgba(232,200,120,0)");

      ctx.beginPath();
      ctx.moveTo(0, pts[1]);
      for (let i = 0; i < pts.length; i += 2) ctx.lineTo(pts[i], pts[i + 1]);
      ctx.lineTo(W, fillFloor);
      ctx.lineTo(0, fillFloor);
      ctx.closePath();
      const fill = ctx.createLinearGradient(0, mid - amp, 0, fillFloor);
      fill.addColorStop(0, "rgba(192,57,43,0.06)");
      fill.addColorStop(0.45, "rgba(192,57,43,0.03)");
      fill.addColorStop(0.62, "rgba(212,166,74,0.1)");
      fill.addColorStop(1, "rgba(212,166,74,0)");
      ctx.fillStyle = fill;
      ctx.fill();

      ctx.beginPath();
      ctx.moveTo(pts[0], pts[1]);
      for (let i = 2; i < pts.length; i += 2) ctx.lineTo(pts[i], pts[i + 1]);
      ctx.lineJoin = "round";
      ctx.lineWidth = 2;
      ctx.shadowColor = "rgba(212,166,74,0.45)";
      ctx.shadowBlur = 14;
      ctx.strokeStyle = stroke;
      ctx.stroke();
      ctx.shadowBlur = 0;

      const gx = W * NECK;
      const glow = ctx.createRadialGradient(gx, mid, 0, gx, mid, H * 0.45);
      glow.addColorStop(0, "rgba(232,200,120,0.08)");
      glow.addColorStop(1, "rgba(232,200,120,0)");
      ctx.fillStyle = glow;
      ctx.fillRect(0, 0, W, H);

      ctx.strokeStyle = "rgba(212,166,74,0.1)";
      ctx.lineWidth = 1;
      ctx.beginPath();
      ctx.moveTo(W * 0.1, mid);
      ctx.lineTo(W * 0.9, mid);
      ctx.stroke();
      ctx.fillStyle = "rgba(212,166,74,0.18)";
      const ticks = 24;
      for (let i = 1; i < ticks; i++) {
        const xN = i / ticks;
        const edge = edgeFade(xN);
        if (edge < 0.15) continue;
        const tx = xN * W;
        const tall = i % 4 === 0;
        const tickCoh = cohAt(xN);
        const tr = Math.round(192 + (212 - 192) * tickCoh);
        const tg = Math.round(57 + (166 - 57) * tickCoh);
        const tb = Math.round(43 + (74 - 43) * tickCoh);
        ctx.fillStyle = "rgba(" + tr + "," + tg + "," + tb + "," + (0.12 + tickCoh * 0.1).toFixed(3) + ")";
        ctx.globalAlpha = edge * 0.85;
        ctx.fillRect(tx, mid - (tall ? 5 : 3), 1, tall ? 10 : 6);
      }
      ctx.globalAlpha = 1;
    }

    function loop(nowMs) {
      if (!running) return;
      if (!startT) startT = nowMs;
      frame((nowMs - startT) / 1000);
      raf = window.requestAnimationFrame(loop);
    }

    function play() {
      if (reduce || running) return;
      running = true;
      raf = window.requestAnimationFrame(loop);
    }
    function pause() {
      running = false;
      if (raf) window.cancelAnimationFrame(raf);
      raf = 0;
    }

    resize();
    if (reduce) frame(0);
    else play();

    const onResize = () => resize();
    const onVis = () => {
      if (reduce) return;
      if (document.hidden) pause();
      else play();
    };
    window.addEventListener("resize", onResize);
    document.addEventListener("visibilitychange", onVis);

    const io = new IntersectionObserver(
      (entries) => {
        if (reduce) return;
        const e = entries[0];
        if (e && e.isIntersecting) play();
        else pause();
      },
      { threshold: 0 }
    );
    io.observe(canvas);

    return () => {
      pause();
      window.removeEventListener("resize", onResize);
      document.removeEventListener("visibilitychange", onVis);
      io.disconnect();
    };
  }, []);

  return (
    <div className="hero-funnel" aria-hidden="true">
      <canvas ref={canvasRef} />
    </div>
  );
}

// HeroWaveform: legacy horizontal wave (used by standalone Hero section).
function HeroWaveform() {
  const canvasRef = React.useRef(null);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;

    const reduce =
      typeof window.matchMedia === "function" &&
      window.matchMedia("(prefers-reduced-motion: reduce)").matches;

    let W = 0, H = 0, dpr = 1;
    let raf = 0;
    let running = false;
    let startT = 0;

    function smoothstep(a, b, x) {
      const t = Math.min(1, Math.max(0, (x - a) / (b - a)));
      return t * t * (3 - 2 * t);
    }
    // Spatial coherence: 0 (pure noise) on the left -> 1 (clean signal) right.
    function cohAt(xN) { return smoothstep(0.34, 0.64, xN); }

    // Static seeds for the noise side.
    const seeds = new Float32Array(2048);
    for (let i = 0; i < seeds.length; i++) seeds[i] = Math.random() * 2 - 1;

    // Sparse particles biased to the noisy (left) side.
    const parts = [];
    for (let i = 0; i < 64; i++) {
      const r = Math.random();
      parts.push({ x: r * r * 0.7, y: Math.random(), s: Math.random() * 2 + 0.6, ph: Math.random() * 6.28 });
    }

    function resize() {
      const rect = canvas.getBoundingClientRect();
      W = Math.max(1, Math.round(rect.width));
      H = Math.max(1, Math.round(rect.height));
      dpr = Math.min(window.devicePixelRatio || 1, 2);
      canvas.width = Math.round(W * dpr);
      canvas.height = Math.round(H * dpr);
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      if (!running || reduce) frame(0, 1);
    }

    // Clean target signal: summed harmonics tapered to zero at the edges.
    function signalAt(xN, t) {
      const env = Math.sin(xN * Math.PI);
      const a = Math.sin(xN * Math.PI * 6 + t * 1.05);
      const b = Math.sin(xN * Math.PI * 13 - t * 0.7) * 0.36;
      const c = Math.sin(xN * Math.PI * 2.5 + t * 0.45) * 0.55;
      return ((a + b + c) / 2) * env;
    }

    function frame(t, intro) {
      ctx.clearRect(0, 0, W, H);
      if (W < 2 || H < 2) return;

      const mid = H * 0.5;
      const breathe = 0.82 + 0.18 * Math.sin(t * 0.6);
      const amp = H * 0.17 * breathe;
      const step = Math.max(2, Math.round(W / 560));

      // Chaos particles on the noise side.
      for (let i = 0; i < parts.length; i++) {
        const p = parts[i];
        const fade = 1 - cohAt(p.x);
        if (fade <= 0.02) continue;
        const jx = reduce ? 0 : Math.sin(t * 2 + p.ph) * 6;
        const jy = reduce ? 0 : Math.cos(t * 2.4 + p.ph) * 8;
        const px = p.x * W + jx;
        const py = mid + (p.y - 0.5) * H * 0.5 + jy;
        ctx.fillStyle = "rgba(192,57,43," + (0.18 * fade).toFixed(3) + ")";
        ctx.fillRect(px, py, p.s, p.s);
      }

      // Build waveform points: noise (left) morphs to signal (right).
      const pts = [];
      for (let x = 0; x <= W; x += step) {
        const xN = x / W;
        const coh = cohAt(xN);
        const si = Math.min(seeds.length - 1, Math.floor(xN * (seeds.length - 1)));
        const sig = signalAt(xN, t);
        const jitter = reduce ? seeds[si] : seeds[si] * 0.7 + Math.sin(xN * 140 + t * 7.5) * 0.5;
        const v = sig * coh + jitter * (1 - coh);
        pts.push(x, mid - v * amp);
      }

      // Horizontal red -> gold gradient (noise -> signal).
      const stroke = ctx.createLinearGradient(0, 0, W, 0);
      stroke.addColorStop(0.00, "rgba(192,57,43,0.85)");
      stroke.addColorStop(0.42, "rgba(176,86,52,0.80)");
      stroke.addColorStop(0.60, "rgba(212,166,74,0.92)");
      stroke.addColorStop(1.00, "rgba(232,200,120,1)");

      // Faint filled area.
      ctx.beginPath();
      ctx.moveTo(0, pts[1]);
      for (let i = 0; i < pts.length; i += 2) ctx.lineTo(pts[i], pts[i + 1]);
      ctx.lineTo(W, H);
      ctx.lineTo(0, H);
      ctx.closePath();
      const fill = ctx.createLinearGradient(0, mid - amp, 0, H);
      fill.addColorStop(0, "rgba(212,166,74,0.12)");
      fill.addColorStop(1, "rgba(212,166,74,0)");
      ctx.fillStyle = fill;
      ctx.fill();

      // Glowing stroke.
      ctx.beginPath();
      ctx.moveTo(pts[0], pts[1]);
      for (let i = 2; i < pts.length; i += 2) ctx.lineTo(pts[i], pts[i + 1]);
      ctx.lineJoin = "round";
      ctx.lineWidth = 2;
      ctx.shadowColor = "rgba(212,166,74,0.5)";
      ctx.shadowBlur = 14;
      ctx.strokeStyle = stroke;
      ctx.stroke();
      ctx.shadowBlur = 0;

      // Resolve glow where the signal locks in.
      const gx = W * 0.6;
      const glow = ctx.createRadialGradient(gx, mid, 0, gx, mid, H * 0.55);
      glow.addColorStop(0, "rgba(232,200,120,0.1)");
      glow.addColorStop(1, "rgba(232,200,120,0)");
      ctx.fillStyle = glow;
      ctx.fillRect(0, 0, W, H);

      // Baseline rule + sparse ticks for the field-guide print feel.
      ctx.strokeStyle = "rgba(212,166,74,0.14)";
      ctx.lineWidth = 1;
      ctx.beginPath();
      ctx.moveTo(0, mid);
      ctx.lineTo(W, mid);
      ctx.stroke();
      ctx.fillStyle = "rgba(212,166,74,0.22)";
      const ticks = 28;
      for (let i = 0; i <= ticks; i++) {
        const tx = (i / ticks) * W;
        const tall = i % 4 === 0;
        ctx.fillRect(tx, mid - (tall ? 5 : 3), 1, tall ? 10 : 6);
      }
    }

    function loop(nowMs) {
      if (!running) return;
      if (!startT) startT = nowMs;
      const t = (nowMs - startT) / 1000;
      frame(t, 1);
      raf = window.requestAnimationFrame(loop);
    }

    function play() {
      if (reduce || running) return;
      running = true;
      raf = window.requestAnimationFrame(loop);
    }
    function pause() {
      running = false;
      if (raf) window.cancelAnimationFrame(raf);
      raf = 0;
    }

    resize();
    if (reduce) frame(0, 1);
    else play();

    const onResize = () => resize();
    const onVis = () => {
      if (reduce) return;
      if (document.hidden) pause();
      else play();
    };
    window.addEventListener("resize", onResize);
    document.addEventListener("visibilitychange", onVis);

    const io = new IntersectionObserver(
      (entries) => {
        if (reduce) return;
        const e = entries[0];
        if (e && e.isIntersecting) play();
        else pause();
      },
      { threshold: 0 }
    );
    io.observe(canvas);

    return () => {
      pause();
      window.removeEventListener("resize", onResize);
      document.removeEventListener("visibilitychange", onVis);
      io.disconnect();
    };
  }, []);

  return (
    <div className="hero-waveform" aria-hidden="true">
      <canvas ref={canvasRef} />
    </div>
  );
}

function Hero() {
  const items = [
    { v: "5×", l: "Grammy nominated" },
    { v: "3,000,000,000+", l: "Streams" },
    { v: "400+", l: "Major records negotiated" },
    { v: "$1,000,000+", l: "In producer fees collected" },
    { v: "10+ yrs", l: "In music industry" },
    { v: "$0 → $20K", l: "Per placement, mapped" },
    { v: "BNYX · Cxdy · Pilgrim", l: "Worked alongside" },
    { v: "100% free tools", l: "Calculators, frameworks" },
  ];

  return (
    <section style={{ position: "relative", paddingTop: 36, paddingBottom: 0 }}>
      <div className="page" style={{ position: "relative" }}>

        <HeroWaveform />

        {/* COVER GRID - 4 col mobile · 8 col tablet · 12 col desktop */}
        <div className="grid" style={{ alignItems: "end", position: "relative", zIndex: 1 }}>

          {/* Left rail: desktop-only editorial detail */}
          <div
            className="col-lg-1 hide-mobile"
            style={{
              display: "flex",
              flexDirection: "column",
              justifyContent: "space-between",
              paddingTop: 12,
              paddingBottom: 24,
              minHeight: "min(78vh, 700px)",
            }}
          >
            <span className="vert">Producer Union · Field Guide</span>
            <span className="caption" style={{ writingMode: "vertical-rl", transform: "rotate(180deg)" }}>
              No. 001
            </span>
          </div>

          {/* Main content column */}
          <div className="col-4 col-md-5 col-lg-8" style={{ paddingBottom: 24 }}>

            <div style={{ marginTop: 24, marginBottom: 32, display: "flex", gap: 16, alignItems: "center", flexWrap: "wrap" }}>
              <SectionLabel label="Field guide" />
              <span className="caption hide-mobile">For producers who've made the decision</span>
            </div>

            <h1 className="h-display display" style={{ margin: 0 }}>
              Most producers<br />
              have <em>talent.</em><br />
              <span className="gold">Almost none</span><br />
              have the <em>roadmap.</em>
            </h1>

            {/* Lede + byline: stacked on mobile, side-by-side on md+ */}
            <div style={{ marginTop: 40, display: "flex", gap: "clamp(24px, 3vw, 40px)", flexWrap: "wrap", alignItems: "flex-start" }}>
              <p className="lede" style={{ margin: 0, flex: "1 1 220px" }}>
                Producer Union is where career-track producers stop guessing and start building. Know what you're worth, how to negotiate it, how to protect it, how to compound it.
              </p>
              <div style={{ flex: "0 0 auto" }}>
                <div className="caption" style={{ marginBottom: 8 }}>Filed by</div>
                <div style={{ fontFamily: "var(--sans)", fontSize: 22, fontWeight: 500 }}>
                  Aidan "Halfway" Crotinger
                </div>
                <div className="caption" style={{ marginTop: 4 }}>FOUNDER · SPLITMIND · DRUMIFY</div>
              </div>
            </div>

            {/* CTAs: full-width stacked on mobile, inline on md+ */}
            <div style={{ marginTop: 40, display: "flex", gap: 12, flexWrap: "wrap" }}>
              <JoinCta href={PU_LINKS.free} style={{ flex: "1 1 180px" }}>Join free on Skool</JoinCta>
              <JoinCta href={PU_LINKS.plus} variant="ghost" style={{ flex: "1 1 180px" }}>Start the Roadmap</JoinCta>
            </div>

            {/* Receipt: mobile only, shown after CTAs */}
            <div className="hero-receipt-mobile" style={{ marginTop: 36, maxWidth: 320 }}>
              <ReceiptCard />
            </div>

          </div>

          {/* Right column: receipt: tablet + desktop only */}
          <div
            className="hero-receipt-desktop col-md-3 col-lg-3"
            style={{
              display: "flex",
              flexDirection: "column",
              justifyContent: "flex-end",
              paddingBottom: 12,
              gap: 24,
            }}
          >
            <ReceiptCard />
          </div>

        </div>
      </div>

      {/* INFINITE TICKER */}
      <div style={{ marginTop: 56 }}>
        <Marquee items={items} />
      </div>

      {/* Secondary ticker, slower, reverse */}
      <Marquee
        slow
        reverse
        accent
        items={[
          { v: "\u201cThis page is the map I never had.\u201d", l: "member" },
          { v: "$14,200 in royalties recovered", l: "in 90 days" },
          { v: "Beat lease \u2192 Major label rate", l: "in one negotiation" },
          { v: "\u201cI left $30K on the table.\u201d", l: "before" },
          { v: "Indie \u00b7 Indie + Distro \u00b7 Signed \u00b7 Major", l: "Five artist tiers" },
          { v: "Performance \u00b7 Mechanical \u00b7 Master \u00b7 Sync", l: "Four royalty streams" },
        ]}
      />

    </section>
  );
}

function ReceiptCard() {
  return (
    <Reveal>
      <div style={{
        background: "var(--bg-paper)",
        color: "var(--bg-paper-ink)",
        padding: "20px 18px 24px",
        position: "relative",
        boxShadow: "0 30px 60px -20px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.04)",
        transform: "rotate(2.2deg)",
        fontFamily: "var(--mono)",
      }}>
        <div style={{ fontSize: 10, letterSpacing: "0.18em", textTransform: "uppercase", color: "rgba(24,19,12,0.55)", marginBottom: 12, display: "flex", justifyContent: "space-between" }}>
          <span>RECEIPT №</span><span>0001</span>
        </div>
        <div style={{ fontFamily: "var(--sans)", fontWeight: 800, fontSize: 22, letterSpacing: "-0.02em", lineHeight: 1.05 }}>
          One Beat,<br />Fully Collected
        </div>
        <div style={{ borderTop: "1px dashed rgba(24,19,12,0.4)", margin: "16px 0" }}></div>
        <Row label="Producer fee" v="$5,000" />
        <Row label="Publishing %" v="50%" />
        <Row label="Master royalty %" v="4%" />
        <Row label="Streaming (24mo est.)" v="$8,400" />
        <Row label="Sync potential" v="$12K+" />
        <div style={{ borderTop: "1px dashed rgba(24,19,12,0.4)", margin: "12px 0" }}></div>
        <Row label="TOTAL VALUE" v="$25,400+" bold />
        <div style={{ borderTop: "1px solid rgba(24,19,12,0.8)", margin: "12px 0 0", paddingTop: 10, fontSize: 9, letterSpacing: "0.16em", textTransform: "uppercase", color: "rgba(24,19,12,0.55)", textAlign: "center" }}>
          ★ ★ ★ THANK YOU ★ ★ ★
        </div>
      </div>
    </Reveal>
  );
}

function Row({ label, v, bold }) {
  return (
    <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11, padding: "3px 0", fontWeight: bold ? 700 : 400 }}>
      <span>{label}</span>
      <span style={{ fontVariantNumeric: "tabular-nums" }}>{v}</span>
    </div>
  );
}

function Marquee({ items, slow, reverse, accent }) {
  const track =
    <div className="marquee__track">
      {items.concat(items).map((it, i) =>
        <span key={i} className="marquee__item" style={accent ? { color: "var(--ink-2)" } : {}}>
          <span className={accent ? "pull-serif" : ""} style={accent ? { fontSize: "0.82em", color: "var(--ink)" } : { color: "var(--gold)" }}>
            {it.v}
          </span>
          <span className="lbl">{it.l}</span>
          <span className="star">✦</span>
        </span>
      )}
    </div>;

  return (
    <div className={`marquee ${slow ? "slow" : ""} ${reverse ? "reverse" : ""}`}>
      {track}
    </div>
  );
}

window.Hero = Hero;
