/* DoraVPN — Refonte v2
   On garde le hero alpin (signature) + manifesto + passport + pricing,
   et on ajoute 5 sections inspirées des meilleurs concurrents :
   1. Trust strip (audit / juridiction / no-logs)
   2. How it works — diagramme avant/après
   3. Threat model — honnête (contre quoi on protège / pas)
   4. Network — carte + serveurs
   5. Comparison — DoraVPN vs marché
   6. Device mockup — app WireGuard
   7. FAQ accordéon
*/
const { useState, useEffect, useRef } = React;

const LIGHT_TWEAKS = /*EDITMODE-BEGIN*/{
  "season": "auto",
  "showBirds": true,
  "showFlag": true
}/*EDITMODE-END*/;

const SEASONS = {
  dawn:   { name:'Aube', skyTop:'#fbc78b', skyMid:'#f4d9b8', skyBot:'#d9d5e0', lkTop:'#a5b8cc', lkBot:'#5e7895', mtFar:'#c6b3d2', mtMid:'#84759f', mtNear:'#5a6a52', celest:'radial-gradient(circle at 38% 38%, #fff6e2, #ffd49a 38%, #ffae6a 62%, #e98448 88%)', celestGlow:'rgba(255,170,110,.55)', sunLeft:'62%', sunTop:'30%', stars:0, haze:0.65 },
  noon:   { name:'Plein jour', skyTop:'#7cc7e8', skyMid:'#b6dceb', skyBot:'#d8eaf2', lkTop:'#7eb8ce', lkBot:'#3d6a8e', mtFar:'#b9b3d4', mtMid:'#6e7eab', mtNear:'#4e7050', celest:'radial-gradient(circle at 38% 38%, #fffef0, #fff3b0 38%, #ffd96a 62%, #f3b03c 88%)', celestGlow:'rgba(255,230,140,.55)', sunLeft:'58%', sunTop:'16%', stars:0, haze:0.55 },
  golden: { name:'Heure dorée', skyTop:'#fbb060', skyMid:'#f7c89c', skyBot:'#d8c6c4', lkTop:'#a08aa0', lkBot:'#5e617e', mtFar:'#d2a9a6', mtMid:'#8e6f8d', mtNear:'#6a604a', celest:'radial-gradient(circle at 38% 38%, #ffe8b8, #ffc068 38%, #f59048 62%, #d76235 88%)', celestGlow:'rgba(255,170,90,.55)', sunLeft:'66%', sunTop:'38%', stars:0, haze:0.75 },
  dusk:   { name:'Crépuscule', skyTop:'#d77a86', skyMid:'#a98aa6', skyBot:'#5d6691', lkTop:'#5c6188', lkBot:'#2a3458', mtFar:'#8a8aa8', mtMid:'#535784', mtNear:'#39435a', celest:'radial-gradient(circle at 38% 38%, #ffd1a0, #f5916e 38%, #c25064 62%, #6b2c5a 88%)', celestGlow:'rgba(220,100,110,.45)', sunLeft:'70%', sunTop:'48%', stars:0.35, haze:0.4, heroInk:'#fbf6ec', heroInkDim:'#e6dcd4', heroInkMute:'#b8b0c0' },
  night:  { name:'Nuit', skyTop:'#0e1a36', skyMid:'#1a2750', skyBot:'#293a6e', lkTop:'#1c2c4a', lkBot:'#0b1428', mtFar:'#3a3f5c', mtMid:'#252b48', mtNear:'#1a1f33', celest:'radial-gradient(circle at 35% 35%, #fefcf2, #e8e4d2 60%, #b8b4a0 90%)', celestGlow:'rgba(220,220,200,.45)', sunLeft:'24%', sunTop:'18%', stars:1, haze:0.1, heroInk:'#fbf9f3', heroInkDim:'#c8cee0', heroInkMute:'#8a92a8' },
};

const pickSeason = (h) => {
  if (h >= 5 && h < 8) return 'dawn';
  if (h >= 8 && h < 17) return 'noon';
  if (h >= 17 && h < 19) return 'golden';
  if (h >= 19 && h < 21) return 'dusk';
  return 'night';
};

/* ─── Reveal helper ─── */
const useInView = (opts = {}) => {
  const ref = useRef(null);
  const [v, setV] = useState(false);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setV(true); io.disconnect(); }
    }, { threshold: 0.12, rootMargin: '0px 0px -8% 0px', ...opts });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return [ref, v];
};
const Reveal = ({ as:Tag='div', delay=0, variant='rv', className='', style, children, ...rest }) => {
  const [ref, inView] = useInView();
  return (
    <Tag ref={ref}
      className={`${variant} ${inView?'in':''} ${className}`.trim()}
      style={{ transitionDelay:`${delay}ms`, ...(style||{}) }}
      {...rest}>{children}</Tag>
  );
};

const Eyebrow = ({ index, children }) => (
  <div className="eyebrow">
    <span className="sq"/>
    {index && <span>§ {index}</span>}
    <span>{children}</span>
  </div>
);

/* ═══════════════════════════ TOP RIBBON (static, not sticky) ═══════════════════════════ */
const TopRibbon = () => {
  const today = new Date().toISOString().slice(0,10);
  return (
    <div className="top-ribbon" role="status" aria-label="Statut tunnel DoraVPN">
      <div className="top-ribbon-inner">
        <div className="tr-cell">
          <span className="tr-dot"/>
          <span className="tr-v">TUNNEL ACTIF</span>
        </div>
        <div className="tr-cell">
          <span className="tr-dot tr-dot-ai"/>
          <span className="tr-v">SENTINELLE IA · ARMÉE</span>
        </div>
        <div className="tr-cell">
          <span className="tr-k">IP sortie</span>
          <span className="tr-v ip">185.246.188.42</span>
        </div>
        <div className="tr-cell hide-sm">
          <span className="tr-k">Sortie</span>
          <span className="tr-v">GVA-04 · Genève</span>
        </div>
        <div className="tr-cell hide-sm">
          <span className="tr-k">Protocole</span>
          <span className="tr-v">WireGuard · AES-256</span>
        </div>
        <div className="tr-cell hide-sm">
          <span className="tr-k">Menaces 24h</span>
          <span className="tr-v">1 247 bloquées</span>
        </div>
        <div className="tr-cell grow hide-sm">
          <span className="tr-k">Log</span>
          <span className="tr-marquee">
            <span>{`[${today} 21:42:07] handshake OK · peer=gva-04 · cipher=chacha20-poly1305 · MTU=1420 · no_logs=true · audit=ISAE-3402 · jurisdiction=CH`}</span>
            <span>{`[${today} 21:42:07] handshake OK · peer=gva-04 · cipher=chacha20-poly1305 · MTU=1420 · no_logs=true · audit=ISAE-3402 · jurisdiction=CH`}</span>
          </span>
        </div>
      </div>
    </div>
  );
};

/* ═══════════════════════════ TOPBAR ═══════════════════════════ */
const Topbar = () => (
  <header className="topbar">
    <div className="topbar-inner">
      <a className="brand">
        <svg width="22" height="22" viewBox="0 0 22 22"><rect width="22" height="22" fill="var(--accent)"/><rect x="9.5" y="4" width="3" height="14" fill="#fff"/><rect x="4" y="9.5" width="14" height="3" fill="#fff"/></svg>
        <span style={{fontWeight:600,letterSpacing:'-0.01em'}}>DoraVPN</span>
        <span className="mono uc" style={{fontSize:10,color:'var(--ink-mute)',marginLeft:6,paddingLeft:10,borderLeft:'1px solid var(--line-2)'}}>GVA · CH</span>
      </a>
      <nav className="nav">
        <a className="active">Accueil</a>
        <a>Réseau</a>
        <a>Tarifs</a>
        <a>FAQ</a>
        <a>À propos</a>
      </nav>
      <div className="topbar-cta">
        <button className="btn btn-ghost" style={{padding:'8px 14px',fontSize:13}}>Se connecter</button>
        <button className="btn btn-ink" style={{padding:'9px 16px',fontSize:13}}>Mon compte →</button>
      </div>
    </div>
  </header>
);

/* ═══════════════════════════ TRUST STRIP (nouveau) ═══════════════════════════ */
const TrustStrip = () => (
  <div className="trust-strip">
    <div className="trust-inner">
      <div className="trust-cell">
        <span className="k">Juridiction</span>
        <span className="v">🇨🇭 Suisse <em>— hors 14-Eyes</em></span>
      </div>
      <div className="trust-cell">
        <span className="k">Données stockées</span>
        <span className="v"><em>Aucune.</em> 0 log.</span>
      </div>
      <div className="trust-cell">
        <span className="k">Garde IA</span>
        <span className="v">Souveraine <em>— on-premise</em></span>
      </div>
      <div className="trust-cell">
        <span className="k">Tarif</span>
        <span className="v">5€/mois <em>— unique</em></span>
      </div>
    </div>
  </div>
);

/* ═══════════════════════════ PILLARS ═══════════════════════════ */
const Pillars = () => (
  <section className="section">
    <Reveal><Eyebrow index="01">Cinq principes — non négociables</Eyebrow></Reveal>
    <Reveal delay={100}>
      <h2 className="display" style={{maxWidth:880,marginBottom:36}}>
        On a retiré tout ce qu'un VPN<br/><span className="it">ne devrait jamais avoir.</span>
        <br/>Et ajouté ce qu'il aurait <span className="it accent">toujours dû faire.</span>
      </h2>
    </Reveal>
    <div className="pillars pillars-5">
      {[
        ['Aucun compte','Un identifiant à 16 chiffres remplace email et mot de passe. Rien à pirater, rien à oublier.','01', false],
        ['Aucun log','Ni trafic, ni connexion, ni IP source. Réquisition judiciaire : rien à fournir.','02', false],
        ['WireGuard uniquement','Le protocole le plus rapide, le plus simple, le plus auditable. Pas de legacy.','03', false],
        ['Paiements anonymes','Espèces, coupon papier, carte cadeau Amazon. Pas de banque, pas de KYC.','04', false],
        ['Garde IA souverain','Modèle en open-weights, isolé, sans accès internet. Il regarde dehors — jamais vos données.','05', true],
      ].map(([t,d,n,ai],i) => (
        <Reveal key={n} delay={i*90} variant="rv-up" className={`pillar ${ai ? 'pillar-ai' : ''}`}>
          <span className="num">/{n}{ai && <span className="num-new">nouveau</span>}</span>
          <div>
            <h3>{t}</h3>
            <p>{d}</p>
          </div>
        </Reveal>
      ))}
    </div>
  </section>
);

/* ═══════════════════════════ HOW IT WORKS — Animation flux de données ═══════════════════════════ */
const HOW_PACKETS = [
  { tag:'BANQUE',       text:'ubs.ch/auth',           hex:'9F4A·2B1C' },
  { tag:'SANTÉ',        text:'« dépression »',         hex:'7E21·A4F9' },
  { tag:'INTIME',       text:'Tinder · session',      hex:'C1B7·49AE' },
  { tag:'OPINION',      text:'amnesty.ch/petitions',  hex:'04F3·B8E7' },
  { tag:'JURIDIQUE',    text:'« divorce avocat »',    hex:'8A02·67DF' },
  { tag:'LOCALISATION', text:'GPS · Plainpalais',     hex:'D5E8·B32A' },
];
const HOW_DURATION = 28; // seconds — slower, more readable

/* ═══════════════════════════ AI SENTINEL — Garde IA souverain ═══════════════════════════ */
// Live feed is intentionally English-only — gives the SOC terminal a
// neutral ops-room feel (sysadmins read English logs regardless of locale).
const AI_EVENTS = [
  { src:'dark-web', msg:'BreachForums scan · 0 client leak detected',                stat:'ok',  klass:'ok'  },
  { src:'config',   msg:'Hardening audit · 412 nodes · fingerprint compliant',       stat:'ok',  klass:'ok'  },
  { src:'threat',   msg:'SYN flood blocked · 185.2.1.4 — CN state actor',            stat:'blk', klass:'blk' },
  { src:'enrich',   msg:'Adversary profiling · ASN 8048 reclassified hostile',       stat:'inf', klass:'inf' },
  { src:'response', msg:'Auto-isolation FR-PAR-03 · CPU anomaly detected',           stat:'act', klass:'act' },
  { src:'dark-web', msg:'Combo-list removed · 2 forums · client data purged',        stat:'ok',  klass:'ok'  },
  { src:'threat',   msg:'State SSH probe stopped · ASN 4134 blacklist 24h',          stat:'blk', klass:'blk' },
  { src:'config',   msg:'WireGuard key rotation · 412/412 nodes · 24h cycle',        stat:'ok',  klass:'ok'  },
  { src:'scenario', msg:'Volumetric DDoS simulation · 99.4% resilience',             stat:'inf', klass:'inf' },
  { src:'threat',   msg:'Hotel network MITM attempt · client alert sent',            stat:'blk', klass:'blk' },
  { src:'response', msg:'CVE-2026-0421 patch deployed · 412 nodes · 47s',            stat:'act', klass:'act' },
  { src:'enrich',   msg:'Cross-ref 14 OSINT sources · actor identified',             stat:'inf', klass:'inf' },
  { src:'dark-web', msg:'TOR marketplace watch · 0 DoraVPN mention',                 stat:'ok',  klass:'ok'  },
  { src:'config',   msg:'Drift detected GVA-02 · auto-rebase · state healthy',       stat:'act', klass:'act' },
  { src:'threat',   msg:'Port 51820 scan · 47 repeat IPs · network ban',             stat:'blk', klass:'blk' },
];

const pad = (n) => String(n).padStart(2, '0');
const fmtTs = (d) => `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;

const AiSentinel = () => {
  // Live feed — un nouveau log toutes les ~2.2s, on garde les 6 derniers.
  const [feed, setFeed] = React.useState(() => {
    const now = new Date();
    return [0, 1, 2, 3, 4, 5].map((i) => {
      const ev = AI_EVENTS[i % AI_EVENTS.length];
      const t = new Date(now.getTime() - (5 - i) * 2200);
      return { ...ev, id: i, ts: fmtTs(t) };
    });
  });
  const idx = React.useRef(6);
  React.useEffect(() => {
    const t = setInterval(() => {
      const ev = AI_EVENTS[idx.current % AI_EVENTS.length];
      const id = idx.current++;
      const ts = fmtTs(new Date());
      setFeed((prev) => [...prev.slice(-5), { ...ev, id, ts }]);
    }, 2200);
    return () => clearInterval(t);
  }, []);

  // Stat counters that wiggle slightly to feel alive
  const [tick, setTick] = React.useState(0);
  React.useEffect(() => {
    const t = setInterval(() => setTick((x) => x + 1), 3400);
    return () => clearInterval(t);
  }, []);
  const wobble = (base) => base + (tick % 7);

  return (
    <Reveal variant="rv-up" delay={350} className="lane ai">
      <div className="lane-head">
        <span className="lane-tag">§ + Garde IA Sentinelle</span>
        <h3>
          La forteresse <span className="glow">veille — et elle pense.</span>
        </h3>
        <span className="lane-meta"><b>IA souveraine · CH</b>aucun autre VPN ne l'offre</span>
      </div>

      {/* Pipeline IA — de la recherche à l'action */}
      <div className="ai-pipeline" aria-label="Pipeline IA souverain">
        <div className="ai-step">
          <div className="ai-step-n">① Recherche</div>
          <h4>Veille <span className="it">dark-web & OSINT</span></h4>
          <p>Crawlers permanents sur les forums clandestins, marketplaces TOR, leak-sites étatiques.</p>
          <div className="ai-step-stat"><b>{wobble(214)}k</b> sources scrutées · 24h</div>
        </div>
        <div className="ai-step">
          <div className="ai-step-n">② Enrichissement</div>
          <h4>Corrélation <span className="it">adversaire</span></h4>
          <p>Fusion ASN, géolocalisation, signatures TTP. L'IA reconstruit le profil de l'attaquant.</p>
          <div className="ai-step-stat"><b>{wobble(48)}</b> sources fusionnées par incident</div>
        </div>
        <div className="ai-step">
          <div className="ai-step-n">③ Scénarios</div>
          <h4>Analyse <span className="it">prospective</span></h4>
          <p>Simulation continue : DDoS, MITM, demande étatique, fuite interne. L'IA répète les attaques avant qu'elles arrivent.</p>
          <div className="ai-step-stat"><b>{wobble(312)}</b> scénarios joués · semaine</div>
        </div>
        <div className="ai-step">
          <div className="ai-step-n">④ Action</div>
          <h4>Réaction <span className="it">automatique</span></h4>
          <p>Patch, isolation, rotation de clés, ban réseau — appliqués en secondes, sans intervention humaine.</p>
          <div className="ai-step-stat"><b>47 s</b> · délai médian de réponse</div>
        </div>
      </div>

      {/* Dôme — la sentinelle observe les 4 nœuds du tunnel */}
      <div className="ai-dome" aria-label="Sentinelles IA en surveillance continue">
        <div className="ai-dome-head">
          <div className="left">
            <span className="pulse-dot"></span>
            <span>DOME SENTINELLE · ACTIF</span>
          </div>
          <div className="right">
            <span>Couverture <b>412/412</b> nœuds · latence ajoutée <b>&lt;3ms</b></span>
          </div>
        </div>
        <div className="ai-sentinels">
          <div className="ai-sent">
            <div className="ai-sent-name">
              Dark-web watch
              <span className="badge">scan</span>
            </div>
            <p>Récupère les bases divulguées, identifie vos données, demande le retrait, vérifie la purge.</p>
            <div className="ai-sent-tick"><b>↓</b> 2 retraits cette semaine</div>
          </div>
          <div className="ai-sent">
            <div className="ai-sent-name">
              Config sentinel
              <span className="badge">audit</span>
            </div>
            <p>Surveille la configuration de chaque serveur 24/7. Tout drift = quarantaine et rebase auto.</p>
            <div className="ai-sent-tick"><b>✓</b> 412 nœuds conformes</div>
          </div>
          <div className="ai-sent">
            <div className="ai-sent-name">
              Threat detect
              <span className="badge alert">live</span>
            </div>
            <p>Détecte SYN flood, MITM, scans étatiques, probes SSH. Décide en quelques secondes.</p>
            <div className="ai-sent-tick"><b>⛔</b> {wobble(1240)} attaques bloquées · 24h</div>
          </div>
          <div className="ai-sent">
            <div className="ai-sent-name">
              Auto-response
              <span className="badge">act</span>
            </div>
            <p>Isole un nœud, patche une CVE, fait tourner les clés WireGuard. Sans réveiller personne.</p>
            <div className="ai-sent-tick"><b>↻</b> rotation clés · cycle 24h</div>
          </div>
        </div>
      </div>

      {/* Terminal — flux temps réel du SOC */}
      <div className="ai-feed" aria-label="Journal en direct du Garde IA">
        <div className="ai-feed-head">
          <div className="left" style={{display:'flex',alignItems:'center',gap:14}}>
            <span className="dots">
              <span></span><span></span><span className="live"></span>
            </span>
            <span>doravpn · soc-ai · live feed</span>
          </div>
          <div className="right">tail -f /var/log/sentinel · GVA · {feed[feed.length-1]?.ts}</div>
        </div>
        <div className="ai-feed-body">
          {feed.map((e) => (
            <div className="ai-line" key={e.id}>
              <span className="ts">[{e.ts}]</span>
              <span className="src">{e.src}</span>
              <span className="msg">{e.msg}</span>
              <span className={`stat ${e.klass}`}>{e.stat}</span>
            </div>
          ))}
        </div>
      </div>

      <p className="lane-caption">
        <strong>Aucun autre VPN ne propose ça.</strong> Notre IA est <em>la nôtre</em> — entraînée, hébergée et
        opérée en Suisse, intégrée directement à nos serveurs. Elle nettoie le dark-web de vos données,
        durcit la configuration de chaque nœud, et bloque les menaces extérieures — qu'elles soient
        criminelles <em>ou étatiques</em>. Le coffre-fort a maintenant son garde du corps.
      </p>

      {/* Bandeau souveraineté */}
      <div className="ai-foot">
        <p>
          Nous <em>possédons</em> notre IA. Pas d'API OpenAI, pas de modèle US, <strong>pas de juridiction étrangère</strong> — la sentinelle reste sous loi suisse.
        </p>
        <div className="stamps">
          <span className="swiss">Hébergée GVA</span>
          <span>Modèles open-weights</span>
          <span>Audit annuel</span>
          <span>Aucun appel externe</span>
        </div>
      </div>
    </Reveal>
  );
};

const HowItWorks = () => {
  // 6 paquets, 2 pistes verticales alternées — pas de chevauchement visuel
  const stagger = (i) => -(i * HOW_DURATION / HOW_PACKETS.length).toFixed(2) + 's';
  const track   = (i) => (i % 2 === 0 ? '-20px' : '20px');

  return (
    <section className="section section-divider">
      <Reveal><Eyebrow index="02">Comment ça marche</Eyebrow></Reveal>
      <Reveal delay={100}>
        <h2 className="display" style={{maxWidth:920,marginBottom:8}}>
          Ce qu'<span className="it">on voit</span> de vous,<br/>avant et après.
        </h2>
      </Reveal>
      <Reveal delay={200}>
        <p style={{fontSize:17,color:'var(--ink-dim)',maxWidth:760,margin:'20px 0 0',lineHeight:1.55}}>
          Chaque seconde, votre appareil envoie des dizaines de paquets : santé, finances, opinions, intimité, position.
          Sans VPN, chaque maillon de la chaîne les <em className="serif" style={{fontStyle:'italic'}}>lit en clair</em>.
          Avec DoraVPN, ils traversent un tunnel chiffré — illisible pour quiconque.
          Et au-dessus du tunnel, notre <em className="serif" style={{fontStyle:'italic'}}>Garde IA souverain</em> veille en continu :
          il scrute le dark-web, durcit chaque serveur, et neutralise les menaces avant qu'elles vous atteignent.
        </p>
      </Reveal>

      <div className="how-anim">

        {/* ───── SANS VPN ───── */}
        <Reveal variant="rv-up" delay={150} className="lane bad">
          <div className="lane-head">
            <span className="lane-tag">§ Sans VPN</span>
            <h3>Tout le monde regarde, <span className="accent">tout est lu.</span></h3>
            <span className="lane-meta">3 espions sur le trajet<span className="pulse"/></span>
          </div>
          <div className="lane-stage">
            <div className="lane-wire"/>
            <div className="lane-nodes">
              <div className="ln-node" data-pos="1">
                <div className="ln-dot">①</div>
                <span className="ln-lab">Vous<small>84.226.18.42</small></span>
              </div>
              <div className="ln-node spy" data-pos="2">
                <div className="ln-dot">②</div>
                <span className="ln-lab">FAI<small>voit le domaine</small></span>
              </div>
              <div className="ln-node spy" data-pos="3">
                <div className="ln-dot">③</div>
                <span className="ln-lab">DNS public<small>voit la requête</small></span>
              </div>
              <div className="ln-node spy" data-pos="4">
                <div className="ln-dot">④</div>
                <span className="ln-lab">Site visité<small>voit votre IP</small></span>
              </div>
            </div>
            <div className="packets">
              {HOW_PACKETS.map((p, i) => (
                <div key={i} className="packet bad"
                     style={{ '--dur': `${HOW_DURATION}s`, '--delay': stagger(i), '--track': track(i) }}>
                  <span className="ptag">{p.tag}</span>
                  <span className="ptxt">{p.text}</span>
                </div>
              ))}
            </div>
          </div>
          <p className="lane-caption">
            Le FAI journalise les domaines, le résolveur DNS l'historique des requêtes, le site enregistre l'IP source.
            La vie privée <em>n'existe simplement pas</em> — vous ignorez qui regarde, quand, et combien de temps c'est conservé.
          </p>
        </Reveal>

        {/* ───── AVEC DORAVPN ───── */}
        <Reveal variant="rv-up" delay={250} className="lane good">
          <div className="lane-head">
            <span className="lane-tag">§ Avec DoraVPN</span>
            <h3>Le même trajet, <span className="accent">à l'abri.</span></h3>
            <span className="lane-meta"><b>WireGuard · ChaCha20</b><span className="pulse"/></span>
          </div>
          <div className="lane-stage">
            <div className="lane-wire"/>
            <div className="tunnel">
              <div className="tunnel-inner"/>
              <div className="tunnel-aura" aria-hidden="true">
                <span className="aura-ring"/>
                <span className="aura-ring"/>
                <span className="aura-ring"/>
              </div>
              <div className="tunnel-aiwatch" aria-label="Garde IA — supervision du tunnel chiffré">
                <span className="taw-badge">
                  <span className="taw-dot"/>
                  <span className="taw-name">IA · Cipher Guard</span>
                  <span className="taw-stat">ChaCha20 · sain</span>
                </span>
              </div>
              <span className="tunnel-label">DoraVPN</span>
              <span className="tunnel-end">0 log · GVA</span>
            </div>
            <div className="lane-nodes">
              <div className="ln-node" data-pos="1">
                <div className="ln-dot">①</div>
                <span className="ln-lab">Vous<small>chiffré client</small></span>
              </div>
              <div className="ln-node" data-pos="2">
                <div className="ln-dot">②</div>
                <span className="ln-lab">FAI<small>ne voit que du bruit</small></span>
              </div>
              <div className="ln-node" data-pos="3">
                <div className="ln-dot">③</div>
                <span className="ln-lab">Serveur Dora<small>déchiffre · oublie</small></span>
              </div>
              <div className="ln-node" data-pos="4">
                <div className="ln-dot">④</div>
                <span className="ln-lab">Site visité<small>voit 185.193.42.7</small></span>
              </div>
            </div>
            <div className="packets">
              {HOW_PACKETS.map((p, i) => (
                <div key={i} className="packet good"
                     style={{ '--dur': `${HOW_DURATION}s`, '--delay': stagger(i), '--track': track(i) }}>
                  <span className="phase phase-plain">
                    <span className="ptag">{p.tag}</span>
                    <span className="ptxt">{p.text}</span>
                  </span>
                  <span className="phase phase-cipher">
                    <span className="ptag">CHIFFRÉ</span>
                    <span className="ptxt">0x{p.hex}</span>
                  </span>
                  <span className="phase phase-clean">
                    <span className="ptag">VIA GVA</span>
                    <span className="ptxt">{p.text}</span>
                  </span>
                </div>
              ))}
            </div>
          </div>
          <p className="lane-caption">
            <strong>Le paquet entre en clair, sort en clair</strong> — mais entre les deux il traverse un segment
            où plus personne ne peut le lire. Le FAI voit passer un flux binaire opaque, le serveur déchiffre
            puis <em>oublie</em>. Le site visité ne voit qu'une IP suisse partagée.
          </p>
        </Reveal>

        {/* ───── + GARDE IA SENTINELLE ───── */}
        <AiSentinel />

        {/* ───── Legend ───── */}
        <div className="how-legend">
          <span className="how-legend-label">Types de données suivis</span>
          {HOW_PACKETS.map(p => <span key={p.tag} className="chip">{p.tag}</span>)}
        </div>
      </div>
    </section>
  );
};

/* ═══════════════════════════ THREAT MODEL (NOUVEAU) ═══════════════════════════ */
const ThreatModel = () => (
  <section style={{background:'var(--paper)', borderTop:'1px solid var(--line)', borderBottom:'1px solid var(--line)'}}>
    <div className="section" style={{paddingTop:120, paddingBottom:120}}>
      <Reveal><Eyebrow index="03">Modèle de menace</Eyebrow></Reveal>
      <Reveal delay={100}>
        <h2 className="display" style={{maxWidth:980,marginBottom:8}}>
          Ce qu'un VPN <span className="it accent">fait.</span><br/>Et ce qu'il <span className="it">ne fera jamais.</span>
        </h2>
      </Reveal>
      <Reveal delay={200}>
        <p style={{fontSize:17,color:'var(--ink-dim)',maxWidth:760,margin:'20px 0 0',lineHeight:1.55}}>
          Le marché vous vend l'invisibilité. Nous, on vend un outil de précision, contre des menaces de précision.
          Voici la frontière exacte — celle que les autres camouflent derrière un slogan.
        </p>
      </Reveal>
      <div className="threat-grid">
        <Reveal variant="rv-up" delay={150} className="threat-col yes">
          <div className="heading">
            <span className="heading-num">§ Ce que DoraVPN neutralise</span>
          </div>
          <ul>
            <li><span className="glyph">✓</span><div><strong>Votre FAI ne voit plus rien</strong><span className="desc">Swisscom, Salt, Sunrise ne peuvent plus profiler votre trafic ni le revendre.</span></div></li>
            <li><span className="glyph">✓</span><div><strong>Votre IP réelle est masquée</strong><span className="desc">Les sites visités voient une IP partagée à Genève — pas la vôtre.</span></div></li>
            <li><span className="glyph">✓</span><div><strong>Wi-Fi publics neutralisés</strong><span className="desc">Café, aéroport, hôtel : aucune interception possible, tout est chiffré.</span></div></li>
            <li><span className="glyph">✓</span><div><strong>Censure géographique contournée</strong><span className="desc">Streaming, presse, sites bloqués — sortie au pays de votre choix.</span></div></li>
            <li><span className="glyph">✓</span><div><strong>Surveillance de masse esquivée</strong><span className="desc">Vous devenez une cible coûteuse à profiler. La masse passe ailleurs.</span></div></li>
            <li><span className="glyph">✓</span><div><strong>DNS protégé</strong><span className="desc">Pas de fuite vers Google ou Cloudflare. Resolver intégré, dans le tunnel.</span></div></li>
          </ul>
        </Reveal>
        <Reveal variant="rv-up" delay={250} className="threat-col no">
          <div className="heading">
            <span className="heading-num">§ Ce qu'un VPN ne fera jamais</span>
          </div>
          <ul>
            <li><span className="glyph">×</span><div><strong>Vous protéger de vous-même</strong><span className="desc">Si vous vous connectez à Gmail, Google sait que vous êtes là. Le VPN n'efface pas vos comptes.</span></div></li>
            <li><span className="glyph">×</span><div><strong>Bloquer les cookies & trackers</strong><span className="desc">C'est le boulot d'un bloqueur (uBlock Origin) — pas d'un VPN.</span></div></li>
            <li><span className="glyph">×</span><div><strong>Vous rendre anonyme</strong><span className="desc">Anonymat = Tor. Un VPN, c'est de la confidentialité, deux choses différentes.</span></div></li>
            <li><span className="glyph">×</span><div><strong>Protéger d'un malware déjà installé</strong><span className="desc">Si un cheval de Troie tourne sur votre machine, il exfiltre par le tunnel comme par ailleurs.</span></div></li>
            <li><span className="glyph">×</span><div><strong>Vous mettre au-dessus des lois</strong><span className="desc">DoraVPN n'est pas un outil pour commettre des crimes. C'est un outil pour exercer un droit.</span></div></li>
            <li><span className="glyph">×</span><div><strong>Remplacer le chiffrement de bout en bout</strong><span className="desc">Signal, Tutanota, ProtonMail restent indispensables pour le contenu.</span></div></li>
          </ul>
        </Reveal>
      </div>
    </div>
  </section>
);

/* ═══════════════════════════ NETWORK MAP (RADAR POLAIRE) ═══════════════════════════ */
const NetworkMap = () => {
  // Projection azimutale équidistante centrée sur Genève.
  // Toutes les villes sont placées par bearing initial + distance grand-cercle.
  // Plus que d'une carte du monde, c'est un instrument : le hub au centre, tout
  // le monde gravite autour.
  const HUB_LAT = 46.20, HUB_LNG = 6.14;
  const R_EARTH = 6371;
  const toRad = d => d * Math.PI / 180;

  // distance grand-cercle (km) + bearing initial (radians, 0 = nord, sens horaire)
  const greatCircle = (lat, lng) => {
    const φ1 = toRad(HUB_LAT), φ2 = toRad(lat);
    const Δφ = φ2 - φ1, Δλ = toRad(lng - HUB_LNG);
    const a = Math.sin(Δφ/2)**2 + Math.cos(φ1)*Math.cos(φ2)*Math.sin(Δλ/2)**2;
    const d = 2 * R_EARTH * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    const y = Math.sin(Δλ) * Math.cos(φ2);
    const x = Math.cos(φ1)*Math.sin(φ2) - Math.sin(φ1)*Math.cos(φ2)*Math.cos(Δλ);
    const θ = Math.atan2(y, x);
    return { d, θ };
  };

  const W = 720, CX = W/2, CY = W/2, R_MAX = 308, MAX_KM = 17500;
  // échelle sqrt → étale le cluster européen sans écraser les villes lointaines
  const rOf = km => Math.sqrt(km / MAX_KM) * R_MAX;

  const raw = [
    { id:'GVA', city:'Genève',     country:'CH', lat:HUB_LAT,lng:HUB_LNG, ms:'4 ms', primary:true },
    { id:'ZRH', city:'Zürich',     country:'CH', lat:47.37, lng:8.55,    ms:'8 ms' },
    { id:'FRA', city:'Francfort',  country:'DE', lat:50.11, lng:8.68,    ms:'14 ms' },
    { id:'PAR', city:'Paris',      country:'FR', lat:48.85, lng:2.35,    ms:'18 ms' },
    { id:'AMS', city:'Amsterdam',  country:'NL', lat:52.37, lng:4.90,    ms:'22 ms' },
    { id:'LON', city:'Londres',    country:'UK', lat:51.51, lng:-0.13,   ms:'24 ms' },
    { id:'MIL', city:'Milan',      country:'IT', lat:45.46, lng:9.19,    ms:'12 ms' },
    { id:'STO', city:'Stockholm',  country:'SE', lat:59.33, lng:18.07,   ms:'34 ms' },
    { id:'MAD', city:'Madrid',     country:'ES', lat:40.42, lng:-3.70,   ms:'28 ms' },
    { id:'NYC', city:'New York',   country:'US', lat:40.71, lng:-74.01,  ms:'82 ms' },
    { id:'LAX', city:'Los Angeles',country:'US', lat:34.05, lng:-118.24, ms:'132 ms' },
    { id:'TOR', city:'Toronto',    country:'CA', lat:43.65, lng:-79.38,  ms:'94 ms' },
    { id:'TYO', city:'Tokyo',      country:'JP', lat:35.68, lng:139.65,  ms:'202 ms' },
    { id:'SYD', city:'Sydney',     country:'AU', lat:-33.87,lng:151.21,  ms:'278 ms' },
  ];

  const servers = raw.map(s => {
    const { d, θ } = greatCircle(s.lat, s.lng);
    const r = rOf(d);
    return { ...s, dist:d, θ, r, x:CX + r*Math.sin(θ), y:CY - r*Math.cos(θ) };
  });

  // Anneaux de distance — repères calibrés
  const rings = [
    { km:1000,  label:'1 000 KM' },
    { km:3000,  label:'3 000 KM' },
    { km:8000,  label:'8 000 KM' },
    { km:16000, label:'16 000 KM' },
  ];

  // Décalages de labels — hand-tuned pour résoudre les collisions :
  // FRA/ZRH/STO sur le même bearing NE, NYC/TOR superposés sur l'Atlantique,
  // LON/PAR au NW, etc. Chaque ville reçoit son offset (px) + ancrage texte.
  const labelOffsets = {
    GVA: { dx:   0, dy: -34, anchor:'middle' }, // hub
    ZRH: { dx:  12, dy:  14, anchor:'start'  }, // poussé vers le bas
    FRA: { dx:  12, dy:  -5, anchor:'start'  }, // poussé vers le haut
    STO: { dx:  12, dy:   4, anchor:'start'  }, // plus loin (r grand) → naturel
    MIL: { dx:  12, dy:  14, anchor:'start'  },
    PAR: { dx: -12, dy:  16, anchor:'end'    }, // descendu pour éviter LON
    LON: { dx: -12, dy:  -6, anchor:'end'    }, // monté pour éviter PAR
    AMS: { dx:   0, dy: -12, anchor:'middle' }, // au-dessus du pin
    MAD: { dx: -12, dy:  14, anchor:'end'    },
    NYC: { dx: -12, dy:  16, anchor:'end'    }, // descendu pour éviter TOR
    TOR: { dx: -12, dy:  -6, anchor:'end'    }, // monté pour éviter NYC
    LAX: { dx: -12, dy:   4, anchor:'end'    },
    TYO: { dx:  12, dy:   4, anchor:'start'  },
    SYD: { dx:  12, dy:   4, anchor:'start'  },
  };

  return (
    <section className="section section-divider">
      <div style={{display:'grid',gridTemplateColumns:'1fr auto',alignItems:'end',gap:32,marginBottom:8}}>
        <div>
          <Reveal><Eyebrow index="04">Le réseau</Eyebrow></Reveal>
          <Reveal delay={100}>
            <h2 className="display" style={{maxWidth:880}}>
              14 villes.<br/><span className="it">Une seule juridiction.</span>
            </h2>
          </Reveal>
        </div>
        <Reveal delay={200}>
          <div className="mono uc" style={{fontSize:11,color:'var(--ink-dim)',textAlign:'right',lineHeight:1.7}}>
            <div><span style={{display:'inline-block',width:8,height:8,background:'#5e7a4a',borderRadius:'50%',marginRight:8,verticalAlign:'middle'}}/>Statut: opérationnel</div>
            <div style={{color:'var(--ink-mute)'}}>Dernière vérif: il y a 12 s</div>
          </div>
        </Reveal>
      </div>
      <div className="network-grid">
        <Reveal delay={150} variant="rv-up" className="map-wrap">
          <svg viewBox={`-40 -40 ${W+80} ${W+80}`} preserveAspectRatio="xMidYMid meet" style={{overflow:'visible'}}>
            <defs>
              <radialGradient id="hubGlow" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0%"  stopColor="var(--accent)" stopOpacity="0.20"/>
                <stop offset="50%" stopColor="var(--accent)" stopOpacity="0.05"/>
                <stop offset="100%" stopColor="var(--accent)" stopOpacity="0"/>
              </radialGradient>
              <radialGradient id="discBg" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0%"  stopColor="var(--paper)" stopOpacity="1"/>
                <stop offset="100%" stopColor="var(--paper)" stopOpacity="0.0"/>
              </radialGradient>
            </defs>

            {/* En-tête radar (top-left) */}
            <g fontFamily="Geist Mono, monospace" fill="var(--ink-mute)" letterSpacing="0.12em">
              <text x="-24" y="-18" fontSize="9" fontWeight="600" fill="var(--ink)">RÉSEAU · 14 SORTIES</text>
              <text x="-24" y="-4"  fontSize="8" opacity="0.7">PROJ. AZIMUTALE — ⊕ GENÈVE</text>
            </g>
            {/* Échelle / légende (top-right) */}
            <g fontFamily="Geist Mono, monospace" fill="var(--ink-mute)" letterSpacing="0.1em" textAnchor="end">
              <text x={W+24} y="-18" fontSize="8" opacity="0.7">DIST. GRAND-CERCLE</text>
              <text x={W+24} y="-4"  fontSize="8" opacity="0.7">ÉCHELLE √(KM)</text>
            </g>

            {/* Réticules de coin */}
            <g stroke="var(--ink-mute)" strokeWidth="0.7" fill="none" opacity="0.55">
              <path d={`M -28 -28 L -28 -10 M -28 -28 L -10 -28`}/>
              <path d={`M ${W+28} -28 L ${W+28} -10 M ${W+28} -28 L ${W+10} -28`}/>
              <path d={`M -28 ${W+28} L -28 ${W+10} M -28 ${W+28} L -10 ${W+28}`}/>
              <path d={`M ${W+28} ${W+28} L ${W+28} ${W+10} M ${W+28} ${W+28} L ${W+10} ${W+28}`}/>
            </g>

            {/* Disque de fond */}
            <circle cx={CX} cy={CY} r={R_MAX} fill="url(#discBg)"/>
            <circle cx={CX} cy={CY} r={R_MAX*1.05} fill="url(#hubGlow)"/>

            {/* Spokes (rayons) tous les 30° */}
            <g stroke="var(--line)" strokeWidth="0.5" opacity="0.7">
              {Array.from({length:12}).map((_,i) => {
                const θ = toRad(i*30);
                const x2 = CX + Math.sin(θ)*R_MAX;
                const y2 = CY - Math.cos(θ)*R_MAX;
                const isCardinal = i % 3 === 0;
                return <line key={i} x1={CX} y1={CY} x2={x2} y2={y2}
                  strokeDasharray={isCardinal ? "1 6" : "1 8"}
                  opacity={isCardinal ? 0.6 : 0.35}/>;
              })}
            </g>

            {/* Anneaux concentriques */}
            <g fill="none" stroke="var(--line-2)" strokeWidth="0.6">
              {rings.map(r => (
                <circle key={r.km} cx={CX} cy={CY} r={rOf(r.km)} strokeDasharray="3 4" opacity="0.85"/>
              ))}
              {/* anneau extérieur plein */}
              <circle cx={CX} cy={CY} r={R_MAX} stroke="var(--ink-mute)" strokeWidth="0.9" opacity="0.5"/>
            </g>

            {/* Graduations sur l'anneau extérieur (tous les 10°) */}
            <g stroke="var(--ink-mute)" strokeWidth="0.6" opacity="0.5">
              {Array.from({length:36}).map((_,i) => {
                const θ = toRad(i*10);
                const len = i % 3 === 0 ? 8 : 4;
                const x1 = CX + Math.sin(θ)*R_MAX;
                const y1 = CY - Math.cos(θ)*R_MAX;
                const x2 = CX + Math.sin(θ)*(R_MAX-len);
                const y2 = CY - Math.cos(θ)*(R_MAX-len);
                return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2}/>;
              })}
            </g>

            {/* Labels d'anneaux (distance) — placés sur le spoke nord, sur fond paper */}
            <g fontFamily="Geist Mono, monospace" fontSize="8" fill="var(--ink-mute)" letterSpacing="0.1em">
              {rings.map(r => {
                const rr = rOf(r.km);
                return (
                  <g key={r.km} transform={`translate(${CX + 4}, ${CY - rr})`}>
                    <rect x="2" y="-7" width={r.label.length*5.4 + 8} height="11" fill="var(--paper)" opacity="0.9"/>
                    <text x="6" y="2">{r.label}</text>
                  </g>
                );
              })}
            </g>

            {/* Cardinaux */}
            <g fontFamily="Geist Mono, monospace" fontSize="11" fontWeight="700" fill="var(--ink)" letterSpacing="0.18em">
              <text x={CX}            y={-6}        textAnchor="middle">N</text>
              <text x={W+10}          y={CY+4}      textAnchor="start">E</text>
              <text x={CX}            y={W+14}      textAnchor="middle">S</text>
              <text x={-10}           y={CY+4}      textAnchor="end">W</text>
            </g>

            {/* Degrés des cardinaux secondaires */}
            <g fontFamily="Geist Mono, monospace" fontSize="7" fill="var(--ink-mute)" opacity="0.55" letterSpacing="0.06em">
              {[30,60,120,150,210,240,300,330].map(deg => {
                const θ = toRad(deg);
                const rr = R_MAX + 14;
                const x = CX + Math.sin(θ)*rr;
                const y = CY - Math.cos(θ)*rr;
                return <text key={deg} x={x} y={y+3} textAnchor="middle">{deg}°</text>;
              })}
            </g>

            {/* Lignes radiales hub → ville */}
            <g stroke="var(--accent)" fill="none">
              {servers.slice(1).map(s => (
                <line key={`l-${s.id}`} x1={CX} y1={CY} x2={s.x} y2={s.y}
                  strokeWidth="0.8" opacity="0.45" strokeDasharray="3 3"/>
              ))}
            </g>

            {/* Pins villes (sauf hub) */}
            {servers.slice(1).map(s => {
              const off = labelOffsets[s.id];
              // petit trait conducteur entre le pin et le label (clarté)
              const stub = Math.hypot(off.dx, off.dy) > 10;
              return (
                <g key={s.id}>
                  <circle cx={s.x} cy={s.y} r="10" fill="var(--accent)" opacity="0.10"/>
                  <circle cx={s.x} cy={s.y} r="4.5" fill="var(--accent)"/>
                  <circle cx={s.x} cy={s.y} r="1.6" fill="var(--paper)"/>
                  {stub && (
                    <line x1={s.x + off.dx*0.2} y1={s.y + off.dy*0.2}
                          x2={s.x + off.dx*0.7} y2={s.y + off.dy*0.7}
                          stroke="var(--ink-mute)" strokeWidth="0.6" opacity="0.5"/>
                  )}
                  <text x={s.x + off.dx} y={s.y + off.dy}
                    fontFamily="Geist Mono, monospace" fontSize="12" fontWeight="700"
                    fill="var(--ink)" letterSpacing="0.06em" textAnchor={off.anchor}>
                    {s.id}
                  </text>
                </g>
              );
            })}

            {/* Hub Genève — au centre */}
            <g>
              <circle cx={CX} cy={CY} r="22" fill="var(--accent)" opacity="0.08" className="pulse"/>
              <circle cx={CX} cy={CY} r="11" fill="var(--accent)" opacity="0.20"/>
              <circle cx={CX} cy={CY} r="6"  fill="var(--accent)"/>
              <circle cx={CX} cy={CY} r="2"  fill="var(--paper)"/>
              <line x1={CX} y1={CY-26} x2={CX} y2={CY-14} stroke="var(--accent)" strokeWidth="1"/>
              <text x={CX} y={CY-32}
                fontFamily="Geist Mono, monospace" fontSize="11" fontWeight="700"
                fill="var(--accent)" textAnchor="middle" letterSpacing="0.16em">
                GVA · HUB
              </text>
              <text x={CX} y={CY-44}
                fontFamily="Geist Mono, monospace" fontSize="8"
                fill="var(--ink-mute)" textAnchor="middle" letterSpacing="0.1em" opacity="0.75">
                46.20°N · 6.14°E
              </text>
            </g>

            {/* Légende compacte (bas-droite) */}
            <g transform={`translate(${W+24}, ${W+16})`} fontFamily="Geist Mono, monospace" fontSize="8" fill="var(--ink-mute)" textAnchor="end" letterSpacing="0.08em">
              <text y="0">{servers.length} NŒUDS · 7 PAYS · 5 CONTINENTS</text>
            </g>
          </svg>
          <div className="mono uc" style={{marginTop:18,paddingTop:18,borderTop:'1px solid var(--line)',display:'grid',gridTemplateColumns:'1fr 1fr',gap:'8px 24px',fontSize:10,color:'var(--ink-mute)',lineHeight:1.6}}>
            <span><span style={{color:'var(--ink-dim)'}}>HUB</span> Genève, CH</span>
            <span style={{textAlign:'right'}}><span style={{color:'var(--ink-dim)'}}>CAP.</span> 84 Gbps</span>
            <span><span style={{color:'var(--ink-dim)'}}>PROJ.</span> azimutale équidistante</span>
            <span style={{textAlign:'right'}}><span style={{color:'var(--ink-dim)'}}>BUILD</span> 2026.05.14</span>
          </div>
        </Reveal>
        <Reveal delay={250} variant="rv-up">
          <p className="mono uc" style={{fontSize:11,color:'var(--ink-mute)',margin:'0 0 4px'}}>Liste des sorties</p>
          <p style={{fontSize:13,color:'var(--ink-dim)',margin:'0 0 18px',lineHeight:1.55}}>
            Toutes les sorties tournent sur une infrastructure que <em className="serif" style={{fontStyle:'italic'}}>nous gérons</em> — pas de revente, pas d'opérateur tiers.
          </p>
          <div className="server-list">
            {servers.slice(0,8).map(s => (
              <div key={s.id} className="server-row">
                <div className="flag">{s.country}</div>
                <div className="city">{s.city}<small>{s.id} · {s.country}</small></div>
                <div className="ping">{s.ms}</div>
                <div className="status" title="Opérationnel"/>
              </div>
            ))}
          </div>
          <p className="mono uc" style={{fontSize:10,color:'var(--ink-mute)',marginTop:18}}>+ 6 autres villes · voir la page Réseau →</p>
        </Reveal>
      </div>
    </section>
  );
};

/* ═══════════════════════════ MANIFESTO ═══════════════════════════ */
const Manifesto = () => (
  <section style={{background:'var(--paper)', borderTop:'1px solid var(--line)', borderBottom:'1px solid var(--line)'}}>
    <div className="section" style={{padding:'140px 32px', textAlign:'center'}}>
      <Reveal>
        <p className="mono uc" style={{fontSize:11,color:'var(--ink-mute)',marginBottom:32}}>— Le manifeste</p>
      </Reveal>
      <Reveal delay={100}>
        <h2 className="serif" style={{
          fontSize:'clamp(34px,4.2vw,60px)', fontWeight:400, lineHeight:1.15,
          letterSpacing:'-0.015em', maxWidth:1100, margin:'0 auto',
          textWrap:'balance', fontStyle:'italic',
        }}>
          « La meilleure protection contre une fuite de données, c'est de
          <span style={{color:'var(--accent)'}}> ne jamais collecter</span> ces données. »
        </h2>
      </Reveal>
      <Reveal delay={250}>
        <div style={{
          maxWidth: 720, margin: '56px auto 0',
          padding: '32px 32px 28px',
          borderTop: '1px solid var(--line)',
          borderBottom: '1px solid var(--line)',
          background: 'var(--bg)',
        }}>
          <p className="mono uc" style={{fontSize:10,color:'var(--accent)',margin:'0 0 14px',letterSpacing:'.2em',fontWeight:600}}>
            — Et son corollaire IA
          </p>
          <p className="serif" style={{
            fontSize:'clamp(20px,2.4vw,28px)', fontWeight:400,
            fontStyle:'italic', lineHeight:1.32, margin:0,
            color:'var(--ink)', letterSpacing:'-0.01em',
          }}>
            « Ce qu'un humain ne voit pas <br/>
            est <span style={{color:'var(--accent)'}}>déjà protégé.</span> »
          </p>
          <p className="mono uc" style={{fontSize:10,color:'var(--ink-mute)',marginTop:18,letterSpacing:'.16em'}}>
            Notre IA regarde dehors — jamais vos données.
          </p>
        </div>
      </Reveal>
      <Reveal delay={400}>
        <p className="mono uc" style={{fontSize:11,color:'var(--ink-mute)',marginTop:36}}>
          DoraVPN · charte d'engagement
        </p>
      </Reveal>
    </div>
  </section>
);

/* ═══════════════════════════ COMPARISON (NOUVEAU) ═══════════════════════════ */
const Comparison = () => {
  const rows = [
    ['Inscription sans email',          'yes', 'no',  'no',  'Identifiant 16 chiffres'],
    ['Paiement en espèces (courrier)',  'yes', 'no',  'no',  'CHF / EUR acceptés'],
    ['Juridiction hors 14-Eyes',        'yes', 'yes', 'no',  'Suisse, indépendante'],
    ['Aucun log (auditable)',           'yes', 'meh', 'meh', 'Architecture sans collecte'],
    ['WireGuard-only',                  'yes', 'no',  'no',  'Pas d\'OpenVPN legacy'],
    ['IA propriétaire (open-weights)',  'yes', 'no',  'no',  'Modèle qu\'on entraîne · pas d\'API tiers'],
    ['IA isolée — sans accès internet', 'yes', 'no',  'no',  'Air-gapped dans nos racks GVA'],
    ['Détection menaces en temps réel', 'yes', 'no',  'meh', 'Sentinelle IA · 412 nœuds, 24/7'],
    ['Veille dark-web de vos données',  'yes', 'no',  'no',  'Retrait actif des leaks'],
    ['Prix unique, non promotionnel',   'yes', 'no',  'no',  '5€/mois, point.'],
    ['Pas d\'app obligatoire',          'yes', 'no',  'no',  'Config .conf standard'],
    ['Code client ouvert',              'meh', 'yes', 'no',  'WireGuard est open, app prévue'],
    ['Réseau de 5000+ serveurs',        'no',  'no',  'yes', 'On préfère 14 bons à 5000 médiocres'],
  ];
  const glyph = (v) => v==='yes' ? '✓' : v==='no' ? '×' : '~';
  return (
    <section className="section section-divider">
      <Reveal><Eyebrow index="05">Comparaison</Eyebrow></Reveal>
      <Reveal delay={100}>
        <h2 className="display" style={{maxWidth:1000,marginBottom:8}}>
          Là où on s'arrête<br/><span className="it">là où les autres commencent.</span>
        </h2>
      </Reveal>
      <Reveal delay={200}>
        <p style={{fontSize:17,color:'var(--ink-dim)',maxWidth:760,margin:'20px 0 0',lineHeight:1.55}}>
          Pas un classement, juste un constat. Les VPN grand public ont une autre cible (le streaming),
          les VPN spécialistes (Mullvad, IVPN) sont proches de nous mais sur un terrain anglo-saxon. DoraVPN occupe une niche : <em className="serif" style={{fontStyle:'italic'}}>la Suisse, sérieuse</em>.
        </p>
      </Reveal>
      <Reveal delay={300} variant="rv-up" className="cmp-wrap">
        <table className="cmp-table">
          <thead>
            <tr>
              <th style={{width:'40%'}}>Critère</th>
              <th className="us">DoraVPN</th>
              <th>VPN spécialistes</th>
              <th>VPN grand public</th>
            </tr>
          </thead>
          <tbody>
            {rows.map(([crit, us, spec, mass, note]) => (
              <tr key={crit}>
                <td>{crit}<small>{note}</small></td>
                <td className="us"><span className={`cmp-glyph ${us}`}>{glyph(us)}</span></td>
                <td><span className={`cmp-glyph ${spec}`}>{glyph(spec)}</span></td>
                <td><span className={`cmp-glyph ${mass}`}>{glyph(mass)}</span></td>
              </tr>
            ))}
          </tbody>
        </table>
      </Reveal>
      <Reveal delay={400}>
        <p className="mono uc" style={{fontSize:10,color:'var(--ink-mute)',marginTop:18,textAlign:'right'}}>
          ✓ Oui · ~ Partiellement · × Non — état du marché au 14.05.2026
        </p>
      </Reveal>
    </section>
  );
};

/* ═══════════════════════════ ABOUT + Passport ═══════════════════════════ */
const About = () => (
  <section className="section section-divider">
    <div style={{display:'grid',gridTemplateColumns:'1fr 1.15fr',gap:80,alignItems:'stretch'}}>
      <div style={{display:'flex',flexDirection:'column'}}>
        <Reveal><Eyebrow index="06">À propos</Eyebrow></Reveal>
        <Reveal delay={120}>
          <h2 className="display" style={{marginBottom:32}}>
            Conçu par des gens dont<br/>le métier est <span className="it accent">de casser les VPN.</span>
          </h2>
        </Reveal>
        <Reveal delay={240} variant="rv-scale" style={{marginTop:'auto'}}>
          <SwissPassport/>
        </Reveal>
      </div>
      <div style={{display:'flex',flexDirection:'column',gap:32,justifyContent:'space-between'}}>
        <Reveal delay={150}>
          <p style={{fontSize:19,lineHeight:1.55,margin:0,maxWidth:640}}>
            DoraVPN est opéré par <strong style={{fontWeight:500}}>CyberAigen</strong>, société de cybersécurité basée à Genève&nbsp;:
            détection de fuites, threat intelligence, durcissement d'infrastructures —
            et depuis 2024, <em className="serif" style={{fontStyle:'italic'}}>une équipe IA</em> qui développe nos propres modèles en open-weights pour la défense.
            Notre métier consiste à savoir précisément <em className="serif" style={{fontStyle:'italic'}}>ce qui peut être enregistré sur un réseau</em>
            {' '}— et ce qui ne devrait jamais l'être. On a conçu le VPN qu'on voulait nous-mêmes utiliser.
          </p>
        </Reveal>
        <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:28}}>
          {[
            ['Juridiction suisse','Hors UE, hors 14-Eyes. Aucune rétention obligatoire imposée aux fournisseurs VPN.'],
            ['Praticiens, pas marketers','Pentests, threat hunting, hardening. Architecture pensée par ceux qui essaieraient de la casser.'],
            ['IA souveraine, hébergée GVA','Modèles open-weights entraînés en interne. Pas d\'OpenAI, pas d\'API US, pas de juridiction étrangère sur la défense.'],
            ['Indépendance financière','Pas d\'investisseurs publicitaires, pas de revente de données. Seul revenu : votre abonnement.'],
            ['Équipe à Genève','Ingénieurs réseau, cryptographes, chercheurs IA. Tous sous loi suisse, tous joignables en personne.'],
            ['Code transparent','Daemons WireGuard open-source, audits annuels publiés, canary signé GPG mis à jour chaque semaine.'],
          ].map(([t,d],i) => (
            <Reveal key={t} delay={220 + i*70} variant="rv-up" style={{borderTop:'1px solid var(--line-2)',paddingTop:14}}>
              <p style={{fontSize:14,fontWeight:500,margin:'0 0 6px'}}>{t}</p>
              <p style={{fontSize:13,color:'var(--ink-dim)',margin:0,lineHeight:1.55}}>{d}</p>
            </Reveal>
          ))}
        </div>
      </div>
    </div>
  </section>
);

/* ═══════════════════════════ DORA — CONFORMITÉ (NOUVEAU) ═══════════════════════════ */
const DoraCompliance = () => {
  const pillars = [
    {
      n:'01', r:'I',
      k:'Gestion du risque ICT',
      d:'Cartographie continue des actifs, principes du moindre privilège, segmentation forte. Aucun composant n\'a plus de droits qu\'il n\'en faut.',
      m:'Architecture zero-trust appliquée à l\'infrastructure VPN — pas seulement aux banques qu\'on durcit.'
    },
    {
      n:'02', r:'II',
      k:'Notification d\'incidents',
      d:'Détection en temps réel par notre IA souveraine, classification stricte, escalade en heures et non en semaines. Procédures écrites, datées, rejouées.',
      m:'Notre Sentinelle IA déclenche la même mécanique d\'alerte pour DoraVPN que pour une banque régulée — en secondes.'
    },
    {
      n:'03', r:'III',
      k:'Tests de résilience',
      d:'TLPT, red team, pen-tests externes, audits indépendants. La résilience se prouve — elle ne se déclare pas.',
      m:'Notre infrastructure VPN est auditée par les mêmes équipes qui auditent les nôtres clientes.'
    },
    {
      n:'04', r:'IV',
      k:'Risque tiers (ICT)',
      d:'Cartographie des dépendances, plans de sortie, élimination des points uniques. Pas de chaîne d\'approvisionnement opaque.',
      m:'Aucun sous-traitant cloud américain. Bare-metal en datacenter suisse. Clés sous contrôle exclusif.'
    },
    {
      n:'05', r:'V',
      k:'Partage d\'information',
      d:'Threat intelligence mutualisée avec les CERT européens, IOCs partagés, signatures à jour en heures.',
      m:'Les signaux détectés chez nos clients régulés alimentent les défenses de DoraVPN — et inversement.'
    },
  ];

  return (
    <section className="dora-sec">
      <div className="section">
        <Reveal>
          <div className="eyebrow">
            <span className="sq"/>
            <span>07 — Conformité · DORA</span>
          </div>
        </Reveal>

        <div className="dora-hero">
          <div>
            <Reveal>
              <h2 className="display">
                Derrière <span className="serif"><em style={{fontStyle:'italic'}}>DoraVPN</em></span>,<br/>
                <span className="dora-word">DORA</span>.
              </h2>
            </Reveal>
            <Reveal delay={120}>
              <p className="dh-intro">
                Pas une coïncidence — un héritage. <strong>CyberAigen</strong>, qui opère DoraVPN, met en conformité <em>DORA</em> les banques, assurances, fintechs et opérateurs cloud critiques européens depuis 2023.
                Le règlement le plus exigeant jamais imposé à un secteur en matière de résilience numérique. Le même socle technique, la même discipline, descendent dans votre VPN.
              </p>
            </Reveal>
          </div>

          <Reveal delay={200}>
            <aside className="dora-stamp">
              <div className="ds-head">
                <span className="ds-tag">Règlement (UE) 2022/2554</span>
                <span className="ds-status">En vigueur</span>
              </div>
              <h3 className="ds-title">Digital Operational <span className="it">Resilience Act</span></h3>
              <div className="ds-sub">Cybersécurité du secteur financier européen</div>
              <div className="ds-meta">
                <div>
                  <span className="ds-k">Adopté</span>
                  <span className="ds-v">14 déc. 2022</span>
                </div>
                <div>
                  <span className="ds-k">Obligatoire dès</span>
                  <span className="ds-v">17 janv. 2025</span>
                </div>
                <div>
                  <span className="ds-k">Champ d'application</span>
                  <span className="ds-v">Banques · Assurances · Fintechs · Crypto-actifs · Prestataires ICT critiques</span>
                </div>
                <div>
                  <span className="ds-k">Sanction maximale</span>
                  <span className="ds-v">10 M€ ou 5% du CA mondial</span>
                </div>
                <div>
                  <span className="ds-k">Piliers</span>
                  <span className="ds-v">5 — du risque ICT à l'info-sharing</span>
                </div>
                <div>
                  <span className="ds-k">Autorité</span>
                  <span className="ds-v">ESA · EBA · EIOPA · ESMA</span>
                </div>
              </div>
              <div className="ds-foot">
                <span>JOUE L 333/1 · Bruxelles</span>
                <span className="stamp">Réf. CyberAigen</span>
              </div>
            </aside>
          </Reveal>
        </div>

        {/* Bridge B2B → grand public */}
        <Reveal delay={250}>
          <div className="dora-bridge">
            <div className="db-side">
              <span className="db-kicker">Ce qu'on fait pour eux</span>
              <span className="db-title">Conformité DORA<br/>pour banques &amp; fintechs</span>
              <span className="db-detail">Bâle · Francfort · Paris · Luxembourg</span>
            </div>
            <div className="db-arrow">
              <span>Même socle</span>
              <span className="glyph">↓</span>
              <span>Même rigueur</span>
            </div>
            <div className="db-side">
              <span className="db-kicker">Ce que vous obtenez</span>
              <span className="db-title">DoraVPN<br/>sur votre téléphone</span>
              <span className="db-detail">5 CHF · 0 log · GVA</span>
            </div>
          </div>
        </Reveal>

        {/* Closer */}
        <Reveal delay={500}>
          <div className="dora-closer">
            <span className="closer-label">— En clair</span>
            <p>
              On vend un VPN grand public à <em>5 CHF par mois</em>. Mais on le construit avec la discipline qu'on doit aux établissements financiers européens. <strong>Pas l'inverse.</strong>
            </p>
          </div>
        </Reveal>
      </div>
    </section>
  );
};

const SwissPassport = () => (
  <div style={{background:'var(--paper)',border:'1px solid var(--line-2)',padding:24,maxWidth:380, marginTop:24,
    boxShadow:'0 14px 40px -20px rgba(40,30,10,.18)'}}>
    <div style={{display:'flex',justifyContent:'space-between',marginBottom:24}}>
      <span className="mono uc" style={{fontSize:9,color:'var(--ink-mute)'}}>SCHWEIZERISCHE EIDGENOSSENSCHAFT</span>
      <svg width="18" height="18" viewBox="0 0 18 18"><rect width="18" height="18" fill="var(--accent)"/><rect x="7.5" y="3" width="3" height="12" fill="#fff"/><rect x="3" y="7.5" width="12" height="3" fill="#fff"/></svg>
    </div>
    <div style={{display:'flex',gap:18}}>
      <div style={{width:74,height:96,background:'repeating-linear-gradient(45deg, var(--line) 0 2px, transparent 2px 6px)',border:'1px solid var(--line-2)'}}/>
      <div style={{flex:1}}>
        <p className="mono uc" style={{fontSize:9,color:'var(--ink-mute)',margin:'0 0 4px'}}>Surname / Nom</p>
        <p className="mono" style={{fontSize:13,fontWeight:500,margin:'0 0 10px'}}>DORAVPN AG</p>
        <p className="mono uc" style={{fontSize:9,color:'var(--ink-mute)',margin:'0 0 4px'}}>Place of business</p>
        <p className="mono" style={{fontSize:13,fontWeight:500,margin:'0 0 10px'}}>GENÈVE · 1200</p>
        <p className="mono uc" style={{fontSize:9,color:'var(--ink-mute)',margin:'0 0 4px'}}>Sector</p>
        <p className="mono" style={{fontSize:13,fontWeight:500,margin:0}}>CYBERSECURITY</p>
      </div>
    </div>
    <div className="mono" style={{marginTop:20, paddingTop:14, borderTop:'1px solid var(--line-2)', fontSize:11, letterSpacing:'.04em', color:'var(--ink-dim)'}}>
      P&lt;CHEDORAVPN&lt;&lt;CYBERSEC&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;<br/>
      CH413882024&lt;0CHE&lt;NOLOG&lt;&lt;NOEMAIL&lt;&lt;26&lt;
    </div>
  </div>
);

/* ═══════════════════════════ DEVICE MOCKUP (NOUVEAU) ═══════════════════════════ */
const DeviceMockup = () => (
  <section style={{background:'var(--paper)', borderTop:'1px solid var(--line)', borderBottom:'1px solid var(--line)'}}>
    <div className="section" style={{padding:'120px 32px'}}>
      <Reveal><Eyebrow index="08">L'application</Eyebrow></Reveal>
      <Reveal delay={100}>
        <h2 className="display" style={{maxWidth:1000,marginBottom:8}}>
          Un seul bouton.<br/><span className="it">Et c'est tout.</span>
        </h2>
      </Reveal>
      <div className="device-section">
        <Reveal delay={200} variant="rv-scale">
          <div className="phone">
            <div className="notch"/>
            <div className="screen">
              <div className="statusbar">
                <span>21:42</span>
                <span style={{display:'flex',gap:8,alignItems:'center'}}>
                  <span style={{width:6,height:6,background:'var(--accent)',borderRadius:'50%'}}/>VPN
                </span>
              </div>
              <div className="app-head">
                <div className="h">Tunnel actif</div>
                <div className="s">DoraVPN · Genève CH</div>
              </div>
              <div className="big-toggle">
                <div className="toggle-text">
                  <div className="state">Connecté · WireGuard</div>
                  <div className="ip">185.193.42.7</div>
                </div>
              </div>
              <div className="meta">
                <div>↓ <strong>248.4 MB</strong><br/>reçus</div>
                <div>↑ <strong>34.1 MB</strong><br/>envoyés</div>
                <div>Latence<br/><strong>4 ms</strong></div>
                <div>Uptime<br/><strong>02:18:44</strong></div>
              </div>
              <div className="nav-pill">
                <div className="active">Statut</div>
                <div>Sorties</div>
                <div>Config</div>
              </div>
            </div>
          </div>
        </Reveal>
        <div className="device-bullets">
          <Reveal delay={150} variant="rv-up" className="b">
            <span className="n">/01</span>
            <div>
              <h4>Pas d'app propriétaire obligatoire</h4>
              <p>Vous recevez un fichier <code style={{fontFamily:'Geist Mono',background:'var(--bg-2)',padding:'1px 6px',border:'1px solid var(--line)'}}>.conf</code> WireGuard standard. Importez-le dans le client officiel (Apple, Google, GNU/Linux, Windows). Notre app est <em className="serif" style={{fontStyle:'italic'}}>optionnelle</em>.</p>
            </div>
          </Reveal>
          <Reveal delay={220} variant="rv-up" className="b">
            <span className="n">/02</span>
            <div>
              <h4>QR code pour mobile</h4>
              <p>Pour iOS et Android, scanner suffit. Aucune saisie d'identifiant à la main, aucun compte à créer dans l'app — la conf <em className="serif" style={{fontStyle:'italic'}}>est</em> votre identité.</p>
            </div>
          </Reveal>
          <Reveal delay={290} variant="rv-up" className="b">
            <span className="n">/03</span>
            <div>
              <h4>Kill switch natif</h4>
              <p>Activé via les paramètres WireGuard standard <code style={{fontFamily:'Geist Mono',background:'var(--bg-2)',padding:'1px 6px',border:'1px solid var(--line)'}}>PostUp / PostDown</code>. Si le tunnel tombe, le trafic est coupé — pas de fuite hors tunnel.</p>
            </div>
          </Reveal>
          <Reveal delay={360} variant="rv-up" className="b">
            <span className="n">/04</span>
            <div>
              <h4>5 appareils par identifiant</h4>
              <p>Téléphone, ordinateur perso, ordinateur pro, tablette, routeur OpenWrt. Tous en parallèle, sans limite de bande passante.</p>
            </div>
          </Reveal>
        </div>
      </div>
    </div>
  </section>
);

/* ═══════════════════════════ 3-STEP ═══════════════════════════ */
const ThreeSteps = () => (
  <section className="section section-divider">
    <Reveal><Eyebrow index="09">Mise en route</Eyebrow></Reveal>
    <div style={{display:'grid',gridTemplateColumns:'auto 1fr',gap:64,alignItems:'start'}}>
      <Reveal delay={100}>
        <h2 className="display" style={{whiteSpace:'nowrap'}}>
          3 minutes.<br/>
          <span style={{color:'var(--ink-dim)'}}>3 étapes.</span><br/>
          <span className="it" style={{color:'var(--accent)',fontSize:'0.7em'}}>0 friction.</span>
        </h2>
      </Reveal>
      <div style={{display:'flex',flexDirection:'column'}}>
        {[
          ['Choisissez votre durée','Espèces par courrier, coupon papier, carte cadeau Amazon, crypto. Aucune banque impliquée, aucun KYC.','00:00'],
          ['Recevez votre identifiant à 16 chiffres','Aucun email, aucun mot de passe à retenir. C\'est tout ce dont vous aurez jamais besoin.','00:45'],
          ['Importez la configuration WireGuard','Fichier .conf sur ordinateur, QR code sur mobile. Le tunnel est actif en quelques secondes.','02:30'],
        ].map(([t,d,time],i) => (
          <Reveal key={i} delay={i*110} variant="rv-up" style={{
            display:'grid',gridTemplateColumns:'60px 1fr 100px',gap:32,
            padding:'28px 0',borderTop:'1px solid var(--line)',alignItems:'baseline',
          }}>
            <span className="serif" style={{fontSize:56,fontWeight:300,color:'var(--accent)',fontStyle:'italic',letterSpacing:'-0.04em'}}>{i+1}</span>
            <div>
              <h3 className="serif" style={{fontSize:28,fontWeight:400,letterSpacing:'-0.015em',margin:'0 0 8px'}}>{t}</h3>
              <p style={{fontSize:14,color:'var(--ink-dim)',margin:0,maxWidth:560,lineHeight:1.6}}>{d}</p>
            </div>
            <span className="mono" style={{fontSize:11,color:'var(--ink-mute)',textAlign:'right'}}>T+{time}</span>
          </Reveal>
        ))}
        <div style={{borderTop:'1px solid var(--line)',paddingTop:24,marginTop:8}}>
          <p className="mono uc" style={{fontSize:11,color:'var(--ink-mute)',margin:'0 0 12px'}}>Compatible avec</p>
          <div style={{display:'flex',flexWrap:'wrap',gap:24}}>
            {['Windows','macOS','Linux','iOS','Android','OpenWrt','OPNsense'].map(p => (
              <span key={p} style={{fontSize:14,color:'var(--ink-dim)'}}>{p}</span>
            ))}
          </div>
        </div>
      </div>
    </div>
  </section>
);

/* ═══════════════════════════ PRICING ═══════════════════════════ */
const useCountUp = (target, dur=1200) => {
  const ref = useRef(null); const [v, setV] = useState(0);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const io = new IntersectionObserver(([e]) => {
      if (!e.isIntersecting) return; io.disconnect();
      const t0 = performance.now();
      const tick = (t) => {
        const p = Math.min(1, (t-t0)/dur);
        setV(target * (1-Math.pow(1-p,3)));
        if (p<1) requestAnimationFrame(tick);
      };
      requestAnimationFrame(tick);
    }, { threshold: .3 });
    io.observe(el);
    return () => io.disconnect();
  }, [target]);
  return [ref, Math.round(v)];
};

const Pricing = () => {
  const [ref, n] = useCountUp(5);
  return (
    <section style={{background:'var(--paper)',borderTop:'1px solid var(--line)',borderBottom:'1px solid var(--line)'}}>
      <div className="section" style={{padding:'120px 32px',display:'grid',gridTemplateColumns:'1fr 1.1fr',gap:80,alignItems:'center'}}>
        <div>
          <Reveal><Eyebrow index="10">Tarif</Eyebrow></Reveal>
          <Reveal delay={100}>
            <p className="mono uc" style={{fontSize:12,color:'var(--ink-dim)',margin:'0 0 16px'}}>
              Un seul prix. Pas de fausse promo, pas de palier piégé.
            </p>
          </Reveal>
          <Reveal delay={150} variant="rv-scale">
            <div ref={ref} style={{display:'flex',alignItems:'baseline',lineHeight:0.85}} className="serif">
              <span style={{fontSize:200,fontWeight:300,letterSpacing:'-0.05em'}}>{n}</span>
              <span style={{fontSize:72,fontWeight:300,marginLeft:10}}>€</span>
              <span style={{fontSize:24,marginLeft:16,color:'var(--ink-dim)',fontStyle:'italic'}}>/ mois</span>
            </div>
          </Reveal>
          <Reveal delay={300}>
            <p style={{fontSize:19,margin:'20px 0 28px',maxWidth:420,lineHeight:1.5}}>
              Un seul tarif. Pour tout le monde. Toujours.<br/>
              <span style={{color:'var(--ink-mute)',fontSize:14}}>Pas de promo agressive, pas de piège à renouvellement, pas d'augmentation surprise.</span>
            </p>
          </Reveal>
          <Reveal delay={400}>
            <button className="btn btn-accent">Obtenir un accès →</button>
          </Reveal>
        </div>
        <Reveal delay={200} style={{borderLeft:'1px solid var(--line-2)',paddingLeft:48}}>
          <p className="mono uc" style={{fontSize:11,color:'var(--ink-mute)',marginBottom:18}}>Durées disponibles</p>
          <div style={{display:'flex',flexDirection:'column'}}>
            {[
              ['1 mois','5 €','—'],
              ['3 mois','15 €','—'],
              ['6 mois','30 €','—'],
              ['12 mois','60 €','+ 1 mois offert'],
              ['24 mois','120 €','+ 3 mois offerts'],
            ].map(([d,p,b],i) => (
              <Reveal key={d} delay={280+i*60} variant="rv-up" style={{
                display:'grid',gridTemplateColumns:'1fr auto 180px',gap:24,
                padding:'18px 0',borderTop:'1px solid var(--line)',alignItems:'center',
              }}>
                <span style={{fontSize:16}}>{d}</span>
                <span className="mono" style={{fontSize:14,color:'var(--ink-dim)'}}>{p}</span>
                <span className="mono uc" style={{fontSize:10,color: b==='—'?'var(--ink-mute)':'var(--moss)',textAlign:'right'}}>{b}</span>
              </Reveal>
            ))}
          </div>
        </Reveal>
      </div>
    </section>
  );
};

/* ═══════════════════════════ FAQ (NOUVEAU) ═══════════════════════════ */
const FAQ = () => {
  const [open, setOpen] = useState(0);
  const items = [
    ['Pourquoi pas d\'email à l\'inscription ?',
     'Parce qu\'un email lie une identité réelle à un service. Si on n\'a pas d\'email, on ne peut pas en faire fuiter, le revendre, ou être contraint de le remettre. L\'identifiant à 16 chiffres remplit la même fonction technique — vous identifier comme client — sans porter d\'information personnelle.'],
    ['Comment payer en espèces ?',
     'Vous recevez à l\'inscription une enveloppe pré-adressée vers une boîte postale à Genève. Vous y glissez un billet (CHF ou EUR), un numéro de référence, et vous postez. À réception, votre identifiant est activé pour la durée correspondante. Aucun nom, aucune adresse, aucune banque dans la boucle.'],
    ['« Aucun log » — comment vérifier ?',
     'On ne demande pas de nous croire sur parole. Notre architecture est documentée publiquement (page Sécurité), un audit indépendant est planifié pour Q3 2026, et le code des composants critiques sera publié. En attendant : la juridiction suisse n\'impose aucune rétention aux opérateurs VPN, contrairement à l\'UE.'],
    ['Pourquoi de l\'IA dans un VPN — vos modèles voient-ils mes données ?',
     'Non, jamais. Notre Sentinelle IA est strictement « outward-facing » : elle analyse la surface externe (dark-web, ASN hostiles, signatures d\'attaque) et l\'état interne de nos serveurs (config, drift, hardening). Elle n\'a aucun accès au tunnel, ni au trafic, ni aux IPs clients. Architecturellement, elle ne peut pas vous voir — c\'est volontaire, c\'est isolé physiquement, et c\'est auditable.'],
    ['Quelle IA — OpenAI ? Anthropic ? un modèle US ?',
     'Aucun des deux. Notre modèle est en open-weights (base Mistral fine-tunée sur nos propres datasets de cybersécurité), entraîné et hébergé dans nos racks à Genève. Il tourne air-gapped — aucune connexion sortante vers internet, aucune API tierce. Si demain OpenAI subit une fuite, ou une cour américaine demande à inspecter nos prompts, ça ne nous concerne pas : nos modèles ne quittent jamais la Suisse, et personne ne peut nous obliger à appeler une IA étrangère.'],
    ['WireGuard plutôt qu\'OpenVPN ?',
     'WireGuard est plus rapide (3-4× sur la même machine), plus simple (4000 lignes de code auditable vs 100 000), et utilise de la cryptographie moderne (ChaCha20, Curve25519). OpenVPN est un excellent protocole de 2001 ; WireGuard est sa réponse 2020. On ne propose pas les deux pour éviter d\'avoir une surface d\'attaque legacy à maintenir.'],
    ['Le streaming fonctionne-t-il ?',
     'Oui pour les plateformes accessibles depuis la Suisse. On ne joue pas au chat et à la souris avec Netflix US ou les bibliothèques géo-restreintes — ce n\'est pas notre métier. Si votre besoin principal est de débloquer du catalogue américain, ExpressVPN ou Surfshark feront ça mieux que nous.'],
    ['Que se passe-t-il en cas de réquisition judiciaire ?',
     'Une autorité suisse peut demander à DoraVPN AG de remettre les données qu\'elle détient sur un client. Comme on ne détient ni email, ni mot de passe, ni log de trafic, ni log de connexion, ni IP source, la réponse est invariablement la même : il n\'y a rien à remettre. C\'est l\'unique vraie protection.'],
    ['Combien d\'appareils ?',
     'Cinq par identifiant, en parallèle. Téléphone, ordi perso, ordi pro, tablette, routeur. Pas de partage : on monitore les usages aberrants (50 IPs distinctes en une journée, par exemple) pour bloquer la revente, sans pour autant identifier qui que ce soit.'],
    ['Et si je veux annuler ?',
     'Vous arrêtez d\'utiliser votre identifiant. Comme il n\'y a pas de débit récurrent, il n\'y a rien à résilier. Si vous avez payé pour 12 mois et que vous ne voulez plus de service après 2 mois, écrivez-nous (anonymement, via le code QR de support) — on rembourse au prorata, en espèces si vous fournissez une adresse postale.'],
  ];
  return (
    <section className="section section-divider">
      <Reveal><Eyebrow index="11">FAQ</Eyebrow></Reveal>
      <div className="faq-grid">
        <Reveal delay={100}>
          <h2 className="display" style={{margin:0}}>
            Les vraies<br/>questions.<br/><span className="it accent">Les vraies réponses.</span>
          </h2>
          <p style={{fontSize:14,color:'var(--ink-dim)',marginTop:20,lineHeight:1.6,maxWidth:280}}>
            On évite la FAQ-théâtre qui ne sert qu'à occuper la page.
            Ici, dix objections récurrentes — traitées sérieusement.
          </p>
        </Reveal>
        <Reveal delay={200} variant="rv-up">
          <div className="faq-list">
            {items.map(([q, a], i) => (
              <div key={i} className={`faq-item ${open === i ? 'open' : ''}`}>
                <button className="faq-q" onClick={() => setOpen(open === i ? -1 : i)}>
                  <span className="num">{String(i+1).padStart(2,'0')}</span>
                  <span>{q}</span>
                  <span className="plus"/>
                </button>
                <div className="faq-a">
                  <div className="faq-a-inner">{a}</div>
                </div>
              </div>
            ))}
          </div>
        </Reveal>
      </div>
    </section>
  );
};

/* ═══════════════════════════ FINAL CTA ═══════════════════════════ */
const FinalCTA = () => (
  <section style={{textAlign:'center',padding:'180px 32px',position:'relative',overflow:'hidden'}}>
    <Reveal><p className="mono uc" style={{fontSize:11,color:'var(--ink-mute)',marginBottom:32}}>— L'engagement</p></Reveal>
    <Reveal delay={120}>
      <h2 className="serif" style={{
        fontSize:'clamp(60px,9vw,140px)', fontWeight:400, letterSpacing:'-0.045em',
        lineHeight:0.92, margin:'0 0 24px', textWrap:'balance',
      }}>
        On ne collecte rien.<br/>
        <span className="it" style={{color:'var(--accent)',fontStyle:'italic'}}>On ne peut rien trahir.</span>
      </h2>
    </Reveal>
    <Reveal delay={250}>
      <p style={{fontSize:20,color:'var(--ink-dim)',maxWidth:680,margin:'0 auto 24px',lineHeight:1.5}}>
        C'est l'unique garantie qui tient devant un tribunal, un pirate, ou nous-mêmes.
        Tout le reste — chartes, promesses, certifications — n'est que littérature.
      </p>
    </Reveal>
    <Reveal delay={320}>
      <p className="serif" style={{
        fontSize:'clamp(18px,2vw,22px)', fontStyle:'italic',
        color:'var(--accent)', maxWidth:680, margin:'0 auto 48px',
        lineHeight:1.5, letterSpacing:'-0.005em',
      }}>
        Et pendant que vous dormez, notre Garde IA souverain veille — <br/>
        sur la forteresse, jamais sur vous.
      </p>
    </Reveal>
    <Reveal delay={350}>
      <button className="btn btn-accent" style={{padding:'20px 40px',fontSize:17}}>
        Générer mon identifiant →
      </button>
      <p className="mono uc" style={{fontSize:11,color:'var(--ink-mute)',marginTop:24}}>
        30 secondes · Sans email · Sans carte bancaire · Sans engagement
      </p>
    </Reveal>
  </section>
);

/* ═══════════════════════════ FOOTER ═══════════════════════════ */
const Foot = () => (
  <footer>
    {/* Big typographic mark */}
    <div className="foot-mark">
      <h2 className="lockup">
        Aucun email.<br/>
        <span className="dim">Aucun log.</span><br/>
        <span className="accent">Aucune trace.</span><br/>
        <span className="dim">Une sentinelle.</span>
      </h2>
      <div className="meta">
        <p className="credo">
          <span>WireGuard</span>
          <span className="sep">·</span>
          <span>Garde IA souverain</span>
          <span className="sep">·</span>
          <span>14 villes</span>
          <span className="sep">·</span>
          <span>5 appareils</span>
          <span className="sep">·</span>
          <span>CHF · EUR · BTC</span>
        </p>
        <p className="signature">
          Genève. Aucune blague, aucune concession.
        </p>
      </div>
    </div>

    {/* 5-column links */}
    <div className="foot-cols">
      <div className="brand-col">
        <div className="brand-mark">
          <svg width="22" height="22" viewBox="0 0 22 22"><rect width="22" height="22" fill="var(--accent)"/><rect x="9.5" y="4" width="3" height="14" fill="#fff"/><rect x="4" y="9.5" width="14" height="3" fill="#fff"/></svg>
          <span>DoraVPN</span>
        </div>
        <p>
          Service VPN opéré par <strong style={{color:'var(--paper)',fontWeight:500}}>CyberAigen</strong>,
          société de cybersécurité genevoise. Conçu pour ne jamais accumuler ce qu'il faudrait protéger.
        </p>
        <div className="legal-id">
          <div><strong>DORAVPN AG</strong></div>
          <div>Genève · 1200 · Suisse</div>
          <div>CHE-413.882.024</div>
        </div>
      </div>

      <div>
        <h5>Produit</h5>
        <ul>
          <li><a>Tarif unique</a></li>
          <li><a>Réseau</a></li>
          <li><a>Comparaison</a></li>
          <li><a>Compatibilité</a></li>
          <li><a>Statut <span className="badge">live</span></a></li>
        </ul>
      </div>

      <div>
        <h5>Sécurité</h5>
        <ul>
          <li><a>Modèle de menace</a></li>
          <li><a>Architecture</a></li>
          <li><a>Garde IA souverain <span className="badge">new</span></a></li>
          <li><a>Audit <span className="badge soon">Q3 26</span></a></li>
          <li><a>Bug bounty</a></li>
          <li><a>Canary warrant</a></li>
        </ul>
      </div>

      <div>
        <h5>Accès</h5>
        <ul>
          <li><a>Se connecter</a></li>
          <li><a>Générer un ID</a></li>
          <li><a>Récupérer</a></li>
          <li><a>Payer en espèces</a></li>
          <li><a>Contact</a></li>
        </ul>
      </div>

      <div>
        <h5>Société</h5>
        <ul>
          <li><a>À propos</a></li>
          <li><a>Manifeste</a></li>
          <li><a>Cadre juridique</a></li>
          <li><a>Presse</a></li>
          <li><a>Affiliation 30%</a></li>
        </ul>
      </div>
    </div>

    {/* Status bar */}
    <div className="foot-status">
      <span className="dot">Réseau opérationnel</span>
      <span className="pipe-sep"/>
      <span className="dot dot-ai">Sentinelle IA armée</span>
      <span className="pipe-sep"/>
      <span>14 villes</span>
      <span className="pipe-sep"/>
      <span>Uptime 99.98%</span>
      <span className="pipe-sep"/>
      <span>Build 2026.05.14</span>
      <span className="spacer"/>
      <div className="lang">
        <span className="active">FR</span>
        <span>DE</span>
        <span>EN</span>
        <span>IT</span>
      </div>
      <span className="pipe-sep"/>
      <span>© 2026 DORAVPN AG</span>
    </div>
  </footer>
);

/* ═══════════════════════════ APP ═══════════════════════════ */
function App() {
  const [t, setTweak] = useTweaks(LIGHT_TWEAKS);
  const [autoSeason, setAutoSeason] = useState(() => pickSeason(new Date().getHours()));

  useEffect(() => {
    if (t.season !== 'auto') return;
    const id = setInterval(() => setAutoSeason(pickSeason(new Date().getHours())), 60_000);
    return () => clearInterval(id);
  }, [t.season]);

  const activeSeasonKey = t.season === 'auto' ? autoSeason : t.season;
  const s = SEASONS[activeSeasonKey] || SEASONS.noon;

  useEffect(() => {
    const r = document.documentElement;
    r.style.setProperty('--sky-top', s.skyTop);
    r.style.setProperty('--sky-mid', s.skyMid);
    r.style.setProperty('--sky-bot', s.skyBot);
    r.style.setProperty('--lk-top',  s.lkTop);
    r.style.setProperty('--lk-bot',  s.lkBot);
    r.style.setProperty('--mt-far',  s.mtFar);
    r.style.setProperty('--mt-mid',  s.mtMid);
    r.style.setProperty('--mt-near', s.mtNear);
    r.style.setProperty('--celest',  s.celest);
    r.style.setProperty('--celest-glow', s.celestGlow);
    r.style.setProperty('--stars-opacity', s.stars);
    r.style.setProperty('--haze-opacity',  s.haze ?? 0.55);
    r.style.setProperty('--hero-ink',     s.heroInk     || '#1a1f2c');
    r.style.setProperty('--hero-ink-dim', s.heroInkDim  || '#5a6273');
    r.style.setProperty('--hero-ink-mute',s.heroInkMute || '#8b91a0');
    const sun = document.querySelector('.sun');
    if (sun) { sun.style.left = s.sunLeft; sun.style.top = s.sunTop; }
  }, [activeSeasonKey]);

  useEffect(() => {
    document.querySelectorAll('.birds').forEach(b => { b.style.display = t.showBirds && activeSeasonKey !== 'night' ? '' : 'none'; });
    document.querySelectorAll('.flag').forEach(f => { f.style.display = t.showFlag ? '' : 'none'; });
  }, [t.showBirds, t.showFlag, activeSeasonKey]);

  return (
    <div>
      <TopRibbon/>
      <Topbar/>
      <AlpineHero
        onGenerate={()=>alert('Démo : ouvrirait le flux de génération')}
        onLogin={()=>alert('Démo : ouvrirait l\'écran de connexion')}
        onAffiliate={()=>alert('Démo : programme d\'affiliation — 30% de commission à vie sur chaque parrainage')}
        showBats={activeSeasonKey === 'dusk' || activeSeasonKey === 'night'}
      />
      <TrustStrip/>
      <Pillars/>
      <HowItWorks/>
      <ThreatModel/>
      <NetworkMap/>
      <Manifesto/>
      <Comparison/>
      <About/>
      <DoraCompliance/>
      <DeviceMockup/>
      <ThreeSteps/>
      <Pricing/>
      <FAQ/>
      <FinalCTA/>
      <Foot/>

      <TweaksPanel title="Tweaks" noDeckControls={true}>
        <TweakSection label="Scène alpine">
          <TweakSelect
            label="Moment"
            value={t.season}
            options={[
              {value:'auto',  label:`⏱ Auto (→ ${SEASONS[autoSeason].name})`},
              {value:'dawn',  label:'🌅 Aube'},
              {value:'noon',  label:'☀ Plein jour'},
              {value:'golden',label:'🌇 Heure dorée'},
              {value:'dusk',  label:'🌆 Crépuscule'},
              {value:'night', label:'🌙 Nuit'},
            ]}
            onChange={(v)=>setTweak('season', v)}
          />
          <TweakToggle
            label="Oiseaux"
            value={t.showBirds}
            onChange={(v)=>setTweak('showBirds', v)}
          />
          <TweakToggle
            label="Drapeau suisse"
            value={t.showFlag}
            onChange={(v)=>setTweak('showFlag', v)}
          />
        </TweakSection>
      </TweaksPanel>
    </div>
  );
}

/* Mount complet uniquement si #root existe (index_beta.html).
   Sur index.html / index_new.html, light-app-v2.jsx est chargé pour exposer
   les composants — le mount des sections se fait via hero-bootstrap.jsx. */
const __betaRoot = document.getElementById('root');
if (__betaRoot) {
  ReactDOM.createRoot(__betaRoot).render(<App/>);
}
/* Expose les composants au scope global pour hero-bootstrap.jsx */
window.BetaComponents = { HowItWorks, About, DoraCompliance, Foot, TopRibbon, TrustStrip, FinalCTA };
