// Otto landing — atoms & shared bits

// Use IntersectionObserver to fade in elements when they enter view
function Reveal({ children, delay = 0, y = 24, style = {} }) {
  const ref = React.useRef(null);
  const [shown, setShown] = React.useState(false);
  React.useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setShown(true); io.disconnect(); }
    }, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
    io.observe(ref.current);
    return () => io.disconnect();
  }, []);
  return (
    <div ref={ref} style={{
      opacity: shown ? 1 : 0,
      transform: shown ? 'translateY(0)' : `translateY(${y}px)`,
      transition: `opacity 800ms cubic-bezier(.2,.8,.2,1) ${delay}ms, transform 900ms cubic-bezier(.2,.8,.2,1) ${delay}ms`,
      ...style,
    }}>{children}</div>
  );
}

// Hook: get current scroll position
function useScrollY() {
  const [y, setY] = React.useState(0);
  React.useEffect(() => {
    let raf = null;
    const onScroll = () => {
      if (raf) return;
      raf = requestAnimationFrame(() => {
        setY(window.scrollY); raf = null;
      });
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, []);
  return y;
}

// Animated count-up that triggers when in view
function CountUpInView({ to, duration = 1200, suffix = '', style = {} }) {
  const ref = React.useRef(null);
  const [n, setN] = React.useState(0);
  const [run, setRun] = React.useState(false);
  React.useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setRun(true); io.disconnect(); }
    }, { threshold: 0.4 });
    io.observe(ref.current);
    return () => io.disconnect();
  }, []);
  React.useEffect(() => {
    if (!run) return;
    let raf, start;
    const step = (t) => {
      if (!start) start = t;
      const p = Math.min((t - start) / duration, 1);
      const eased = 1 - Math.pow(1 - p, 3);
      setN(to * eased);
      if (p < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [run, to, duration]);
  const display = Number.isInteger(to) ? Math.round(n) : n.toFixed(1);
  return <span ref={ref} style={style}>{display}{suffix}</span>;
}

// Marker chip with sage dot
function MarkerLabel({ children, tone = 'sage' }) {
  const c = tone === 'amber' ? OttoTokens.amber : tone === 'clay' ? OttoTokens.clay : OttoTokens.sage;
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center', gap: 10,
      fontFamily: OttoTokens.sans, fontSize: 13, fontWeight: 600,
      letterSpacing: 1.6, textTransform: 'uppercase',
      color: OttoTokens.inkMuted,
    }}>
      {children}
    </div>
  );
}

// Big editorial headline
function Headline({ size = 'lg', children, style = {} }) {
  const sizes = {
    xl: { fs: 'clamp(48px, 7.6vw, 112px)', lh: 1.02, ls: -2 },
    lg: { fs: 'clamp(40px, 5.4vw, 80px)', lh: 1.04, ls: -1.5 },
    md: { fs: 'clamp(32px, 3.6vw, 56px)', lh: 1.08, ls: -1 },
  }[size];
  return (
    <h2 style={{
      fontFamily: OttoTokens.serif, fontWeight: 400,
      fontSize: sizes.fs, lineHeight: sizes.lh, letterSpacing: sizes.ls,
      color: OttoTokens.ink, margin: 0,
      textWrap: 'balance',
      ...style,
    }}>{children}</h2>
  );
}

// Body lede
function Lede({ children, style = {} }) {
  return (
    <p style={{
      fontFamily: OttoTokens.sans,
      fontSize: 'clamp(18px, 1.4vw, 22px)',
      lineHeight: 1.55, color: OttoTokens.inkMuted, margin: 0,
      maxWidth: 620, textWrap: 'pretty',
      ...style,
    }}>{children}</p>
  );
}

// Container w/ responsive padding
function Container({ children, max = 1280, style = {} }) {
  return (
    <div style={{
      width: '100%', maxWidth: max, margin: '0 auto',
      padding: '0 clamp(20px, 4vw, 56px)',
      ...style,
    }}>{children}</div>
  );
}

// Big rounded button
function CTA({ children, kind = 'primary', href = '#', style = {}, onClick }) {
  const kinds = {
    primary: { bg: OttoTokens.ink, fg: '#FAF7F1', bd: 'transparent' },
    sage: { bg: OttoTokens.sage, fg: '#fff', bd: 'transparent' },
    ghost: { bg: 'transparent', fg: OttoTokens.ink, bd: 'rgba(28,26,23,0.18)' },
  };
  const s = kinds[kind];
  return (
    <a href={href} onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 10,
      minHeight: 60, padding: '0 28px',
      borderRadius: 999,
      background: s.bg, color: s.fg,
      border: `1.5px solid ${s.bd}`,
      fontFamily: OttoTokens.sans, fontSize: 17, fontWeight: 600,
      letterSpacing: -0.2, textDecoration: 'none',
      cursor: 'pointer',
      transition: 'transform 180ms ease, box-shadow 180ms ease',
      ...style,
    }}
    onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-2px)'; e.currentTarget.style.boxShadow = '0 12px 28px -16px rgba(28,26,23,0.45)'; }}
    onMouseLeave={e => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = 'none'; }}
    >{children}</a>
  );
}

Object.assign(window, { Reveal, useScrollY, CountUpInView, MarkerLabel, Headline, Lede, Container, CTA });
