/* ============================================================
   VFC SHARED — design tokens live in styles.css; this file holds
   the components every page renders (nav, footer, buttons, badges).
   Loaded by index.html and curriculum.html so there is one source
   of truth for chrome that appears on both.
   ============================================================ */

const CONTACT = { name: 'Elizabeth Walker Sobhani', email: 'vfcportugal@qi-center.org', whatsapp: '+86 15801161371', site: 'qicenter.cn' };

const NAV_LINKS = [
  ['About', '/#about'], ['How it works', '/#how'], ['Awards', '/#awards'],
  ['Speakers', '/#confirmed'], ['Winners', '/#winners'], ['Get involved', '/#involved'],
];
// Cross-page destinations — rendered after a divider so they read as
// "leaves this page", unlike the in-page anchors above.
const NAV_PAGES = [['Pre-Curriculum', '/curriculum']];

function LightbulbMark({ tone = 'gold', size = 40, style }) {
  const rays = tone === 'blue-bulb' ? '#FFC000' : '#FFC000';
  const bulb = (tone === 'blue' || tone === 'blue-bulb') ? '#003DA6' : '#FFC000';
  return (
    <svg width={size} height={size} viewBox="0 0 48 48" fill="none" aria-hidden="true" style={{ flex: 'none', ...style }}>
      <g strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round">
        <g stroke={rays}>
          <path d="M24 3.5v4" /><path d="M38.5 9.5l-2.8 2.8" /><path d="M44.5 24h-4" />
          <path d="M9.5 9.5l2.8 2.8" /><path d="M3.5 24h4" />
        </g>
        <g stroke={bulb}>
          <path d="M17 31c-3.1-2-5-5.2-5-8.9A12 12 0 0 1 36 22c0 3.7-1.9 6.9-5 8.9-1.3.8-2 2-2 3.6v.5H19v-.5c0-1.6-.7-2.8-2-3.6Z" />
          <path d="M19 39h10" /><path d="M21 43h6" />
        </g>
      </g>
    </svg>
  );
}

function Logo({ tone = 'on-dark', size = 'md', style }) {
  const onDark = tone === 'on-dark';
  const sc = { sm: 0.78, md: 1, lg: 1.4 }[size] || 1;
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 12 * sc, fontFamily: 'var(--font-display)', lineHeight: 0.92, textDecoration: 'none', ...style }}>
      <LightbulbMark tone={onDark ? 'gold' : 'blue-bulb'} size={40 * sc} />
      <span style={{ display: 'inline-flex', flexDirection: 'column' }}>
        <span style={{ fontWeight: 900, fontSize: 22 * sc, letterSpacing: '-0.01em', color: onDark ? 'var(--white)' : 'var(--blue-primary)' }}>Venture For Change</span>
        <span style={{ fontWeight: 700, fontSize: 13 * sc, letterSpacing: '0.34em', textTransform: 'uppercase', color: 'var(--gold)', marginTop: 3 * sc }}>Portugal</span>
      </span>
    </span>
  );
}

function Eyebrow({ children, tone = 'on-dark', pill = false, style }) {
  const color = tone === 'on-dark' ? 'var(--eyebrow-on-dark)' : 'var(--eyebrow-on-light)';
  return (
    <span style={{
      display: 'inline-block', fontFamily: 'var(--font-sans)', fontWeight: 600,
      fontSize: 'var(--fs-eyebrow)', letterSpacing: 'var(--ls-eyebrow)', textTransform: 'uppercase',
      color, lineHeight: 1,
      ...(pill ? { padding: '7px 12px', borderRadius: 'var(--radius-pill)', background: tone === 'on-dark' ? 'rgba(255,192,0,0.14)' : 'var(--ice)' } : {}),
      ...style,
    }}>{children}</span>
  );
}

function Badge({ children, tone = 'neutral', style }) {
  const tones = {
    neutral:  { background: 'var(--ice)', color: 'var(--blue-primary)' },
    gold:     { background: 'rgba(255,192,0,0.18)', color: 'var(--navy)' },
    deadline: { background: 'rgba(239,57,31,0.10)', color: 'var(--red)' },
    success:  { background: 'rgba(7,141,0,0.10)', color: 'var(--green)' },
    ondark:   { background: 'rgba(255,255,255,0.12)', color: 'var(--white)' },
    'gold-on-blue': { background: 'rgba(0,32,96,0.55)', color: 'var(--gold)', border: '1px solid rgba(255,192,0,0.38)', fontWeight: 700 },
  };
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontFamily: 'var(--font-sans)', fontWeight: 600, fontSize: 13, lineHeight: 1, padding: '6px 12px', borderRadius: 'var(--radius-pill)', ...tones[tone], ...style }}>
      {children}
    </span>
  );
}

function StatBar({ items = [], tone = 'on-dark' }) {
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: '10px 18px', fontFamily: 'var(--font-sans)', fontWeight: 600, fontSize: 15, color: tone === 'on-dark' ? 'var(--white)' : 'var(--blue-primary)' }}>
      {items.map((item, i) => (
        <React.Fragment key={i}>
          {i > 0 && <span aria-hidden="true" style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--gold)', flex: 'none' }} />}
          <span>{item}</span>
        </React.Fragment>
      ))}
    </div>
  );
}
function Button({ children, variant = 'primary', size = 'md', href, target, rel, arrow = false, disabled = false, type = 'button', onClick, style }) {
  const sizes = { sm: { padding: '8px 16px', fontSize: 14 }, md: { padding: '13px 24px', fontSize: 16 }, lg: { padding: '17px 32px', fontSize: 18 } };
  const variants = {
    primary: { background: 'var(--cta-bg)', color: 'var(--cta-text)', border: '2px solid transparent' },
    alt:     { background: 'var(--cta-alt-bg)', color: 'var(--cta-alt-text)', border: '2px solid transparent' },
    secondary: { background: 'transparent', color: 'var(--blue-primary)', border: '2px solid var(--blue-primary)' },
    'secondary-on-dark': { background: 'transparent', color: 'var(--white)', border: '2px solid var(--border-on-dark)' },
  };
  const base = {
    display: 'inline-flex', alignItems: 'center', gap: 8, fontFamily: 'var(--font-sans)', fontWeight: 600, lineHeight: 1,
    borderRadius: 'var(--radius-md)', cursor: disabled ? 'not-allowed' : 'pointer', opacity: disabled ? 0.5 : 1,
    textDecoration: 'none', whiteSpace: 'nowrap',
    transition: 'background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out)',
    ...sizes[size], ...variants[variant], ...style,
  };
  const hoverBg = { primary: 'var(--cta-bg-hover)', alt: 'var(--cta-alt-bg-hover)', secondary: 'var(--ice)', 'secondary-on-dark': 'rgba(255,255,255,0.10)' }[variant];
  const onEnter = (e) => {
    if (disabled) return;
    e.currentTarget.style.background = hoverBg;
    e.currentTarget.style.transform = 'translateY(-1px)';
    if (variant === 'primary') e.currentTarget.style.boxShadow = 'var(--shadow-gold)';
    if (variant === 'alt') e.currentTarget.style.boxShadow = 'var(--shadow-md)';
  };
  const onLeave = (e) => {
    if (disabled) return;
    e.currentTarget.style.background = variants[variant].background;
    e.currentTarget.style.transform = 'translateY(0)';
    e.currentTarget.style.boxShadow = 'none';
  };
  const Tag = href && !disabled ? 'a' : 'button';
  // External links get noopener by default so the opened tab cannot reach
  // back into this one via window.opener.
  const tagProps = Tag === 'a'
    ? { href, target, rel: rel || (target === '_blank' ? 'noopener noreferrer' : undefined) }
    : { type, disabled };
  return (
    <Tag {...tagProps} onClick={onClick} style={base} onMouseEnter={onEnter} onMouseLeave={onLeave}
      onMouseDown={(e) => { if (!disabled) e.currentTarget.style.transform = 'translateY(0) scale(0.98)'; }}
      onMouseUp={(e) => { if (!disabled) e.currentTarget.style.transform = 'translateY(-1px)'; }}>
      {children}
      {arrow && <span aria-hidden="true" style={{ fontSize: '1.05em', lineHeight: 1 }}>→</span>}
    </Tag>
  );
}

function SectionHead({ tone = 'on-light', eyebrow, title, sub, center }) {
  return (
    <div data-reveal="" style={{ textAlign: center ? 'center' : 'left', maxWidth: center ? 720 : 640, margin: center ? '0 auto' : undefined }}>
      <Eyebrow tone={tone}>{eyebrow}</Eyebrow>
      <h2 style={{ margin: '14px 0 0', fontWeight: 700, fontSize: 'clamp(28px,3.4vw,36px)', lineHeight: 1.12, letterSpacing: '-0.01em', color: tone === 'on-dark' ? '#fff' : 'var(--blue-primary)' }}>{title}</h2>
      {sub && <p style={{ margin: '14px 0 0', fontSize: 17, lineHeight: 1.6, color: tone === 'on-dark' ? 'rgba(255,255,255,0.82)' : 'var(--text-body)' }}>{sub}</p>}
    </div>
  );
}

function Nav() {
  const [scrolled, setScrolled] = React.useState(false);
  const [open, setOpen] = React.useState(false);
  React.useEffect(() => {
    const fn = () => setScrolled(window.scrollY > 24);
    window.addEventListener('scroll', fn, { passive: true });
    return () => window.removeEventListener('scroll', fn);
  }, []);
  return (
    <header style={{
      position: 'sticky', top: 0, zIndex: 50,
      background: scrolled ? 'rgba(0,32,96,0.92)' : 'var(--blue-primary)',
      backdropFilter: scrolled ? 'saturate(140%) blur(8px)' : 'none',
      boxShadow: scrolled ? '0 6px 18px rgba(0,32,96,0.28)' : 'none',
      transition: 'background var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out)',
    }}>
      <div style={{ maxWidth: 'var(--container)', margin: '0 auto', padding: '14px 24px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 24 }}>
        <a href="/" style={{ textDecoration: 'none' }}><Logo tone="on-dark" size="sm" /></a>
        <nav style={{ display: 'flex', alignItems: 'center', gap: 26 }} className="vfc-navlinks">
          {NAV_LINKS.map(([label, href]) => (
            <a key={href} href={href} style={{ color: 'rgba(255,255,255,0.86)', textDecoration: 'none', fontSize: 15, fontWeight: 500, transition: 'color var(--dur-fast)' }}
              onMouseEnter={(e) => e.currentTarget.style.color = 'var(--gold)'}
              onMouseLeave={(e) => e.currentTarget.style.color = 'rgba(255,255,255,0.86)'}>{label}</a>
          ))}
          <span aria-hidden="true" style={{ width: 1, height: 20, background: 'rgba(255,255,255,0.28)' }} />
          {NAV_PAGES.map(([label, href]) => (
            <a key={href} href={href} style={{ color: '#fff', textDecoration: 'none', fontSize: 15, fontWeight: 600, transition: 'color var(--dur-fast)' }}
              onMouseEnter={(e) => e.currentTarget.style.color = 'var(--gold)'}
              onMouseLeave={(e) => e.currentTarget.style.color = '#fff'}>{label}</a>
          ))}
          <Button variant="primary" size="sm" href="/#register" arrow>Register</Button>
        </nav>
        <button className="vfc-burger" onClick={() => setOpen(o => !o)} aria-label="Menu" style={{ background: 'transparent', border: 'none', color: '#fff', cursor: 'pointer', padding: 6 }}>
          <i data-lucide={open ? 'x' : 'menu'} style={{ width: 26, height: 26 }}></i>
        </button>
      </div>
      {open && (
        <div style={{ padding: '4px 24px 18px', display: 'flex', flexDirection: 'column', gap: 4 }}>
          {NAV_LINKS.map(([label, href]) => (
            <a key={href} href={href} onClick={() => setOpen(false)} style={{ color: '#fff', textDecoration: 'none', fontSize: 16, fontWeight: 500, padding: '10px 0', borderBottom: '1px solid rgba(255,255,255,0.12)' }}>{label}</a>
          ))}
          {NAV_PAGES.map(([label, href]) => (
            <a key={href} href={href} onClick={() => setOpen(false)} style={{ color: 'var(--gold)', textDecoration: 'none', fontSize: 16, fontWeight: 700, padding: '14px 0 10px' }}>{label} →</a>
          ))}
          <a href="/#register" onClick={() => setOpen(false)} style={{ color: '#fff', textDecoration: 'none', fontSize: 16, fontWeight: 600, padding: '10px 0' }}>Register</a>
        </div>
      )}
    </header>
  );
}

function Footer() {
  return (
    <footer id="contact" style={{ background: 'var(--navy)', color: '#fff', padding: '64px 24px 40px' }}>
      <div style={{ maxWidth: 'var(--container)', margin: '0 auto' }}>
        <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 40 }} className="vfc-foot-grid">
          <div>
            <Logo tone="on-dark" size="md" />
            <p style={{ margin: '18px 0 0', maxWidth: 380, fontSize: 15.5, lineHeight: 1.6, color: 'rgba(255,255,255,0.74)' }}>
              A social-entrepreneurship Learning Summit for students in Grades 7–12.
            </p>
          </div>
          <div>
            <div style={{ fontSize: 12, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.12em', color: 'var(--gold)' }}>Contact</div>
            <div style={{ marginTop: 14, display: 'grid', gap: 10, fontSize: 15.5 }}>
              <a href={`mailto:${CONTACT.email}`} style={{ color: 'rgba(255,255,255,0.86)', textDecoration: 'none', display: 'flex', gap: 8, alignItems: 'center' }}>
                <i data-lucide="mail" style={{ width: 16, height: 16, color: 'var(--gold)' }}></i>{CONTACT.email}
              </a>
              <span style={{ color: 'rgba(255,255,255,0.86)', display: 'flex', gap: 8, alignItems: 'center' }}>
                <i data-lucide="message-circle" style={{ width: 16, height: 16, color: 'var(--gold)' }}></i>WhatsApp {CONTACT.whatsapp}
              </span>
              <a href="https://www.qicenter.cn" target="_blank" rel="noopener noreferrer" style={{ color: 'rgba(255,255,255,0.86)', textDecoration: 'none', display: 'flex', gap: 8, alignItems: 'center' }}>
                <i data-lucide="globe" style={{ width: 16, height: 16, color: 'var(--gold)' }}></i>{CONTACT.site}
              </a>
              <a href="https://www.qicenter.cn" target="_blank" rel="noopener noreferrer" style={{ color: 'rgba(255,255,255,0.86)', textDecoration: 'none', display: 'flex', gap: 8, alignItems: 'center' }}>
                <i data-lucide="external-link" style={{ width: 16, height: 16, color: 'var(--gold)' }}></i>Venture For Change Asia
              </a>
            </div>
          </div>
        </div>
        <div style={{ marginTop: 40, paddingTop: 22, borderTop: '1px solid rgba(255,255,255,0.14)', display: 'flex', justifyContent: 'space-between', flexWrap: 'wrap', gap: 12, fontSize: 13.5, color: 'rgba(255,255,255,0.6)' }}>
          <span>© 2026 Qi Social Innovation Center</span>
          <span>Cultivating a Generation of Youth Social Innovators</span>
        </div>
      </div>
    </footer>
  );
}

/* ============================================================
   SCROLL REVEAL — any element tagged data-reveal fades and slides
   in the first time it enters the viewport. data-reveal="<n>"
   staggers the delay so grid children cascade. Self-installing so
   both pages pick it up; the MutationObserver catches nodes React
   mounts after this file runs.
   ============================================================ */
(function () {
  if (typeof window === 'undefined' || typeof document === 'undefined') return;

  const STAGGER = 90;
  const reduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  const io = ('IntersectionObserver' in window) && !reduced
    ? new IntersectionObserver((entries) => {
        entries.forEach((entry) => {
          if (!entry.isIntersecting) return;
          entry.target.classList.add('vfc-in');
          io.unobserve(entry.target);
        });
      }, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' })
    : null;

  function bind() {
    document.querySelectorAll('[data-reveal]:not([data-reveal-bound])').forEach((el) => {
      el.setAttribute('data-reveal-bound', '');
      el.classList.add('vfc-reveal');
      // No observer (reduced motion or no support): show it, skip the animation.
      if (!io) { el.classList.add('vfc-in'); return; }
      const step = parseInt(el.getAttribute('data-reveal'), 10);
      if (step > 0) el.style.setProperty('--reveal-delay', (step * STAGGER) + 'ms');
      io.observe(el);
    });
  }

  // React re-renders on hover/scroll state; coalesce to one pass a frame.
  let queued = false;
  function schedule() {
    if (queued) return;
    queued = true;
    requestAnimationFrame(() => { queued = false; bind(); });
  }

  // Fail open. The class that hides an element is added by this script, so
  // a page with no JS is never blank — but if the observer loads and then
  // never reports (some embedded/headless contexts never deliver
  // callbacks), content would stay invisible. If anything is still hidden
  // while on screen, treat the observer as dead and just show everything.
  function failOpen() {
    const stuck = Array.from(document.querySelectorAll('.vfc-reveal:not(.vfc-in)')).some((el) => {
      const r = el.getBoundingClientRect();
      return r.top < window.innerHeight * 0.9 && r.bottom > 0;
    });
    if (!stuck) return;
    document.querySelectorAll('.vfc-reveal').forEach((el) => el.classList.add('vfc-in'));
  }

  function start() {
    bind();
    new MutationObserver(schedule).observe(document.body, { childList: true, subtree: true });
    setTimeout(failOpen, 2500);
    // A tab that loads in the background never runs rAF or the observer, so
    // binding happens only once it is looked at — re-arm the guard then too.
    document.addEventListener('visibilitychange', function once() {
      if (document.hidden) return;
      document.removeEventListener('visibilitychange', once);
      setTimeout(failOpen, 2500);
    });
  }

  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start);
  else start();
})();
