// Résonance — all screens
// Uses primitives from primitives.jsx (global scope)

const { useState, useEffect, useRef } = React;

// ═════════════════════════════════════════════════════════════
// Screen wrapper
// ═════════════════════════════════════════════════════════════
function Screen({ intent, children, tabBar = null, noStatus = false }) {
  const { intensity } = window.__rzTweaks || { intensity: 1 };
  return (
    <div data-screen-label={intent} style={{
      width: '100%', height: '100%', position: 'relative', overflow: 'hidden',
      background: RZ.white, fontFamily: 'Inter',
    }}>
      <OrbBackground intent={intent} intensity={intensity}/>
      <div style={{ position: 'relative', zIndex: 2, height: '100%', display: 'flex', flexDirection: 'column' }}>
        {!noStatus && <StatusBar/>}
        <div style={{ flex: 1, overflow: 'auto', WebkitOverflowScrolling: 'touch' }}>
          {children}
        </div>
      </div>
      {tabBar}
    </div>
  );
}

// ═════════════════════════════════════════════════════════════
// S1 — Splash (5-slide narrative carousel)
// Each slide has its own bespoke visualisation. The two forms
// (orange = data, blue = felt) journey from separated → fused.
// ═════════════════════════════════════════════════════════════

// Splash-only soft palette (not the full app token set)
const SP = {
  orange: '#F0A090',  // corps / data
  blue:   '#90B8F0',  // esprit / ressenti
  mauve:  '#8A5B95',  // résonance
};

// Shared rectangle (data) — used in slides 1–4 with offset/sync overrides
function DataRect({ size, x = 0, pulseSync = false }) {
  return (
    <div style={{
      position: 'absolute', left: x, top: '50%', transform: 'translateY(-50%)',
      width: size * 0.36, height: size * 0.60,
      borderRadius: 4,
      boxShadow: `inset 0 0 0 1px rgba(255,255,255,0.22), 0 12px 32px -10px ${SP.orange}99`,
      animation: pulseSync
        ? 'rz-sync-pulse 4.6s cubic-bezier(0.55,0.1,0.4,0.9) infinite'
        : 'rz-data-pulse 1.5s steps(2,end) infinite',
      backgroundImage: `repeating-linear-gradient(90deg, rgba(255,255,255,0.20) 0 1px, transparent 1px ${size * 0.06}px), repeating-linear-gradient(0deg, rgba(255,255,255,0.20) 0 1px, transparent 1px ${size * 0.06}px), linear-gradient(180deg, ${SP.orange} 0%, ${SP.orange}cc 100%)`,
    }}/>
  );
}

// Shared blob (felt) — slides 1–4
function FeltBlob({ size, x, syncBreath = false }) {
  return (
    <div style={{
      position: 'absolute', right: x, top: '50%',
      width: size * 0.46, height: size * 0.46, borderRadius: '50%',
      background: `radial-gradient(circle at 35% 35%, ${SP.blue}f2 0%, ${SP.blue}77 58%, ${SP.blue}00 100%)`,
      filter: `blur(${size * 0.035}px)`,
      transformOrigin: 'center',
      animation: syncBreath
        ? 'rz-sync-breath 4.6s cubic-bezier(0.55,0.1,0.4,0.9) infinite'
        : 'rz-organic-breath 5.3s cubic-bezier(0.55,0.1,0.4,0.9) infinite',
      transform: 'translateY(-50%)',
    }}/>
  );
}

// — Slide 1 : La fissure ——————————————————————————————————————
function FissureViz({ size = 240 }) {
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <DataRect size={size} x={0}/>
      <FeltBlob size={size} x={0}/>
      {/* dashed crack */}
      <div style={{
        position: 'absolute', left: '50%', top: '14%', bottom: '14%', transform: 'translateX(-50%)',
        width: 1, borderLeft: '1px dashed rgba(24,20,15,0.20)',
      }}/>
    </div>
  );
}

// — Slide 2 : La trace ———————————————————————————————————————
//   horizontal cartography line forms across the middle, with tick
//   marks dropping side-by-side from each form
function TraceViz({ size = 240 }) {
  const cy = size * 0.5;
  // Pre-compute deterministic tick positions
  const dataTicks  = [0.10, 0.20, 0.30].map(p => size * p);
  const feltTicks  = [0.62, 0.74, 0.86].map(p => size * p);
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <DataRect size={size} x={0}/>
      <FeltBlob size={size} x={0}/>
      {/* horizontal trace line drawing across — stroke-dashoffset reveal */}
      <svg width={size} height={size} style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
        <line
          x1={size * 0.04} y1={cy + size * 0.18}
          x2={size * 0.96} y2={cy + size * 0.18}
          stroke="rgba(24,20,15,0.32)" strokeWidth="1"
          strokeDasharray={size * 0.92} strokeDashoffset={size * 0.92}
          style={{ animation: 'rz-trace-draw 3.2s ease-out forwards' }}
        />
        {/* data ticks (orange) — appear with pulse */}
        {dataTicks.map((tx, i) => (
          <line key={'d'+i} x1={tx} y1={cy + size * 0.14} x2={tx} y2={cy + size * 0.22}
            stroke={SP.orange} strokeWidth="1.5"
            style={{ animation: `rz-tick-in 0.4s ${0.5 + i * 0.5}s both ease-out` }}/>
        ))}
        {/* felt ticks (blue) — appear with breath */}
        {feltTicks.map((tx, i) => (
          <line key={'f'+i} x1={tx} y1={cy + size * 0.14} x2={tx} y2={cy + size * 0.22}
            stroke={SP.blue} strokeWidth="1.5"
            style={{ animation: `rz-tick-in 0.4s ${0.9 + i * 0.6}s both ease-out` }}/>
        ))}
      </svg>
      {/* dashed crack remains, lighter */}
      <div style={{
        position: 'absolute', left: '50%', top: '14%', bottom: '14%', transform: 'translateX(-50%)',
        width: 1, borderLeft: '1px dashed rgba(24,20,15,0.12)',
      }}/>
    </div>
  );
}

// — Slide 3 : La voix ————————————————————————————————————————
//   sound wave emanates from blue (right) and travels LEFT, crossing
//   the fissure. Data side reacts with a subtle bloom when it arrives.
function VoiceViz({ size = 240 }) {
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <DataRect size={size} x={0}/>
      <FeltBlob size={size} x={0}/>
      {/* concentric voice arcs — emit from blob centre, travel left */}
      <svg width={size} height={size} style={{ position: 'absolute', inset: 0, pointerEvents: 'none', overflow: 'visible' }}>
        <defs>
          <radialGradient id="voiceFade" cx="100%" cy="50%" r="100%">
            <stop offset="0%"  stopColor={SP.blue} stopOpacity="0"/>
            <stop offset="55%" stopColor={SP.blue} stopOpacity="0.8"/>
            <stop offset="100%" stopColor={SP.blue} stopOpacity="0"/>
          </radialGradient>
        </defs>
        {[0, 1, 2].map(k => {
          const cx = size * 0.74, cy = size * 0.5, r = size * 0.10;
          return (
            <path key={k}
              d={`M ${cx} ${cy - r} A ${r} ${r} 0 0 0 ${cx} ${cy + r}`}
              fill="none" stroke={SP.blue} strokeWidth="1.4" strokeLinecap="round"
              style={{
                transformOrigin: `${cx}px ${cy}px`,
                animation: `rz-voice-wave 3.2s ${k * 1.06}s ease-out infinite`,
                opacity: 0,
              }}
            />
          );
        })}
      </svg>
      {/* data-side bloom — reacts when wave arrives */}
      <div style={{
        position: 'absolute', left: size * 0.18, top: '50%',
        width: size * 0.10, height: size * 0.10, borderRadius: '50%',
        background: `radial-gradient(circle, ${SP.orange}cc 0%, ${SP.orange}00 70%)`,
        transform: 'translateY(-50%)',
        animation: 'rz-data-listen 3.2s 1.4s ease-out infinite',
        opacity: 0,
      }}/>
      {/* crack — almost gone */}
      <div style={{
        position: 'absolute', left: '50%', top: '20%', bottom: '20%', transform: 'translateX(-50%)',
        width: 1, borderLeft: '1px dashed rgba(24,20,15,0.10)',
      }}/>
    </div>
  );
}

// — Slide 4 : La rencontre ————————————————————————————————————
//   forms move closer and OVERLAP. mauve blooms in contact zone.
//   pulse + breath now share rhythm.
function EncounterViz({ size = 240 }) {
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      {/* shifted positions — they meet in the middle */}
      <div style={{
        position: 'absolute', left: size * 0.12, top: '50%', transform: 'translateY(-50%)',
        width: size * 0.36, height: size * 0.60, borderRadius: 4,
        boxShadow: `inset 0 0 0 1px rgba(255,255,255,0.22), 0 12px 32px -10px ${SP.orange}99`,
        animation: 'rz-sync-pulse 4.6s cubic-bezier(0.55,0.1,0.4,0.9) infinite',
        backgroundImage: `repeating-linear-gradient(90deg, rgba(255,255,255,0.20) 0 1px, transparent 1px ${size * 0.06}px), repeating-linear-gradient(0deg, rgba(255,255,255,0.20) 0 1px, transparent 1px ${size * 0.06}px), linear-gradient(180deg, ${SP.orange} 0%, ${SP.orange}cc 100%)`,
      }}/>
      <div style={{
        position: 'absolute', right: size * 0.10, top: '50%',
        width: size * 0.50, height: size * 0.50, borderRadius: '50%',
        background: `radial-gradient(circle at 35% 35%, ${SP.blue}f2 0%, ${SP.blue}77 58%, ${SP.blue}00 100%)`,
        filter: `blur(${size * 0.035}px)`,
        transform: 'translateY(-50%)',
        animation: 'rz-sync-breath 4.6s cubic-bezier(0.55,0.1,0.4,0.9) infinite',
      }}/>
      {/* mauve bloom in contact zone — synced with shared rhythm */}
      <div style={{
        position: 'absolute', left: '50%', top: '50%',
        width: size * 0.30, height: size * 0.42, borderRadius: '50%',
        background: `radial-gradient(ellipse at center, ${SP.mauve}cc 0%, ${SP.mauve}55 45%, ${SP.mauve}00 78%)`,
        filter: `blur(${size * 0.06}px)`,
        transform: 'translate(-50%, -50%)',
        mixBlendMode: 'multiply',
        animation: 'rz-sync-bloom 4.6s cubic-bezier(0.55,0.1,0.4,0.9) infinite',
      }}/>
    </div>
  );
}

// — Slide 5 : La résonance ————————————————————————————————————
//   single mauve orb, calm deep breath. fissure invisible.
function ResonanceOrb({ size = 240 }) {
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      {/* outer halo */}
      <div style={{
        position: 'absolute', left: '50%', top: '50%',
        width: size * 0.92, height: size * 0.92, borderRadius: '50%',
        background: `radial-gradient(circle, ${SP.mauve}33 0%, ${SP.mauve}00 65%)`,
        filter: `blur(${size * 0.05}px)`,
        transform: 'translate(-50%, -50%)',
        animation: 'rz-resonance-halo 6.2s cubic-bezier(0.45,0,0.55,1) infinite',
      }}/>
      {/* core orb */}
      <div style={{
        position: 'absolute', left: '50%', top: '50%',
        width: size * 0.62, height: size * 0.62, borderRadius: '50%',
        background: `radial-gradient(circle at 38% 36%, #b489be 0%, ${SP.mauve} 55%, #5e3d68 100%)`,
        boxShadow: `inset 0 -8px 24px rgba(0,0,0,0.18), inset 0 8px 18px rgba(255,255,255,0.18), 0 18px 50px -12px ${SP.mauve}88`,
        transform: 'translate(-50%, -50%)',
        animation: 'rz-resonance-breath 6.2s cubic-bezier(0.45,0,0.55,1) infinite',
      }}/>
      {/* highlight */}
      <div style={{
        position: 'absolute', left: '40%', top: '38%',
        width: size * 0.16, height: size * 0.10, borderRadius: '50%',
        background: 'radial-gradient(ellipse at center, rgba(255,255,255,0.45) 0%, rgba(255,255,255,0) 70%)',
        filter: 'blur(2px)', transform: 'translate(-50%, -50%)',
      }}/>
    </div>
  );
}

const SPLASH_SLIDES = [
  { viz: 'fissure',   title: ['Apprends','à t\'écouter.'],                          body: 'Résonance relie ce que tu mesures à ce que tu ressens.' },
  { viz: 'trace',     title: ['Tes séances et tes ressentis,','réunis.'],            body: 'Un journal d\'entraînement qui prend en compte ce que tu vis.' },
  { viz: 'voice',     title: ['Nuance','tes séances.'],                              body: 'Pose à la voix ce qui ne se mesure pas.' },
  { viz: 'encounter', title: ['Prends','du recul.'],                                 body: 'Au fil du temps, ce qui te porte et ce qui te pèse devient visible.' },
  { viz: 'resonance', title: ['Tu as rendez-vous','avec toi.'],                      body: 'Résonance commence ici.' },
];

function SplashViz({ kind, size = 240 }) {
  if (kind === 'fissure')   return <FissureViz size={size}/>;
  if (kind === 'trace')     return <TraceViz size={size}/>;
  if (kind === 'voice')     return <VoiceViz size={size}/>;
  if (kind === 'encounter') return <EncounterViz size={size}/>;
  if (kind === 'resonance') return <ResonanceOrb size={size}/>;
  return null;
}

function S1_Splash({ go }) {
  const [i, setI] = useState(0);
  const last = i === SPLASH_SLIDES.length - 1;
  const next = () => last ? go('S1b_Login') : setI(i + 1);
  const prev = () => i > 0 && setI(i - 1);

  useEffect(() => {
    const onKey = (e) => {
      if (e.key === 'ArrowRight') next();
      else if (e.key === 'ArrowLeft') prev();
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [i]);

  // touch swipe
  const touch = useRef({ x: 0 });
  const onTouchStart = (e) => { touch.current.x = e.touches[0].clientX; };
  const onTouchEnd = (e) => {
    const dx = e.changedTouches[0].clientX - touch.current.x;
    if (dx > 40) prev(); else if (dx < -40) next();
  };

  const slide = SPLASH_SLIDES[i];

  return (
    <Screen intent="onboard">
      <div onTouchStart={onTouchStart} onTouchEnd={onTouchEnd}
        style={{ display: 'flex', flexDirection: 'column', height: '100%', padding: '0 0 24px' }}>

        {/* Passer */}
        <div style={{ display: 'flex', justifyContent: 'flex-end', padding: '4px 22px 0' }}>
          <div onClick={() => go('S5_Journal')} style={{ fontSize: 13, color: RZ.fg2, cursor: 'pointer', padding: '6px 4px' }}>Passer</div>
        </div>

        {/* Hero orb — animated, transitions across slides */}
        <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative' }}>
          <div key={i} style={{ animation: 'rz-fade 520ms cubic-bezier(0.4,0,0.2,1)' }}>
            <SplashViz kind={slide.viz} size={240}/>
          </div>
        </div>

        {/* RÉSONANCE wordmark above the card */}
        <div style={{ textAlign: 'center', marginBottom: 14 }}>
          <div style={{ display: 'inline-block', fontSize: 11, fontWeight: 700, color: RZ.fg1, letterSpacing: 4, fontFamily: 'Inter' }}>
            RÉSONANCE
          </div>
        </div>

        {/* Glass card */}
        <div style={{ padding: '0 16px' }}>
          <Glass raised style={{ padding: '22px 22px 18px', borderRadius: 22 }}>
            <div key={'t' + i} style={{ animation: 'rz-slide-up 420ms cubic-bezier(0.4,0,0.2,1)' }}>
              <div style={{ fontSize: 26, fontWeight: 700, color: RZ.fg1, letterSpacing: -0.5, lineHeight: 1.15, marginBottom: 12 }}>
                {slide.title.map((l, k) => <div key={k}>{l}</div>)}
              </div>
              <div style={{ fontSize: 13.5, color: RZ.fg2, lineHeight: 1.55, marginBottom: 18, minHeight: 62 }}>
                {slide.body}
              </div>
            </div>

            {/* Dots */}
            <div style={{ display: 'flex', justifyContent: 'center', gap: 6, marginBottom: 18 }}>
              {SPLASH_SLIDES.map((_, k) => (
                <div key={k} onClick={() => setI(k)} style={{
                  width: k === i ? 22 : 6, height: 6, borderRadius: 6,
                  background: k === i ? RZ.fg1 : 'rgba(24,20,15,0.18)',
                  transition: 'all 280ms ease', cursor: 'pointer',
                }}/>
              ))}
            </div>

            <PrimaryBtn onClick={next}>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                {last ? 'Commencer' : 'Suivant'}
                <Icon name="arrowRight" size={15} color={RZ.white}/>
              </span>
            </PrimaryBtn>
          </Glass>
        </div>

      </div>
    </Screen>
  );
}

// ═════════════════════════════════════════════════════════════
// S1b — Login (after splash)
// ═════════════════════════════════════════════════════════════
function AppleLogo({ color = '#fff' }) {
  return (
    <svg width="14" height="16" viewBox="0 0 16 18" fill="none" aria-hidden>
      <path fill={color} d="M11.62 9.49c0-1.79 1.46-2.65 1.53-2.69-.84-1.22-2.14-1.39-2.6-1.41-1.1-.11-2.16.65-2.72.65-.57 0-1.43-.63-2.36-.62-1.21.02-2.34.71-2.96 1.79-1.27 2.2-.32 5.46.91 7.25.6.88 1.31 1.86 2.24 1.83.91-.04 1.25-.59 2.34-.59 1.09 0 1.4.59 2.36.57.97-.02 1.59-.89 2.18-1.78.68-1.02.96-2 .98-2.05-.02-.01-1.88-.72-1.9-2.86zm-1.79-5.27c.51-.61.85-1.46.76-2.31-.73.03-1.62.49-2.15 1.1-.47.54-.89 1.4-.78 2.23.82.06 1.66-.41 2.17-1.02z"/>
    </svg>
  );
}

function GoogleLogo() {
  return (
    <svg width="16" height="16" viewBox="0 0 18 18" fill="none" aria-hidden>
      <path d="M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.49h4.84c-.21 1.13-.84 2.08-1.79 2.72v2.27h2.9c1.7-1.56 2.69-3.86 2.69-6.64z" fill="#4285F4"/>
      <path d="M9 18c2.43 0 4.47-.81 5.96-2.18l-2.9-2.27c-.8.54-1.83.86-3.06.86-2.35 0-4.34-1.59-5.05-3.72H.95v2.34A8.99 8.99 0 0 0 9 18z" fill="#34A853"/>
      <path d="M3.95 10.69c-.18-.54-.28-1.12-.28-1.69s.1-1.15.28-1.69V4.96H.95C.34 6.16 0 7.55 0 9c0 1.45.34 2.84.95 4.04l3-2.35z" fill="#FBBC05"/>
      <path d="M9 3.58c1.32 0 2.51.45 3.45 1.34l2.58-2.58C13.46.89 11.43 0 9 0A8.99 8.99 0 0 0 .95 4.96l3 2.34C4.66 5.17 6.65 3.58 9 3.58z" fill="#EA4335"/>
    </svg>
  );
}

// — Aura orb — organic, non-spherical, morphing blob aura
//   Uses SVG turbulence + animated blob path + drifting color clouds.
function AuraOrb({ size = 140 }) {
  const id = React.useId ? React.useId() : 'aura';
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <svg viewBox="0 0 200 200" width={size} height={size} style={{ overflow: 'visible' }}>
        <defs>
          {/* turbulent displacement gives organic edge */}
          <filter id={`turb-${id}`} x="-30%" y="-30%" width="160%" height="160%">
            <feTurbulence type="fractalNoise" baseFrequency="0.014 0.018" numOctaves="2" seed="3">
              <animate attributeName="baseFrequency" dur="14s" repeatCount="indefinite"
                values="0.012 0.018; 0.020 0.014; 0.012 0.018"/>
            </feTurbulence>
            <feDisplacementMap in="SourceGraphic" scale="22"/>
            <feGaussianBlur stdDeviation="1.2"/>
          </filter>
          <filter id={`soft-${id}`} x="-30%" y="-30%" width="160%" height="160%">
            <feGaussianBlur stdDeviation="6"/>
          </filter>
          {/* mauve core radial */}
          <radialGradient id={`core-${id}`} cx="42%" cy="38%" r="65%">
            <stop offset="0%"  stopColor="#b48abd"/>
            <stop offset="45%" stopColor={SP.mauve}/>
            <stop offset="100%" stopColor="#3d2746"/>
          </radialGradient>
          {/* warm cloud */}
          <radialGradient id={`warm-${id}`} cx="50%" cy="50%" r="50%">
            <stop offset="0%"  stopColor={SP.orange} stopOpacity="0.75"/>
            <stop offset="100%" stopColor={SP.orange} stopOpacity="0"/>
          </radialGradient>
          {/* cool cloud */}
          <radialGradient id={`cool-${id}`} cx="50%" cy="50%" r="50%">
            <stop offset="0%"  stopColor={SP.blue} stopOpacity="0.70"/>
            <stop offset="100%" stopColor={SP.blue} stopOpacity="0"/>
          </radialGradient>
          <radialGradient id={`mauv-${id}`} cx="50%" cy="50%" r="50%">
            <stop offset="0%"  stopColor={SP.mauve} stopOpacity="0.85"/>
            <stop offset="100%" stopColor={SP.mauve} stopOpacity="0"/>
          </radialGradient>
        </defs>

        {/* outer soft aura — organic blob, slowly morphing */}
        <g style={{ filter: `url(#turb-${id})`, mixBlendMode: 'multiply' }}>
          <ellipse cx="100" cy="105" rx="78" ry="72" fill={`url(#warm-${id})`}>
            <animate attributeName="rx" dur="8s" repeatCount="indefinite"
              values="78;82;74;78" calcMode="spline" keySplines="0.4 0 0.6 1;0.4 0 0.6 1;0.4 0 0.6 1"/>
            <animate attributeName="ry" dur="8s" repeatCount="indefinite"
              values="72;68;76;72" calcMode="spline" keySplines="0.4 0 0.6 1;0.4 0 0.6 1;0.4 0 0.6 1"/>
            <animate attributeName="cx" dur="11s" repeatCount="indefinite" values="100;108;94;100"/>
            <animate attributeName="cy" dur="9s" repeatCount="indefinite" values="105;98;110;105"/>
          </ellipse>
          <ellipse cx="100" cy="100" rx="70" ry="74" fill={`url(#cool-${id})`}>
            <animate attributeName="rx" dur="9s" repeatCount="indefinite" values="70;74;66;70"/>
            <animate attributeName="ry" dur="9s" repeatCount="indefinite" values="74;70;78;74"/>
            <animate attributeName="cx" dur="13s" repeatCount="indefinite" values="100;94;106;100"/>
            <animate attributeName="cy" dur="10s" repeatCount="indefinite" values="100;106;94;100"/>
          </ellipse>
          <ellipse cx="100" cy="100" rx="64" ry="68" fill={`url(#mauv-${id})`}>
            <animate attributeName="rx" dur="7s" repeatCount="indefinite" values="64;70;60;64"/>
            <animate attributeName="ry" dur="7s" repeatCount="indefinite" values="68;62;72;68"/>
          </ellipse>
        </g>

        {/* inner organic core — also displaced for non-perfect roundness */}
        <g style={{ filter: `url(#turb-${id})` }}>
          <ellipse cx="100" cy="98" rx="38" ry="40" fill={`url(#core-${id})`}>
            <animate attributeName="rx" dur="6s" repeatCount="indefinite" values="38;42;36;38"/>
            <animate attributeName="ry" dur="6s" repeatCount="indefinite" values="40;36;42;40"/>
            <animate attributeName="cx" dur="9s" repeatCount="indefinite" values="100;103;97;100"/>
            <animate attributeName="cy" dur="8s" repeatCount="indefinite" values="98;101;95;98"/>
          </ellipse>
        </g>

        {/* highlight — soft, slightly off-center */}
        <ellipse cx="88" cy="84" rx="8" ry="5" fill="rgba(255,255,255,0.55)"
          style={{ filter: `url(#soft-${id})` }}/>
      </svg>
    </div>
  );
}

function S1b_Login({ go }) {
  const [email, setEmail] = useState('');
  const valid = /\S+@\S+\.\S+/.test(email);

  return (
    <Screen intent="onboard">
      <TopBar onBack={() => go('S1_Splash')}/>
      <div style={{ display: 'flex', flexDirection: 'column', minHeight: 'calc(100% - 0px)', padding: '0 20px 24px' }}>

        {/* Aura orb — abstract, layered halos */}
        <div style={{ display: 'flex', justifyContent: 'center', margin: '0 0 14px' }}>
          <AuraOrb size={132}/>
        </div>

        {/* wordmark */}
        <div style={{ textAlign: 'center', marginBottom: 10 }}>
          <span style={{ display: 'inline-block', fontSize: 10.5, fontWeight: 700, color: RZ.fg1, letterSpacing: 4 }}>RÉSONANCE</span>
        </div>

        {/* heading */}
        <div style={{ textAlign: 'center', marginBottom: 22 }}>
          <div style={{ fontSize: 26, fontWeight: 700, color: RZ.fg1, letterSpacing: -0.5, lineHeight: 1.15 }}>
            Bon retour.
          </div>
          <div style={{ fontSize: 13.5, color: RZ.fg2, marginTop: 6, lineHeight: 1.5, maxWidth: 280, margin: '6px auto 0' }}>
            Reprends ton journal là où tu l'avais laissé.
          </div>
        </div>

        {/* auth card */}
        <Glass raised style={{ padding: 16, borderRadius: 22 }}>
          {/* Apple */}
          <button onClick={() => go('S5_Journal')} style={{
            width: '100%', padding: '13px 16px', borderRadius: 14, border: 'none',
            background: RZ.fg1, color: '#fff', fontSize: 14.5, fontWeight: 600, fontFamily: 'Inter',
            display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10,
            cursor: 'pointer', marginBottom: 9,
          }}>
            <AppleLogo color="#fff"/>
            Continuer avec Apple
          </button>
          {/* Google */}
          <button onClick={() => go('S5_Journal')} style={{
            width: '100%', padding: '13px 16px', borderRadius: 14,
            border: '1px solid rgba(24,20,15,0.10)',
            background: '#fff', color: RZ.fg1, fontSize: 14.5, fontWeight: 600, fontFamily: 'Inter',
            display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10,
            cursor: 'pointer', marginBottom: 12,
          }}>
            <GoogleLogo/>
            Continuer avec Google
          </button>

          {/* divider */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, margin: '4px 0 12px' }}>
            <div style={{ flex: 1, height: 1, background: 'rgba(24,20,15,0.10)' }}/>
            <div style={{ fontSize: 10, fontWeight: 600, color: RZ.fg3, letterSpacing: 1.6 }}>OU PAR EMAIL</div>
            <div style={{ flex: 1, height: 1, background: 'rgba(24,20,15,0.10)' }}/>
          </div>

          {/* email field */}
          <input
            type="email" placeholder="ton@email.com" autoComplete="email"
            value={email} onChange={e => setEmail(e.target.value)}
            style={{
              width: '100%', padding: '13px 16px', borderRadius: 14,
              border: '1px solid rgba(24,20,15,0.10)', background: '#fff',
              fontSize: 14.5, color: RZ.fg1, fontFamily: 'Inter', boxSizing: 'border-box',
              marginBottom: 10, outline: 'none',
            }}
          />
          <PrimaryBtn onClick={() => valid && go('S5_Journal')} style={{ opacity: valid ? 1 : 0.45, pointerEvents: valid ? 'auto' : 'none' }}>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
              Recevoir un lien magique
              <Icon name="arrowRight" size={15} color={RZ.white}/>
            </span>
          </PrimaryBtn>

          <div style={{ textAlign: 'center', marginTop: 10, fontSize: 11.5, color: RZ.fg3, lineHeight: 1.5 }}>
            Aucun mot de passe à retenir.<br/>On t'envoie un lien sécurisé.
          </div>
        </Glass>

        <div style={{ flex: 1, minHeight: 16 }}/>

        {/* create account */}
        <div style={{ textAlign: 'center', fontSize: 13, color: RZ.fg2, marginTop: 16 }}>
          Première fois ici&nbsp;?{' '}
          <span onClick={() => go('S2_Choice')} style={{ color: RZ.fg1, fontWeight: 600, cursor: 'pointer', textDecoration: 'underline', textUnderlineOffset: 3 }}>
            Crée ton espace
          </span>
        </div>

        {/* fine print */}
        <div style={{ textAlign: 'center', fontSize: 10.5, color: RZ.fg3, marginTop: 14, lineHeight: 1.55, maxWidth: 280, margin: '14px auto 0' }}>
          En continuant, tu acceptes nos{' '}
          <span style={{ textDecoration: 'underline', cursor: 'pointer' }}>conditions</span>
          {' '}et notre{' '}
          <span style={{ textDecoration: 'underline', cursor: 'pointer' }}>politique de confidentialité</span>.
        </div>

      </div>
    </Screen>
  );
}

// ═════════════════════════════════════════════════════════════
// S2 — Onboarding choice
// ═════════════════════════════════════════════════════════════
function S2_Choice({ go }) {
  return (
    <Screen intent="onboard">
      <TopBar onBack={() => go('S1_Splash')}/>
      <div style={{ padding: '0 20px 32px' }}>
        <div style={{ fontSize: 26, fontWeight: 700, color: RZ.fg1, letterSpacing: -0.4, marginBottom: 8 }}>
          Comment veux-tu<br/>qu'on se rencontre&nbsp;?
        </div>
        <div style={{ fontSize: 14, color: RZ.fg2, lineHeight: 1.5, marginBottom: 28 }}>
          Deux chemins. Choisis celui qui te correspond.
        </div>
        <Glass raised style={{ padding: 20, marginBottom: 14, cursor: 'pointer' }} onClick={() => go('S3b_Conversation')}>
          <div style={{ display: 'flex', alignItems: 'flex-start', gap: 14 }}>
            <div style={{ width: 48, height: 48, borderRadius: 14, background: 'rgba(23,114,254,0.12)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
              <Icon name="mic" size={22} color={RZ.blue}/>
            </div>
            <div style={{ flex: 1 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>
                <div style={{ fontSize: 16, fontWeight: 600, color: RZ.fg1 }}>Conversation guidée</div>
                <span style={{ fontSize: 9, fontWeight: 600, padding: '2px 7px', borderRadius: 20, background: 'rgba(138,91,149,0.18)', color: RZ.mauve, letterSpacing: 0.3 }}>Recommandé</span>
              </div>
              <div style={{ fontSize: 13, color: RZ.fg2, lineHeight: 1.5 }}>
                Je te pose quelques questions vocales. On fait connaissance — 5&nbsp;min.
              </div>
            </div>
          </div>
        </Glass>
        <Glass style={{ padding: 20, cursor: 'pointer' }} onClick={() => go('S3a_Setup')}>
          <div style={{ display: 'flex', alignItems: 'flex-start', gap: 14 }}>
            <div style={{ width: 48, height: 48, borderRadius: 14, background: 'rgba(24,20,15,0.05)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
              <Icon name="settings" size={22}/>
            </div>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 16, fontWeight: 600, color: RZ.fg1, marginBottom: 4 }}>Setup rapide</div>
              <div style={{ fontSize: 13, color: RZ.fg2, lineHeight: 1.5 }}>
                Quelques choix manuels — 2&nbsp;min. Tu pourras parler plus tard.
              </div>
            </div>
          </div>
        </Glass>
        <div style={{ fontSize: 11, color: RZ.fg3, textAlign: 'center', marginTop: 24, lineHeight: 1.5 }}>
          Plus tu m'alimentes, plus je comprends ce qui résonne pour toi.
        </div>
      </div>
    </Screen>
  );
}

// ═════════════════════════════════════════════════════════════
// S3a — Setup rapide
// ═════════════════════════════════════════════════════════════
function S3a_Setup({ go }) {
  const [sports, setSports] = useState(['run']);
  const [volume, setVolume] = useState('3-5');
  const [motivation, setMotivation] = useState('wellness');
  const toggleSport = s => setSports(sports.includes(s) ? sports.filter(x => x !== s) : [...sports, s]);
  const canContinue = sports.length > 0;

  return (
    <Screen intent="onboard">
      <TopBar onBack={() => go('S2_Choice')} title="Setup rapide" subtitle="1 sur 1"/>
      <div style={{ padding: '4px 20px 120px' }}>
        <div style={{ marginBottom: 24 }}>
          <div style={{ fontSize: 12, fontWeight: 500, color: RZ.fg3, textTransform: 'uppercase', letterSpacing: 0.8, marginBottom: 12 }}>Sports pratiqués</div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
            {[['run','Course','run'],['bike','Vélo','bike'],['swim','Natation','swim'],['trail','Trail','trail'],['strength','Muscu','strength']].map(([k,l,i]) => (
              <Chip key={k} on={sports.includes(k)} icon={i} onClick={() => toggleSport(k)}>{l}</Chip>
            ))}
          </div>
        </div>
        <div style={{ marginBottom: 24 }}>
          <div style={{ fontSize: 12, fontWeight: 500, color: RZ.fg3, textTransform: 'uppercase', letterSpacing: 0.8, marginBottom: 12 }}>Volume hebdomadaire</div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
            {[['<3','moins de 3h'],['3-5','3 – 5 h'],['5-8','5 – 8 h'],['>8','8 h et plus']].map(([k,l]) => (
              <Chip key={k} on={volume === k} onClick={() => setVolume(k)}>{l}</Chip>
            ))}
          </div>
        </div>
        <div>
          <div style={{ fontSize: 12, fontWeight: 500, color: RZ.fg3, textTransform: 'uppercase', letterSpacing: 0.8, marginBottom: 12 }}>Ce qui te porte</div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
            {[['perf','Performance'],['wellness','Bien-être'],['maintain','Maintien'],['compete','Compétition']].map(([k,l]) => (
              <Chip key={k} on={motivation === k} onClick={() => setMotivation(k)}>{l}</Chip>
            ))}
          </div>
        </div>
      </div>
      <div style={{ position: 'absolute', bottom: 24, left: 20, right: 20, zIndex: 30 }}>
        <PrimaryBtn disabled={!canContinue} onClick={() => canContinue && go('S4_Strava')}>C'est parti →</PrimaryBtn>
      </div>
    </Screen>
  );
}

// ═════════════════════════════════════════════════════════════
// S3b — Conversation IA
// ═════════════════════════════════════════════════════════════
function S3b_Conversation({ go }) {
  const [step, setStep] = useState(0);
  const turns = [
    { who: 'ai', text: <>Bonjour 👋 Je suis Résonance.<br/><br/>Je suis là pour t'aider à mieux comprendre ce que tu ressens dans ta pratique.</> },
    { who: 'ai', text: <>Raconte-moi : comment s'est passée ta dernière séance&nbsp;?</>, prompt: true },
    { who: 'user', text: <em>« Un 10k tranquille ce matin. Je me sentais étonnamment léger, alors que j'ai mal dormi… »</em> },
    { who: 'ai', text: <>Je t'entends. Ton corps t'a porté malgré la fatigue — c'est précieux à remarquer.<br/><br/>Qu'est-ce qui t'amène vers Résonance&nbsp;?</>, prompt: true },
    { who: 'user', text: <em>« J'en ai marre des scores qui me disent que je suis 'en retard'. Je veux écouter autrement. »</em> },
    { who: 'ai', text: <>Merci de me faire confiance.<br/><br/>Je commence à te connaître. On va construire quelque chose ensemble. 🌊</> },
  ];
  const visible = turns.slice(0, step + 1);
  const done = step >= turns.length - 1;
  const current = turns[step];

  return (
    <Screen intent="nuance">
      <TopBar onBack={() => go('S2_Choice')} title="Conversation" subtitle={`${Math.min(step+1, turns.length)} / ${turns.length}`}/>
      <div style={{ padding: '8px 20px 200px', display: 'flex', flexDirection: 'column', gap: 12 }}>
        {visible.map((t, i) => (
          <div key={i} style={{
            alignSelf: t.who === 'ai' ? 'flex-start' : 'flex-end',
            maxWidth: '85%',
            animation: 'rz-slide-up 400ms ease-out',
          }}>
            {t.who === 'ai' ? (
              <Glass raised style={{ padding: '14px 16px', borderRadius: 18, borderBottomLeftRadius: 6 }}>
                <div style={{ fontSize: 14, color: RZ.fg1, lineHeight: 1.55 }}>{t.text}</div>
              </Glass>
            ) : (
              <div style={{
                background: RZ.black, color: RZ.white,
                padding: '12px 16px', borderRadius: 18, borderBottomRightRadius: 6,
                fontSize: 13, lineHeight: 1.55,
              }}>{t.text}</div>
            )}
          </div>
        ))}
      </div>
      <div style={{ position: 'absolute', bottom: 28, left: 20, right: 20, zIndex: 30, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12 }}>
        {!done ? (
          current && current.prompt ? (
            <>
              <div onClick={() => setStep(step + 1)} style={{
                width: 72, height: 72, borderRadius: '50%', background: RZ.black,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                boxShadow: '0 8px 24px -8px rgba(24,20,15,0.4)', cursor: 'pointer',
              }}>
                <Icon name="mic" size={26} color={RZ.white}/>
              </div>
              <div style={{ fontSize: 11, color: RZ.fg3 }}>Appuie pour répondre</div>
            </>
          ) : (
            <SecondaryBtn onClick={() => setStep(step + 1)} style={{ width: 'auto', padding: '12px 24px' }}>Continuer</SecondaryBtn>
          )
        ) : (
          <PrimaryBtn onClick={() => go('S4_Strava')}>Commencer</PrimaryBtn>
        )}
      </div>
    </Screen>
  );
}

// ═════════════════════════════════════════════════════════════
// S4 — Strava connect
// ═════════════════════════════════════════════════════════════
function S4_Strava({ go, ctx }) {
  return (
    <Screen intent="onboard">
      <TopBar onBack={() => go('S2_Choice')}/>
      <div style={{ padding: '12px 24px 32px', height: '100%', display: 'flex', flexDirection: 'column' }}>
        <div style={{ fontSize: 24, fontWeight: 700, color: RZ.fg1, letterSpacing: -0.4, marginBottom: 10 }}>
          Connecte Strava<br/>pour que je suive tes séances.
        </div>
        <div style={{ fontSize: 14, color: RZ.fg2, lineHeight: 1.5, marginBottom: 28 }}>
          Je lis tes activités.<br/>Je n'écris rien sur ton compte Strava.
        </div>
        <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div style={{ position: 'relative', width: 260, height: 140 }}>
            <div style={{ position: 'absolute', left: 0, top: 24, width: 84, height: 84, borderRadius: 24, background: 'linear-gradient(135deg, #FC5200, #FC442C)', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 12px 28px -10px rgba(252,82,0,0.5)' }}>
              <Icon name="strava" size={44} color={RZ.white} strokeWidth={0}/>
            </div>
            <div style={{ position: 'absolute', left: 96, top: 40, right: 96, height: 52, display: 'flex', alignItems: 'center', gap: 4 }}>
              <div className="rz-pulse-dot" style={{ width: 5, height: 5, borderRadius: '50%', background: RZ.mauve, animationDelay: '0s' }}/>
              <div className="rz-pulse-dot" style={{ width: 5, height: 5, borderRadius: '50%', background: RZ.mauve, animationDelay: '0.15s' }}/>
              <div className="rz-pulse-dot" style={{ width: 5, height: 5, borderRadius: '50%', background: RZ.mauve, animationDelay: '0.3s' }}/>
              <div className="rz-pulse-dot" style={{ width: 5, height: 5, borderRadius: '50%', background: RZ.mauve, animationDelay: '0.45s' }}/>
              <div className="rz-pulse-dot" style={{ width: 5, height: 5, borderRadius: '50%', background: RZ.mauve, animationDelay: '0.6s' }}/>
            </div>
            <div style={{ position: 'absolute', right: 0, top: 24, width: 84, height: 84 }}>
              <NuanceViz state="resonance" size={84}/>
            </div>
          </div>
        </div>
        <Glass style={{ padding: 14, marginBottom: 14 }}>
          <div style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
            <Icon name="lock" size={18} color={RZ.fg2}/>
            <div style={{ fontSize: 12, color: RZ.fg2, lineHeight: 1.5 }}>
              Tes activités restent privées. Rien n'est partagé avec Strava ou qui que ce soit.
            </div>
          </div>
        </Glass>
        <PrimaryBtn onClick={() => go(ctx?.from === 'settings' ? 'S15_Settings' : 'S5_Journal')}>
          Connecter Strava
        </PrimaryBtn>
        <GhostBtn onClick={() => go('S5_Journal')} style={{ alignSelf: 'center', marginTop: 6 }}>
          Pas maintenant — je le ferai plus tard
        </GhostBtn>
      </div>
    </Screen>
  );
}

Object.assign(window, { Screen, S1_Splash, S2_Choice, S3a_Setup, S3b_Conversation, S4_Strava });
