/* global React */
const { useState: useStateAI, useEffect: useEffectAI, useRef: useRefAI, useMemo: useMemoAI } = React;

/* ----------------------------------------------------------------- */
/*  ASPACE AI — Creative Concierge                                   */
/*                                                                    */
/*  Design intent:                                                    */
/*    - A spatial design object, not a chat widget                    */
/*    - Single-screen layout, never scrolls internally                */
/*    - Header / breathing void / cinematic input                     */
/*    - Editorial typography over chat bubbles                        */
/*    - Ambient electric-blue atmosphere with restraint               */
/* ----------------------------------------------------------------- */

const SUGGESTIONS = [
  { k: 'find',    label: 'Find a private studio', hint: 'Match a room to your work.' },
  { k: 'viewing', label: 'Book a viewing',        hint: '30-min in-person tour.' },
  { k: 'shoot',   label: 'Plan a shoot',          hint: 'Photo, video, LED wall.' },
  { k: 'explore', label: 'Explore ASPACE',        hint: 'Take the long way through.' },
];

const AI_REPLIES = {
  find: {
    text: "Tell me what you're making — light-driven photography, video with an LED wall, fashion, or workshop work — and I'll match a room to your workflow.",
    rec: { id: '03', title: 'Atelier 03', label: 'PRIVATE · 18M²' },
  },
  viewing: {
    text: "I can hold a 30-minute viewing for you. Wednesday the 13th at 10:00 is open. Want me to pencil it in?",
    rec: { id: '01', title: 'North Light', label: 'PRIVATE · 16M²' },
  },
  shoot: {
    text: "For a shoot we have natural light, an LED wall room and a treated voice room. Tell me the format and I'll suggest the right one.",
    rec: { id: '02', title: 'Motion Lab', label: 'CREATIVE · 22M²' },
  },
  explore: {
    text: "ASPACE is six private studios, a production room and a long communal table — five minutes from Centraal, in the middle of where things actually get made.",
    rec: { id: '06', title: 'The Living Room', label: 'LOUNGE · COMMUNAL' },
  },
};

/* ----------------------------------------------------------------- */
/*  TRIGGER — boutique-hotel concierge launcher                       */
/*                                                                    */
/*  Reference language: members club door · suite intercom · Apple    */
/*  retail genius bar invitation. Smoked graphite glass, monochrome   */
/*  spatial orb with a single electric-blue centre, no pulse.         */
/*  Mobile collapses to a compact orb-only chip.                      */
/* ----------------------------------------------------------------- */

function AITrigger({ onOpen, blue, hidden }) {
  const t = (window.useT && window.useT()) || ((k) => k);
  const [hover, setHover] = useStateAI(false);
  const [compact, setCompact] = useStateAI(typeof window !== 'undefined' ? window.innerWidth < 560 : false);
  useEffectAI(() => {
    const onR = () => setCompact(window.innerWidth < 560);
    window.addEventListener('resize', onR);
    return () => window.removeEventListener('resize', onR);
  }, []);

  return (
    <button
      onClick={onOpen}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      aria-label={t('ai.triggerAria')}
      style={{
        all: 'unset', cursor: 'pointer',
        position: 'fixed',
        right: 'clamp(16px, 2.4vw, 36px)',
        bottom: 'clamp(16px, 2.4vw, 36px)',
        zIndex: 9400,
        opacity: hidden ? 0 : 1,
        pointerEvents: hidden ? 'none' : 'auto',
        transform: hover ? 'translateY(-1px)' : 'translateY(0)',
        transition: 'transform 520ms cubic-bezier(0.22,1,0.36,1), opacity 520ms ease',
      }}
    >
      {/* Smoked graphite glass — desaturated, low contrast, hospitality-grade */}
      <div style={{
        position: 'relative',
        display: 'inline-flex', alignItems: 'center',
        gap: compact ? 0 : 11,
        padding: compact ? '8px' : '8px 18px 8px 10px',
        borderRadius: 999,
        background: hover
          ? 'linear-gradient(180deg, rgba(34,34,38,0.66) 0%, rgba(18,18,20,0.54) 100%)'
          : 'linear-gradient(180deg, rgba(26,26,30,0.58) 0%, rgba(14,14,16,0.46) 100%)',
        backdropFilter: 'blur(22px) saturate(130%)',
        WebkitBackdropFilter: 'blur(22px) saturate(130%)',
        border: hover ? '1px solid rgba(255,255,255,0.18)' : '1px solid rgba(255,255,255,0.10)',
        boxShadow: hover
          ? '0 1px 0 rgba(255,255,255,0.12) inset, 0 -1px 0 rgba(0,0,0,0.45) inset, 0 22px 48px -22px rgba(0,0,0,0.55)'
          : '0 1px 0 rgba(255,255,255,0.08) inset, 0 -1px 0 rgba(0,0,0,0.40) inset, 0 14px 32px -18px rgba(0,0,0,0.45)',
        transition: 'background 420ms ease, border-color 420ms ease, box-shadow 520ms ease, padding 420ms ease, gap 420ms ease',
      }}>
        {/* Spatial orb — concentric monochrome layers, single blue centre */}
        <span aria-hidden="true" style={{
          position: 'relative',
          flexShrink: 0,
          width: 30, height: 30,
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        }}>
          <svg width="30" height="30" viewBox="0 0 30 30" style={{ display: 'block', overflow: 'visible' }}>
            {/* Outermost halo — softest, almost a breath of light */}
            <circle cx="15" cy="15" r="13.2" fill="none"
              stroke="rgba(255,255,255,0.08)" strokeWidth="0.6" />
            {/* Mid ring */}
            <circle cx="15" cy="15" r="9.6" fill="none"
              stroke="rgba(255,255,255,0.16)" strokeWidth="0.6" />
            {/* Inner ring — slightly brighter to hint at depth */}
            <circle cx="15" cy="15" r="6" fill="none"
              stroke="rgba(255,255,255,0.26)" strokeWidth="0.6" />
            {/* Subtle tonal lens — graphite radial fill */}
            <defs>
              <radialGradient id="ai-lens" cx="50%" cy="50%" r="50%">
                <stop offset="0%"  stopColor="rgba(255,255,255,0.10)" />
                <stop offset="60%" stopColor="rgba(255,255,255,0.02)" />
                <stop offset="100%" stopColor="rgba(255,255,255,0)" />
              </radialGradient>
            </defs>
            <circle cx="15" cy="15" r="13" fill="url(#ai-lens)" />
            {/* Single electric-blue accent — the only colour in the launcher */}
            <circle cx="15" cy="15" r="1.6" fill={blue}
              style={{ opacity: hover ? 1 : 0.92, transition: 'opacity 480ms ease' }} />
          </svg>
        </span>

        {/* Text block — only on roomy viewports */}
        {!compact && (
          <span style={{
            display: 'inline-flex', flexDirection: 'column',
            lineHeight: 1.18,
            color: 'rgba(255,255,255,0.94)',
          }}>
            <span style={{
              fontFamily: "'Inter Tight', sans-serif",
              fontWeight: 500, fontSize: 13.5,
              letterSpacing: '-0.005em',
            }}>{t('ai.triggerTitle')}</span>
            <span style={{
              marginTop: 2,
              fontSize: 8.5,
              letterSpacing: '0.22em',
              textTransform: 'uppercase',
              color: 'rgba(255,255,255,0.42)',
            }}>{t('ai.triggerTagline')}</span>
          </span>
        )}
      </div>
    </button>
  );
}

/* ----------------------------------------------------------------- */
/*  PRESENCE ORB — alive breathing AI signature next to the title     */
/* ----------------------------------------------------------------- */

function PresenceOrb({ blue, hovered }) {
  const [t, setT] = useStateAI(0);
  useEffectAI(() => {
    let raf, t0 = performance.now();
    const tick = (n) => { setT((n - t0) / 1000); raf = requestAnimationFrame(tick); };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);
  const breath = (Math.sin(t * 1.6) + 1) * 0.5;
  const orbit  = (t * 30) % 360;
  const halo   = hovered ? 1 : 0;

  return (
    <span aria-hidden="true" style={{
      position: 'relative',
      width: 52, height: 52, flexShrink: 0,
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
    }}>
      {/* outer halo */}
      <span style={{
        position: 'absolute', inset: -18,
        borderRadius: '50%',
        background: `radial-gradient(circle, ${blue}26 0%, transparent 65%)`,
        opacity: 0.55 + breath * 0.35 + halo * 0.25,
        filter: `blur(${6 + breath * 4}px)`,
        transition: 'opacity 480ms ease',
      }}/>
      {/* core ring rotation */}
      <span style={{
        position: 'absolute', inset: 0,
        borderRadius: '50%',
        border: `1px solid ${blue}`,
        opacity: 0.32,
        transform: `rotate(${orbit}deg) scale(${1 + halo * 0.04})`,
        background: `conic-gradient(from 0deg, transparent 60%, ${blue} 82%, transparent 100%)`,
        WebkitMaskImage: 'radial-gradient(circle, transparent 62%, black 64%)',
        maskImage: 'radial-gradient(circle, transparent 62%, black 64%)',
        transition: 'transform 480ms cubic-bezier(0.22,1.2,0.36,1)',
      }}/>
      {/* inner ring counter-rotation */}
      <span style={{
        position: 'absolute', inset: 9,
        borderRadius: '50%',
        border: `1px solid ${blue}`,
        opacity: 0.18,
        transform: `rotate(${-orbit * 0.7}deg)`,
      }}/>
      {/* breathing core */}
      <span style={{
        width: 10 + breath * 6, height: 10 + breath * 6,
        borderRadius: '50%',
        background: blue,
        boxShadow: `0 0 ${14 + breath * 18}px ${blue}, 0 0 ${30 + breath * 24}px ${blue}55`,
      }}/>
    </span>
  );
}

/* ----------------------------------------------------------------- */
/*  PANEL — the cinematic spatial interface                           */
/* ----------------------------------------------------------------- */

function AIPanel({ open, onClose, blue }) {
  const tx = (window.useT && window.useT()) || ((k) => k);
  const suggestions = tx('ai.suggestions') || [];
  const replies = tx('ai.replies') || {};
  // Only the most recent exchange lives on screen — no scroll, ever.
  const [exchange, setExchange] = useStateAI(null);   // { user, ai, rec } | null
  const [input, setInput] = useStateAI('');
  const [thinking, setThinking] = useStateAI(false);
  const [closeHover, setCloseHover] = useStateAI(false);
  const [orbHover, setOrbHover] = useStateAI(false);
  const [focused, setFocused] = useStateAI(false);
  const [pillHoverIdx, setPillHoverIdx] = useStateAI(-1);
  const [magnets, setMagnets] = useStateAI({});
  const [clock, setClock] = useStateAI(0);
  const inputRef = useRefAI(null);

  // Ambient time (for atmosphere drift + send button core)
  useEffectAI(() => {
    let raf, t0 = performance.now();
    const tick = (n) => { setClock((n - t0) / 1000); raf = requestAnimationFrame(tick); };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  // Esc, body lock, focus input on open. Reset state on close.
  useEffectAI(() => {
    if (!open) {
      const t = setTimeout(() => { setExchange(null); setInput(''); setThinking(false); }, 520);
      return () => clearTimeout(t);
    }
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    document.documentElement.style.overflow = 'hidden';
    document.body.style.overflow = 'hidden';
    if (window.lenis && typeof window.lenis.stop === 'function') window.lenis.stop();
    const focus = setTimeout(() => inputRef.current?.focus(), 600);
    return () => {
      window.removeEventListener('keydown', onKey);
      // Always reset (never restore stale 'hidden' from chained overlays).
      document.documentElement.style.overflow = '';
      document.body.style.overflow = '';
      if (window.lenis && typeof window.lenis.start === 'function') window.lenis.start();
      clearTimeout(focus);
    };
  }, [open, onClose]);

  const respond = (key, label) => {
    const fb = AI_REPLIES[key] || AI_REPLIES.find;
    const r  = replies[key] || replies.find || {};
    const text     = r.text     || fb.text;
    const recTitle = r.recTitle || (fb.rec && fb.rec.title);
    const recLabel = r.recLabel || (fb.rec && fb.rec.label);
    setExchange({ user: label, ai: null, rec: null });
    setThinking(true);
    setTimeout(() => {
      setThinking(false);
      setExchange({ user: label, ai: text, rec: { title: recTitle, label: recLabel } });
    }, 900);
  };

  const sendInput = () => {
    if (!input.trim()) return;
    const guess = Object.keys(AI_REPLIES).find(k => input.toLowerCase().includes(k.slice(0, 4))) || 'find';
    respond(guess, input.trim());
    setInput('');
  };

  const reset = () => { setExchange(null); setInput(''); inputRef.current?.focus(); };

  // Magnetic pill hover handler
  const onPillMove = (i, e) => {
    const el = e.currentTarget;
    const r = el.getBoundingClientRect();
    const dx = (e.clientX - (r.left + r.width / 2)) * 0.10;
    const dy = (e.clientY - (r.top + r.height / 2)) * 0.10;
    setMagnets(prev => ({ ...prev, [i]: { x: dx, y: dy } }));
  };
  const onPillLeave = (i) => {
    setMagnets(prev => ({ ...prev, [i]: { x: 0, y: 0 } }));
    setPillHoverIdx(idx => idx === i ? -1 : idx);
  };

  // Slow ambient atmosphere drift
  const ambientX = 50 + Math.sin(clock * 0.18) * 6;
  const ambientY = 38 + Math.cos(clock * 0.22) * 4;
  const ambientPulse = 0.5 + (Math.sin(clock * 0.9) + 1) * 0.25;

  // Send button live core
  const sendBreath = (Math.sin(clock * 2.4) + 1) * 0.5;
  const sendOrbit  = (clock * 90) % 360;

  return (
    <React.Fragment>
      {/* Backdrop — strong scrim so the panel reads as a separate layer */}
      <div onClick={onClose} aria-hidden="true" style={{
        position: 'fixed', inset: 0, zIndex: 9700,
        background: 'rgba(6,6,8,0.62)',
        backdropFilter: 'blur(22px) saturate(120%)',
        WebkitBackdropFilter: 'blur(22px) saturate(120%)',
        opacity: open ? 1 : 0,
        pointerEvents: open ? 'auto' : 'none',
        transition: 'opacity 720ms cubic-bezier(0.22,1,0.36,1)',
      }}/>

      {/* Stage — the design object itself */}
      <aside aria-hidden={!open} aria-label={tx('ai.panelAria')} data-aurora={open ? "ai-panel" : undefined} style={{
        position: 'fixed', zIndex: 9800,
        pointerEvents: open ? 'auto' : 'none',
        top: '50%', left: '50%',
        width: 'min(1180px, calc(100vw - clamp(16px, 4vw, 56px)))',
        height: 'min(780px, calc(100dvh - clamp(16px, 4vw, 56px)))',
        transform: open
          ? 'translate(-50%, -50%) scale(1)'
          : 'translate(-50%, -46%) scale(0.96)',
        opacity: open ? 1 : 0,
        transition: 'opacity 640ms cubic-bezier(0.22,1,0.36,1), transform 800ms cubic-bezier(0.22,1.2,0.36,1)',
        borderRadius: 'clamp(20px, 2.4vw, 32px)',
        overflow: 'hidden',
        background: 'rgba(244,242,236,0.94)',
        backdropFilter: 'blur(30px) saturate(140%)',
        WebkitBackdropFilter: 'blur(30px) saturate(140%)',
        border: '1px solid rgba(255,255,255,0.55)',
        boxShadow: `
          0 60px 140px -40px rgba(0,0,0,0.55),
          0 16px 40px -16px rgba(0,0,0,0.22),
          inset 0 1px 0 rgba(255,255,255,0.55),
          0 0 80px rgba(0,194,255,0.10)
        `,
        display: 'flex', flexDirection: 'column',
      }}>
        {/* ----- ATMOSPHERE LAYER (light pools + grain) ----- */}
        <div aria-hidden="true" style={{
          position: 'absolute', inset: 0,
          pointerEvents: 'none',
          background: `
            radial-gradient(720px 520px at ${ambientX}% ${ambientY}%, rgba(0,194,255,${0.13 + ambientPulse * 0.05}) 0%, transparent 60%),
            radial-gradient(620px 460px at ${100 - ambientX}% ${100 - ambientY}%, rgba(255,238,210,0.18) 0%, transparent 65%),
            radial-gradient(900px 640px at 50% 110%, rgba(10,10,11,0.10) 0%, transparent 70%)
          `,
          transition: 'background 1200ms ease',
        }}/>
        {/* fine grain (does NOT block fixed positioning since it's inside the panel) */}
        <div aria-hidden="true" style={{
          position: 'absolute', inset: 0,
          pointerEvents: 'none',
          opacity: 0.22, mixBlendMode: 'overlay',
          backgroundImage: "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.6 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>\")",
        }}/>
        {/* faint storyline line entering from top-right */}
        <svg aria-hidden="true" viewBox="0 0 1200 800" preserveAspectRatio="none" style={{
          position: 'absolute', inset: 0, width: '100%', height: '100%', pointerEvents: 'none', opacity: 0.55,
        }}>
          <defs>
            <linearGradient id="ai-line" x1="0" y1="0" x2="1" y2="0">
              <stop offset="0%" stopColor={blue} stopOpacity="0"/>
              <stop offset="55%" stopColor={blue} stopOpacity="0.55"/>
              <stop offset="100%" stopColor={blue} stopOpacity="0"/>
            </linearGradient>
          </defs>
          <path d={`M 1300 -40 Q 800 ${120 + Math.sin(t*0.4)*6} 540 ${260 + Math.cos(t*0.3)*4} T -80 760`}
                stroke="url(#ai-line)" strokeWidth="1.2" fill="none"/>
        </svg>

        {/* ----- CONTENT LAYER ----- */}
        <div className="ai-stage" style={{
          position: 'relative', zIndex: 1,
          flex: 1, minHeight: 0,
          display: 'grid',
          gridTemplateRows: 'auto minmax(0,1fr) auto',
          padding: 'clamp(28px, 4vw, 56px) clamp(24px, 4vw, 64px)',
          gap: 'clamp(20px, 2.4vw, 36px)',
          color: '#0A0A0B',
        }}>
          {/* ===== HEADER ===== */}
          <header style={{
            display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between',
            gap: 24,
          }}>
            <div
              onMouseEnter={() => setOrbHover(true)}
              onMouseLeave={() => setOrbHover(false)}
              style={{ display: 'flex', alignItems: 'center', gap: 'clamp(14px, 1.6vw, 22px)' }}
            >
              <PresenceOrb blue={blue} hovered={orbHover}/>
              <div style={{ display: 'flex', flexDirection: 'column', lineHeight: 1, gap: 6 }}>
                <span style={{
                  fontSize: 11, letterSpacing: '0.22em', textTransform: 'uppercase',
                  color: 'rgba(10,10,11,0.55)',
                  opacity: open ? 1 : 0,
                  transform: open ? 'translateY(0)' : 'translateY(8px)',
                  transition: 'opacity 600ms ease 200ms, transform 800ms cubic-bezier(0.22,1,0.36,1) 200ms',
                }}>{tx('ai.panelEyebrow')}</span>
                <span style={{
                  fontFamily: "'Inter Tight',sans-serif", fontWeight: 500,
                  fontSize: 'clamp(28px, 3.6vw, 52px)',
                  letterSpacing: '-0.025em',
                  color: '#0A0A0B',
                  opacity: open ? 1 : 0,
                  transform: open ? 'translateY(0)' : 'translateY(14px)',
                  transition: 'opacity 720ms ease 280ms, transform 1000ms cubic-bezier(0.22,1,0.36,1) 280ms',
                }}>{tx('ai.panelHeading')}</span>
              </div>
            </div>

            <button
              onClick={onClose}
              onMouseEnter={() => setCloseHover(true)}
              onMouseLeave={() => setCloseHover(false)}
              aria-label={tx('ai.closeAria')}
              style={{
                all: 'unset', cursor: 'pointer', flexShrink: 0,
                width: 'clamp(40px, 3.4vw, 50px)',
                height: 'clamp(40px, 3.4vw, 50px)',
                borderRadius: '50%',
                border: '1px solid rgba(10,10,11,0.18)',
                background: closeHover ? '#0A0A0B' : 'rgba(255,255,255,0.45)',
                color: closeHover ? '#fff' : '#0A0A0B',
                display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                transform: `rotate(${closeHover ? 90 : 0}deg) scale(${closeHover ? 1.06 : 1})`,
                transition: 'transform 520ms cubic-bezier(0.22,1.2,0.36,1), background 320ms ease, color 320ms ease, border-color 320ms ease',
              }}>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7"><path d="M6 6l12 12M18 6L6 18"/></svg>
            </button>
          </header>

          {/* ===== BODY (suggestions OR exchange) ===== */}
          <section style={{
            position: 'relative',
            display: 'flex',
            alignItems: 'center', justifyContent: 'center',
            minHeight: 0,
          }}>
            {/* Initial state: floating editorial suggestions */}
            <div style={{
              position: 'absolute', inset: 0,
              display: 'grid',
              gridTemplateColumns: 'repeat(2, minmax(0, 1fr))',
              gridAutoRows: '1fr',
              gap: 'clamp(14px, 1.6vw, 26px)',
              alignContent: 'center',
              opacity: !exchange ? 1 : 0,
              transform: !exchange ? 'translateY(0)' : 'translateY(-12px)',
              transition: 'opacity 520ms cubic-bezier(0.22,1,0.36,1), transform 700ms cubic-bezier(0.22,1,0.36,1)',
              // only clickable when the panel itself is open AND we're in
              // initial-state. Otherwise we'd swallow clicks meant for the
              // page underneath.
              pointerEvents: open && !exchange ? 'auto' : 'none',
            }} className="ai-suggest-grid">
              {suggestions.map((s, i) => {
                const m = magnets[i] || { x: 0, y: 0 };
                const active = pillHoverIdx === i;
                return (
                  <button
                    key={s.id}
                    onClick={() => respond(s.id, s.label)}
                    onMouseMove={(e) => { setPillHoverIdx(i); onPillMove(i, e); }}
                    onMouseLeave={() => onPillLeave(i)}
                    onFocus={() => setPillHoverIdx(i)}
                    onBlur={() => setPillHoverIdx(-1)}
                    className="ai-pill"
                    style={{
                      transform: `translate(${m.x}px, ${m.y}px) ${active ? 'translateZ(0)' : ''}`,
                      transitionDelay: open ? `${320 + i * 70}ms` : '0ms',
                      opacity: open ? 1 : 0,
                      // initial entrance
                      animationDelay: `${360 + i * 80}ms`,
                    }}
                    aria-label={s.label}
                  >
                    {/* ambient glow plate */}
                    <span aria-hidden="true" className="ai-pill-glow"
                      style={{
                        background: `radial-gradient(220px 140px at 50% 50%, ${blue}1f 0%, transparent 70%)`,
                        opacity: active ? 1 : 0,
                      }}/>
                    {/* underline */}
                    <span aria-hidden="true" className="ai-pill-rule"
                      style={{ background: active ? blue : 'rgba(10,10,11,0.12)' }}/>
                    <span className="ai-pill-eyebrow">0{i+1}</span>
                    <span className="ai-pill-title">{s.label.toUpperCase()}</span>
                    <span className="ai-pill-hint">{s.hint}</span>
                    {/* arrow */}
                    <span aria-hidden="true" className="ai-pill-arrow"
                      style={{
                        background: active ? blue : 'transparent',
                        borderColor: active ? blue : 'rgba(10,10,11,0.22)',
                        color: active ? '#000' : '#0A0A0B',
                      }}>
                      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8"><path d="M7 17L17 7M9 7h8v8"/></svg>
                    </span>
                  </button>
                );
              })}
            </div>

            {/* Active exchange: editorial layout */}
            <div style={{
              position: 'absolute', inset: 0,
              display: 'flex', flexDirection: 'column',
              justifyContent: 'center',
              gap: 'clamp(18px, 2vw, 32px)',
              maxWidth: 920, marginInline: 'auto',
              opacity: exchange ? 1 : 0,
              transform: exchange ? 'translateY(0)' : 'translateY(12px)',
              transition: 'opacity 560ms cubic-bezier(0.22,1,0.36,1) 80ms, transform 720ms cubic-bezier(0.22,1,0.36,1) 80ms',
              pointerEvents: open && exchange ? 'auto' : 'none',
            }}>
              {exchange && (
                <React.Fragment>
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                    <span style={{ fontSize: 10, letterSpacing: '0.22em', textTransform: 'uppercase', color: 'rgba(10,10,11,0.45)' }}>{tx('ai.exchange.you')}</span>
                    <span style={{ fontFamily: "'Inter Tight',sans-serif", fontWeight: 400, fontSize: 'clamp(16px, 1.4vw, 19px)', letterSpacing: '-0.005em', color: 'rgba(10,10,11,0.7)' }}>{exchange.user}</span>
                  </div>

                  <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
                    <span style={{ fontSize: 10, letterSpacing: '0.22em', textTransform: 'uppercase', color: 'rgba(10,10,11,0.45)', display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                      <span style={{ width: 6, height: 6, borderRadius: '50%', background: blue, boxShadow: `0 0 10px ${blue}` }}/>
                      {tx('ai.exchange.concierge')}
                    </span>
                    {thinking ? (
                      <div style={{ display: 'flex', alignItems: 'center', gap: 10, color: 'rgba(10,10,11,0.5)' }}>
                        <span className="ai-dot" style={{ background: blue }}/>
                        <span className="ai-dot" style={{ background: blue, animationDelay: '0.15s' }}/>
                        <span className="ai-dot" style={{ background: blue, animationDelay: '0.3s' }}/>
                      </div>
                    ) : (
                      <p style={{
                        margin: 0,
                        fontFamily: "'Inter Tight',sans-serif",
                        fontWeight: 400,
                        fontSize: 'clamp(20px, 2vw, 30px)',
                        lineHeight: 1.35,
                        letterSpacing: '-0.012em',
                        color: '#0A0A0B',
                      }}>{exchange.ai}</p>
                    )}
                  </div>

                  {exchange.rec && !thinking && (
                    <a href="#contact" data-open-contact style={{
                      alignSelf: 'flex-start',
                      display: 'inline-flex', alignItems: 'center', gap: 14,
                      padding: '14px 16px 14px 22px',
                      borderRadius: 999,
                      background: 'rgba(255,255,255,0.55)',
                      border: '1px solid rgba(10,10,11,0.10)',
                      color: '#0A0A0B', textDecoration: 'none',
                      backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)',
                      transition: 'transform 320ms cubic-bezier(0.22,1.2,0.36,1), border-color 280ms ease, background 280ms ease',
                    }} className="ai-rec-pill">
                      <span style={{ fontSize: 10, letterSpacing: '0.18em', color: 'rgba(10,10,11,0.55)', textTransform: 'uppercase' }}>{tx('ai.exchange.recPrefix')}{exchange.rec.label}</span>
                      <span style={{ fontFamily: "'Inter Tight',sans-serif", fontWeight: 500, fontSize: 16 }}>{exchange.rec.title}</span>
                      <span style={{
                        width: 32, height: 32, borderRadius: '50%',
                        background: blue, color: '#000',
                        display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
                        boxShadow: `0 0 18px ${blue}55`,
                      }}>
                        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M7 17L17 7M9 7h8v8"/></svg>
                      </span>
                    </a>
                  )}

                  <button onClick={reset} className="ai-link-btn"
                    style={{ alignSelf: 'flex-start' }}>
                    <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'currentColor' }}/>
                    {tx('ai.exchange.askAgain')}
                  </button>
                </React.Fragment>
              )}
            </div>
          </section>

          {/* ===== INPUT — cinematic capsule + energy send ===== */}
          <footer style={{
            display: 'flex', alignItems: 'center',
            opacity: open ? 1 : 0,
            transform: open ? 'translateY(0)' : 'translateY(20px)',
            transition: 'opacity 680ms ease 360ms, transform 880ms cubic-bezier(0.22,1,0.36,1) 360ms',
          }}>
            <div className="ai-capsule" style={{
              position: 'relative',
              flex: 1,
              display: 'flex', alignItems: 'center', gap: 'clamp(10px, 1.4vw, 18px)',
              padding: 'clamp(8px, 1vw, 12px) clamp(8px, 1vw, 12px) clamp(8px, 1vw, 12px) clamp(20px, 2.2vw, 32px)',
              borderRadius: 999,
              minHeight: 'clamp(60px, 6vw, 76px)',
              background: 'rgba(255,255,255,0.55)',
              backdropFilter: 'blur(18px) saturate(140%)',
              WebkitBackdropFilter: 'blur(18px) saturate(140%)',
              border: `1px solid ${focused ? blue : 'rgba(10,10,11,0.10)'}`,
              boxShadow: focused
                ? `0 0 0 4px ${blue}1f, 0 24px 60px -24px rgba(0,0,0,0.30), inset 0 1px 0 rgba(255,255,255,0.65), 0 0 60px ${blue}24`
                : '0 18px 48px -22px rgba(0,0,0,0.22), inset 0 1px 0 rgba(255,255,255,0.55)',
              transition: 'border-color 360ms ease, box-shadow 480ms ease',
              transform: `translateY(${focused ? -2 : 0}px)`,
            }}>
              <span aria-hidden="true" style={{
                color: 'rgba(10,10,11,0.4)', display: 'inline-flex',
              }}>
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6">
                  <path d="M12 19V5"/><path d="M5 12l7-7 7 7"/>
                </svg>
              </span>
              <input
                ref={inputRef}
                value={input}
                onChange={e => setInput(e.target.value)}
                onFocus={() => setFocused(true)}
                onBlur={() => setFocused(false)}
                onKeyDown={e => { if (e.key === 'Enter') sendInput(); }}
                placeholder={exchange ? tx('ai.input.placeholderContinue') : tx('ai.input.placeholderIdle')}
                aria-label={tx('ai.input.aria')}
                style={{
                  all: 'unset', flex: 1,
                  fontFamily: "'Inter Tight',sans-serif",
                  fontSize: 'clamp(15px, 1.2vw, 18px)',
                  letterSpacing: '-0.005em',
                  color: '#0A0A0B',
                  minWidth: 0,
                }}
              />

              {/* Send — energy core */}
              <button onClick={sendInput} aria-label={tx('ai.input.sendAria')}
                disabled={!input.trim()}
                className="ai-send"
                style={{
                  position: 'relative',
                  width: 'clamp(48px, 4.4vw, 60px)',
                  height: 'clamp(48px, 4.4vw, 60px)',
                  borderRadius: '50%',
                  background: '#0A0A0B',
                  color: '#fff',
                  flexShrink: 0,
                  cursor: input.trim() ? 'pointer' : 'default',
                  opacity: input.trim() ? 1 : 0.55,
                  transition: 'opacity 320ms ease',
                }}>
                {/* outer halo */}
                <span aria-hidden="true" style={{
                  position: 'absolute', inset: -6,
                  borderRadius: '50%',
                  background: `radial-gradient(circle, ${blue}33 0%, transparent 70%)`,
                  filter: 'blur(8px)',
                  opacity: 0.5 + sendBreath * 0.4,
                  pointerEvents: 'none',
                }}/>
                {/* orbiting conic */}
                <span aria-hidden="true" style={{
                  position: 'absolute', inset: 4,
                  borderRadius: '50%',
                  background: `conic-gradient(from 0deg, transparent 55%, ${blue} 80%, transparent 100%)`,
                  WebkitMaskImage: 'radial-gradient(circle, transparent 56%, black 60%)',
                  maskImage: 'radial-gradient(circle, transparent 56%, black 60%)',
                  transform: `rotate(${sendOrbit}deg)`,
                  opacity: 0.6,
                }}/>
                {/* inner core */}
                <span aria-hidden="true" style={{
                  position: 'absolute', top: '50%', left: '50%',
                  width: 14 + sendBreath * 4, height: 14 + sendBreath * 4,
                  borderRadius: '50%',
                  background: blue,
                  boxShadow: `0 0 ${14 + sendBreath * 14}px ${blue}, 0 0 ${28 + sendBreath * 18}px ${blue}55`,
                  transform: 'translate(-50%, -50%)',
                  opacity: 0.18,
                }}/>
                {/* arrow icon */}
                <span aria-hidden="true" className="ai-send-icon" style={{
                  position: 'absolute', inset: 0,
                  display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                  color: '#fff',
                }}>
                  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
                    <path d="M5 12h14M13 6l6 6-6 6"/>
                  </svg>
                </span>
              </button>
            </div>
          </footer>
        </div>
      </aside>

      {/* ----- styles ----- */}
      <style>{`
        .ai-pill {
          all: unset;
          /* all: unset resets pointer-events to auto, which would let
             closed-panel pills swallow clicks on the underlying page.
             Inherit from the aside (none when closed). */
          pointer-events: inherit;
          cursor: pointer;
          position: relative;
          display: grid;
          grid-template-columns: auto 1fr auto;
          grid-template-rows: auto auto;
          align-items: end;
          column-gap: clamp(12px, 1.4vw, 22px);
          padding: clamp(18px, 2vw, 28px) clamp(20px, 2.4vw, 32px) clamp(20px, 2.4vw, 28px);
          border-radius: clamp(14px, 1.4vw, 22px);
          background: rgba(255,255,255,0.30);
          border: 1px solid transparent;
          color: #0A0A0B;
          backdrop-filter: blur(6px);
          -webkit-backdrop-filter: blur(6px);
          transition: transform 420ms cubic-bezier(0.22,1.2,0.36,1), background 360ms ease, border-color 360ms ease;
          will-change: transform;
          animation: ai-pill-in 880ms cubic-bezier(0.22,1,0.36,1) backwards;
        }
        .ai-pill:hover, .ai-pill:focus-visible {
          background: rgba(255,255,255,0.65);
          border-color: rgba(10,10,11,0.08);
        }
        .ai-pill-glow {
          position: absolute; inset: -10px;
          border-radius: inherit;
          pointer-events: none;
          transition: opacity 480ms ease;
          filter: blur(2px);
        }
        .ai-pill-rule {
          grid-column: 1 / -1;
          grid-row: 1;
          height: 1px;
          align-self: start;
          margin-bottom: clamp(14px, 1.6vw, 22px);
          transition: background 320ms ease;
        }
        .ai-pill-eyebrow {
          grid-column: 1; grid-row: 2;
          font-size: 10px; letter-spacing: 0.22em; text-transform: uppercase;
          color: rgba(10,10,11,0.5);
          align-self: end;
        }
        .ai-pill-title {
          grid-column: 2; grid-row: 2;
          font-family: 'Inter Tight', sans-serif;
          font-weight: 500;
          font-size: clamp(20px, 2.2vw, 32px);
          letter-spacing: -0.018em;
          line-height: 1;
        }
        .ai-pill-hint {
          grid-column: 2; grid-row: 3;
          font-size: 12px;
          color: rgba(10,10,11,0.5);
          margin-top: 8px;
          letter-spacing: 0.01em;
        }
        .ai-pill-arrow {
          grid-column: 3; grid-row: 2;
          width: clamp(40px, 3vw, 48px); height: clamp(40px, 3vw, 48px);
          border-radius: 50%;
          border: 1px solid;
          display: inline-flex; align-items: center; justify-content: center;
          transition: background 320ms ease, border-color 320ms ease, color 320ms ease, transform 480ms cubic-bezier(0.22,1.2,0.36,1);
        }
        .ai-pill:hover .ai-pill-arrow,
        .ai-pill:focus-visible .ai-pill-arrow {
          transform: rotate(-45deg) scale(1.05);
        }
        @keyframes ai-pill-in {
          from { opacity: 0; transform: translateY(20px); }
          to   { opacity: 1; transform: translateY(0); }
        }

        .ai-rec-pill:hover { transform: translateY(-2px); border-color: rgba(10,10,11,0.18); background: rgba(255,255,255,0.75); }

        .ai-link-btn {
          all: unset; cursor: pointer;
          display: inline-flex; align-items: center; gap: 10px;
          font-size: 12px; letter-spacing: 0.18em; text-transform: uppercase;
          color: rgba(10,10,11,0.55);
          padding: 6px 0;
          transition: color 280ms ease, gap 280ms ease;
        }
        .ai-link-btn:hover { color: #0A0A0B; gap: 14px; }

        .ai-send:not(:disabled):hover { transform: scale(1.06); }
        .ai-send:not(:disabled):active { transform: scale(0.98); }
        .ai-send { transition: transform 320ms cubic-bezier(0.22,1.2,0.36,1); }
        .ai-send:not(:disabled):hover .ai-send-icon { transform: rotate(-45deg); }
        .ai-send-icon { transition: transform 480ms cubic-bezier(0.22,1.2,0.36,1); }

        .ai-dot {
          width: 7px; height: 7px; border-radius: 50%;
          display: inline-block;
          animation: ai-pulse 1.2s ease-in-out infinite;
        }
        @keyframes ai-pulse {
          0%, 100% { opacity: 0.25; transform: translateY(0); }
          50%      { opacity: 1; transform: translateY(-4px); }
        }

        @media (max-width: 760px) {
          .ai-suggest-grid { grid-template-columns: 1fr !important; }
          .ai-pill { padding: 18px 20px 22px !important; }
          .ai-pill-title { font-size: 22px !important; }
          .ai-pill-hint { font-size: 12px !important; }
        }

        @media (prefers-reduced-motion: reduce) {
          .ai-pill { animation: none !important; }
          .ai-pill, .ai-send, .ai-send-icon, .ai-pill-arrow { transition-duration: 80ms !important; }
        }
      `}</style>
    </React.Fragment>
  );
}

function ASpaceAI({ blue }) {
  const [open, setOpen] = useStateAI(false);
  // Allow other components to open the panel via custom event
  useEffectAI(() => {
    const onOpen = () => setOpen(true);
    window.addEventListener('aspace:openAI', onOpen);
    return () => window.removeEventListener('aspace:openAI', onOpen);
  }, []);
  return (
    <React.Fragment>
      <AITrigger blue={blue} hidden={open} onOpen={() => setOpen(true)}/>
      <AIPanel open={open} onClose={() => setOpen(false)} blue={blue}/>
    </React.Fragment>
  );
}

window.ASpaceAI = ASpaceAI;
