// sections.jsx — Sections 2, 3, 4 (Routing, Modalities, Memory)
const { useState: uS, useEffect: uE, useRef: uR } = React;

// ─── SECTION 2: Routing demo (carousel 4 cas + animation + réponse streamée) ─
const ROUTING_SLIDES = [
  {
    label: 'Code',
    prompt: 'Code-moi un composant React avec animation spring.',
    model: 'claude-opus-4.7',
    reason: 'Code complexe + raisonnement',
    candidates: [
      { id: 'gpt-5.4', accent: '#0A0A0F' },
      { id: 'gemini-3.1-pro', accent: '#4285F4' },
      { id: 'claude-opus-4.7', accent: '#A855F7', winner: true },
    ],
    reply:
      'Pour un spring fluide, branche `useSpring` de `@react-spring/web` avec une tension vers 280 et une friction basse (~22). Garde la vue « présentation » pure : l’état animé vit dans le hook, le rendu ne fait qu’afficher les valeurs interpolées.',
  },
  {
    label: 'Rédaction',
    prompt: 'Écris un email de relance client professionnel.',
    model: 'mistral-large',
    reason: 'Rédaction française',
    candidates: [
      { id: 'gpt-5.4', accent: '#10A37F' },
      { id: 'mistral-large', accent: '#EA580C', winner: true },
      { id: 'claude-sonnet-4.6', accent: '#C084FC' },
    ],
    reply:
      'Objet : point sur votre dossier — Bonjour Mme Arnaud, je me permets de revenir vers vous suite à notre échange du 3 mai. Avez-vous pu consulter la proposition jointe ? Je reste disponible cette semaine pour en parler 15 minutes au créneau qui vous convient.',
  },
  {
    label: 'Actualité',
    prompt: 'Quelles sont les dernières news sur l\'IA cette semaine ?',
    model: 'sonar-pro',
    reason: 'Recherche web temps réel',
    candidates: [
      { id: 'gemini-flash', accent: '#4285F4' },
      { id: 'sonar-pro', accent: '#14B8A6', winner: true },
      { id: 'grok-4', accent: '#0A0A0F' },
    ],
    reply:
      'Les titres forts cette semaine : nouvelles offres « agent » qui enchaînent recherche et action, baisses de tarifs sur certaines API frontier, et une accélération des modèles open-weight côté licences commerciales. Je peux creuser un fil (réglementation, cloud, startups) si tu veux.',
  },
  {
    label: 'Maths',
    prompt: 'Résous cette équation différentielle : dy/dx = 2xy',
    model: 'deepseek-r1',
    reason: 'Raisonnement mathématique',
    candidates: [
      { id: 'claude-opus-4.7', accent: '#A855F7' },
      { id: 'gpt-5.4', accent: '#0A0A0F' },
      { id: 'deepseek-r1', accent: '#3B82F6', winner: true },
    ],
    reply:
      'Variables séparables : dy/y = 2x dx. En intégrant, ln|y| = x² + C, donc y = K·e^(x²) avec K réel (et la solution triviale y = 0 si tu inclus K = 0). Donne une condition initiale y(x0) = y0 pour fixer K.',
  },
];

/** Fichiers SVG @lobehub/icons-static-svg (copiés dans /public/icons/lobehub). */
function lobehubIconFileForModelId(modelId) {
  var s = String(modelId || '').toLowerCase();
  if (s.indexOf('claude') !== -1 || s.indexOf('opus') !== -1 || s.indexOf('sonnet') !== -1) return 'claude.svg';
  if (s.indexOf('gpt') !== -1 || s.indexOf('o1') !== -1 || s.indexOf('o3') !== -1 || s.indexOf('chatgpt') !== -1) return 'openai.svg';
  if (s.indexOf('gemini') !== -1) return 'gemini.svg';
  if (s.indexOf('mistral') !== -1) return 'mistral.svg';
  if (s.indexOf('sonar') !== -1 || s.indexOf('perplexity') !== -1) return 'perplexity.svg';
  if (s.indexOf('grok') !== -1) return 'grok.svg';
  if (s.indexOf('deepseek') !== -1) return 'deepseek.svg';
  return 'openai.svg';
}

/** Icônes LobeHub pour les modèles image / vidéo du mock « Image ». */
function lobehubIconFileForImageModelId(modelId) {
  var s = String(modelId || '').toLowerCase();
  if (s.indexOf('flux') !== -1) return 'flux.svg';
  if (s.indexOf('sd-') !== -1 || s.indexOf('stability') !== -1) return 'stability-color.svg';
  if (s.indexOf('recraft') !== -1) return 'recraft.svg';
  if (s.indexOf('kling') !== -1) return 'kling-color.svg';
  if (s.indexOf('wan') !== -1) return 'qwen-color.svg';
  if (s.indexOf('gemini') !== -1) return 'gemini.svg';
  return 'openai.svg';
}

function RoutingModelIcon(props) {
  var modelId = props.modelId;
  var size = props.size != null ? props.size : 18;
  var cn = props.className || '';
  var file = lobehubIconFileForModelId(modelId);
  return (
    <img
      className={cn}
      src={'/icons/lobehub/' + file}
      alt=""
      width={size}
      height={size}
      draggable={false}
      decoding="async"
    />
  );
}

function RoutingDemo() {
  const reduceMotion =
    typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  const [slideIndex, setSlideIndex] = uS(0);
  const [typed, setTyped] = uS('');
  const [phase, setPhase] = uS('typing');
  const [candIn, setCandIn] = uS(false);
  const [candPick, setCandPick] = uS(false);
  const [showPill, setShowPill] = uS(false);
  const [replyShown, setReplyShown] = uS('');
  const timersRef = uR([]);
  const hoverPauseAdvanceRef = uR(false);
  const demoWindowRef = uR(null);
  const [demoInView, setDemoInView] = uS(reduceMotion);
  const demoBootLagOnceRef = uR(true);

  const cur = ROUTING_SLIDES[slideIndex];

  const clearTimers = () => {
    timersRef.current.forEach(function (id) {
      clearTimeout(id);
    });
    timersRef.current = [];
  };

  const schedule = function (fn, ms) {
    const id = setTimeout(fn, ms);
    timersRef.current.push(id);
    return id;
  };

  uE(() => {
    if (reduceMotion) {
      setDemoInView(true);
      return undefined;
    }
    const el = demoWindowRef.current;
    if (!el) return undefined;
    const io = new IntersectionObserver(
      function (entries) {
        var e = entries[0];
        if (e && e.isIntersecting) {
          setDemoInView(true);
          io.unobserve(el);
        }
      },
      { threshold: 0.22, rootMargin: '0px 0px -6% 0px' },
    );
    io.observe(el);
    return function () {
      io.disconnect();
    };
  }, [reduceMotion]);

  uE(() => {
    clearTimers();
    setTyped('');
    setPhase('typing');
    setCandIn(false);
    setCandPick(false);
    setShowPill(false);
    setReplyShown('');

    if (!demoInView) {
      return function () {
        clearTimers();
      };
    }

    const prompt = cur.prompt;
    const reply = cur.reply;
    const typeMs = reduceMotion ? 0 : 11;
    const afterType = reduceMotion ? 0 : 80;
    const candInAt = afterType + (reduceMotion ? 0 : 18);
    const pickAt = afterType + (reduceMotion ? 0 : 280);
    /* Moment « choix » : laisser respirer l’animation vainqueur avant le pill */
    const celebrateMs = reduceMotion ? 0 : 1680;
    const pillAt = pickAt + celebrateMs;
    const streamStart = pillAt + (reduceMotion ? 0 : 340);

    var bootDelay = reduceMotion ? 0 : (demoBootLagOnceRef.current ? 760 : 0);
    if (!reduceMotion && demoBootLagOnceRef.current) {
      demoBootLagOnceRef.current = false;
    }

    function runScenario() {
      if (reduceMotion) {
        setTyped(prompt);
        setCandPick(true);
        setShowPill(true);
        setReplyShown(reply);
        setPhase('complete');
        schedule(function waitUnpauseThenAdvanceRm() {
          if (hoverPauseAdvanceRef.current) {
            schedule(waitUnpauseThenAdvanceRm, 180);
            return;
          }
          setSlideIndex(function (j) {
            return (j + 1) % ROUTING_SLIDES.length;
          });
        }, 2200);
        return;
      }

      let pi = 0;
      function typePrompt() {
        pi += 1;
        setTyped(prompt.slice(0, pi));
        if (pi < prompt.length) {
          schedule(typePrompt, typeMs);
        } else {
          schedule(function () {
            setPhase('routing');
          }, afterType);
          schedule(function () {
            setCandIn(true);
          }, candInAt);
          schedule(function () {
            setCandPick(true);
          }, pickAt);
          schedule(function () {
            setPhase('picked');
            setCandIn(false);
            setShowPill(true);
          }, pillAt);
          schedule(function () {
            setPhase('streaming');
            let ri = 0;
            function typeReply() {
              ri += 1;
              setReplyShown(reply.slice(0, ri));
              if (ri < reply.length) {
                schedule(typeReply, reduceMotion ? 0 : 12);
              } else {
                schedule(function () {
                  setPhase('complete');
                  function waitUnpauseThenAdvance() {
                    if (hoverPauseAdvanceRef.current) {
                      schedule(waitUnpauseThenAdvance, 180);
                      return;
                    }
                    setSlideIndex(function (j) {
                      return (j + 1) % ROUTING_SLIDES.length;
                    });
                  }
                  schedule(waitUnpauseThenAdvance, 2600);
                }, reduceMotion ? 60 : 90);
              }
            }
            typeReply();
          }, streamStart);
        }
      }
      typePrompt();
    }

    schedule(runScenario, bootDelay);

    return function () {
      clearTimers();
    };
  }, [slideIndex, reduceMotion, demoInView]);

  function goSlide(i) {
    clearTimers();
    setSlideIndex(i);
  }

  return (
    <section id="section-produit" className="section section-after-hero routing-demo-section">
      <Reveal as="div" className="container-narrow" style={{ textAlign: 'center' }}>
        <div className="eyebrow" style={{ marginBottom: 16 }}>02 · Routing intelligent</div>
        <h2 className="h2 routing-demo-h2" style={{ margin: '0 auto' }}>
          En fonction de ta demande.
          <br aria-hidden="true" />
          <span className="routing-demo-h2__grad brand-grad-text">
            On choisit le bon modèle.&nbsp;À&nbsp;chaque&nbsp;fois.
          </span>
        </h2>
        <p className="lede routing-demo-lede" style={{ margin: '24px auto 0' }}>
          Chatflix choisit le modèle adapté à ta demande — sans menus techniques à décrypter.
        </p>
      </Reveal>

      <Reveal as="div" delay={195} className="container-narrow" style={{ marginTop: 56 }}>
        <div
          ref={demoWindowRef}
          className={
            'glass routing-demo-window' +
            (demoInView ? ' routing-demo-window--revealed' : ' routing-demo-window--await-scroll')
          }
          style={{ padding: '24px 22px 14px', position: 'relative' }}
          onMouseEnter={function () {
            hoverPauseAdvanceRef.current = true;
          }}
          onMouseLeave={function () {
            hoverPauseAdvanceRef.current = false;
          }}
        >
          <div className="routing-demo-tabs" role="tablist" aria-label="Exemples de routage">
            {ROUTING_SLIDES.map(function (s, i) {
              return (
                <button
                  key={s.label}
                  type="button"
                  role="tab"
                  aria-selected={i === slideIndex}
                  className={'routing-demo-tab' + (i === slideIndex ? ' routing-demo-tab--active' : '')}
                  onClick={function () {
                    goSlide(i);
                  }}
                >
                  {s.label}
                </button>
              );
            })}
          </div>

          <div className="routing-demo-window-fill">
            <div className="routing-demo-composer-hold">
              <Composer value={typed} placeholder="…" autoLabel="1.0" />
            </div>

            <div
              className={
                'routing-demo-lower' +
                (phase !== 'typing' ? ' routing-demo-lower--locked' : '') +
                (phase === 'streaming' || phase === 'complete' ? ' routing-demo-lower--reply-active' : '')
              }
            >
              <div className="routing-demo-slot-clip">
                <div className="routing-demo-slot" aria-live="polite">
                  {phase === 'routing' && (
                    <div className="routing-demo-candidates" key={slideIndex + '-cand'}>
                      {cur.candidates.map(function (c, i) {
                        return (
                          <div
                            key={c.id}
                            className={
                              'routing-demo-cand' +
                              (candIn ? ' routing-demo-cand--in' : '') +
                              (candPick && !c.winner ? ' routing-demo-cand--out' : '') +
                              (candPick && c.winner ? ' routing-demo-cand--win routing-demo-cand--win-glory' : '')
                            }
                            style={{ transitionDelay: candIn ? i * 22 + 'ms' : '0ms' }}
                          >
                            <span className="routing-demo-cand-icon" aria-hidden="true">
                              <RoutingModelIcon modelId={c.id} size={17} />
                            </span>
                            <span>{c.id}</span>
                            {candPick && c.winner && (
                              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#2563EB" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                                <path d="M20 6L9 17l-5-5" />
                              </svg>
                            )}
                          </div>
                        );
                      })}
                    </div>
                  )}

                  {(phase === 'picked' || phase === 'streaming' || phase === 'complete') && (
                    <div className="routing-demo-route-row" key={slideIndex + '-pill'}>
                      <div className={'routing-demo-pill' + (showPill ? ' routing-demo-pill--show routing-demo-pill--snap' : '')}>
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" aria-hidden="true">
                          <path d="M5 12h14M13 5l7 7-7 7" />
                        </svg>
                        <span>routé vers</span>
                        <span
                          className="routing-demo-pill-model"
                          style={{ color: cur.candidates.filter(function (x) { return x.winner; })[0].accent }}
                        >
                          <RoutingModelIcon modelId={cur.model} size={18} className="routing-demo-pill-model__icon" />
                          <span>{cur.model}</span>
                        </span>
                      </div>
                      <div className="routing-demo-reason">{cur.reason}</div>
                    </div>
                  )}
                </div>
              </div>

              <div className="routing-demo-reply-shell">
                {(phase === 'streaming' || phase === 'complete') && (
                  <div className="routing-demo-reply">
                    {replyShown}
                    {replyShown.length < cur.reply.length && <span className="caret" />}
                  </div>
                )}
              </div>
            </div>
          </div>
        </div>
      </Reveal>
    </section>
  );
}

// ─── SECTION 3: Modalities ───────────────────────────────────────
/** Décalage entre le début de chaque carte (voir `--modalities-chain-offset`). */
var MODALITIES_CARD_CHAIN_SLOT_MS = 260;
/** Après la surface mock (ms, voir nth-child(3) CSS) avant `ModalitiesMockStage--in`. */
var MODALITIES_MOCK_SURFACE_MS = 110;
var MODALITIES_MOCK_STAGE_LAG_MS = 40;

function modalitiesChainOffsetMs(i) {
  return i * MODALITIES_CARD_CHAIN_SLOT_MS;
}

function Modalities() {
  const cards = [
    {
      eyebrow: 'Chat', title: 'Discute avec 20+ modèles',
      bullets: ['Routing automatique', 'Mémoire de tes préférences', 'Modèles spécialisés par tâche'],
      mock: <ChatMock />,
    },
    {
      eyebrow: 'Image', title: '8 moteurs d\'image. Un seul prompt.',
      bullets: ['Logo, photo, illustration, paysage', 'Le bon modèle est choisi pour toi', 'Ratio 1:1 / 16:9 / 9:16'],
      mock: <ImageMock />,
    },
    {
      eyebrow: 'Code', title: 'Décris. Génère. Modifie en direct.',
      bullets: ['Sites, scripts, composants, jeux', 'Preview live à droite', 'TypeScript, Python, Rust, Go'],
      mock: <CodeMock />,
    },
    {
      eyebrow: 'Voix', title: 'Appelle ton IA pour avoir une conversation naturelle.',
      bullets: ['Conversation vocale temps réel', 'Transcription en direct', 'Mémoire conservée entre les appels'],
      mock: <VoiceMock />,
    },
  ];

  return (
    <section id="section-modeles" className="section">
      <Reveal as="div" className="container-narrow" style={{ textAlign: 'center', marginBottom: 72 }}>
        <div className="eyebrow" style={{ marginBottom: 16 }}>03 · Modalités</div>
        <h2 className="h2">
          <span className="brand-grad-text">Une app.</span> Toutes les façons de créer.
        </h2>
        <p className="lede modalities-lede" style={{ margin: '24px auto 0' }}>
          Chats, images, vidéos, code, voix et plus : Chatflix orchestre 20+ modèles dans une interface unique.
        </p>
      </Reveal>

      <Reveal as="div" stagger className="container modalities-cards-reveal" style={{
        display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(420px, 1fr))', gap: 24,
      }}>
        {cards.map((c, i) => (
          <div
            key={i}
            className="glass lift modalities-card"
            style={{
              padding: 28, display: 'flex', flexDirection: 'column',
              ['--modalities-chain-offset']: modalitiesChainOffsetMs(i) + 'ms',
            }}
          >
            <div className="eyebrow modalities-card-seq-item">{c.eyebrow}</div>
            <h3 className="h3 modalities-card-seq-item" style={{ marginTop: 8, marginBottom: 20 }}>{c.title}</h3>
            <div
              className="surface-glass-shadow surface-glass-shadow--modalities modalities-card-seq-item"
              style={{
                flex: 1, minHeight: 220, marginBottom: 24,
                borderRadius: 32, overflow: 'hidden',
                background: 'rgba(250,250,251,0.6)',
                border: '1px solid rgba(10,10,15,0.05)',
              }}
            >
              {React.cloneElement(c.mock, {
                modalitiesStaggerMs:
                  modalitiesChainOffsetMs(i) +
                  MODALITIES_MOCK_SURFACE_MS +
                  MODALITIES_MOCK_STAGE_LAG_MS,
              })}
            </div>
            <ul style={{ listStyle: 'none', display: 'flex', flexDirection: 'column', gap: 8 }}>
              {c.bullets.map((b, bi) => (
                <li
                  key={b}
                  className="modalities-card-seq-item modalities-card-seq-bullet"
                  style={{
                    ['--modalities-bullet-idx']: bi,
                    display: 'flex', alignItems: 'center', gap: 10,
                    fontSize: 14, color: 'var(--ink-2)',
                  }}
                >
                  <span style={{
                    width: 16, height: 16, borderRadius: 99, flexShrink: 0,
                    background: 'rgba(37,99,235,0.12)',
                    boxShadow: 'none',
                    display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                  }}>
                    <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="#2563EB" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round">
                      <path d="M20 6L9 17l-5-5"/>
                    </svg>
                  </span>
                  {b}
                </li>
              ))}
            </ul>
          </div>
        ))}
      </Reveal>
    </section>
  );
}

/** Entrée échelonnée des mocks modalités au scroll (respecte prefers-reduced-motion). */
function ModalitiesMockStage({ children, style, className = '', staggerMs = 0 }) {
  const ref = uR(null);
  const reduceMotion =
    typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  const [shown, setShown] = uS(reduceMotion);
  uE(() => {
    if (reduceMotion) return undefined;
    const el = ref.current;
    if (!el) return undefined;
    var timeoutId;
    const io = new IntersectionObserver(
      ([e]) => {
        if (e.isIntersecting) {
          timeoutId = window.setTimeout(function () {
            setShown(true);
          }, staggerMs);
          io.unobserve(el);
        }
      },
      { threshold: 0.12, rootMargin: '0px 0px -28px 0px' },
    );
    io.observe(el);
    return () => {
      io.disconnect();
      if (timeoutId) window.clearTimeout(timeoutId);
    };
  }, [reduceMotion, staggerMs]);
  return (
    <div
      ref={ref}
      className={
        'modalities-mock-stage' +
        (shown ? ' modalities-mock-stage--in' : '') +
        (className ? ' ' + className : '')
      }
      style={style}
    >
      {children}
    </div>
  );
}

function ChatMock({ modalitiesStaggerMs = 0 }) {
  return (
    <ModalitiesMockStage staggerMs={modalitiesStaggerMs} style={{ padding: 20, height: '100%', display: 'flex', flexDirection: 'column', gap: 10 }}>
      <div
        className="modalities-mock-item modalities-mock-item--chat-user"
        style={{
          alignSelf: 'flex-end', maxWidth: '75%',
          background: '#2563EB', color: '#fff',
          padding: '10px 14px', borderRadius: '16px 16px 4px 16px',
          fontSize: 13,
        }}
      >
        Compare GPT-5 et Claude Opus pour du code TypeScript.
      </div>
      <div
        className="modalities-mock-item modalities-mock-item--chat-ai"
        style={{
          alignSelf: 'flex-start', maxWidth: '85%',
          background: '#fff', border: '1px solid rgba(10,10,15,0.06)',
          padding: '10px 14px', borderRadius: '16px 16px 16px 4px',
          fontSize: 13, color: 'var(--ink-2)',
        }}
      >
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 6 }}>
          <ModelPill
            name="claude-opus-4.7"
            iconSrc={'/icons/lobehub/' + lobehubIconFileForModelId('claude-opus-4.7')}
          />
        </div>
        Pour TypeScript strict, Claude Opus tend à mieux respecter les types stricts<span style={{
          display: 'inline-block', width: 6, height: 12, background: '#0A0A0F',
          marginLeft: 2, verticalAlign: 'middle', animation: 'caret 1s steps(1) infinite',
        }} />
      </div>
    </ModalitiesMockStage>
  );
}

function ImageMock({ modalitiesStaggerMs = 0 }) {
  var ratioChoices = [
    { label: '1:1', pw: 13, ph: 13, selected: false },
    { label: '16:9', pw: 20, ph: 11, selected: true },
    { label: '9:16', pw: 11, ph: 20, selected: false },
  ];
  var imageModels = ['flux-pro', 'sd-3.5', 'recraft', 'kling', 'wan-2', 'gemini-img'];
  return (
    <ModalitiesMockStage staggerMs={modalitiesStaggerMs} style={{ padding: 20, height: '100%', display: 'flex', flexDirection: 'column', gap: 10 }}>
      <div className="modalities-mock-item" style={{ display: 'flex', gap: 6, flexWrap: 'wrap', alignItems: 'center' }}>
        {ratioChoices.map(function (r) {
          var sel = r.selected;
          return (
            <span
              key={r.label}
              className="pill pill-mono"
              style={{
                gap: 7,
                ...(sel ? { background: 'rgba(37,99,235,0.08)', color: '#2563EB', borderColor: 'rgba(37,99,235,0.2)' } : {}),
              }}
            >
              <span
                className="modalities-pill-ratio-mark"
                style={{
                  width: r.pw,
                  height: r.ph,
                  borderRadius: 3,
                  flexShrink: 0,
                  border: sel ? '1.5px solid rgba(37,99,235,0.45)' : '1px solid rgba(10,10,15,0.14)',
                  background: sel ? 'rgba(37,99,235,0.12)' : 'rgba(10,10,15,0.05)',
                }}
                aria-hidden
              />
              {r.label}
            </span>
          );
        })}
        <span className="pill pill-mono">1K</span>
        <span className="pill pill-mono">4K</span>
      </div>
      <div
        className="modalities-mock-item modalities-mock-item--image-canvas"
        style={{
          flex: 1, borderRadius: 12,
          background: 'linear-gradient(135deg, #FFB088 0%, #FF4D8D 40%, #C44CFF 70%, #4C7DFF 100%)',
          position: 'relative', overflow: 'hidden',
        }}
      >
        <div className="placeholder-stripe" style={{ position: 'absolute', inset: 0, mixBlendMode: 'overlay', opacity: 0.4 }} />
        <div
          className="modalities-mock-flux-badge"
          style={{
            position: 'absolute', bottom: 10, left: 10,
            fontFamily: 'var(--font-mono)', fontSize: 10, color: '#fff',
            background: 'rgba(0,0,0,0.3)', padding: '3px 8px', borderRadius: 6,
          }}
        >flux-pro-1.4 · 1280×720</div>
      </div>
      <div className="modalities-mock-item modalities-mock-item--chips">
        {imageModels.map(function (m) {
          return (
            <div key={m} className="modalities-mock-chip">
              <ModelPill
                name={m}
                iconSrc={'/icons/lobehub/' + lobehubIconFileForImageModelId(m)}
              />
            </div>
          );
        })}
      </div>
    </ModalitiesMockStage>
  );
}

function CodeMock({ modalitiesStaggerMs = 0 }) {
  return (
    <ModalitiesMockStage staggerMs={modalitiesStaggerMs} style={{ height: '100%', display: 'flex' }}>
      <div
        className="modalities-mock-item"
        style={{
          flex: 1, padding: 14,
          fontFamily: 'var(--font-mono)', fontSize: 11,
          color: 'var(--ink-2)', background: '#FAFAFB',
          borderRight: '1px solid rgba(10,10,15,0.05)',
        }}
      >
        <div style={{ color: '#8A8A95' }}>{`// composant Card.tsx`}</div>
        <div><span style={{ color: '#C44CFF' }}>export function</span> <span style={{ color: '#2563EB' }}>Card</span>() {'{'}</div>
        <div style={{ paddingLeft: 14 }}><span style={{ color: '#C44CFF' }}>return</span> &lt;<span style={{ color: '#FF4D8D' }}>div</span>&gt;…&lt;/<span style={{ color: '#FF4D8D' }}>div</span>&gt;</div>
        <div>{'}'}<span style={{ display: 'inline-block', width: 6, height: 12, background: '#0A0A0F', marginLeft: 2, verticalAlign: 'middle', animation: 'caret 1s steps(1) infinite' }} /></div>
      </div>
      <div
        className="modalities-mock-item"
        style={{
          flex: 1, padding: 16, background: '#fff',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}
      >
        <div
          className="modalities-mock-code-preview"
          style={{
            width: '85%', height: 80, borderRadius: 12,
            background: 'rgba(250,250,251,1)',
            border: '1px solid rgba(10,10,15,0.06)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
          }}
        >
          <div className="modalities-point-planet" aria-hidden="true">
            {Array.from({ length: 28 }).map(function (_, i) {
              return <span key={i} style={{ '--dot-i': i }} />;
            })}
          </div>
        </div>
      </div>
    </ModalitiesMockStage>
  );
}

function VoiceMock({ modalitiesStaggerMs = 0 }) {
  return (
    <ModalitiesMockStage staggerMs={modalitiesStaggerMs} style={{
      padding: 20, height: '100%', display: 'flex', flexDirection: 'column',
      alignItems: 'center', justifyContent: 'center', gap: 14,
    }}>
      <div
        className="modalities-mock-item modalities-mock-item--voice-mic"
        style={{
          width: 72, height: 72, borderRadius: 99,
          background: 'linear-gradient(135deg, #FF8A4C, #C44CFF)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          animation: 'pulseRing 2.4s ease-out infinite',
        }}
      >
        <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="2.2" strokeLinecap="round">
          <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/>
          <path d="M19 10v2a7 7 0 0 1-14 0v-2M12 19v4M8 23h8"/>
        </svg>
      </div>
      <div className="modalities-mock-item modalities-mock-item--voice-wave" style={{ display: 'flex', alignItems: 'flex-end', gap: 3, height: 32 }}>
        {[14, 22, 8, 28, 18, 30, 12, 24, 16, 22, 10].map((h, i) => (
          <div key={i} style={{
            width: 3, height: h, borderRadius: 99,
            background: 'rgba(37,99,235,0.7)',
            animation: `wave ${0.7 + (i % 3) * 0.2}s ease-in-out ${i * 0.08}s infinite alternate`,
          }} />
        ))}
      </div>
      <div className="modalities-mock-item" style={{ fontSize: 12, color: 'var(--ink-3)', fontFamily: 'var(--font-mono)' }}>
        00:42 · gpt-5-realtime
      </div>
    </ModalitiesMockStage>
  );
}

// ─── SECTION 4: Memory ───────────────────────────────────────────
function Memory() {
  const facts = [
    { text: 'Travaille dans le SaaS B2B', tag: 'metier', label: 'metier' },
    { text: 'Prefere les reponses concises, sans jargon', tag: 'style', label: 'style' },
    { text: 'Code en TypeScript / Next.js', tag: 'stack', label: 'stack' },
    { text: 'Communication en francais, tutoiement', tag: 'langue', label: 'langue' },
    { text: 'Base a Paris, fuseau Europe/Paris', tag: 'contexte', label: 'contexte' },
  ];
  const [syncMin, setSyncMin] = uS(2);
  const [factsShown, setFactsShown] = uS(0);
  uE(() => {
    const id = window.setInterval(function () {
      setSyncMin(function (v) {
        return v >= 4 ? 2 : v + 1;
      });
    }, 30000);
    return function () {
      window.clearInterval(id);
    };
  }, []);
  uE(() => {
    var from = performance.now();
    var dur = 800;
    var rafId;
    var tick = function (now) {
      var p = Math.min(1, (now - from) / dur);
      setFactsShown(Math.round(47 * p));
      if (p < 1) rafId = window.requestAnimationFrame(tick);
    };
    rafId = window.requestAnimationFrame(tick);
    return function () {
      if (rafId) window.cancelAnimationFrame(rafId);
    };
  }, []);
  return (
    <section id="section-memoire" className="section">
      <div className="container" style={{
        display: 'grid', gridTemplateColumns: 'minmax(0, 1.1fr) minmax(0, 1fr)', gap: 80, alignItems: 'start',
      }}>
        <Reveal as="div">
          <div className="eyebrow" style={{ marginBottom: 16 }}>04 · Mémoire</div>
          <h2 className="h2">
            Plus tu l'utilises, <br /><span className="brand-grad-text">plus elle te connaît.</span>
          </h2>
          <p className="lede" style={{ marginTop: 24 }}>
            Chatflix retient ton style, ton métier, tes préférences. Pas le texte verbatim de tes conversations — des <strong style={{ color: 'var(--ink)', fontWeight: 600 }}>faits atomiques structurés</strong>, que tu peux consulter, modifier ou supprimer.
          </p>
          <p className="lede" style={{ marginTop: 16 }}>
            Résultat : à la 50ème conversation, tu n'expliques plus qui tu es. Tu écris, elle comprend.
          </p>
          <ul style={{ listStyle: 'none', marginTop: 32, display: 'flex', flexDirection: 'column', gap: 16 }}>
            {[
              { icon: 'brain', title: 'Mémoire active', desc: 'Préférences, contexte métier, style de réponse' },
              { icon: 'lock', title: 'Conforme RGPD by design', desc: 'Opt-in explicite, droit à l\'effacement, export en un clic' },
              { icon: 'spark', title: 'Ta memoire t\'appartient', desc: 'Exportable, modifiable, supprimable a tout moment' },
              { icon: 'sync', title: 'Synchronisee partout', desc: 'Web, mobile, desktop - ta memoire te suit' },
            ].map(b => (
              <li key={b.title} style={{ display: 'flex', gap: 16 }}>
                <div style={{
                  width: 30, height: 30, borderRadius: 999, flexShrink: 0,
                  background: 'rgba(37,99,235,0.14)',
                  color: '#2563EB',
                  border: '1px solid rgba(37,99,235,0.08)',
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                }}><MemoryIcon name={b.icon} /></div>
                <div>
                  <div style={{ fontWeight: 600, fontSize: 16, letterSpacing: '-0.01em' }}>{b.title}</div>
                  <div style={{ color: 'var(--ink-2)', fontSize: 14, marginTop: 2 }}>{b.desc}</div>
                </div>
              </li>
            ))}
          </ul>
        </Reveal>

        <Reveal as="div" delay={195}>
          <div className="glass memory-window" style={{ padding: 24, position: 'relative' }}>
            <div style={{
              display: 'flex', alignItems: 'center', justifyContent: 'space-between',
              marginBottom: 16, paddingBottom: 16,
              borderBottom: '1px solid rgba(10,10,15,0.05)',
            }}>
              <div>
                <div style={{ fontSize: 15, fontWeight: 600, letterSpacing: '-0.01em' }}>Ma mémoire</div>
                <div style={{ fontSize: 12, color: 'var(--ink-3)', marginTop: 2 }}>
                  {factsShown} facts · synchronise il y a {syncMin} min
                </div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                <span className="memory-active-dot" style={{ width: 8, height: 8, borderRadius: 99, background: '#34C759' }} />
                <span style={{ fontSize: 12, color: 'var(--ink-3)' }}>active</span>
              </div>
            </div>
            <div className="memory-preview-card">
              <div className="memory-preview-card__label">Elle te connait deja</div>
              <div className="memory-preview-card__prompt">Prompt: "Ecris un mail de relance pour un lead SaaS B2B."</div>
              <div className="memory-preview-card__answer">Reponse adaptee: ton clair, format concis, proposition d\'appel 15 min.</div>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              {facts.map((f, i) => (
                <FactCard key={i} fact={f} index={i} total={facts.length} />
              ))}
            </div>
          </div>
        </Reveal>
      </div>
    </section>
  );
}

function FactCard({ fact, index, total }) {
  const ref = uR(null);
  const reduceMotion =
    typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  const [shown, setShown] = uS(reduceMotion);
  uE(() => {
    if (reduceMotion) return undefined;
    const el = ref.current;
    if (!el) return undefined;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) {
        window.setTimeout(function () {
          setShown(true);
        }, 200 + index * 150);
        io.unobserve(el);
      }
    }, { threshold: 0.18, rootMargin: '0px 0px -6% 0px' });
    io.observe(el);
    return () => io.disconnect();
  }, [index, reduceMotion]);
  return (
    <div
      ref={ref}
      className={
        'memory-fact-card' +
        (shown ? ' memory-fact-card--shown' : '')
      }
    >
      <div style={{ minWidth: 0, flex: 1 }}>
        <div className="memory-fact-card__text" style={{ fontSize: 13.5, color: 'var(--ink)', letterSpacing: '-0.005em' }}>
          {fact.text}
        </div>
        <div className="memory-fact-card__meta">
          <span className={'memory-fact-card__tag memory-fact-card__tag--' + fact.tag}>{fact.label}</span>
        </div>
      </div>
      <div className="memory-fact-card__actions">
        <button type="button" className="memory-fact-card__btn" aria-label="Modifier">
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
        </button>
        <button type="button" className="memory-fact-card__btn" aria-label="Supprimer">
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3 6h18M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6M10 11v6M14 11v6"/></svg>
        </button>
      </div>
    </div>
  );
}

function MemoryIcon({ name }) {
  if (name === 'brain') return <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round"><path d="M9 3a3 3 0 0 0-3 3 3 3 0 0 0-3 3v3a3 3 0 0 0 3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3V6a3 3 0 0 0-3-3z"/><path d="M15 3a3 3 0 0 1 3 3 3 3 0 0 1 3 3v3a3 3 0 0 1-3 3 3 3 0 0 1-3 3 3 3 0 0 1-3-3"/></svg>;
  if (name === 'lock') return <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>;
  if (name === 'sync') return <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 0 1 15-6.7"/><path d="M21 12a9 9 0 0 1-15 6.7"/><path d="M18 2v4h-4"/><path d="M6 22v-4h4"/></svg>;
  return <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3l2.4 5.4L20 10l-4 3.9.9 5.6L12 17l-4.9 2.5.9-5.6L4 10l5.6-1.6z"/></svg>;
}

Object.assign(window, { RoutingDemo, Modalities, Memory });
