// Motion primitives + drop-release signup modal.
// Adds: ScrollReveal, FloatingPouch, PageFadeIn, AnimatedArrow,
// DropProvider/useDrop, and DropSignupModal.

// ──────────────────────────────────────────────────────────────
// One-time CSS injection — keyframes + base motion classes.
// ──────────────────────────────────────────────────────────────
(function injectMotionCss() {
  if (document.getElementById('site-motion-css')) return;
  const s = document.createElement('style');
  s.id = 'site-motion-css';
  s.textContent = `
    @keyframes rg-fade-up { from { opacity:0; transform:translateY(28px); } to { opacity:1; transform:translateY(0); } }
    @keyframes rg-fade    { from { opacity:0; } to { opacity:1; } }
    @keyframes rg-float-a { 0%,100% { transform:translateY(0) rotate(var(--rg-rot,0deg)); } 50% { transform:translateY(-8px) rotate(var(--rg-rot,0deg)); } }
    @keyframes rg-stamp   { 0% { opacity:0; transform:scale(.85); } 60% { opacity:1; transform:scale(1.04); } 100% { opacity:1; transform:scale(1); } }
    @keyframes rg-marquee { from { transform:translateX(0); } to { transform:translateX(-50%); } }
    @keyframes rg-arrow   { 0%,100% { transform:translateX(0); } 50% { transform:translateX(3px); } }
    @keyframes rg-spin    { from { transform:rotate(0deg); } to { transform:rotate(360deg); } }

    .rg-fade-up { opacity:0; transform:translateY(28px); transition: opacity .9s cubic-bezier(.2,.7,.3,1), transform .9s cubic-bezier(.2,.7,.3,1); }
    .rg-fade-up.rg-in { opacity:1; transform:translateY(0); }

    .rg-fade { opacity:0; transition: opacity 1.2s ease; }
    .rg-fade.rg-in { opacity:1; }

    .rg-float { animation: rg-float-a 6s ease-in-out infinite; will-change: transform; }
    .rg-stamp-in { animation: rg-stamp .9s cubic-bezier(.2,.9,.3,1.05) both; }

    .rg-page { animation: rg-fade-up .55s cubic-bezier(.2,.7,.3,1) both; }

    .rg-marquee-track { display:flex; gap:48px; animation: rg-marquee 38s linear infinite; will-change: transform; }

    .rg-btn { position:relative; overflow:hidden; }
    .rg-btn:hover .rg-arrow { animation: rg-arrow 1s ease-in-out infinite; }
    .rg-btn::after { content:''; position:absolute; inset:0; background:currentColor; opacity:0; transition: opacity .25s; pointer-events:none; mix-blend-mode:overlay; }
    .rg-btn:hover::after { opacity:.08; }
    .rg-btn:active { transform: translateY(1px); }

    .rg-card-lift { transition: transform .35s cubic-bezier(.2,.7,.3,1), box-shadow .35s; }
    .rg-card-lift:hover { transform: translateY(-4px); }

    .rg-pouch-lift { transition: transform .45s cubic-bezier(.2,.7,.3,1); will-change: transform; }

    .rg-link-underline { position:relative; }
    .rg-link-underline::after { content:''; position:absolute; left:0; right:0; bottom:-3px; height:1px; background:currentColor; transform:scaleX(0); transform-origin:left; transition: transform .35s cubic-bezier(.2,.7,.3,1); }
    .rg-link-underline:hover::after { transform:scaleX(1); }

    .rg-spinner { width:18px; height:18px; border-radius:50%; border:1.5px solid currentColor; border-top-color:transparent; animation: rg-spin .9s linear infinite; }

    /* respect reduced motion */
    @media (prefers-reduced-motion: reduce) {
      .rg-fade-up, .rg-fade, .rg-float, .rg-stamp-in, .rg-page, .rg-marquee-track { animation: none !important; transition: none !important; opacity:1 !important; transform:none !important; }
    }
  `;
  document.head.appendChild(s);
})();

// ──────────────────────────────────────────────────────────────
// ScrollReveal — wraps children, adds .rg-in once they enter viewport.
// ──────────────────────────────────────────────────────────────
function ScrollReveal({ children, delay = 0, as: As = 'div', className = '', style }) {
  const ref = React.useRef(null);
  const [seen, setSeen] = React.useState(false);
  React.useEffect(() => {
    if (!ref.current || seen) return;
    if (typeof IntersectionObserver === 'undefined') { setSeen(true); return; }
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) { setSeen(true); obs.disconnect(); } });
    }, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, [seen]);
  return (
    <As ref={ref} className={`rg-fade-up ${seen ? 'rg-in' : ''} ${className}`}
        style={{ transitionDelay: `${delay}ms`, ...(style || {}) }}>
      {children}
    </As>
  );
}

// Stagger helper — wraps a list and gives each child an incrementing delay.
function Stagger({ children, step = 80, start = 0, className = '', style }) {
  const arr = React.Children.toArray(children);
  return (
    <div className={className} style={style}>
      {arr.map((c, i) => (
        <ScrollReveal key={i} delay={start + i * step}>{c}</ScrollReveal>
      ))}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// FloatingPouch — wraps a pouch and gives it a gentle infinite float,
// while preserving its base rotate/translate transforms via CSS vars.
// ──────────────────────────────────────────────────────────────
function FloatingPouch({ children, rotate = 0, translateX = 0, translateY = 0, delay = 0, duration = 6, lift = 0 }) {
  return (
    <div style={{
      position:'absolute', left:'50%', top:'50%',
      transform:`translate(-50%, -50%) translateX(${translateX}px) translateY(${translateY}px)`,
    }}>
      <div
        className="rg-pouch-lift"
        style={{
          transform:`rotate(${rotate}deg)`,
          animation:`rg-float-a ${duration}s ease-in-out ${delay}s infinite`,
          ['--rg-rot']:`${rotate}deg`,
          transition:'transform .45s cubic-bezier(.2,.7,.3,1)',
        }}
        onMouseEnter={(e) => { e.currentTarget.style.animationPlayState = 'paused'; e.currentTarget.style.transform = `rotate(${rotate}deg) translateY(${-(lift || 14)}px) scale(1.04)`; }}
        onMouseLeave={(e) => { e.currentTarget.style.animationPlayState = 'running'; e.currentTarget.style.transform = `rotate(${rotate}deg)`; }}
      >{children}</div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// Animated arrow that scoots on parent .rg-btn hover.
// ──────────────────────────────────────────────────────────────
function AnimatedArrow({ children = '→' }) {
  return <span className="rg-arrow" style={{ display:'inline-block' }}>{children}</span>;
}

// ──────────────────────────────────────────────────────────────
// Drop signup context + modal
// ──────────────────────────────────────────────────────────────
const DropContext = React.createContext({ open: () => {}, isOpen: false });

function DropProvider({ children }) {
  const [isOpen, setIsOpen] = React.useState(false);
  const [source, setSource] = React.useState(null);
  const open = (src) => { setSource(src || null); setIsOpen(true); };
  const close = () => setIsOpen(false);
  return (
    <DropContext.Provider value={{ open, close, isOpen, source }}>
      {children}
    </DropContext.Provider>
  );
}

const useDrop = () => React.useContext(DropContext);

// Reusable "Sign up for drop release" button. Pulls action from context.
function DropCTA({ children = 'Sign up for drop release', variant = 'solid', source, fg, bg, style, full }) {
  const { open } = useDrop();
  const v = variant === 'solid'
    ? { background: bg || site.ink, color: fg || site.paper, border:`1px solid ${bg || site.ink}` }
    : { background:'transparent', color: fg || site.ink, border:`1px solid ${fg || site.ink}` };
  return (
    <button
      className="rg-btn"
      onClick={() => open(source)}
      style={{
        ...v, fontFamily: site.mono, fontSize:11, letterSpacing:'.28em',
        textTransform:'uppercase', padding:'16px 22px',
        cursor:'pointer', borderRadius:0,
        display:'inline-flex', alignItems:'center', gap:10,
        width: full ? '100%' : 'auto', justifyContent: full ? 'center' : 'flex-start',
        transition:'background .25s ease, color .25s ease, transform .15s ease',
        ...style,
      }}
    >
      <span>{children}</span>
      <AnimatedArrow />
    </button>
  );
}

// The modal itself — apothecary-styled email collector.
function DropSignupModal() {
  const { isOpen, close, source } = useDrop();
  const [email, setEmail]   = React.useState('');
  const [stage, setStage]   = React.useState('form'); // 'form' | 'loading' | 'done'
  const [interest, setInterest] = React.useState(['all']);
  // viewport reflects iPhone-narrow cases so we full-screen the modal there
  const isNarrow = (typeof window !== 'undefined') ? window.innerWidth < 720 : false;

  React.useEffect(() => {
    if (isOpen) {
      setStage('form'); setEmail(''); setInterest(source ? [source] : ['all']);
    }
  }, [isOpen, source]);

  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') close(); };
    if (isOpen) window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [isOpen, close]);

  const submit = (e) => {
    e.preventDefault();
    if (!email) return;
    setStage('loading');
    // Fake the network call — show success after a beat.
    setTimeout(() => setStage('done'), 950);
  };

  const toggle = (id) => setInterest((prev) =>
    prev.includes(id) ? prev.filter((x) => x !== id) : [...prev.filter((x) => x !== 'all'), id]
  );

  return (
    <>
      <div
        data-rg-blur
        onClick={close}
        style={{
          position:'fixed', inset:0, background:'rgba(15,10,6,.55)', zIndex:80,
          opacity: isOpen ? 1 : 0, pointerEvents: isOpen ? 'auto' : 'none',
          transition:'opacity .3s ease',
        }}
      />
      <div
        role="dialog"
        aria-modal="true"
        style={{
          position:'fixed', zIndex:81,
          ...(isNarrow ? {
            inset: 0,
            transform: `translateY(${isOpen ? 0 : 100}%)`,
            transition:'transform .35s cubic-bezier(.2,.7,.3,1)',
            overflowY:'auto',
          } : {
            top:'50%', left:'50%',
            transform:`translate(-50%, -50%) scale(${isOpen ? 1 : .96})`,
            opacity: isOpen ? 1 : 0,
            transition:'opacity .3s ease, transform .3s cubic-bezier(.2,.7,.3,1)',
            width: 'min(92vw, 560px)',
          }),
          pointerEvents: isOpen ? 'auto' : 'none',
          background: site.paper, color: site.ink,
          boxShadow: isNarrow ? 'none' : '0 30px 80px rgba(15,10,6,.4), 0 0 0 .5px rgba(31,22,16,.2)',
          padding: isNarrow ? '64px 24px 40px' : '40px 40px 32px',
          paddingTop: isNarrow ? 'calc(env(safe-area-inset-top) + 56px)' : '40px',
          paddingBottom: isNarrow ? 'calc(env(safe-area-inset-bottom) + 32px)' : '32px',
        }}
      >
        {/* close */}
        <button onClick={close} style={{
          position:'absolute', top:14, right:18, background:'transparent', border:'none',
          fontFamily: site.mono, fontSize:11, letterSpacing:'.28em', cursor:'pointer', color: site.ink, opacity:.7,
        }}>CLOSE ✕</button>

        {/* stamped seal */}
        <div className="rg-stamp-in" style={{display:'flex', justifyContent:'center', marginTop:6}}>
          <SiteSeal size={62} fg={site.ink} />
        </div>

        {stage !== 'done' && (
          <>
            <div style={{textAlign:'center', marginTop:14}}>
              <div style={{fontFamily: site.mono, fontSize:10, letterSpacing:'.32em', opacity:.65}}>PRE-LAUNCH · SS 26</div>
              <h2 style={{fontFamily: site.serif, fontStyle:'italic', fontWeight:500, fontSize: isNarrow ? 36 : 46, lineHeight:1, letterSpacing:'-.02em', margin:'12px 0 0'}}>The first drop opens soon.</h2>
              <p style={{fontFamily: site.serif, fontStyle:'italic', fontSize:17, lineHeight:1.45, marginTop:14, opacity:.85, maxWidth:420, marginInline:'auto'}}>
                Leave your inbox. We will write only when the apothecary opens — once for the drop, and a small thank-you note after.
              </p>
            </div>

            <form onSubmit={submit} style={{marginTop:26}}>
              <div style={{display:'flex', border:`1px solid ${site.ink}`, opacity: stage === 'loading' ? .6 : 1, transition:'opacity .2s'}}>
                <input
                  type="email" required value={email}
                  onChange={(e) => setEmail(e.target.value)}
                  placeholder="your@inbox.com" autoFocus
                  disabled={stage === 'loading'}
                  style={{flex:1, padding:'16px 18px', border:'none', background:'transparent', fontFamily: site.serif, fontStyle:'italic', fontSize:18, color: site.ink, outline:'none'}}
                />
                <button type="submit" className="rg-btn" disabled={stage === 'loading'} style={{
                  background: site.ink, color: site.paper, border:'none', padding:'0 22px',
                  fontFamily: site.mono, fontSize:11, letterSpacing:'.28em', cursor:'pointer',
                  display:'flex', alignItems:'center', gap:10, textTransform:'uppercase',
                }}>
                  {stage === 'loading' ? <span className="rg-spinner"></span> : <><span>Notify me</span><AnimatedArrow /></>}
                </button>
              </div>

              <div style={{marginTop:18, display:'flex', flexDirection:'column', gap:8}}>
                <div style={{fontFamily: site.mono, fontSize:10, letterSpacing:'.32em', opacity:.55}}>WHAT TO TELL ME ABOUT</div>
                <div style={{display:'flex', flexWrap:'wrap', gap:8}}>
                  {[
                    ['all','Everything'],
                    ['hydrate','Hydrate · 01'],
                    ['recover','Recover · 02'],
                    ['sleep','Sleep · 03'],
                    ['revive','Revive · 04'],
                    ['focus','Focus · 05'],
                  ].map(([id, label]) => {
                    const active = interest.includes(id);
                    return (
                      <button key={id} type="button" onClick={() => toggle(id)} style={{
                        background: active ? site.ink : 'transparent', color: active ? site.paper : site.ink,
                        border:`.5px solid ${site.ink}`, padding:'8px 12px', fontFamily: site.mono, fontSize:9,
                        letterSpacing:'.26em', cursor:'pointer', transition:'all .15s ease',
                      }}>{label.toUpperCase()}</button>
                    );
                  })}
                </div>
              </div>

              <div style={{marginTop:18, fontFamily: site.mono, fontSize:9, letterSpacing:'.24em', opacity:.55, textAlign:'center'}}>
                NO SPAM · UNSUBSCRIBE IN ONE CLICK · 식약처 등록 진행 중
              </div>
            </form>
          </>
        )}

        {stage === 'done' && (
          <div style={{textAlign:'center', marginTop:18}}>
            <div style={{fontFamily: site.mono, fontSize:10, letterSpacing:'.32em', color: site.warm}}>SEALED.</div>
            <h2 style={{fontFamily: site.serif, fontStyle:'italic', fontWeight:500, fontSize:46, lineHeight:1, letterSpacing:'-.02em', margin:'14px 0 0'}}>You are on the list.</h2>
            <p style={{fontFamily: site.serif, fontStyle:'italic', fontSize:17, lineHeight:1.45, marginTop:14, opacity:.85, maxWidth:420, marginInline:'auto'}}>
              We will write to <strong style={{fontStyle:'normal', fontFamily: site.mono, fontSize:13, letterSpacing:'.1em'}}>{email}</strong> the morning the apothecary opens. Until then, drink water.
            </p>
            <button onClick={close} className="rg-btn" style={{
              marginTop:24, background: site.ink, color: site.paper, border:'none',
              padding:'14px 22px', fontFamily: site.mono, fontSize:11, letterSpacing:'.28em',
              cursor:'pointer', display:'inline-flex', alignItems:'center', gap:10,
            }}>
              <span>Back to the shelf</span><AnimatedArrow />
            </button>
          </div>
        )}
      </div>
    </>
  );
}

Object.assign(window, {
  ScrollReveal, Stagger, FloatingPouch, AnimatedArrow,
  DropContext, DropProvider, useDrop, DropCTA, DropSignupModal,
  useViewport,
});

// ──────────────────────────────────────────────────────────────
// useViewport — width + breakpoint flags, updates on resize.
// ──────────────────────────────────────────────────────────────
function useViewport() {
  const get = () => ({
    width:  typeof window !== 'undefined' ? window.innerWidth  : 1440,
    height: typeof window !== 'undefined' ? window.innerHeight : 900,
  });
  const [vp, setVp] = React.useState(get);
  React.useEffect(() => {
    const onResize = () => setVp(get());
    window.addEventListener('resize', onResize);
    window.addEventListener('orientationchange', onResize);
    return () => {
      window.removeEventListener('resize', onResize);
      window.removeEventListener('orientationchange', onResize);
    };
  }, []);
  return {
    width: vp.width, height: vp.height,
    isMobile:  vp.width < 720,
    isTablet:  vp.width >= 720 && vp.width < 1100,
    isDesktop: vp.width >= 1100,
  };
}
