// Home / Overview — cinematic globe hero + narrative (why · how · what it unlocks)
const { useState: uS, useEffect: uE, useMemo: uM, useRef: uR } = React;

// Count-up number that animates when scrolled into view
function CountUp({ value, dur = 1500, suffix = '%' }) {
  const [v, setV] = uS(0);
  const ref = uR(null);
  const started = uR(false);
  uE(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !started.current) {
          started.current = true;
          const start = performance.now();
          const tick = (t) => {
            const p = Math.min(1, (t - start) / dur);
            const eased = 1 - Math.pow(1 - p, 3);
            setV(value * eased);
            if (p < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
        }
      });
    }, { threshold: 0.4 });
    io.observe(el);
    const fallback = setTimeout(() => { if (!started.current) setV(value); }, 1400);
    return () => { io.disconnect(); clearTimeout(fallback); };
  }, [value]);
  return <span ref={ref}>{Math.round(v)}<span style={{ fontSize: '.5em', verticalAlign: 'baseline', marginLeft: 1 }}>{suffix}</span></span>;
}

// Fade/slide-up on scroll into view
function Reveal({ children, as = 'div', style, delay = 0 }) {
  const ref = uR(null);
  uE(() => {
    const el = ref.current;
    if (!el) return;
    el.style.opacity = '0';
    el.style.transform = 'translateY(26px)';
    el.style.transition = `opacity .8s cubic-bezier(.22,.61,.36,1) ${delay}ms, transform .8s cubic-bezier(.22,.61,.36,1) ${delay}ms`;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) { el.style.opacity = '1'; el.style.transform = 'none'; io.unobserve(el); }
      });
    }, { threshold: 0.15, rootMargin: '0px 0px -8% 0px' });
    io.observe(el);
    const fallback = setTimeout(() => { el.style.opacity = '1'; el.style.transform = 'none'; }, 1100);
    return () => { io.disconnect(); clearTimeout(fallback); };
  }, []);
  return React.createElement(as, { ref, style }, children);
}

function RevealLine({ children, delay = 0, as = 'span', color }) {
  const ref = uR(null);
  uE(() => {
    if (!ref.current) return;
    const el = ref.current;
    el.style.opacity = '0';
    el.style.transform = 'translateY(14px)';
    el.style.transition = 'opacity 720ms cubic-bezier(.22,.61,.36,1), transform 720ms cubic-bezier(.22,.61,.36,1)';
    const t = setTimeout(() => { el.style.opacity = '1'; el.style.transform = 'translateY(0)'; }, delay);
    return () => clearTimeout(t);
  }, [delay]);
  return React.createElement(as, { ref, style: { display: as === 'span' ? 'inline-block' : 'block', willChange: 'opacity, transform', color } }, children);
}

// Large glowing, draggable, auto-rotating globe for the dark hero
function HeroGlobe({ data }) {
  const { countries, perCountry } = data.summary;
  const [topo, setTopo] = uS(null);
  const rotRef = uR(18);
  const [, force] = uS(0);
  const autoRef = uR(true);
  const dragRef = uR(null);
  const metric = 'ownEver';
  const vals = perCountry.map((r) => r[metric]).filter((v) => typeof v === 'number');
  const max = Math.max(...vals);

  uE(() => {
    let raf, last = performance.now();
    const tick = (t) => {
      const dt = t - last; last = t;
      if (autoRef.current) { rotRef.current = (rotRef.current + dt * 0.011) % 360; force((n) => n + 1); }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  uE(() => {
    function loadScript(src) {
      return new Promise((res, rej) => {
        if (document.querySelector(`script[src="${src}"]`)) { res(); return; }
        const s = document.createElement('script');
        s.src = src; s.async = true; s.onload = res; s.onerror = rej;
        document.head.appendChild(s);
      });
    }
    (async () => {
      if (!window.d3) await loadScript('https://unpkg.com/d3@7.9.0/dist/d3.min.js');
      if (!window.topojson) await loadScript('https://unpkg.com/topojson-client@3.1.0/dist/topojson-client.min.js');
      const url = window.__resources?.worldAtlas || 'https://unpkg.com/world-atlas@2.0.2/countries-110m.json';
      const r = await fetch(url);
      setTopo(await r.json());
    })();
  }, []);

  const isoToCountry = uM(() => {
    const m = {};
    const map = window.COUNTRY_ISO || {};
    for (const c of countries) if (map[c]) m[map[c]] = c;
    return m;
  }, [countries, topo]);

  const valFor = (name) => { const row = perCountry[countries.indexOf(name)]; return row ? row[metric] : null; };
  const colorFor = (name) => {
    const v = valFor(name);
    if (v == null) return '#ece1d2';
    const t = Math.min(1, v / max);
    return `color-mix(in srgb, var(--brand) ${Math.round((0.28 + 0.72 * t) * 100)}%, #f0e6d8)`;
  };

  const W = 520, H = 520;
  let path = null, geo = null, sphere = null, graticule = null;
  if (window.d3 && topo && window.topojson) {
    const projection = window.d3.geoOrthographic().scale(248).translate([W / 2, H / 2]).rotate([rotRef.current, -12, 0]).clipAngle(90);
    path = window.d3.geoPath(projection);
    geo = window.topojson.feature(topo, topo.objects.countries);
    sphere = { type: 'Sphere' };
    graticule = window.d3.geoGraticule10();
  }

  const onDown = (e) => { const x = (e.touches ? e.touches[0].clientX : e.clientX); dragRef.current = { x, rot: rotRef.current }; autoRef.current = false; };
  const onMove = (e) => { if (!dragRef.current) return; const x = (e.touches ? e.touches[0].clientX : e.clientX); rotRef.current = dragRef.current.rot + (x - dragRef.current.x) * 0.45; force((n) => n + 1); };
  const onUp = () => { if (!dragRef.current) return; dragRef.current = null; setTimeout(() => { autoRef.current = true; }, 2500); };

  return (
    <div style={{ position: 'relative', width: '100%', maxWidth: 520, margin: '0 auto', aspectRatio: '1 / 1' }}>
      <div style={{ position: 'absolute', inset: '-10%', background: 'radial-gradient(circle at 50% 42%, rgba(210,120,60,.22), rgba(179,27,27,.10) 46%, transparent 70%)', filter: 'blur(8px)', pointerEvents: 'none' }} />
      {!path ?
        <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--muted)', fontFamily: 'Inter Tight, sans-serif' }}>Loading globe…</div>
        :
        <svg viewBox={`0 0 ${W} ${H}`} style={{ position: 'relative', width: '100%', height: '100%', display: 'block', cursor: dragRef.current ? 'grabbing' : 'grab', touchAction: 'pan-y' }}
          onMouseDown={onDown} onMouseMove={onMove} onMouseUp={onUp} onMouseLeave={onUp}
          onTouchStart={onDown} onTouchMove={onMove} onTouchEnd={onUp}>
          <circle cx={W / 2} cy={H / 2} r={248} fill="#fdf9f3" stroke="rgba(179,27,27,.28)" strokeWidth="1" />
          <path d={path(graticule)} fill="none" stroke="rgba(60,50,40,.10)" strokeWidth=".5" />
          {geo.features.map((feat, fi) => {
            const iso = String(feat.id).padStart(3, '0');
            const name = isoToCountry[iso];
            const inStudy = !!name;
            return (
              <path key={feat.id || fi} d={path(feat)}
                style={{ fill: inStudy ? colorFor(name) : '#e9ded1', stroke: '#fdf9f3', strokeWidth: .4 }} />
            );
          })}
        </svg>}
    </div>);
}

function HeroBlock({ data, setRoute }) {
  return (
    <section className="hero" style={{ background: 'radial-gradient(120% 120% at 82% 4%, #fbe9e6 0%, #fdf6ef 42%, var(--paper) 72%)', position: 'relative', overflow: 'hidden' }}>
      <div className="container">
        <div className="meta-row sans" style={{ color: 'var(--muted)' }}>
          <RevealLine delay={0}>2026 EDITION</RevealLine>
          <span>•</span>
          <RevealLine delay={160}>25 countries · 25,880 respondents</RevealLine>
        </div>
        <div className="grid" style={{ alignItems: 'center' }}>
          <div>
            <h1>
              <RevealLine delay={240} as="span">Cornell Bitcoin</RevealLine><br />
              <RevealLine delay={360} as="span">Adoption Index</RevealLine>
            </h1>
            <RevealLine delay={620} as="div">
              <p className="lede sans" style={{ marginTop: 28, color: 'var(--ink-2)' }}>
                A global study of awareness, ownership, understanding, and trust in bitcoin across
                25 countries — exploring whether bitcoin will be a tool for financial freedom for all.
              </p>
            </RevealLine>
            <RevealLine delay={780} as="div">
              <div style={{ display: 'flex', gap: 12, marginTop: 32, flexWrap: 'wrap' }}>
                <button className="sans" onClick={() => setRoute('findings')} style={{ background: 'var(--brand)', color: '#fff', padding: '13px 22px', border: 0, cursor: 'pointer', fontSize: 13, letterSpacing: '.02em' }}>
                  See the Key Findings →
                </button>
                <button className="sans" onClick={() => setRoute('map')} style={{ padding: '13px 22px', border: '1px solid var(--rule)', background: 'transparent', cursor: 'pointer', color: 'var(--fg)', fontSize: 13 }}>
                  Explore the Data
                </button>
              </div>
            </RevealLine>
          </div>
          <div>
            <HeroGlobe data={data} />
          </div>
        </div>
      </div>
    </section>);
}

// Animated headline stats band
function ImpactBand({ data }) {
  const g = data.summary.global;
  const stats = [
    { v: Math.round(g.awareness * 100), label: 'have heard of bitcoin', base: 'All respondents' },
    { v: Math.round(g.knows21M * 100), label: 'can name the 21-million supply cap', base: 'Among those aware' },
    { v: Math.round(g.financialFreedom * 100), label: 'say it increases financial freedom', base: 'Among those aware · rated 5–7 of 1–7' },
  ];
  return (
    <section className="section" style={{ paddingTop: 56, paddingBottom: 56, borderBottom: '1px solid var(--rule)' }}>
      <div className="container">
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 1, background: 'var(--rule)', border: '1px solid var(--rule)' }}>
          {stats.map((s, i) => (
            <Reveal key={i} delay={i * 120} style={{ background: 'var(--surface)', padding: '32px 28px' }}>
              <div style={{ fontFamily: 'Source Serif 4, serif', fontSize: 'clamp(48px, 6vw, 76px)', lineHeight: 1, letterSpacing: '-0.03em', color: i === 1 ? 'var(--brand)' : 'var(--fg)' }}>
                <CountUp value={s.v} />
              </div>
              <div style={{ fontFamily: 'Source Serif 4, serif', fontSize: 18, marginTop: 14, maxWidth: '22ch', color: 'var(--ink-2)' }}>{s.label}</div>
              <div className="sans" style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, textTransform: 'uppercase', letterSpacing: '.12em', color: 'var(--muted)', marginTop: 10 }}>{s.base}</div>
            </Reveal>
          ))}
        </div>
      </div>
    </section>);
}

// A single woven voice from the interviews
function VoicePull({ data }) {
  const all = data.quotes?.quotes || [];
  const find = (c, re) => all.find((q) => q.country === c && !q.paraphrase && re.test(q.text));
  let picks = [find('EL SALVADOR', /nobody controls/), find('TURKEY', /just paper/), find('VENEZUELA', /disappear/)].filter(Boolean);
  if (picks.length < 3) picks = all.filter((q) => !q.paraphrase).slice(0, 3);
  return (
    <section className="section" style={{ background: 'var(--surface)', paddingTop: 64, paddingBottom: 64, borderBottom: '1px solid var(--rule)' }}>
      <div className="container">
        <Reveal>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 16, marginBottom: 24, flexWrap: 'wrap' }}>
            <div className="eyebrow sans" style={{ color: 'var(--brand)' }}>From the interviews</div>
            <a onClick={() => window.navTo('voices')} style={{ color: 'var(--brand)', cursor: 'pointer', fontFamily: 'Inter Tight, sans-serif', fontSize: 13, fontWeight: 600 }}>Read more voices →</a>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 20 }}>
            {picks.map((q, i) => <QuoteCard key={i} q={q} compact />)}
          </div>
        </Reveal>
      </div>
    </section>);
}

// Teaser: top-5 financial-freedom countries
function FreedomTeaser({ data }) {
  const rows = [...data.summary.perCountry].filter((r) => r.financialFreedom != null)
    .sort((a, b) => b.financialFreedom - a.financialFreedom).slice(0, 5);
  const max = rows[0]?.financialFreedom || 1;
  return (
    <div style={{ marginTop: 28, border: '1px solid var(--rule)', background: 'var(--surface)', padding: '22px 24px' }}>
      <div className="eyebrow sans" style={{ marginBottom: 4 }}>Where belief runs highest</div>
      <div style={{ fontFamily: 'Source Serif 4, serif', fontSize: 17, marginBottom: 4 }}>Agree Bitcoin Increases Financial Freedom</div>
      <div className="sans" style={{ fontFamily: 'Inter Tight, sans-serif', fontSize: 11.5, color: 'var(--muted)', marginBottom: 16 }}>Rated above neutral (5–7 of 1–7) · among those aware of Bitcoin</div>
      <div style={{ display: 'grid', gridTemplateColumns: '130px 1fr 46px', gap: 10, alignItems: 'center' }}>
        {rows.map((r) => (
          <React.Fragment key={r.name}>
            <div className="sans" style={{ fontFamily: 'Inter Tight, sans-serif', fontSize: 13 }}>
              <span style={{ marginRight: 7 }}>{flagEmoji(COUNTRY_META[r.name]?.iso || '')}</span>{titleCase(r.name)}
            </div>
            <div style={{ height: 12, background: 'var(--surface-2)' }}><div style={{ height: '100%', width: (r.financialFreedom / max * 100) + '%', background: 'var(--brand)' }} /></div>
            <div className="mono" style={{ textAlign: 'right', fontFamily: 'JetBrains Mono, monospace', fontSize: 12 }}>{fmtPct(r.financialFreedom, 0)}</div>
          </React.Fragment>
        ))}
      </div>
      <div className="sans" style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, textTransform: 'uppercase', letterSpacing: '.12em', color: 'var(--muted)', marginTop: 14 }}>Among those aware of Bitcoin</div>
    </div>);
}

function StoryBlock({ n, eyebrow, dark, children }) {
  return (
    <section className="section" style={{ background: dark ? 'var(--surface)' : 'var(--paper)', paddingTop: 64, paddingBottom: 64, borderBottom: '1px solid var(--rule)' }}>
      <div className="container">
        <Reveal>
          <div className="grid" style={{ alignItems: 'start' }}>
            <div>
              <div style={{ fontFamily: 'Source Serif 4, serif', fontSize: 64, lineHeight: 1, color: 'var(--rule)', letterSpacing: '-0.02em' }}>{n}</div>
              <div className="eyebrow sans" style={{ marginTop: 14, color: 'var(--brand)' }}>{eyebrow}</div>
            </div>
            <div>{children}</div>
          </div>
        </Reveal>
      </div>
    </section>);
}

function StorySection({ data }) {
  const g = data.summary.global;
  const aware = Math.round(g.awareness * 100);
  const cap = Math.round(g.knows21M * 100);
  return (
    <>
      <StoryBlock n="01" eyebrow="Why this study" dark>
        <h2 style={{ fontSize: 'clamp(30px, 3.6vw, 46px)' }}>Bitcoin is known by nearly everyone. Understood by few.</h2>
        <p className="big">
          {aware}% of people have heard of bitcoin. Yet only <strong>{cap}%</strong> can name
          its single most defining rule — that no more than 21 million will ever exist.
        </p>
        <p>
          That gap is not a trivia problem. Bitcoin is increasingly discussed as a savings
          technology, a hedge against inflation, and — in some countries — a way to move money
          when the banking system fails people. When a technology this consequential is
          recognized by almost everyone but genuinely understood by almost no one, the door
          opens to hype, mis-selling, avoidable loss, and policy built on guesswork rather than
          evidence.
        </p>
        <p>
          We set out to replace speculation with data: <em>around the world, what do ordinary
          people actually know, believe, and do about bitcoin — and where might it matter most?</em>
        </p>
      </StoryBlock>

      <StoryBlock n="02" eyebrow="How it was done">
        <h2 style={{ fontSize: 'clamp(30px, 3.6vw, 46px)' }}>One questionnaire. 25 countries. 25,880 people.</h2>
        <p>
          Working with the survey firm Morning Consult, we fielded a single, carefully
          translated questionnaire to nationally representative samples across 25 countries
          between December 2024 and March 2025. The countries were chosen to span very
          different worlds — high-inflation economies and stable reserve-currency holders,
          places with near-universal banking and places where millions are unbanked.
        </p>
        <p>
          The study pairs <strong>quantitative</strong> measures — awareness, ownership,
          knowledge, and perceptions, all weighted to each country's population — with
          <strong> qualitative</strong> responses on people's reasons and hesitations, so the
          numbers come with the human "why" behind them.
        </p>
        <p style={{ marginTop: 8 }}>
          <a onClick={() => window.navTo('methodology')} style={{ color: 'var(--brand)', cursor: 'pointer', fontFamily: 'Inter Tight, sans-serif', fontWeight: 600 }}>
            Read the full methodology →
          </a>
        </p>
      </StoryBlock>

      <StoryBlock n="03" eyebrow="What it could unlock" dark>
        <h2 style={{ fontSize: 'clamp(30px, 3.6vw, 46px)' }}>Whose problem does bitcoin actually solve?</h2>
        <p className="big">Belief in bitcoin is strongest where the financial system is weakest.</p>
        <p>
          Across the study, the people most likely to say bitcoin increases their financial
          freedom are not in the wealthiest democracies — they are in countries living with
          inflation, currency controls, or fragile institutions. Understanding that pattern
          matters far beyond markets: it shapes how governments regulate, how aid and
          remittances move, how the next generation saves, and whether a borderless money
          becomes a tool for inclusion or another avenue for harm.
        </p>
        <FreedomTeaser data={data} />
        <div style={{ display: 'flex', gap: 12, marginTop: 28, flexWrap: 'wrap' }}>
          <a onClick={() => window.navTo('findings')} style={{ background: 'var(--ink)', color: 'var(--paper)', padding: '12px 20px', cursor: 'pointer', fontSize: 13, fontFamily: 'Inter Tight, sans-serif', letterSpacing: '.02em' }}>
            Explore the Key Findings →
          </a>
          <a onClick={() => window.navTo('countries')} style={{ padding: '12px 20px', border: '1px solid var(--rule)', cursor: 'pointer', color: 'var(--fg)', fontSize: 13, fontFamily: 'Inter Tight, sans-serif' }}>
            Browse by Country
          </a>
        </div>
      </StoryBlock>
    </>);
}

function HomePage({ data, setRoute }) {
  return (
    <>
      <HeroBlock data={data} setRoute={setRoute} />
      <ImpactBand data={data} />
      <StorySection data={data} />
      <VoicePull data={data} />
    </>);
}

Object.assign(window, { HomePage });
