/* =========================================================
   ALLEGEDLY — Interactive widgets
   Calculator, Quiz, Disloyalty Flow, Sticker generator,
   Wall of Disloyalty, Verification Loop.
   ========================================================= */

const { useState: uS, useEffect: uE, useRef: uR, useMemo: uM, useCallback: uC } = React;

/* =========================================================
   1) Verification Loop — pinned cinematic, scroll-scrubbed
   4 beats: intake → ship → 30d → reassess.
   Right column: 4 lines of "ALLEGEDLY" that flip to "ACTUALLY"
   as you scrub past each beat.
   ========================================================= */
const VLOOP_BEATS = [
  { id:'B/01', name:'INTAKE',       sub:'Day 0',  body:'Structured assessment captures focus, energy, stress, sleep. The "before" measurement that every claim will be checked against.', claim:'Allegedly effective' },
  { id:'B/02', name:'SHIP',         sub:'Day 1',  body:'Two of three SKUs prescribed by the intake. Daily dose. The third is the upsell after the verification.', claim:'Allegedly the right protocol' },
  { id:'B/03', name:'REASSESS',     sub:'Day 30', body:'The same instrument, 30 days later. Customer sees their own delta. The footnote starts losing its asterisk.', claim:'Allegedly improved' },
  { id:'B/04', name:'COMPOUND',     sub:'Forever',body:'Every subscriber compounds the dataset. At 1k subs we have more longitudinal data than Thesis. At 10k it is a moat nobody else can rebuild.', claim:'Allegedly a moat' },
];

function VerificationLoop() {
  const stageRef = uR(null);
  const trackRef = uR(null);
  const [progress, setProgress] = uS(0); // 0..1

  uE(() => {
    let st;
    let cancelled = false;
    const tryBoot = () => {
      if (cancelled) return;
      if (!window.gsap || !window.ScrollTrigger || !stageRef.current) {
        return setTimeout(tryBoot, 80);
      }
      // global lock: only one vloop boot allowed at a time
      if (window.__vloopBooted) {
        // kill prior pin first
        window.ScrollTrigger.getAll().filter(s => s.trigger?.classList?.contains('vloop-stage')).forEach(s => s.kill());
      }
      window.__vloopBooted = true;
      const gsap = window.gsap;
      const ScrollTrigger = window.ScrollTrigger;
      st = ScrollTrigger.create({
        trigger: stageRef.current,
        start: 'top top',
        end: '+=' + (window.innerHeight * 3.2),
        pin: true,
        scrub: 0.6,
        onUpdate: (self) => setProgress(self.progress),
        invalidateOnRefresh: true,
      });
      gsap.fromTo(stageRef.current.querySelector('.vloop-path'),
        { strokeDashoffset: 1 },
        { strokeDashoffset: 0, ease: 'none', scrollTrigger: st }
      );
      // a fresh refresh after the pin is created — pin offsets need accurate measurements
      requestAnimationFrame(() => ScrollTrigger.refresh());
    };
    tryBoot();
    return () => { cancelled = true; if (st) st.kill(); window.__vloopBooted = false; };
  }, []);

  const beatIdx = Math.min(VLOOP_BEATS.length - 1, Math.floor(progress * VLOOP_BEATS.length));
  const sectionProgress = (progress * VLOOP_BEATS.length) - beatIdx;

  return (
    <div ref={stageRef} className="vloop-stage" data-zone="VERIFICATION LOOP">
      <div className="vloop-grid">
        {/* left: SVG ledger */}
        <div className="vloop-ledger">
          <div className="vloop-tape">
            <span className="t-data">★ LEDGER · ALG-LOOP-001 · CASE TRACE</span>
            <span className="t-data" style={{opacity:0.5}}>{Math.round(progress*100)}% · BEAT {String(beatIdx+1).padStart(2,'0')}/04</span>
          </div>
          <svg viewBox="0 0 600 460" className="vloop-svg" preserveAspectRatio="xMidYMid meet">
            <defs>
              <marker id="vloop-ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
                <path d="M0,0 L10,5 L0,10 z" fill="var(--silver)"/>
              </marker>
            </defs>
            {/* graph paper grid */}
            <g opacity="0.08" stroke="var(--light)" strokeWidth="0.5">
              {Array.from({length:13}).map((_,i)=><line key={'v'+i} x1={i*50} y1="0" x2={i*50} y2="460"/>)}
              {Array.from({length:10}).map((_,i)=><line key={'h'+i} x1="0" y1={i*50} x2="600" y2={i*50}/>)}
            </g>

            {/* The path is one continuous winding ledger, broken into 4 nodes */}
            <path
              className="vloop-path"
              d="M 50 100 L 200 100 L 200 220 L 380 220 L 380 340 L 540 340"
              fill="none" stroke="var(--silver)" strokeWidth="1.5"
              strokeDasharray="1" pathLength="1"
              markerEnd="url(#vloop-ar)"
            />

            {/* 4 nodes */}
            {[
              { x:50,  y:100, label:'INTAKE',   sub:'D0' },
              { x:200, y:220, label:'SHIP',     sub:'D1' },
              { x:380, y:340, label:'REASSESS', sub:'D30' },
              { x:540, y:340, label:'COMPOUND', sub:'∞' },
            ].map((n, i) => {
              const active = beatIdx >= i;
              return (
                <g key={i} transform={`translate(${n.x},${n.y})`}>
                  <circle r="22" fill="none" stroke="var(--silver)" strokeWidth="1" opacity={active ? 0.9 : 0.25}/>
                  <circle r={active ? 7 : 3} fill="var(--silver)" style={{transition:'r 0.4s var(--bezier)'}}/>
                  <text y="-32" textAnchor="middle" fontFamily="var(--data)" fontSize="9" letterSpacing="2.2"
                        fill={active ? '#fff' : 'rgba(242,239,232,0.5)'}>STEP 0{i+1}</text>
                  <text y="40" textAnchor="middle" fontFamily="var(--sans)" fontSize="14" letterSpacing="2"
                        fill={active ? '#fff' : 'rgba(242,239,232,0.55)'}>{n.label}</text>
                  <text y="54" textAnchor="middle" fontFamily="var(--data)" fontSize="9" letterSpacing="2"
                        fill="var(--silver)" opacity={active ? 0.85 : 0.4}>{n.sub}</text>
                </g>
              );
            })}
          </svg>
        </div>

        {/* right: claims that morph allegedly→actually */}
        <div className="vloop-claims">
          <div className="t-data" style={{color:'var(--silver)', opacity:0.7, marginBottom:14}}>★ CLAIMS LEDGER — STATUS</div>
          {VLOOP_BEATS.map((b, i) => {
            const passed = beatIdx > i || (beatIdx === i && sectionProgress > 0.5);
            return (
              <div key={b.id} ref={trackRef} className={'vloop-claim ' + (beatIdx === i ? 'is-active' : '') + (passed ? ' is-verified' : '')}>
                <div className="vloop-claim-head">
                  <span className="t-data" style={{color:'var(--silver)'}}>{b.id}</span>
                  <span className="t-sans vloop-claim-name">{b.name} · {b.sub}</span>
                </div>
                <div className="vloop-claim-flip">
                  <span className="flip-from">{b.claim}.</span>
                  <span className="flip-to">{b.claim.replace(/Allegedly/i, 'Actually')}.</span>
                </div>
                <p className="vloop-claim-body">{b.body}</p>
              </div>
            );
          })}
          <div className="vloop-bar">
            <div className="vloop-bar-fill" style={{width: (progress*100) + '%'}}/>
          </div>
        </div>
      </div>
    </div>
  );
}

/* =========================================================
   2) LTV/CAC Calculator
   ========================================================= */
function Calculator() {
  const [arpu, setArpu] = uS(88);
  const [margin, setMargin] = uS(78);
  const [lifeMo, setLifeMo] = uS(8);
  const [cac, setCac] = uS(48);
  const [discPct, setDiscPct] = uS(20); // % of acquisition that's zero-CAC

  const grossPerMo = arpu * (margin/100);
  const ltv = grossPerMo * lifeMo;
  const blendedCac = cac * (1 - discPct/100);
  const ratio = blendedCac > 0 ? ltv / blendedCac : 0;
  const payback = grossPerMo > 0 ? blendedCac / grossPerMo : 0;

  const Slider = ({ label, val, set, min, max, step, fmt }) => (
    <div style={{padding:'10px 0', borderTop:'1px solid var(--line)'}}>
      <div className="between" style={{marginBottom:6}}>
        <span className="t-data" style={{fontSize:9, opacity:0.45}}>{label}</span>
        <span className="t-sans" style={{fontSize:18, color:'var(--light)'}}>{fmt ? fmt(val) : val}</span>
      </div>
      <input
        type="range" min={min} max={max} step={step || 1}
        value={val}
        onChange={(e) => set(Number(e.target.value))}
        style={{width:'100%', accentColor:'var(--silver)'}}
      />
    </div>
  );

  const Stat = ({ label, value, hint, color }) => (
    <div className="metric" style={{background:'#000', borderColor:'rgba(242,239,232,0.08)'}}>
      <div className="t-data l" style={{opacity:0.4}}>{label}</div>
      <div className="v" style={{color: color || 'var(--light)', marginTop:8}}>{value}</div>
      {hint && <div className="t-mono" style={{fontSize:10, opacity:0.35, marginTop:6}}>{hint}</div>}
    </div>
  );

  return (
    <div style={{
      display:'grid', gridTemplateColumns:'1.1fr 1fr', gap:'clamp(20px,4vw,48px)',
      marginTop:'clamp(20px,3vw,32px)',
      background:'var(--panel)', border:'1px solid var(--line)',
      padding:'clamp(20px,3vw,36px)', borderRadius:2,
    }} data-zone="UNIT ECONOMICS CALC">
      <div>
        <div className="t-data" style={{fontSize:9, opacity:0.4, marginBottom:12}}>Adjust the inputs ↓</div>
        <Slider label="Blended ARPU / mo (USD)" val={arpu} set={setArpu} min={49} max={149} fmt={v => `$${v}`}/>
        <Slider label="Gross margin %" val={margin} set={setMargin} min={60} max={92} fmt={v => `${v}%`}/>
        <Slider label="Customer lifespan (months)" val={lifeMo} set={setLifeMo} min={3} max={24}/>
        <Slider label="Paid CAC (USD)" val={cac} set={setCac} min={20} max={120} fmt={v => `$${v}`}/>
        <Slider label="Zero-CAC mix (Disloyalty + Sticker)" val={discPct} set={setDiscPct} min={0} max={50} fmt={v => `${v}%`}/>
      </div>

      <div>
        <div className="t-data" style={{fontSize:9, opacity:0.4, marginBottom:12}}>Live napkin math →</div>
        <div className="grid g-2">
          <Stat label="LTV" value={`$${Math.round(ltv).toLocaleString()}`} color="var(--teal)" hint={`${lifeMo} mo × $${Math.round(grossPerMo)} gross`}/>
          <Stat label="Blended CAC" value={`$${Math.round(blendedCac)}`} color="var(--silver)" hint={`paid $${cac} × ${100-discPct}% paid mix`}/>
          <Stat label="LTV / CAC" value={`${ratio.toFixed(1)}x`} color={ratio >= 10 ? 'var(--amber)' : ratio >= 5 ? 'var(--teal)' : 'var(--light-2)'} hint={ratio >= 10 ? 'angels lean forward' : ratio >= 5 ? 'venture-grade' : 'work to do'}/>
          <Stat label="Payback (months)" value={payback.toFixed(1)} color="var(--light)" hint="time to recoup CAC"/>
        </div>
        <div style={{marginTop:14, padding:'14px 16px', background:'#000', border:'1px solid var(--silver)', borderRadius:2}}>
          <div className="t-data" style={{fontSize:9, color:'var(--silver)', opacity:0.7, marginBottom:6}}>The napkin verdict</div>
          <p className="t-mono" style={{fontSize:12, opacity:0.7, lineHeight:1.7, margin:0}}>
            {ratio >= 12 ? 'This is the math angels write checks against. ' : ratio >= 8 ? 'Healthy. Add retention rigor and this scales. ' : ratio >= 5 ? 'Venture-grade. Push the zero-CAC mix. ' : 'Tune the levers. The model wants more.'}
            Industry standard for supplements: 3-5x. Thesis estimated: 5-8x. Allegedly target: 10-16x.
          </p>
        </div>
      </div>
    </div>
  );
}

/* =========================================================
   3) Intake Quiz — prescribe 2 of 3 SKUs
   ========================================================= */
const QUIZ_Q = [
  { id:'goal', q:'What are you optimizing right now?',
    opts:[
      {l:'Deep focus / flow states', w:{focus:3, energy:1, calm:0}},
      {l:'Sustained energy without the crash', w:{focus:1, energy:3, calm:0}},
      {l:'Stress + sleep + actually recovering', w:{focus:0, energy:0, calm:3}},
      {l:'All of the above, honestly', w:{focus:2, energy:2, calm:2}},
    ]},
  { id:'caffeine', q:'How much caffeine, day-to-day?',
    opts:[
      {l:'I am the caffeine', w:{focus:0, energy:2, calm:2}},
      {l:'1-3 cups, dependably', w:{focus:1, energy:1, calm:1}},
      {l:'Tea-only / occasional', w:{focus:2, energy:1, calm:0}},
      {l:'Zero. I quit.', w:{focus:1, energy:2, calm:1}},
    ]},
  { id:'block', q:'What\'s blocking your edge?',
    opts:[
      {l:'Foggy brain by 2pm', w:{focus:3, energy:1, calm:0}},
      {l:'Energy bottoms out mid-afternoon', w:{focus:1, energy:3, calm:0}},
      {l:'I cannot turn my head off at night', w:{focus:0, energy:0, calm:3}},
      {l:'Stress is eating my recovery', w:{focus:0, energy:1, calm:3}},
    ]},
  { id:'belief', q:'And finally — do you actually believe this stuff works?',
    opts:[
      {l:'Yes. Show me the protocol.', w:{focus:1, energy:1, calm:1}},
      {l:'Skeptical but curious.', w:{focus:1, energy:1, calm:1}},
      {l:'Prove it.', w:{focus:1, energy:1, calm:1}},
      {l:'Allegedly.', w:{focus:1, energy:1, calm:1}},
    ]},
];

const SKUS = {
  focus:  { name:'CLARITY', sub:'Focus', color:'var(--teal)',   ing:'Lion\'s Mane · Bacopa · Ginkgo · L-Theanine', variant:'focus'},
  energy: { name:'VITALITY', sub:'Energy', color:'var(--orange)', ing:'Cordyceps · Rhodiola · Eleuthero · Maca',     variant:'energy'},
  calm:   { name:'BALANCE', sub:'Calm',  color:'var(--purple)',  ing:'Ashwagandha · Reishi · Schisandra · Chamomile', variant:'calm'},
};

/* four layer-cake strip backgrounds — subtle lightness ladder, Bureau Gris */
const QUIZ_CAKE_BG = [
  'oklch(10% 0.007 248)',
  'oklch(13% 0.007 252)',
  'oklch(16% 0.008 255)',
  'oklch(19% 0.008 258)',
];

function Quiz() {
  const [step, setStep] = uS(0); // 0..n questions, then 'result'
  const [answers, setAnswers] = uS({});
  const [scores, setScores] = uS({focus:0, energy:0, calm:0});
  const [hovered, setHovered] = uS(null);

  function choose(qid, opt) {
    const next = {...answers, [qid]: opt.l};
    const nextScores = {...scores};
    Object.keys(opt.w).forEach(k => { nextScores[k] = (nextScores[k]||0) + opt.w[k]; });
    setAnswers(next);
    setScores(nextScores);
    if (step + 1 < QUIZ_Q.length) setStep(step + 1);
    else setStep('result');
  }

  function reset() {
    setStep(0); setAnswers({}); setScores({focus:0, energy:0, calm:0});
  }

  // resolve top 2 SKUs from scores
  const ranked = Object.entries(scores).sort((a,b) => b[1]-a[1]);
  const top2 = ranked.slice(0,2).map(([k]) => k);
  const third = ranked[2]?.[0];

  if (step === 'result') {
    return (
      <div style={{marginTop:'clamp(20px,3vw,32px)'}}>
        <div className="between" style={{marginBottom:16}}>
          <div className="t-data" style={{fontSize:9, opacity:0.5, color:'var(--silver)'}}>CASE FILE GENERATED — PRESCRIPTION ENCLOSED</div>
          <button className="btn ghost" onClick={reset} style={{padding:'8px 14px', fontSize:10}}>retake</button>
        </div>

        <div style={{display:'grid', gridTemplateColumns:'repeat(3, 1fr)', gap:'clamp(12px,2vw,24px)'}}>
          {['focus','energy','calm'].map(k => {
            const isTop = top2.includes(k);
            const sku = SKUS[k];
            return (
              <div key={k} style={{
                opacity: isTop ? 1 : 0.35,
                transform: isTop ? 'none' : 'scale(0.94)',
                transition:'all 0.5s var(--bezier)',
                position:'relative',
              }}>
                {isTop && (
                  <div style={{
                    position:'absolute', top:-10, left:0, right:0, textAlign:'center', zIndex:2,
                  }}>
                    <span className="zip" style={{background:sku.color}}>PRESCRIBED</span>
                  </div>
                )}
                {!isTop && (
                  <div style={{
                    position:'absolute', top:-10, left:0, right:0, textAlign:'center', zIndex:2,
                  }}>
                    <span className="zip ghost">+ THE UPSELL</span>
                  </div>
                )}
                <SKU variant={sku.variant} name={sku.name} sub={sku.sub} ingredients={sku.ing}/>
                <div style={{marginTop:14, textAlign:'center'}}>
                  <div className="t-sans" style={{fontSize:20, letterSpacing:'0.04em', color: sku.color}}>{sku.name}</div>
                  <div className="t-mono" style={{fontSize:10, opacity:0.45, marginTop:4}}>{sku.ing}</div>
                </div>
              </div>
            );
          })}
        </div>

        <div className="offset" style={{marginTop:24}}>
          <p className="t-serif" style={{fontSize:'clamp(16px,2.2vw,22px)', fontStyle:'italic', lineHeight:1.4}}>
            Your protocol: 2 of 3, daily for 30 days. We follow up. You see what changed. <span style={{color:'var(--silver)'}}>That's the loop.</span>
          </p>
        </div>
        <FN>This is a demo. We're legally required to tell you "prescribe" is used loosely. We're not doctors. Allegedly.</FN>
      </div>
    );
  }

  const q = QUIZ_Q[step];

  return (
    <div style={{marginTop:'clamp(20px,3vw,32px)'}}>
      <div className="between" style={{marginBottom:18}}>
        <div className="t-data" style={{fontSize:9, opacity:0.5}}>INTAKE QUESTION {String(step+1).padStart(2,'0')} / {String(QUIZ_Q.length).padStart(2,'0')}</div>
        <div style={{display:'flex', gap:4, alignItems:'center'}}>
          {QUIZ_Q.map((_,i) => (
            <div key={i} style={{
              width: i === step ? 24 : 8, height:2,
              background: i <= step ? 'var(--silver)' : 'oklch(56% 0.008 252 / 0.10)',
              transition:'all 0.4s'
            }}/>
          ))}
        </div>
      </div>

      <h3 className="t-serif" style={{fontSize:'clamp(24px,3.5vw,40px)', lineHeight:1.15, marginBottom:24, maxWidth:640}}>
        {q.q}
      </h3>

      {/* layer cake — 4 full-width stacked strips, Flash/AS aesthetic */}
      <div style={{
        display:'flex', flexDirection:'column',
        overflow:'hidden',
        border:'1px solid var(--line)', borderRadius:2,
      }}>
        {q.opts.map((opt, i) => (
          <button key={i} onClick={() => choose(q.id, opt)}
            onMouseEnter={() => setHovered(i)}
            onMouseLeave={() => setHovered(null)}
            style={{
              background: hovered === i ? 'oklch(56% 0.008 252 / 0.22)' : QUIZ_CAKE_BG[i],
              color: hovered === i ? 'var(--light)' : 'var(--light-2)',
              border:'none',
              borderBottom: i < 3 ? '1px solid var(--line)' : 'none',
              padding:0,
              textAlign:'left',
              cursor:'pointer',
              display:'flex', alignItems:'stretch',
              width:'100%',
              transition:'background 0.14s, color 0.14s',
            }}
          >
            {/* index column */}
            <div style={{
              display:'flex', alignItems:'center', justifyContent:'center',
              width:68, minHeight:80,
              borderRight:'1px solid var(--line)',
              fontFamily:'var(--mono)', fontSize:10, letterSpacing:'0.22em',
              color: hovered === i ? 'var(--silver)' : 'oklch(56% 0.008 252 / 0.45)',
              flexShrink:0,
              transition:'color 0.14s',
              userSelect:'none',
            }}>0{i+1}</div>

            {/* label */}
            <div style={{
              flex:1,
              padding:'22px 24px',
              fontFamily:'var(--mono)', fontSize:13, letterSpacing:'0.025em', lineHeight:1.4,
              display:'flex', alignItems:'center',
            }}>{opt.l}</div>

            {/* arrow */}
            <div style={{
              display:'flex', alignItems:'center',
              paddingRight:22,
              fontFamily:'var(--mono)', fontSize:11,
              color:'var(--silver)',
              opacity: hovered === i ? 0.75 : 0.18,
              transition:'opacity 0.14s',
              userSelect:'none',
            }}>→</div>
          </button>
        ))}
      </div>

      {step > 0 && (
        <button onClick={() => { setStep(s => s-1); }} style={{
          marginTop:18, background:'transparent', color:'var(--light)', opacity:0.4,
          border:'none', cursor:'pointer', fontFamily:"'Share Tech Mono', monospace",
          fontSize:10, letterSpacing:'0.18em', textTransform:'uppercase',
        }}>← back</button>
      )}
    </div>
  );
}

/* =========================================================
   4) Disloyalty submission flow
   ========================================================= */
const COMPETITORS = ['Thesis', 'AG1 / Athletic Greens', 'Mud\\Wtr', 'Four Sigmatic', 'Magic Mind', 'Other'];

function DisloyaltyFlow() {
  const [step, setStep] = uS(0); // 0 select 1 upload 2 verifying 3 approved
  const [comp, setComp] = uS('');
  const [file, setFile] = uS(null);
  const [progress, setProgress] = uS(0);
  const fileRef = uR(null);

  uE(() => {
    if (step !== 2) return;
    setProgress(0);
    const t = setInterval(() => {
      setProgress(p => {
        const next = p + Math.random() * 18;
        if (next >= 100) {
          clearInterval(t);
          setTimeout(() => setStep(3), 350);
          return 100;
        }
        return next;
      });
    }, 220);
    return () => clearInterval(t);
  }, [step]);

  function reset(){ setStep(0); setComp(''); setFile(null); setProgress(0); }

  function onFile(e) {
    const f = e.target.files?.[0];
    if (f) { setFile(f); setStep(2); }
  }
  function dropFile(e) {
    e.preventDefault();
    const f = e.dataTransfer.files?.[0];
    if (f) { setFile(f); setStep(2); }
  }

  return (
    <div style={{
      background:'var(--panel-2)', border:'1px solid var(--line)',
      padding:'clamp(20px,3vw,36px)', borderRadius:2, marginTop:'clamp(20px,3vw,32px)',
      position:'relative',
    }} data-zone="DISLOYALTY INTAKE">
      <div style={{position:'absolute', top:0, left:0, right:0, height:2, background:'var(--silver)'}}/>

      <div className="between" style={{marginBottom:18}}>
        <div className="t-data" style={{fontSize:9, opacity:0.5, color:'var(--silver)'}}>DISLOYALTY INTAKE — PROOF OF UNLOYALTY</div>
        <div className="t-data" style={{fontSize:9, opacity:0.4}}>STEP {Math.min(step+1, 4)} / 04</div>
      </div>

      {step === 0 && (
        <div>
          <h3 className="t-serif" style={{fontSize:'clamp(22px,3vw,32px)', lineHeight:1.2, marginBottom:8}}>
            Who are you leaving?
          </h3>
          <p className="body-mono" style={{marginBottom:18}}>
            Tell us who you've been giving money to. We won't judge. We're going to convert you for free.
          </p>
          <div style={{display:'grid', gridTemplateColumns:'repeat(auto-fit, minmax(180px, 1fr))', gap:8}}>
            {COMPETITORS.map(c => (
              <button key={c} onClick={() => { setComp(c); setStep(1); }} style={{
                background:'transparent', color:'inherit',
                border:'1px solid var(--line)', borderRadius:2,
                padding:'14px 18px', textAlign:'left',
                fontFamily:"'Space Mono', monospace", fontSize:12,
                cursor:'pointer', transition:'all 0.25s ease',
              }}
              onMouseEnter={(e)=>{e.currentTarget.style.borderColor='var(--silver)';}}
              onMouseLeave={(e)=>{e.currentTarget.style.borderColor='var(--line)';}}
              >
                <span className="strike" style={{textDecorationThickness:2, textDecorationColor:'var(--silver)'}}>{c}</span>
              </button>
            ))}
          </div>
        </div>
      )}

      {step === 1 && (
        <div>
          <div className="t-data" style={{fontSize:9, color:'var(--silver)', opacity:0.7, marginBottom:8}}>SUBJECT: <span style={{color:'#fff', opacity:0.85}}>{comp}</span></div>
          <h3 className="t-serif" style={{fontSize:'clamp(22px,3vw,32px)', lineHeight:1.2, marginBottom:8}}>
            Show us the receipt.
          </h3>
          <p className="body-mono" style={{marginBottom:18}}>
            Drop a receipt, subscription screenshot, empty bag, or public review of {comp}. We auto-verify ~80% in seconds. The rest go to a human, &lt; 2 min.
          </p>
          <div
            onClick={() => fileRef.current?.click()}
            onDragOver={(e) => e.preventDefault()}
            onDrop={dropFile}
            style={{
              border:'2px dashed rgba(230,50,22,0.35)',
              padding:'clamp(28px,5vw,48px)',
              textAlign:'center', borderRadius:2,
              background:'rgba(230,50,22,0.025)',
              cursor:'pointer',
              transition:'all 0.25s ease',
            }}
            onMouseEnter={(e)=>{e.currentTarget.style.background='rgba(230,50,22,0.06)';}}
            onMouseLeave={(e)=>{e.currentTarget.style.background='rgba(230,50,22,0.025)';}}
          >
            <div className="t-sans" style={{fontSize:'clamp(28px,4vw,40px)', color:'var(--silver)', letterSpacing:'0.04em'}}>DROP PROOF</div>
            <div className="t-data" style={{fontSize:10, opacity:0.5, marginTop:8}}>JPG · PNG · PDF · or click to upload</div>
            <input ref={fileRef} type="file" hidden onChange={onFile} accept="image/*,.pdf"/>
          </div>
          <div style={{display:'flex', gap:8, marginTop:14, flexWrap:'wrap'}}>
            <span className="zip ghost">RECEIPT · STRONG</span>
            <span className="zip ghost">SUB SCREENSHOT · STRONGEST</span>
            <span className="zip ghost">EMPTY BAG · STRONG</span>
            <span className="zip ghost">SOCIAL POST · MEDIUM</span>
          </div>
          <button onClick={() => setStep(0)} className="t-data" style={{
            marginTop:16, background:'transparent', color:'var(--light)', opacity:0.4,
            border:'none', cursor:'pointer', fontSize:10,
          }}>← change subject</button>
        </div>
      )}

      {step === 2 && (
        <div>
          <h3 className="t-serif" style={{fontSize:'clamp(22px,3vw,32px)', lineHeight:1.2, marginBottom:8}}>
            Running the gauntlet.
          </h3>
          <p className="body-mono" style={{marginBottom:24}}>
            Two-layer verification. OCR checks the receipt. Image-recognition checks the bag. ML checks for fraud.
          </p>
          <div style={{maxWidth:520}}>
            {[
              ['OCR — extracting text from upload', 25],
              ['Brand match — confirming the competitor', 55],
              ['Fraud check — ML + heuristics', 80],
              ['Human spot-check — last 20%', 100],
            ].map(([label, threshold], i) => (
              <div key={i} className="between" style={{marginBottom:10, gap:14}}>
                <span className="t-mono" style={{fontSize:11, opacity:progress >= threshold ? 1 : 0.45, flex:1}}>
                  {label}
                </span>
                <span className="t-data" style={{fontSize:9, color:'var(--silver)', opacity:progress >= threshold ? 0.8 : 0.3}}>
                  {progress >= threshold ? 'OK' : '...'}
                </span>
              </div>
            ))}
          </div>
          <div style={{marginTop:18, height:2, background:'rgba(242,239,232,0.1)', position:'relative', maxWidth:520}}>
            <div style={{position:'absolute', left:0, top:0, bottom:0, width:`${progress}%`, background:'var(--silver)', transition:'width 0.2s'}}/>
          </div>
        </div>
      )}

      {step === 3 && (
        <div style={{textAlign:'center', padding:'clamp(20px,4vw,40px) 0'}}>
          <span className="stamp" style={{opacity:0.85, fontSize:'clamp(20px,3.5vw,30px)'}}>APPROVED</span>
          <h3 className="t-serif" style={{fontSize:'clamp(28px,4vw,48px)', lineHeight:1.1, marginTop:18, marginBottom:8}}>
            It's on the house.
          </h3>
          <p className="body-mono" style={{margin:'0 auto 18px', maxWidth:480}}>
            Your first month of Allegedly is free. We just converted a {comp} subscriber for $0 CAC.
            We'll see you in 30 days for your verification.
          </p>
          <button onClick={reset} className="btn ghost" style={{margin:'0 auto'}}>submit another</button>
        </div>
      )}
    </div>
  );
}

/* =========================================================
   5) Sticker generator + draggable sticker
   ========================================================= */
function StickerStudio() {
  const [text, setText] = uS('ALLEGEDLY');
  const [target, setTarget] = uS('THESIS');
  const [rotation, setRotation] = uS(-8);

  // draggable sticker positions
  const stickerRef = uR(null);
  const [pos, setPos] = uS({ x:0, y:0 });
  const drag = uR({ active:false, sx:0, sy:0, ox:0, oy:0 });

  function down(e){
    const t = e.touches?.[0] || e;
    drag.current = { active:true, sx:t.clientX, sy:t.clientY, ox:pos.x, oy:pos.y };
    e.preventDefault();
  }
  function move(e){
    if(!drag.current.active) return;
    const t = e.touches?.[0] || e;
    setPos({ x: drag.current.ox + (t.clientX - drag.current.sx), y: drag.current.oy + (t.clientY - drag.current.sy) });
  }
  function up(){ drag.current.active = false; }
  uE(() => {
    window.addEventListener('mousemove', move);
    window.addEventListener('mouseup', up);
    window.addEventListener('touchmove', move, {passive:false});
    window.addEventListener('touchend', up);
    return () => {
      window.removeEventListener('mousemove', move);
      window.removeEventListener('mouseup', up);
      window.removeEventListener('touchmove', move);
      window.removeEventListener('touchend', up);
    };
  }, [pos]);

  return (
    <div style={{marginTop:'clamp(20px,3vw,32px)'}}>
      <div style={{display:'grid', gridTemplateColumns:'1fr 1.1fr', gap:'clamp(20px,4vw,48px)', alignItems:'stretch'}}>
        <div>
          <div className="t-data" style={{fontSize:9, opacity:0.4, marginBottom:12}}>Customize your stamp ↓</div>
          <label className="field-label">Sticker text</label>
          <input className="field" value={text} maxLength={20} onChange={e => setText(e.target.value.toUpperCase())} />
          <label className="field-label" style={{marginTop:18}}>Target brand</label>
          <select className="field" value={target} onChange={e => setTarget(e.target.value)} style={{appearance:'none'}}>
            {['THESIS','ATHLETIC GREENS','MUD\\WTR','FOUR SIGMATIC','MAGIC MIND','HUEL','LIQUID I.V.','PRIME','THE COMPETITION'].map(o => <option key={o} value={o}>{o}</option>)}
          </select>
          <label className="field-label" style={{marginTop:18}}>Rotation</label>
          <input type="range" min={-25} max={25} value={rotation} onChange={e => setRotation(Number(e.target.value))} style={{width:'100%', accentColor:'var(--silver)'}}/>

          <div style={{marginTop:18, padding:14, background:'#000', border:'1px solid var(--silver)', borderRadius:2}}>
            <p className="t-mono" style={{fontSize:11, opacity:0.7, lineHeight:1.7, margin:0}}>
              Drag the sticker onto the competitor jar. Take a screenshot. Tag <span className="red">@allegedly.co</span>.
              Sticker cost: <span className="red">$0.03/unit</span>. Brand activism, in vinyl form.
            </p>
          </div>
        </div>

        <div style={{
          position:'relative', minHeight:380,
          background:'#0a0c10',
          border:'1px solid var(--line)', borderRadius:2,
          overflow:'hidden',
        }} data-zone="STICKER LAB">
          {/* faux competitor jar */}
          <div style={{
            position:'absolute', left:'50%', top:'50%', transform:'translate(-50%, -50%)',
            width:200, height:280, borderRadius:'14px',
            background:'linear-gradient(180deg, #e8e4da, #c4bfb1)',
            boxShadow:'inset 0 8px 16px rgba(0,0,0,0.15), inset 0 -10px 0 rgba(0,0,0,0.18), 0 30px 60px -20px rgba(0,0,0,0.5)',
            display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', padding:'24px 18px',
            color:'#0a0c0f', textAlign:'center', userSelect:'none',
          }}>
            <div className="t-data" style={{fontSize:9, opacity:0.5, marginBottom:8}}>★ COMPETITOR</div>
            <div className="t-sans" style={{fontSize:32, letterSpacing:'0.04em', lineHeight:1}}>{target}</div>
            <div className="t-serif" style={{fontSize:13, fontStyle:'italic', opacity:0.5, marginTop:6}}>"trust us, allegedly"</div>
            <div style={{marginTop:14, padding:'3px 10px', background:'rgba(0,0,0,0.06)', fontFamily:'var(--data)', fontSize:8, letterSpacing:'0.16em'}}>UNVERIFIED · OPEN-LABEL · n=133</div>
          </div>

          {/* draggable sticker */}
          <div
            ref={stickerRef}
            onMouseDown={down}
            onTouchStart={down}
            style={{
              position:'absolute',
              left:`calc(50% + ${pos.x}px)`,
              top:`calc(40% + ${pos.y}px)`,
              transform:`translate(-50%, -50%) rotate(${rotation}deg)`,
              background:'var(--silver)', color:'#fff',
              fontFamily:"'Bebas Neue', sans-serif",
              fontSize:'clamp(18px, 2.5vw, 28px)',
              letterSpacing:'0.04em',
              padding:'6px 14px',
              border:'3px solid #fff',
              boxShadow:'0 12px 30px rgba(0,0,0,0.4)',
              cursor: drag.current.active ? 'grabbing' : 'grab',
              userSelect:'none',
              touchAction:'none',
              whiteSpace:'nowrap',
              transition: drag.current.active ? 'none' : 'transform 0.4s var(--bezier)',
            }}
            title="drag me onto the jar"
          >
            "{text}"
          </div>

          <div style={{position:'absolute', bottom:10, left:14, right:14, display:'flex', justifyContent:'space-between'}}>
            <div className="t-data" style={{fontSize:9, opacity:0.4}}>STICKER LAB · v1.0</div>
            <div className="t-data" style={{fontSize:9, opacity:0.4}}>DRAG TO PLACE → SHARE</div>
          </div>
        </div>
      </div>
    </div>
  );
}

/* =========================================================
   6) Wall of Disloyalty
   ========================================================= */
const WALL_DATA = [
  { name:'OPERATIVE 047', from:'Thesis', months:14, hometown:'BROOKLYN, NY' },
  { name:'OPERATIVE 091', from:'AG1', months:9, hometown:'AUSTIN, TX' },
  { name:'OPERATIVE 003', from:'Mud\\Wtr', months:22, hometown:'PORTLAND, OR' },
  { name:'OPERATIVE 112', from:'Magic Mind', months:6, hometown:'LOS ANGELES, CA' },
  { name:'OPERATIVE 128', from:'Four Sigmatic', months:11, hometown:'DENVER, CO' },
  { name:'OPERATIVE 144', from:'Rasa', months:7, hometown:'OAKLAND, CA' },
  { name:'OPERATIVE 200', from:'AG1', months:18, hometown:'CHICAGO, IL' },
  { name:'OPERATIVE 207', from:'Thesis', months:5, hometown:'NEW YORK, NY' },
  { name:'OPERATIVE 215', from:'Huel', months:13, hometown:'BOSTON, MA' },
  { name:'OPERATIVE 230', from:'Mud\\Wtr', months:9, hometown:'SEATTLE, WA' },
  { name:'OPERATIVE 244', from:'Liquid I.V.', months:6, hometown:'MIAMI, FL' },
  { name:'OPERATIVE 259', from:'Prime', months:8, hometown:'NASHVILLE, TN' },
];

function WallOfDisloyalty() {
  const [filter, setFilter] = uS('ALL');
  const opts = ['ALL', ...Array.from(new Set(WALL_DATA.map(d => d.from)))];
  const items = filter === 'ALL' ? WALL_DATA : WALL_DATA.filter(d => d.from === filter);
  return (
    <div style={{marginTop:'clamp(20px,3vw,32px)'}}>
      <div className="row" style={{gap:6, marginBottom:14}}>
        <span className="t-data" style={{fontSize:9, opacity:0.4, marginRight:8}}>FILTER BY DEFECTION FROM →</span>
        {opts.map(o => (
          <button key={o} onClick={() => setFilter(o)} className="t-data" style={{
            background: filter === o ? 'var(--silver)' : 'transparent',
            color: filter === o ? '#fff' : 'var(--light)',
            border:'1px solid', borderColor: filter === o ? 'var(--silver)' : 'var(--line)',
            padding:'5px 10px', fontSize:9, letterSpacing:'0.16em',
            cursor:'pointer', borderRadius:1,
          }}>{o}</button>
        ))}
      </div>

      <div className="wall">
        {items.map((d, i) => (
          <div key={i} className="wall-cell" data-zone={`OPERATIVE ${d.name}`}>
            <div className="rank">#{String(i+1).padStart(3,'0')}</div>
            <div className="name">{d.name}</div>
            <div className="meta">{d.hometown}</div>
            <div className="from">
              left <span className="strike">{d.from}</span> · {d.months} mo loyal
            </div>
          </div>
        ))}
      </div>
      <FN>The Wall is real-but-anonymized. Disloyalty Ambassadors opt in to public identification. Most don't. (Wisdom.)</FN>
    </div>
  );
}

/* expose */
Object.assign(window, { VerificationLoop, Calculator, Quiz, DisloyaltyFlow, StickerStudio, WallOfDisloyalty });
