// Solutions ALXL — hi-fi sections (scrolly + chain + case + contact)
const { useState, useEffect, useRef, useMemo } = React;

// === Hook: scroll progress within a ref ===
function useScrollProgress(ref) {
  const [p, setP] = useState(0);
  useEffect(() => {
    function on() {
      const el = ref.current; if (!el) return;
      const rect = el.getBoundingClientRect();
      const vh = window.innerHeight;
      const total = rect.height - vh;
      const scrolled = Math.max(0, Math.min(total, -rect.top));
      setP(total > 0 ? scrolled / total : 0);
    }
    window.addEventListener("scroll", on, { passive: true });
    window.addEventListener("resize", on);
    on();
    return () => { window.removeEventListener("scroll", on); window.removeEventListener("resize", on); };
  }, [ref]);
  return p;
}

// === HERO ===
function Hero({ t }) {
  return (
    <section id="top" className="hero">
      <div className="hero__grid" />
      <div className="wrap hero__inner">
        <div>
          <div className="hero__meta">
            {t.hero.meta.map(([k,v]) => (
              <div key={k} className="hero__meta-item"><div className="k">{k}</div><div className="v">{v}</div></div>
            ))}
          </div>
          <div className="eyebrow light" style={{marginBottom: 28}}>{t.hero.eyebrow}</div>
          <h1>
            {t.hero.title_a}<br/>
            {t.hero.title_b}<br/>
            <span className="accent">{t.hero.title_c}</span>
          </h1>
          <p className="lede hero__sub">{t.hero.sub}</p>
          <div className="hero__cta">
            <a href="#contact" className="btn btn--primary">{t.hero.cta1} <span className="btn__arrow">→</span></a>
            <a href="#how" className="btn btn--ghost-light">{t.hero.cta2}</a>
          </div>
        </div>
        <BlueprintFigure t={t} />
      </div>
    </section>
  );
}

function BlueprintFigure({ t }) {
  // a stylized data-convergence schematic
  return (
    <div className="hero__visual">
      <svg viewBox="0 0 560 560" fill="none" stroke="rgba(255,255,255,.5)" strokeWidth="1">
        {/* dimension border */}
        <rect x="40" y="40" width="480" height="480" stroke="rgba(255,255,255,.18)" strokeDasharray="2 6" />
        {/* corner ticks */}
        {[[40,40],[520,40],[40,520],[520,520]].map(([x,y],i)=>(
          <g key={i} stroke="rgba(255,255,255,.7)">
            <line x1={x-10} y1={y} x2={x+10} y2={y}/>
            <line x1={x} y1={y-10} x2={x} y2={y+10}/>
          </g>
        ))}
        {/* dim line top */}
        <g stroke="rgba(255,255,255,.55)" strokeWidth=".8">
          <line x1="60" y1="22" x2="500" y2="22"/>
          <line x1="60" y1="16" x2="60" y2="28"/>
          <line x1="500" y1="16" x2="500" y2="28"/>
          <text x="280" y="18" fill="rgba(255,255,255,.7)" fontFamily="JetBrains Mono" fontSize="10" textAnchor="middle">DATA CHAIN · 6 STAGES</text>
        </g>

        {/* sensors on left side */}
        {[120, 220, 320, 420].map((y,i)=>(
          <g key={i}>
            <circle cx="100" cy={y} r="14" stroke="#4a90ff" strokeWidth="1.4"/>
            <circle cx="100" cy={y} r="4" fill="#4a90ff" stroke="none"/>
            <text x="60" y={y+4} fill="rgba(255,255,255,.55)" fontFamily="JetBrains Mono" fontSize="10" textAnchor="end">CH{i+1}</text>
          </g>
        ))}

        {/* converging lines */}
        {[120,220,320,420].map((y,i)=>(
          <path key={i} d={`M 114 ${y} C 200 ${y}, 240 280, 280 280`} stroke="#4a90ff" strokeWidth="1.2" opacity=".7"/>
        ))}

        {/* central processing block */}
        <rect x="280" y="240" width="120" height="80" stroke="#fff" strokeWidth="1.4" fill="rgba(30,111,217,.18)"/>
        <text x="340" y="275" fill="#fff" fontFamily="JetBrains Mono" fontSize="11" textAnchor="middle">DAQ · CALIB</text>
        <text x="340" y="293" fill="rgba(255,255,255,.7)" fontFamily="JetBrains Mono" fontSize="9" textAnchor="middle">↓ TIMESTAMPED</text>

        {/* DB cylinder */}
        <g transform="translate(420, 220)">
          <ellipse cx="40" cy="20" rx="38" ry="10" stroke="#4a90ff" strokeWidth="1.4"/>
          <path d="M 2 20 V 100" stroke="#4a90ff" strokeWidth="1.4"/>
          <path d="M 78 20 V 100" stroke="#4a90ff" strokeWidth="1.4"/>
          <ellipse cx="40" cy="100" rx="38" ry="10" stroke="#4a90ff" strokeWidth="1.4" fill="rgba(30,111,217,.18)"/>
          <ellipse cx="40" cy="60" rx="38" ry="10" stroke="rgba(255,255,255,.3)" strokeWidth=".7" strokeDasharray="2 3" fill="none"/>
          <text x="40" y="64" fill="rgba(255,255,255,.7)" fontFamily="JetBrains Mono" fontSize="9" textAnchor="middle">BDD</text>
        </g>
        <path d="M 400 280 L 420 270" stroke="#4a90ff" strokeWidth="1.2"/>

        {/* report PDF icon bottom */}
        <g transform="translate(220, 420)">
          <rect width="120" height="80" stroke="#fff" strokeWidth="1.4" fill="none"/>
          <line x1="10" y1="20" x2="80" y2="20" stroke="rgba(255,255,255,.4)"/>
          <line x1="10" y1="32" x2="100" y2="32" stroke="rgba(255,255,255,.4)"/>
          <line x1="10" y1="44" x2="70" y2="44" stroke="rgba(255,255,255,.4)"/>
          <path d="M 10 56 L 30 50 L 50 58 L 70 48 L 90 54 L 110 50" stroke="#4a90ff" strokeWidth="1.4" fill="none"/>
          <text x="60" y="72" fill="rgba(255,255,255,.55)" fontFamily="JetBrains Mono" fontSize="9" textAnchor="middle">RAPPORT.PDF</text>
        </g>
        <path d="M 340 320 L 280 420" stroke="#4a90ff" strokeWidth="1.2"/>

        {/* annotation */}
        <text x="510" y="540" fill="rgba(255,255,255,.45)" fontFamily="JetBrains Mono" fontSize="9" textAnchor="end">{t.hero.scale}</text>
        <text x="50" y="540" fill="rgba(255,255,255,.45)" fontFamily="JetBrains Mono" fontSize="9">{t.hero.sheet}</text>
      </svg>
    </div>
  );
}

// === KPI strip ===
function KpiStrip({ t }) {
  return (
    <section className="kpi-strip">
      <div className="wrap kpi-strip__inner">
        {t.kpi.map(([v, unit, k], i) => (
          <div key={i} className="kpi">
            <div className="v">{v}<span className="unit">{unit}</span></div>
            <div className="k">{k}</div>
          </div>
        ))}
      </div>
    </section>
  );
}

// === Manifesto strip ===
function Manifesto({ t }) {
  return (
    <section id="how" className="manifesto">
      <div className="wrap manifesto__inner">
        <div className="eyebrow muted">{t.manifesto.eyebrow}</div>
        <h2>
          {t.manifesto.headline_a} {t.manifesto.headline_b}<br/>
          {t.manifesto.headline_c}<em>{t.manifesto.headline_em}</em>{t.manifesto.headline_d}
        </h2>
      </div>
    </section>
  );
}

// === SCROLLY 1 — Besoins → Specs (sticky right column reveals specs as user scrolls steps) ===
function ScrollyNeedsSpecs({ t }) {
  const containerRef = useRef(null);
  const p = useScrollProgress(containerRef);
  const n = t.scrolly.steps.length;
  // active index: divide scroll progress into n bands
  const active = Math.min(n - 1, Math.max(0, Math.floor(p * n * 1.05)));

  return (
    <section ref={containerRef} className="scrolly section--paper">
      <div className="wrap" style={{ paddingTop: 80, paddingBottom: 8 }}>
        <div className="section__head" style={{ marginBottom: 24 }}>
          <div>
            <div className="eyebrow">{t.scrolly.eyebrow}</div>
          </div>
          <div>
            <h2>{t.scrolly.title}</h2>
            <p className="blurb" style={{ marginTop: 14, color: "var(--mute)" }}>{t.scrolly.blurb}</p>
          </div>
        </div>
      </div>

      <div className="scrolly__inner">
        <div className="scrolly__left">
          <div className="scrolly__steps">
            {t.scrolly.steps.map((s, i) => (
              <div key={i} className={`scrolly__step ${i === active ? "is-active" : ""}`}>
                <div className="scrolly__quote">{s.quote}</div>
                <div className="scrolly__quote-meta mono" style={{ color: "var(--mute)", fontSize: 12, letterSpacing: ".14em" }}>{s.who.toUpperCase()}</div>
              </div>
            ))}
          </div>
        </div>
        <div className="scrolly__right">
          <div className="scrolly__sticky">
            <div className="eyebrow light" style={{ marginBottom: 18 }}>{t.viz.output_label}</div>
            <div style={{ display: "grid", gap: 16 }}>
              {t.scrolly.steps.map((s, i) => (
                <SpecCard key={i} spec={s.spec} state={i < active ? "done" : i === active ? "current" : "pending"} vt={t.viz} />
              ))}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

function SpecCard({ spec, state, vt }) {
  return (
    <div className={`spec-card ${state === "pending" ? "is-pending" : ""} ${state === "current" ? "is-current" : ""}`}>
      <div className="spec-card__head">
        <span className="mono spec-card__id">{spec.id}</span>
        <span className="mono" style={{ color: state === "done" ? "var(--green)" : "rgba(255,255,255,.45)", fontSize: 11, letterSpacing: ".14em" }}>
          {state === "done" ? vt.signed : state === "current" ? vt.draft : "—"}
        </span>
      </div>
      <div className="spec-card__title">{spec.title}</div>
      <div className="spec-card__body">
        {spec.rows.map(([k, v]) => (
          <React.Fragment key={k}><div className="k">{k}</div><div>{v}</div></React.Fragment>
        ))}
      </div>
      <div className="spec-card__sign">
        <span>{vt.sign_off}</span><div className="spec-card__sign-line" /><span>ALXL · 2026</span>
      </div>
    </div>
  );
}

// === SCROLLY 2 — Prototype assembly ===
function ScrollyAssembly({ t }) {
  const containerRef = useRef(null);
  const p = useScrollProgress(containerRef);
  const n = t.assembly.steps.length;
  const active = Math.min(n - 1, Math.max(0, Math.floor(p * n * 1.05)));

  return (
    <section ref={containerRef} className="assembly">
      <div className="wrap" style={{ paddingTop: 120, paddingBottom: 16 }}>
        <div className="section__head">
          <div>
            <div className="eyebrow light">{t.assembly.eyebrow}</div>
          </div>
          <div>
            <h2 style={{ color: "#fff" }}>{t.assembly.title}</h2>
            <p className="blurb" style={{ marginTop: 14 }}>{t.assembly.blurb}</p>
          </div>
        </div>
      </div>

      <div className="assembly__grid">
        <div className="assembly__copy">
          {t.assembly.steps.map((s, i) => (
            <div key={s.id} className="assembly__step">
              <div className="assembly__step-inner" style={{ opacity: i === active ? 1 : .35, transition: "opacity .4s ease" }}>
                <div className="eyebrow light">Couche {s.id}</div>
                <h3 style={{ color: "#fff", fontSize: 40, lineHeight: 1.02, marginTop: 12, fontWeight: 500 }}>{s.name}</h3>
                <p style={{ marginTop: 16, color: "rgba(255,255,255,.75)", maxWidth: 44 + "ch" }}>{s.desc}</p>
                <div className="layer-list">
                  {s.deliverables.map((d, j) => (
                    <div key={j} className="layer-list__item">
                      <div className="layer-list__id">{`0${j+1}`}</div>
                      <div>
                        <div className="layer-list__name">{d}</div>
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            </div>
          ))}
        </div>
        <div className="assembly__stage">
          <div className="assembly__sticky">
            <AssemblyFigure active={active} t={t} />
          </div>
        </div>
      </div>
    </section>
  );
}

function AssemblyFigure({ active, t }) {
  // i = 0 mech (bottom of stack), i = 1 acquisition (middle), i = 2 software (top)
  const labels = ["Mécanique", "Acquisition", "Logiciel"];
  const SVG_W = 480, SVG_H = 560;
  const CX = SVG_W / 2;          // 240
  const CY = SVG_H / 2;          // 280  — vertical center
  const SPACING = 70;            // center-to-center between stacked panels (isometric overlap)
  const PANEL_HALF_H = 45;       // panel is 90 tall, its centre is 45 from its top

  // For a given (active, i), compute the centre Y if the layer is visible.
  // Visible layers are stacked top→bottom in the order [software, acquisition, mech]
  // (i.e. in descending i), and the whole stack stays centred on CY.
  // Rank from top within visible group = active - i (0 = topmost).
  const targetCenterY = (i) => {
    const rankFromTop = active - i;
    const groupTop = CY - (active * SPACING) / 2;
    return groupTop + rankFromTop * SPACING;
  };

  return (
    <svg viewBox={`0 0 ${SVG_W} ${SVG_H}`} style={{ width: "min(90%, 480px)" }} fill="none">
      {/* faint axis at vertical centre */}
      <line x1="60" y1={CY} x2={SVG_W - 60} y2={CY} stroke="rgba(255,255,255,.10)" strokeDasharray="3 5"/>

      {/* annotation top */}
      <g fill="rgba(255,255,255,.55)" fontFamily="JetBrains Mono" fontSize="10">
        <text x={CX} y="36" textAnchor="middle">{t.assembly.stage_label}</text>
      </g>

      {/* progress dots at right (top = L03, bottom = L01) */}
      <g>
        {[2, 1, 0].map((i, row) => (
          <g key={i} transform={`translate(${SVG_W - 60}, ${CY - 90 + row * 90})`}>
            <circle cx="0" cy="0" r="5"
              fill={active >= i ? "#4a90ff" : "transparent"}
              stroke={active >= i ? "#4a90ff" : "rgba(255,255,255,.4)"} strokeWidth="1.4"/>
            <text x="14" y="4" fill={active === i ? "#fff" : "rgba(255,255,255,.45)"} fontFamily="JetBrains Mono" fontSize="10">L0{i+1}</text>
          </g>
        ))}
      </g>

      {/* Render layers BOTTOM (mech) → TOP (software) so top draws over bottom for iso overlap */}
      {[0, 1, 2].map((i) => {
        const isVisible = active >= i;
        const isActive = active === i;
        // when not yet visible, sit above the SVG with 0 opacity so reveal slides+fades in
        const visibleCY = targetCenterY(i);
        const hiddenCY = CY - 220;   // entry point above the stack
        const centerY = isVisible ? visibleCY : hiddenCY;
        const tx = CX - 120;         // panel is 240 wide → shift so its centre lands at CX
        const ty = centerY - PANEL_HALF_H;

        const stroke   = isActive ? "#4a90ff" : isVisible ? "#fff" : "rgba(255,255,255,.45)";
        const sw       = isActive ? 1.8 : 1.2;
        const fillTop  = isActive ? "rgba(30,111,217,.22)" : isVisible ? "rgba(255,255,255,.08)" : "rgba(255,255,255,.04)";
        const fillL    = isActive ? "rgba(30,111,217,.34)" : isVisible ? "rgba(255,255,255,.12)" : "rgba(255,255,255,.06)";
        const fillR    = isActive ? "rgba(30,111,217,.16)" : isVisible ? "rgba(255,255,255,.06)" : "rgba(255,255,255,.03)";

        return (
          <g key={i}
             style={{
               transform: `translate(${tx}px, ${ty}px)`,
               transition: "transform .9s cubic-bezier(.6,.05,.25,1), opacity .6s ease",
               opacity: isVisible ? 1 : 0,
             }}>
            {/* iso panel */}
            <polygon points="0,30 120,0 240,30 120,60" stroke={stroke} strokeWidth={sw} fill={fillTop}/>
            <polygon points="0,30 120,60 120,90 0,60"   stroke={stroke} strokeWidth={sw} fill={fillL}/>
            <polygon points="120,60 240,30 240,60 120,90" stroke={stroke} strokeWidth={sw} fill={fillR}/>

            {/* ornaments per layer */}
            {i === 0 && (
              <>
                <circle cx="60" cy="20" r="8" stroke={stroke} strokeWidth="1" fill="none"/>
                <circle cx="180" cy="20" r="8" stroke={stroke} strokeWidth="1" fill="none"/>
                <line x1="60" y1="20" x2="180" y2="20" stroke={stroke} strokeWidth=".6" strokeDasharray="2 3"/>
              </>
            )}
            {i === 1 && (
              <>
                <rect x="30" y="14" width="22" height="8" fill="#4a90ff" opacity={isVisible ? 1 : .5}/>
                <rect x="60" y="16" width="14" height="4" fill={stroke} opacity=".6"/>
                <rect x="82" y="14" width="22" height="8" fill={stroke} opacity=".5"/>
                <circle cx="175" cy="22" r="5" fill="#4a90ff" opacity={isVisible ? 1 : .5}/>
                <line x1="30" y1="30" x2="210" y2="30" stroke="#4a90ff" strokeWidth=".6" opacity={isVisible ? .8 : .3}/>
              </>
            )}
            {i === 2 && (
              <>
                <line x1="30" y1="14" x2="100" y2="14" stroke={stroke} strokeWidth=".8" opacity=".8"/>
                <line x1="30" y1="22" x2="80" y2="22" stroke={stroke} strokeWidth=".8" opacity=".8"/>
                <line x1="140" y1="14" x2="210" y2="14" stroke={stroke} strokeWidth=".8" opacity=".8"/>
                <line x1="140" y1="22" x2="180" y2="22" stroke={stroke} strokeWidth=".8" opacity=".8"/>
                <circle cx="110" cy="30" r="2.5" fill={stroke}/>
              </>
            )}

            {/* label below panel, left of panel so it doesn't collide with next layer */}
            <text x="-12" y="48"
                  textAnchor="end"
                  fill={isActive ? "#fff" : isVisible ? "rgba(255,255,255,.7)" : "rgba(255,255,255,.4)"}
                  fontFamily="JetBrains Mono" fontSize="11" letterSpacing="1">
              {labels[i].toUpperCase()}
            </text>
          </g>
        );
      })}
    </svg>
  );
}

// === CHAIN ===
function ChainSection({ t }) {
  const [open, setOpen] = useState(0);
  const node = t.chain.nodes[open];
  return (
    <section id="banc" className="section section--paper-2">
      <div className="wrap">
        <div className="section__head">
          <div><div className="eyebrow">{t.chain.eyebrow}</div></div>
          <div>
            <h2>{t.chain.title}</h2>
            <p className="blurb" style={{ marginTop: 14, color: "var(--mute)" }}>{t.chain.blurb}</p>
          </div>
        </div>
        <div className="chain-wrap">
          <div className="chain">
            {t.chain.nodes.map((n, i) => (
              <div key={n.id} className={`chain__node ${open === i ? "is-open" : ""}`} onClick={() => setOpen(i)}>
                <div className="chain__id">{n.id} · {n.sub}</div>
                <div className="chain__name">{n.name}</div>
                <div style={{ flex: 1 }} />
                <div className="chain__sub">{n.title}</div>
              </div>
            ))}
          </div>
        </div>
        <div className="chain__detail">
          <div>
            <div className="eyebrow light">{node.id} · {node.name}</div>
            <h3 style={{ marginTop: 12 }}>{node.title}</h3>
            <p className="chain__detail-body" style={{ marginTop: 14 }}>{node.body}</p>
            <div className="chain__detail-tools">
              {node.tools.map(tool => <span key={tool} className="tag">{tool}</span>)}
            </div>
          </div>
          <ChainVisual idx={open} vt={t.viz} />
        </div>
      </div>
    </section>
  );
}

function ChainVisual({ idx, vt }) {
  // Different mini-figures for each step
  if (idx === 0) return <SensorViz vt={vt}/>;
  if (idx === 1) return <CalibViz vt={vt}/>;
  if (idx === 2) return <DaqViz vt={vt}/>;
  if (idx === 3) return <DbViz vt={vt}/>;
  if (idx === 4) return <AnalysisViz vt={vt}/>;
  return <ReportViz vt={vt}/>;
}

const vizFrame = { background:"#050a14", border:"1px solid rgba(255,255,255,.12)", padding:18, borderRadius:2, minHeight: 200, display:"flex", flexDirection:"column" };
const vizLabel = { fontFamily:"'JetBrains Mono',monospace", fontSize:10, color:"rgba(255,255,255,.45)", letterSpacing:".14em", marginTop:"auto", paddingTop: 12 };

function SensorViz({vt}) {
  return (
    <div style={vizFrame}>
      <svg viewBox="0 0 320 160" style={{ width:"100%", height: 160 }} fill="none" stroke="#4a90ff">
        <rect x="40" y="50" width="60" height="60" stroke="#fff" strokeWidth="1.2"/>
        <text x="70" y="84" fill="rgba(255,255,255,.7)" fontFamily="JetBrains Mono" fontSize="10" textAnchor="middle">CAPTEUR</text>
        <path d="M 100 80 L 200 80" stroke="#4a90ff" strokeWidth="1.4"/>
        <rect x="200" y="40" width="100" height="80" stroke="#fff" strokeWidth="1.2"/>
        <path d="M 210 80 Q 230 60 250 80 T 290 80" stroke="#4a90ff" strokeWidth="1.4"/>
        <text x="250" y="135" fill="rgba(255,255,255,.5)" fontFamily="JetBrains Mono" fontSize="9" textAnchor="middle">{vt.sensor_a}</text>
      </svg>
      <div style={vizLabel}>{vt.sensor_b}</div>
    </div>
  );
}
function CalibViz({vt}) {
  return (
    <div style={vizFrame}>
      <svg viewBox="0 0 320 160" style={{ width:"100%", height: 160 }}>
        <g stroke="rgba(255,255,255,.15)">
          {[0,1,2,3,4].map(i => <line key={i} x1={40+i*60} y1="20" x2={40+i*60} y2="120"/>)}
          {[0,1,2,3].map(i => <line key={i} x1="40" y1={20+i*30} x2="280" y2={20+i*30}/>)}
        </g>
        <line x1="40" y1="120" x2="280" y2="20" stroke="#4a90ff" strokeWidth="1.6"/>
        <line x1="40" y1="120" x2="280" y2="40" stroke="#fff" strokeWidth="1" strokeDasharray="3 3"/>
        <text x="60" y="140" fill="rgba(255,255,255,.55)" fontFamily="JetBrains Mono" fontSize="9">{vt.calib_a}</text>
        <text x="280" y="14" fill="#4a90ff" fontFamily="JetBrains Mono" fontSize="9" textAnchor="end">R² = 0.9994</text>
      </svg>
      <div style={vizLabel}>{vt.calib_b}</div>
    </div>
  );
}
function DaqViz({vt}) {
  return (
    <div style={vizFrame}>
      <svg viewBox="0 0 320 160" style={{ width:"100%", height: 160 }} fill="none">
        <rect x="80" y="40" width="160" height="80" stroke="#fff" strokeWidth="1.2"/>
        <text x="160" y="76" fill="#fff" fontFamily="JetBrains Mono" fontSize="11" textAnchor="middle">{vt.daq_a}</text>
        <text x="160" y="94" fill="rgba(255,255,255,.5)" fontFamily="JetBrains Mono" fontSize="9" textAnchor="middle">{vt.daq_b}</text>
        {[0,1,2,3].map(i => (
          <g key={i}>
            <line x1="20" y1={50+i*16} x2="80" y2={50+i*16} stroke="#4a90ff" strokeWidth="1.2"/>
            <circle cx="22" cy={50+i*16} r="3" fill="#4a90ff"/>
          </g>
        ))}
        <text x="14" y="14" fill="rgba(255,255,255,.5)" fontFamily="JetBrains Mono" fontSize="9">{vt.daq_c}</text>
        <path d="M 240 80 L 300 80" stroke="#4a90ff" strokeWidth="1.4"/>
        <text x="270" y="74" fill="rgba(255,255,255,.55)" fontFamily="JetBrains Mono" fontSize="9" textAnchor="middle">{vt.daq_d}</text>
      </svg>
      <div style={vizLabel}>{vt.daq_e}</div>
    </div>
  );
}
function DbViz({vt}) {
  return (
    <div style={vizFrame}>
      <svg viewBox="0 0 320 160" style={{ width:"100%", height: 160 }} fill="none" stroke="#4a90ff">
        <ellipse cx="160" cy="40" rx="60" ry="14" strokeWidth="1.4"/>
        <line x1="100" y1="40" x2="100" y2="120" strokeWidth="1.4"/>
        <line x1="220" y1="40" x2="220" y2="120" strokeWidth="1.4"/>
        <ellipse cx="160" cy="120" rx="60" ry="14" strokeWidth="1.4" fill="rgba(30,111,217,.15)"/>
        <ellipse cx="160" cy="65" rx="60" ry="14" stroke="rgba(255,255,255,.3)" strokeWidth=".8" strokeDasharray="2 3"/>
        <ellipse cx="160" cy="90" rx="60" ry="14" stroke="rgba(255,255,255,.3)" strokeWidth=".8" strokeDasharray="2 3"/>
        <text x="160" y="78" fill="rgba(255,255,255,.7)" fontFamily="JetBrains Mono" fontSize="10" textAnchor="middle">{vt.db_a}</text>
        <text x="160" y="104" fill="rgba(255,255,255,.5)" fontFamily="JetBrains Mono" fontSize="9" textAnchor="middle">{vt.db_b}</text>
      </svg>
      <div style={vizLabel}>{vt.db_c}</div>
    </div>
  );
}
function AnalysisViz({vt}) {
  return (
    <div style={vizFrame}>
      <svg viewBox="0 0 320 160" style={{ width:"100%", height: 160 }} fill="none">
        <g stroke="rgba(255,255,255,.12)">
          {[0,1,2,3,4].map(i => <line key={i} x1="20" y1={20+i*25} x2="300" y2={20+i*25}/>)}
        </g>
        <path d="M 20 80 Q 60 30 100 80 T 180 80 T 260 80 L 300 80" stroke="rgba(255,255,255,.4)" strokeWidth="1" strokeDasharray="2 2"/>
        <path d="M 20 80 Q 60 50 100 80 T 180 80 T 260 80 L 300 80" stroke="#4a90ff" strokeWidth="1.8"/>
        <text x="290" y="40" fill="#4a90ff" fontFamily="JetBrains Mono" fontSize="10" textAnchor="end">τ = 0.42 s</text>
        <text x="290" y="54" fill="#4a90ff" fontFamily="JetBrains Mono" fontSize="10" textAnchor="end">ζ = 0.71</text>
      </svg>
      <div style={vizLabel}>{vt.analysis_c}</div>
    </div>
  );
}
function ReportViz({vt}) {
  return (
    <div style={vizFrame}>
      <svg viewBox="0 0 320 160" style={{ width:"100%", height: 160 }} fill="none">
        <rect x="80" y="20" width="160" height="120" stroke="#fff" strokeWidth="1.2"/>
        <line x1="92" y1="40" x2="220" y2="40" stroke="rgba(255,255,255,.4)" strokeWidth="1"/>
        <line x1="92" y1="52" x2="200" y2="52" stroke="rgba(255,255,255,.3)" strokeWidth="1"/>
        <line x1="92" y1="62" x2="190" y2="62" stroke="rgba(255,255,255,.3)" strokeWidth="1"/>
        <rect x="92" y="76" width="128" height="40" fill="rgba(30,111,217,.18)" stroke="#4a90ff" strokeWidth=".8"/>
        <path d="M 92 100 L 110 90 L 130 102 L 150 84 L 170 96 L 190 88 L 220 92" stroke="#4a90ff" strokeWidth="1.4"/>
        <line x1="92" y1="124" x2="180" y2="124" stroke="rgba(255,255,255,.3)" strokeWidth="1"/>
        <text x="160" y="156" fill="rgba(255,255,255,.5)" fontFamily="JetBrains Mono" fontSize="9" textAnchor="middle">{vt.report_a}</text>
      </svg>
      <div style={vizLabel}>{vt.report_b}</div>
    </div>
  );
}

// === CASE STUDY ===
function CaseStudy({ t }) {
  return (
    <section id="cas" className="section section--paper">
      <div className="wrap">
        <div className="section__head">
          <div><div className="eyebrow">{t.cas.eyebrow}</div></div>
          <div>
            <h2>{t.cas.title}</h2>
            <p className="blurb" style={{ marginTop: 14, color: "var(--mute)" }}>{t.cas.blurb}</p>
          </div>
        </div>

        <div className="case">
          {/* BEFORE */}
          <div className="case-col case-col--before">
            <div className="case-col__tag">
              <span className="dot"/>
              <span className="eyebrow muted" style={{color:"var(--red)"}}>{t.cas.before.tag}</span>
            </div>
            <h3>{t.cas.before.title}</h3>
            <div>
              {t.cas.before.rows.map(([k, v]) => (
                <div key={k} className="case-row">
                  <div className="k">{k}</div><div className="v">{v}</div>
                </div>
              ))}
            </div>
            <div className="case-visual case-visual--chart">
              <BeforeChart vt={t.viz}/>
            </div>
          </div>

          {/* AFTER */}
          <div className="case-col case-col--after">
            <div className="case-col__tag"><span className="dot"/><span className="eyebrow light">{t.cas.after.tag}</span></div>
            <h3>{t.cas.after.title}</h3>
            <div>
              {t.cas.after.rows.map(([k, v]) => (
                <div key={k} className="case-row"><div className="k">{k}</div><div className="v">{v}</div></div>
              ))}
            </div>
            <div className="case-visual">
              <LiveTrace />
              <div className="case-visual__label">{t.cas.after.scope}</div>
            </div>
          </div>
        </div>

        <div className="metrics-strip">
          {t.cas.metrics.map((m, i) => (
            <div key={i} className="metric">
              <div className="v">{m[0]}{m.length === 3 ? <span className="unit">{m[1]}</span> : null}</div>
              <div className="k">{m[m.length - 1]}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

function BeforeChart({ vt }) {
  // Sparse, static, hand-recorded points on a paper-style grid (manual readings)
  const points = [
    [42, 84], [78, 80], [106, 92], [138, 76],
    [174, 88], [206, 70], [232, 96], [266, 78],
    [298, 84], [322, 72], [350, 90], [378, 76],
    [402, 86], [422, 74],
  ];
  return (
    <svg viewBox="0 0 440 170" style={{ position:"absolute", inset: 0, width:"100%", height:"100%" }} preserveAspectRatio="none">
      <g stroke="rgba(13,31,58,.10)" strokeWidth=".6">
        {Array.from({length:11}).map((_,i)=><line key={"v"+i} x1={20+i*40} y1="20" x2={20+i*40} y2="150"/>)}
        {Array.from({length:7}).map((_,i)=><line key={"h"+i} x1="20" y1={20+i*22} x2="420" y2={20+i*22}/>)}
      </g>
      <g stroke="rgba(13,31,58,.45)" strokeWidth="1">
        <line x1="20" y1="150" x2="420" y2="150"/>
        <line x1="20" y1="20" x2="20" y2="150"/>
      </g>
      <g fontFamily="JetBrains Mono" fontSize="8" fill="rgba(13,31,58,.55)">
        <text x="12" y="30" textAnchor="end">P</text>
        <text x="420" y="164" textAnchor="end">t</text>
      </g>
      <g stroke="#c8413f" strokeWidth="1.3" fill="none">
        {points.map(([x,y],i)=>(
          <g key={i}>
            <line x1={x-4} y1={y-4} x2={x+4} y2={y+4}/>
            <line x1={x-4} y1={y+4} x2={x+4} y2={y-4}/>
          </g>
        ))}
      </g>
      <g fontFamily="JetBrains Mono" fontSize="9" fill="rgba(13,31,58,.55)">
        <text x="410" y="34" textAnchor="end">Δt ≈ ?</text>
        <text x="410" y="46" textAnchor="end">n = 14</text>
      </g>
      <text x="28" y="166" fontFamily="JetBrains Mono" fontSize="9" fill="rgba(13,31,58,.55)">{vt.avant_chart_label}</text>
    </svg>
  );
}

function LiveTrace() {
  const [t, setT] = useState(0);
  useEffect(() => {
    let raf;
    const tick = () => { setT(p => p + 0.012); raf = requestAnimationFrame(tick); };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);
  // 3 traces, panning right
  const w = 420, h = 160;
  const path = (phase, amp, offset, freq) => {
    let d = `M 0 ${h/2 + offset}`;
    for (let x = 0; x <= w; x += 6) {
      const y = h/2 + offset + Math.sin((x*freq + phase)*0.02) * amp + Math.sin((x*freq + phase)*0.08) * amp * 0.4;
      d += ` L ${x} ${y}`;
    }
    return d;
  };
  return (
    <svg viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ position:"absolute", inset: 0, width:"100%", height:"100%" }}>
      <g stroke="rgba(255,255,255,.07)" strokeWidth=".5">
        {Array.from({length:8}).map((_,i)=><line key={i} x1={i*60} y1="0" x2={i*60} y2={h}/>)}
        {Array.from({length:5}).map((_,i)=><line key={i} x1="0" y1={i*40} x2={w} y2={i*40}/>)}
      </g>
      <path d={path(t * 100, 24, -18, 1)} stroke="#4a90ff" strokeWidth="1.6" fill="none"/>
      <path d={path(t * 80 + 30, 16, 14, 1.4)} stroke="#4e9e6e" strokeWidth="1.4" fill="none"/>
      <path d={path(t * 60 + 60, 10, 40, 1.8)} stroke="#d9a72e" strokeWidth="1.2" fill="none"/>
    </svg>
  );
}

// === CONTACT ===
function Contact({ t }) {
  return (
    <section id="contact" className="contact">
      <div className="contact__grid-bg" />
      <div className="wrap contact__inner">
        <div>
          <div className="eyebrow light">{t.contact.eyebrow}</div>
          <h2 style={{ marginTop: 20 }}>{t.contact.title}</h2>
          <p style={{ marginTop: 22, color: "rgba(255,255,255,.7)", maxWidth: "48ch" }}>{t.contact.blurb}</p>
        </div>
        <div className="contact__list">
          {t.contact.rows.map(([k, v, href]) => (
            href ? (
              <a key={k} href={href} className="contact__row">
                <div className="k">{k}</div><div className="v">{v}</div><div>→</div>
              </a>
            ) : (
              <div key={k} className="contact__row" style={{cursor:"default"}}>
                <div className="k">{k}</div><div className="v">{v}</div><div/>
              </div>
            )
          ))}
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { Hero, KpiStrip, Manifesto, ScrollyNeedsSpecs, ScrollyAssembly, ChainSection, CaseStudy, Contact, BeforeChart });
