const { useState, useEffect, useRef, useCallback } = React;

const STOPS = [
  { id: 1, num: '01', short: 'Das Problem',   tag: 'Cloud‑KI ist ein Risiko',     desc: 'Warum jede Eingabe in eine Public‑Cloud Sie und Ihre Mandanten exponiert.', theme: 'dark' },
  { id: 2, num: '02', short: 'Das Risiko',    tag: 'Was Sie verlieren können',    desc: '§203, DSGVO, Berufsrecht – die konkreten Konsequenzen.', theme: 'dark' },
  { id: 3, num: '03', short: 'Die Wende',     tag: 'KI ohne Kompromiss',          desc: 'Wenn die KI zu Ihnen kommt, statt umgekehrt.',           theme: 'light' },
  { id: 4, num: '04', short: 'Das Produkt',   tag: 'LocKi – lokal, deutsch, sicher', desc: 'Private KI‑Infrastruktur im Direktvergleich.', theme: 'light' },
  { id: 5, num: '05', short: 'Der Prozess',   tag: 'Analyse · Setup · Schulung',  desc: 'In drei Schritten zur souveränen Organisation.',           theme: 'light' },
  { id: 6, num: '06', short: 'Jetzt starten', tag: 'Strategiegespräch buchen',    desc: '30 Minuten. Kostenlos. Kein Verkaufsgespräch.', theme: 'light' }
];

const themeOf = (i) => STOPS[i].theme === 'dark' ? 'dark' : 'light';

function Icon({ name, style, className }) {
  return <span className={`material-symbols-outlined ${className || ''}`} style={style}>{name}</span>;
}

// ---------- Header ----------
function Header({ index, theme, onOpenOverview, onJump, onOpenMenu }) {
  return (
    <header className={`header ${theme}`} role="banner">
      <div className="header-inner">
        <a className="brand" href="#top" onClick={(e) => { e.preventDefault(); onJump(0); }}>
          <div className="brand-mark" aria-hidden="true">PT</div>
          <div className="brand-name">
            Philipp Taller
            <small>Consulting · Sichere KI</small>
          </div>
        </a>

        <nav className="linkbar" aria-label="Hauptnavigation">
          <a href="/schulungen">Schulungen</a>
          <span className="sep" aria-hidden="true" />
          <a href="/impressum">Impressum</a>
          <span className="sep" aria-hidden="true" />
          <a href="/datenschutz">Datenschutz</a>
        </nav>

        <div className="header-right">
          <a className="header-cta" href="mailto:ai@philipptaller.com">
            <Icon name="mail" style={{ fontSize: 14 }} />
            <span>Schreiben</span>
          </a>
          <a className="header-cta solid"
             href="https://cal.philipptaller.com/phitall/30min"
             target="_blank" rel="noopener noreferrer">
            Gespräch buchen
            <Icon name="arrow_forward" style={{ fontSize: 14 }} />
          </a>
          <button className="menu-btn" onClick={onOpenMenu} aria-label="Menü öffnen">
            <Icon name="menu" />
          </button>
        </div>
      </div>

      <div className="subheader">
        <div className="crumb">
          <span className="ix">{STOPS[index].num} / 06</span>
          <span className="ttl">{STOPS[index].short}</span>
        </div>
        <div className="progress-wrap" aria-label="Tour‑Fortschritt">
          <div className="progress" role="progressbar" aria-valuemin="1" aria-valuemax="6" aria-valuenow={index + 1}>
            {STOPS.map((s, i) => {
              const cls = i < index ? 'done' : i === index ? 'current' : '';
              return (
                <button key={s.id}
                        className={`seg ${cls}`}
                        onClick={() => onJump(i)}
                        aria-label={`Stop ${s.num}: ${s.short}`}
                        aria-current={i === index ? 'true' : undefined} />
              );
            })}
          </div>
        </div>
        <button className="overview-btn" onClick={onOpenOverview} aria-label="Übersicht aller Stationen öffnen">
          <Icon name="grid_view" />
          <span>Übersicht</span>
        </button>
      </div>
    </header>
  );
}

// ---------- Botbar ----------
function Botbar({ index, theme, onPrev, onNext, onOpenOverview }) {
  const isLast = index === STOPS.length - 1;
  return (
    <nav className={`botbar ${theme}`} aria-label="Tour‑Navigation">
      <div>
        {index > 0 && (
          <button className="nav-link back" onClick={onPrev} aria-label="Vorheriger Stop">
            <Icon name="arrow_back" />
            <span>Zurück</span>
          </button>
        )}
      </div>
      <div className="stop-counter-pill" aria-hidden="true">
        <span className="ring" />
        {String(index + 1).padStart(2, '0')} / {String(STOPS.length).padStart(2, '0')}
      </div>
      <button className="nav-link fwd"
              onClick={isLast ? onOpenOverview : onNext}
              aria-label={isLast ? 'Übersicht ansehen' : 'Nächster Stop'}>
        <span>{isLast ? 'Übersicht' : 'Weiter'}</span>
        <Icon name="arrow_forward" />
      </button>
    </nav>
  );
}

// ---------- Image card placeholder ----------
function ImageCard({ light, accent, title, sub, status, image, focus }) {
  return (
    <div className={`img-card ${light ? 'light' : ''} ${image ? 'has-image' : ''}`} aria-hidden="true">
      <div className="placeholder" style={image ? { backgroundImage: `url('${image}')`, backgroundSize: 'cover', backgroundPosition: focus || 'center' } : undefined} />
      <div className="meta">
        {accent && <div className="accent" />}
        <h4>{title}</h4>
        <p>{sub} {status && <span className="status">{status}</span>}</p>
      </div>
    </div>
  );
}

// ---------- Stop 01 ----------
function Stop1() {
  return (
    <div className="stop-inner s1">
      <div className="deco-num" aria-hidden="true">01</div>
      <div className="split">
        <div>
          <div className="label overline">Stop 01 / 06 · Das Problem</div>
          <h1>
            Sie nutzen KI? Dann haben Sie ein <span className="em">Datenschutz‑Problem.</span>
          </h1>
          <p className="lede">
            Cloud‑KIs wie ChatGPT, Copilot oder Gemini verarbeiten Ihre Eingaben auf Servern in den USA.
            Für Berufsgeheimnisträger und Unternehmen entstehen kritische rechtliche Grauzonen,
            die den Kern Ihrer professionellen Haftung berühren.
          </p>
          <div className="pill-row">
            <span className="pill"><Icon name="lock" /> §203 StGB</span>
            <span className="pill"><Icon name="warning" /> DSGVO Drittstaaten‑Risiko</span>
            <span className="pill"><Icon name="assignment_ind" /> Berufsrechtliche Pflicht</span>
          </div>
        </div>
        <div>
          <ImageCard
            accent
            title="Risiko‑Analyse"
            sub="Status der Datenverarbeitung:"
            status="Ungesichert"
          />
        </div>
      </div>
    </div>
  );
}

// ---------- Stop 02 ----------
function Stop2() {
  const cards = [
    { ic: 'gavel', t: '§203 StGB',
      d: 'Verletzung von Privatgeheimnissen kann mit Freiheitsstrafe bis zu einem Jahr oder Geldstrafe geahndet werden.',
      tag: 'Strafrecht' },
    { ic: 'euro', t: 'DSGVO‑Bußgelder',
      d: 'Existenzbedrohende Sanktionen von bis zu 20 Mio. € oder 4 % des weltweiten Jahresumsatzes sind möglich.',
      tag: 'Datenschutz' },
    { ic: 'badge', t: 'Berufsrecht',
      d: 'Der Entzug der Zulassung ist die ultimative Konsequenz bei schwerwiegenden Verstößen gegen die Verschwiegenheitspflicht.',
      tag: 'Zulassung' },
  ];
  return (
    <div className="stop-inner s2">
      <div className="deco-num" aria-hidden="true">02</div>
      <div className="head">
        <div className="label overline">Stop 02 / 06 · Das Risiko</div>
        <h2>Was auf dem Spiel steht.</h2>
        <p className="lede">
          §203 StGB ist kein theoretisches Konstrukt. Er bildet das Fundament des Vertrauensverhältnisses
          zwischen Mandant und Berater. Ein Bruch hat weitreichende Folgen, die weit über finanziellen Schaden hinausgehen.
        </p>
      </div>
      <div className="cards">
        {cards.map((c) => (
          <div key={c.t} className="risk-card">
            <div className="ic"><Icon name={c.ic} /></div>
            <h3>{c.t}</h3>
            <p>{c.d}</p>
            <div className="tag">{c.tag}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ---------- Stop 03 ----------
function Stop3({ onNext }) {
  return (
    <div className="stop-inner s3">
      <div className="deco-num" aria-hidden="true">03</div>
      <div className="split">
        <div>
          <div className="label overline">Stop 03 / 06 · Die Lösung</div>
          <h2>
            Es gibt einen Weg. KI und Compliance – <span className="em">kein Widerspruch.</span>
          </h2>
          <p className="lede">
            Wenn die KI nicht in die Cloud geht, sondern zu Ihnen kommt, lösen sich die regulatorischen
            Fesseln auf. Die Wende beginnt dort, wo Datenhoheit zum Standard wird.
          </p>
          <div className="quote-box">
            <p className="q">„Lokale KI ist nicht die Zukunft. Sie ist der einzige Weg für Unternehmen, die Vertrauen als Währung begreifen."</p>
            <div className="who">— Philipp Taller</div>
          </div>
          <button className="cta-inline" onClick={onNext}>
            LocKi kennenlernen
            <Icon name="arrow_forward" />
          </button>
        </div>
        <div>
          <div className="scene" aria-hidden="true">
            <div className="scene-frame" />
            <div className="scene-shield"><Icon name="verified_user" /></div>
            <div className="scene-card top-right">
              <div className="ic"><Icon name="shield" /></div>
              <div className="meta">
                <div className="lab">Status</div>
                <div className="val">Compliance Sicher</div>
              </div>
            </div>
            <div className="scene-card bot-left">
              <div className="ic"><Icon name="account_tree" /></div>
              <div className="meta">
                <div className="lab">Deployment</div>
                <div className="val">100 % On‑Premise</div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ---------- Stop 04 ----------
function Stop4() {
  const rows = [
    ['Datenspeicherung',     'bad',  'good'],
    ['§203‑Risiko',          'warn', 'good'],
    ['DSGVO',                'warn', 'good'],
    ['Sprache (lokal optimiert)', 'warn', 'good'],
    ['Verfügbarkeit offline','bad',  'good'],
    ['Echte Datenhoheit',    'bad',  'good'],
  ];
  return (
    <div className="stop-inner s4">
      <div className="deco-num" aria-hidden="true">04</div>
      <div className="split">
        <div>
          <div className="label overline">Stop 04 / 06 · Das Produkt</div>
          <h2>Ihre KI. Ihre Daten. Ihr Haus.</h2>
          <p className="lede">
            LocKi ist eine autarke KI‑Infrastruktur, speziell für sensible Berufsgeheimnisträger entwickelt.
            Während herkömmliche Modelle Ihre Daten in externen Clouds verarbeiten, bleibt bei LocKi jedes
            Wort innerhalb Ihrer eigenen vier Wände.
          </p>
          <div className="feature-chips">
            <span className="chip"><Icon name="lock" />Lokal</span>
            <span className="chip"><Icon name="language" />Deutsch</span>
            <span className="chip"><Icon name="bolt" />Schnell</span>
            <span className="chip"><Icon name="verified" />§203‑konform</span>
          </div>
          <a className="cta-inline" href="mailto:ai@philipptaller.com">
            Infrastruktur anfragen
            <Icon name="arrow_forward" />
          </a>
        </div>
        <div className="compare" aria-label="Vergleich Public Cloud vs LocKi">
          <div className="compare-head">
            <Icon name="compare_arrows" />
            <h4>Public Cloud vs LocKi</h4>
          </div>
          <table>
            <thead>
              <tr>
                <th>Kriterium</th>
                <th>Cloud</th>
                <th className="locki">LocKi</th>
              </tr>
            </thead>
            <tbody>
              {rows.map(([label, a, b]) => (
                <tr key={label}>
                  <td className="row-label">{label}</td>
                  <td className="cell-mid"><span className={`dot ${a}`} /></td>
                  <td className="cell-mid"><span className={`dot ${b}`} /></td>
                </tr>
              ))}
            </tbody>
          </table>
          <div className="compare-foot">
            <span className="left">Status: Einsatzbereit</span>
            <span className="arrow"><Icon name="north_east" style={{ fontSize: 14 }} /></span>
          </div>
        </div>
      </div>
    </div>
  );
}

// ---------- Stop 05 ----------
function Stop5() {
  const steps = [
    { num: '01', ic: 'search', t: 'Analyse',
      d: 'Ein intensives 45‑Minuten‑Gespräch zur Identifikation Ihrer spezifischen Anforderungen und Engpässe.' },
    { num: '02', ic: 'build',  t: 'Setup',
      d: 'Fachgerechte Installation vor Ort, nahtlos integriert in Ihre bestehende Infrastruktur.' },
    { num: '03', ic: 'school', t: 'Schulung',
      d: 'Ihr Team lernt LocKi kennen. Praxisnahe Workshops für einen reibungslosen Übergang in den neuen Alltag.' },
  ];
  return (
    <div className="stop-inner s5">
      <div className="deco-num" aria-hidden="true">05</div>
      <div className="head">
        <div className="label overline">Stop 05 / 06 · Der Prozess</div>
        <h2>In drei Schritten zur <span className="em">souveränen</span> Organisation.</h2>
      </div>
      <div className="steps">
        {steps.map((s, i) => (
          <React.Fragment key={s.num}>
            <div className="step-card">
              <div className="ic-tile"><Icon name={s.ic} /></div>
              <div className="num">{s.num}</div>
              <h3>{s.t}</h3>
              <p>{s.d}</p>
            </div>
            {i < steps.length - 1 && (
              <div className="arrow-link" aria-hidden="true">
                <Icon name="arrow_forward" style={{ fontSize: 22 }} />
              </div>
            )}
          </React.Fragment>
        ))}
      </div>
      <div className="cta-row">
        <a className="cta-inline"
           href="https://cal.philipptaller.com/phitall/30min"
           target="_blank" rel="noopener noreferrer">
          Beratungsgespräch vereinbaren
          <Icon name="arrow_forward" />
        </a>
      </div>
    </div>
  );
}

// ---------- Stop 06 ----------
function Stop6() {
  const [open, setOpen] = useState(true);
  const [team, setTeam] = useState(10);
  const [hours, setHours] = useState(4);
  const result = team * hours * 180 * 48;
  const fmt = result.toLocaleString('de-DE');

  return (
    <div className="stop-inner s6">
      <div className="deco-num" aria-hidden="true">06</div>
      <div className="split">
        <div>
          <div className="label overline">Stop 06 / 06 · Jetzt starten</div>
          <h2>Bereit für rechtssichere KI?</h2>
          <p className="lede">
            30 Minuten. Kostenlos. Kein Verkaufsgespräch. Wir analysieren Ihre aktuelle Situation
            und zeigen Ihnen den direkten Weg zur rechtssicheren Implementierung.
          </p>
          <div className="cta-stack">
            <a className="cta-primary"
               href="https://cal.philipptaller.com/phitall/30min"
               target="_blank" rel="noopener noreferrer">
              Kostenloses Strategiegespräch buchen
              <Icon name="arrow_forward" />
            </a>
            <a className="cta-secondary" href="mailto:ai@philipptaller.com">
              Oder erst eine Frage stellen <Icon name="arrow_forward" />
            </a>
          </div>
        </div>
        <div>
          <ImageCard
            light accent
            image="assets/philipp-portrait.png"
            focus="50% 45%"
            title="Ihr nächster Schritt"
            sub="Format:"
            status="30 Min · per Video"
          />
        </div>
      </div>

      <div className="roi-bridge" aria-hidden="true">
        <div className="bridge-rule" />
        <p>Noch nicht überzeugt? Berechnen Sie Ihr Einsparpotenzial.</p>
        <div className="bridge-rule" />
      </div>

      <div className="roi">
        <button className={`roi-toggle ${open ? 'open' : ''}`}
                onClick={() => setOpen(o => !o)}
                aria-expanded={open}>
          <div className="lefts">
            <div className="ic-tile"><Icon name="calculate" /></div>
            <div className="ttl">Effizienz‑Rechner: Ihr Potenzial</div>
          </div>
          <Icon name="expand_more" className="chev" />
        </button>
        <div className={`roi-panel ${open ? 'open' : ''}`} aria-hidden={!open}>
          <div className="roi-grid">
            <div className="roi-sliders">
              <div className="slider-block">
                <label>Teamgröße</label>
                <span />
                <span className="val">{team} Personen</span>
                <input type="range" min="1" max="50" value={team}
                       onChange={(e) => setTeam(parseInt(e.target.value, 10))} />
              </div>
              <div className="slider-block">
                <label>Zeitersparnis (Std. / Woche)</label>
                <span />
                <span className="val">{hours} Stunden</span>
                <input type="range" min="1" max="20" value={hours}
                       onChange={(e) => setHours(parseInt(e.target.value, 10))} />
              </div>
            </div>
            <div className="roi-result">
              <div className="lab">Jährliches Einsparpotenzial</div>
              <div className="big">{fmt} €</div>
              <div className="foot">Basierend auf 180 € Stundensatz über 48 Wochen.</div>
            </div>
          </div>
        </div>
      </div>

      <div className="stop-footer">
        <div>© 2026 Philipp Taller Consulting</div>
        <div className="fl">
          <a href="/schulungen">Schulungen</a>
          <a href="/impressum">Impressum</a>
          <a href="/datenschutz">Datenschutz</a>
        </div>
      </div>
    </div>
  );
}

// ---------- Overview ----------
function Overview({ open, current, onClose, onJump }) {
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open, onClose]);

  return (
    <div className={`overlay ${open ? 'open' : ''}`} role="dialog" aria-modal="true" aria-label="Übersicht aller Stops">
      <div className="overlay-inner">
        <div className="overlay-head">
          <div className="overlay-title">
            Alle Stationen <span className="accent">– die Tour im Überblick</span>
          </div>
          <button className="close-btn" onClick={onClose} aria-label="Übersicht schließen">
            <Icon name="close" style={{ fontSize: 18 }} />
          </button>
        </div>
        <div className="overlay-grid">
          {STOPS.map((s, i) => (
            <button key={s.id}
                    className={`tile ${i === current ? 'active' : ''}`}
                    onClick={() => onJump(i)}>
              <div className="num">{s.num} — {s.short}</div>
              <div className="ttl">{s.tag}</div>
              <div className="desc">{s.desc}</div>
              {i === current && <div className="here">← Du bist hier</div>}
            </button>
          ))}
        </div>
        <div className="overlay-pages">
          <a href="/schulungen"><Icon name="menu_book" />Schulungsangebote</a>
          <a href="/impressum"><Icon name="gavel" />Impressum</a>
          <a href="/datenschutz"><Icon name="lock" />Datenschutzerklärung</a>
        </div>
      </div>
    </div>
  );
}

// ---------- Mobile menu ----------
function MobileMenu({ open, onClose, onJump }) {
  return (
    <div className={`mobile-menu ${open ? 'open' : ''}`} role="dialog" aria-modal="true">
      <button className="close" onClick={onClose} aria-label="Menü schließen">
        <Icon name="close" />
      </button>
      <a href="#" onClick={(e) => { e.preventDefault(); onJump(0); onClose(); }}>
        Tour starten <Icon name="arrow_forward" style={{ fontSize: 18 }} />
      </a>
      <a href="https://cal.philipptaller.com/phitall/30min" target="_blank" rel="noopener noreferrer">
        Gespräch buchen <Icon name="arrow_forward" style={{ fontSize: 18 }} />
      </a>
      <a href="mailto:ai@philipptaller.com">
        Schreiben <Icon name="mail" style={{ fontSize: 18 }} />
      </a>
      <a href="/schulungen">Schulungen <Icon name="open_in_new" style={{ fontSize: 16 }} /></a>
      <a href="/impressum">Impressum</a>
      <a href="/datenschutz">Datenschutz</a>
    </div>
  );
}

// ---------- Stop body ----------
function StopBody({ index, onNext }) {
  switch (index) {
    case 0: return <Stop1 />;
    case 1: return <Stop2 />;
    case 2: return <Stop3 onNext={onNext} />;
    case 3: return <Stop4 />;
    case 4: return <Stop5 />;
    case 5: return <Stop6 />;
  }
}
const stopBg = (i) => i <= 1 ? 'var(--anthrazit)' : 'var(--warm-white)';

function App() {
  const [index, setIndex] = useState(0);
  const [direction, setDirection] = useState('forward');
  const [overlayOpen, setOverlayOpen] = useState(false);
  const [menuOpen, setMenuOpen] = useState(false);
  const [prevIndex, setPrevIndex] = useState(null);
  const touchStart = useRef(null);

  const goTo = useCallback((next) => {
    setIndex((cur) => {
      if (next === cur) return cur;
      setDirection(next > cur ? 'forward' : 'back');
      setPrevIndex(cur);
      window.setTimeout(() => setPrevIndex(null), 380);
      return next;
    });
  }, []);

  const next = useCallback(() => { if (index < STOPS.length - 1) goTo(index + 1); }, [index, goTo]);
  const prev = useCallback(() => { if (index > 0) goTo(index - 1); }, [index, goTo]);

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

  useEffect(() => {
    let lastWheel = 0;
    const onWheel = (e) => {
      if (overlayOpen || menuOpen) return;
      const now = Date.now();
      if (now - lastWheel < 700) return;
      lastWheel = now;
      if (e.deltaY > 0) next();
      else if (e.deltaY < 0) prev();
    };
    window.addEventListener('wheel', onWheel, { passive: true });
    return () => window.removeEventListener('wheel', onWheel);
  }, [next, prev, overlayOpen, menuOpen]);

  useEffect(() => {
    const onStart = (e) => { touchStart.current = { x: e.touches[0].clientX, y: e.touches[0].clientY }; };
    const onEnd = (e) => {
      if (touchStart.current == null) return;
      const dx = e.changedTouches[0].clientX - touchStart.current.x;
      const dy = e.changedTouches[0].clientY - touchStart.current.y;
      touchStart.current = null;
      // Only navigate if horizontal swipe clearly dominates over vertical scroll
      if (Math.abs(dx) > 50 && Math.abs(dx) > Math.abs(dy) * 1.5) {
        if (dx < 0) next(); else prev();
      }
    };
    window.addEventListener('touchstart', onStart, { passive: true });
    window.addEventListener('touchend', onEnd, { passive: true });
    return () => {
      window.removeEventListener('touchstart', onStart);
      window.removeEventListener('touchend', onEnd);
    };
  }, [next, prev]);

  useEffect(() => {
    const saved = parseInt(localStorage.getItem('pt_tour_idx') || '0', 10);
    if (!isNaN(saved) && saved >= 0 && saved < STOPS.length) setIndex(saved);
  }, []);
  useEffect(() => { localStorage.setItem('pt_tour_idx', String(index)); }, [index]);

  const theme = themeOf(index);
  const bg = stopBg(index);

  return (
    <div data-screen-label={STOPS[index].num + ' ' + STOPS[index].short}
         style={{
           height: '100dvh', width: '100vw', position: 'relative',
           background: bg, transition: 'background-color 500ms ease', overflow: 'hidden'
         }}>
      <Header index={index} theme={theme}
              onOpenOverview={() => setOverlayOpen(true)}
              onJump={goTo}
              onOpenMenu={() => setMenuOpen(true)} />

      {prevIndex !== null && (
        <div key={`prev-${prevIndex}`}
             className={`stop s${prevIndex + 1}`}
             style={{
               opacity: 0,
               transform: direction === 'back' ? 'translateX(20px)' : 'translateX(-20px)',
               pointerEvents: 'none'
             }}
             aria-hidden="true">
          <StopBody index={prevIndex} />
        </div>
      )}

      <div key={`cur-${index}`}
           className={`stop s${index + 1} active`}
           style={{
             animation: direction === 'back'
               ? 'slideInBack 360ms ease-out'
               : 'slideInFwd 360ms ease-out'
           }}
           role="main">
        <StopBody index={index} onNext={next} />
      </div>

      <style>{`
        @keyframes slideInFwd {
          from { opacity: 0; transform: translateX(20px); }
          to   { opacity: 1; transform: translateX(0); }
        }
        @keyframes slideInBack {
          from { opacity: 0; transform: translateX(-20px); }
          to   { opacity: 1; transform: translateX(0); }
        }
      `}</style>

      <Botbar index={index} theme={theme}
              onPrev={prev} onNext={next}
              onOpenOverview={() => setOverlayOpen(true)} />

      <Overview open={overlayOpen}
                current={index}
                onClose={() => setOverlayOpen(false)}
                onJump={(i) => { goTo(i); setOverlayOpen(false); }} />

      <MobileMenu open={menuOpen}
                  onClose={() => setMenuOpen(false)}
                  onJump={goTo} />
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
