// Tempo — Mentions légales : CGU, CGV, politique de confidentialité, disclaimer trading.
// ─────────────────────────────────────────────────────────────────────────
// Rendu AVANT connexion (écran Login) comme après (Réglages) : aucune dépendance
// à la session. Composants :
//   LegalModal({ kind, onClose })  — modale des documents ('cgu' | 'cgv' | 'privacy'),
//                                    feuille pleine largeur sous 900 px
//   LegalLinks({ compact })        — liens CGU · CGV · Confidentialité (comme le pied de
//                                    page de landing.html), auto-gérés (modale interne)
//   TradingDisclaimer({ compact }) — avertissement risque trading (global)
//   LEGAL_VERSION                  — date de version des documents
//   LEGAL_CONTACT                  — adresse de contact (RGPD, support), domaine tempo-trading.com
//   LEGAL_IDENTITY                 — identité de l’éditeur (qui est aussi le vendeur) :
//                                    SOURCE UNIQUE reprise par les CGU, les CGV et la confidentialité
//   LEGAL_CGV                      — conditions générales de vente (abonnement Pro), même structure que LEGAL_CGU
//
// AVANT COMMERCIALISATION (charte §10, décision de Guillaume) : renseigner
// LEGAL_IDENTITY ci-dessous — nom ou raison sociale, forme juridique, SIRET,
// adresse, téléphone, directeur de la publication — puis le régime de TVA, le
// prestataire de paiement et le médiateur de la consommation. Ne pas activer le
// paiement avant, et faire relire par un professionnel du droit. Reprendre la
// même identité dans les mentions légales de landing.html.
// Tant qu’un champ vaut null, la phrase qui en dépend est reformulée pour rester
// vraie, ou omise : aucun « À compléter » n’est jamais affiché, et un seul
// console.warn liste au chargement les champs manquants.
// LEGAL_CONTACT doit être une boîte réellement relevée : activer Email Routing
// sur tempo-trading.com dans Cloudflare (voir SECURITY.md).

// LEGAL_VERSION identifie le TEXTE accepté : elle est affichée en tête et en
// pied de chaque document, citée dans les CGV et enregistrée à l’inscription
// (accepted_terms_version, preuve du consentement). Toute modification de fond
// d’un des trois documents impose donc une nouvelle date : deux textes
// différents ne doivent jamais porter la même version. Elle vaut le jour de la
// MISE EN LIGNE du texte : à réajuster au déploiement s’il n’a pas lieu ce
// jour-là, et à reprendre mot pour mot dans landing.html (« version du … »).
// Historique : 6 septembre 2026 ; 9 octobre 2026 (confidentialité §2, §4 et §7,
// CGU §1, CGV).
const LEGAL_VERSION = '9 octobre 2026';
const LEGAL_CONTACT = 'contact@tempo-trading.com';

// ─── Identité de l’éditeur (vendeur) : source unique ─────────────────
// Rien n’est inventé : un champ inconnu reste à null.
const LEGAL_IDENTITY = {
  nom: null,                  // raison sociale, ou prénom et nom de l’entrepreneur individuel
  forme: null,                // forme juridique : « entrepreneur individuel », « SASU »…
  siret: null,                // numéro SIRET (14 chiffres)
  adresse: null,              // adresse postale complète du siège
  telephone: null,            // téléphone (obligatoire pour la vente à distance)
  directeurPublication: null, // directeur de la publication (LCEN, art. 6-III)
  tva: null,                  // « TVA non applicable, article 293 B du CGI », ou « TVA 20 % incluse » + n° de TVA intracommunautaire
  paiement: null,             // nom du prestataire de paiement et lien vers ses conditions
  mediateur: null,            // médiateur de la consommation : nom, adresse postale, site internet, modalités de saisine
};
const LEGAL_IDENTITY_LABELS = {
  nom: 'nom ou raison sociale',
  forme: 'forme juridique',
  siret: 'SIRET',
  adresse: 'adresse',
  telephone: 'téléphone',
  directeurPublication: 'directeur de la publication',
  tva: 'régime de TVA',
  paiement: 'prestataire de paiement',
  mediateur: 'médiateur de la consommation',
};

// Identité assemblée « Nom, forme, SIRET …, adresse[, tél. …] », ou '' tant que
// le nom n’est pas renseigné (la phrase qui l’utilise est alors reformulée ou omise).
function legalEditorLine(withPhone = false) {
  const id = LEGAL_IDENTITY;
  if (!id.nom) return '';
  return [
    id.nom,
    id.forme,
    id.siret ? 'SIRET ' + id.siret : null,
    id.adresse,
    withPhone && id.telephone ? 'tél. ' + id.telephone : null,
  ].filter(Boolean).join(', ');
}
// Nom et adresse postale seuls (formulaire de rétractation, garant de la conformité).
function legalPostalLine() {
  const id = LEGAL_IDENTITY;
  return id.nom ? [id.nom, id.adresse].filter(Boolean).join(', ') : '';
}
const LEGAL_EDITOR = legalEditorLine();
const LEGAL_SELLER = legalEditorLine(true);
const LEGAL_POSTAL = legalPostalLine();

// Hébergeurs (LCEN, art. 6-III) : mêmes coordonnées que les mentions légales de landing.html.
const LEGAL_HOSTING = 'Hébergement du site : Cloudflare, Inc. (Cloudflare Pages), 101 Townsend St, San Francisco, CA 94107, États-Unis, tél. +1 (650) 319-8930. Données applicatives : Supabase Pte. Ltd., 65 Chulia Street #38-02/03, OCBC Centre, Singapour 049513, legal@supabase.io.';

// Un seul avertissement au chargement, pour le développeur (jamais à l’écran).
(function legalWarnMissing() {
  const missing = Object.keys(LEGAL_IDENTITY_LABELS)
    .filter(k => !LEGAL_IDENTITY[k])
    .map(k => LEGAL_IDENTITY_LABELS[k]);
  if (missing.length) console.warn('[Tempo] Mentions légales incomplètes (LEGAL_IDENTITY, design/legal.jsx) : ' + missing.join(', '));
})();

// ─── Contenus (tableaux {t: titre, p: [paragraphes]}) ────────────────
// Un paragraphe peut valoir null (information absente) : il n’est pas rendu.
const LEGAL_CGU = {
  title: 'Conditions générales d’utilisation',
  sections: [
    { t: '1. Éditeur', p: [
      LEGAL_EDITOR ? `Tempo est édité par : ${LEGAL_EDITOR}.` : null,
      LEGAL_IDENTITY.directeurPublication ? `Directeur de la publication : ${LEGAL_IDENTITY.directeurPublication}.` : null,
      `Contact : ${LEGAL_CONTACT}.`,
      LEGAL_HOSTING,
    ]},
    { t: '2. Objet du service', p: [
      'Tempo est un journal de trading personnel : saisie et import de trades, suivi d’habitudes et de routines, statistiques de performance, backtest sur données historiques et analyse de contexte de marché.',
      'Tempo est un outil de journalisation, d’entraînement et d’analyse personnelle. Tempo ne fournit aucun conseil en investissement, aucune recommandation d’achat ou de vente, aucun signal de trading, et n’est pas un prestataire de services d’investissement.',
      'Les offres (plan Starter gratuit, plan Pro payant) et les conditions de souscription, de paiement, de résiliation et de rétractation sont décrites dans les Conditions générales de vente (CGV), qui complètent les présentes conditions.',
    ]},
    { t: '3. Compte utilisateur', p: [
      'La création d’un compte requiert une adresse email valide et un mot de passe. Tu es responsable de la confidentialité de tes identifiants et de toute activité réalisée depuis ton compte.',
      'Tu peux supprimer ton compte à tout moment depuis Réglages → Données : tes données personnelles sont alors définitivement effacées (voir Politique de confidentialité).',
    ]},
    { t: '4. Avertissement sur les risques (important)', p: [
      'Le trading d’instruments financiers (futures, devises, métaux, indices, CFD…) comporte un risque élevé de perte, pouvant excéder le capital investi. Les performances passées — y compris les résultats de backtests — ne préjugent pas des performances futures.',
      'Les statistiques, indicateurs, analyses de contexte et résultats de backtest affichés par Tempo sont fournis à titre strictement informatif et pédagogique, sans garantie d’exactitude ni d’exhaustivité. Toute décision d’investissement relève de ta seule responsabilité.',
      'Les résultats de backtest sont des simulations : elles n’intègrent pas parfaitement les conditions réelles d’exécution (liquidité, glissement de prix, coûts variables) et ne constituent pas une promesse de gains.',
    ]},
    { t: '5. Données de marché et sources externes', p: [
      'Les données de marché, calendriers économiques et actualités affichés proviennent de sources publiques tierces. Elles peuvent être différées, incomplètes ou temporairement indisponibles ; Tempo ne garantit ni leur exactitude ni leur continuité.',
    ]},
    { t: '6. Utilisation acceptable', p: [
      'Tu t’engages à ne pas perturber le service, ne pas tenter d’accéder aux données d’autres utilisateurs, ne pas revendre ou extraire massivement les données fournies, et à respecter les conditions des sources de données tierces.',
    ]},
    { t: '7. Propriété intellectuelle', p: [
      `L’interface, le code et la marque Tempo restent la propriété de l’éditeur. Tes données (trades, notes, captures) restent les tiennes : tu peux les supprimer à tout moment depuis Réglages et en demander une copie dans un format structuré (CSV/JSON) en écrivant à ${LEGAL_CONTACT} ; elle t’est fournie sous un mois.`,
    ]},
    { t: '8. Responsabilité', p: [
      'Tempo est fourni « en l’état ». Dans les limites permises par la loi, l’éditeur ne saurait être tenu responsable des pertes financières liées à des décisions de trading, des interruptions de service, ou de l’inexactitude de données issues de sources tierces. Ces limites s’entendent sous réserve des garanties légales et, pour les abonnés au plan Pro, des engagements de disponibilité et de conformité prévus aux articles 8 et 9 des Conditions générales de vente.',
    ]},
    { t: '9. Évolution du service et des conditions', p: [
      'Le service et les présentes conditions peuvent évoluer. En cas de modification substantielle, tu seras informé dans l’application. La poursuite de l’utilisation vaut acceptation des conditions mises à jour.',
    ]},
    { t: '10. Droit applicable', p: [
      'Les présentes conditions sont régies par le droit français. Tout litige relève des tribunaux compétents français, après tentative de résolution amiable.',
    ]},
  ],
};

const LEGAL_PRIVACY = {
  title: 'Politique de confidentialité',
  sections: [
    { t: '1. Responsable du traitement', p: [
      `Le responsable du traitement est l’éditeur de Tempo${LEGAL_EDITOR ? ' (' + LEGAL_EDITOR + ')' : ''}. Contact : ${LEGAL_CONTACT}.`,
    ]},
    { t: '2. Données collectées', p: [
      'Compte : adresse email, mot de passe (haché par Supabase, jamais lisible), préférences de profil (pseudo, devise, fuseau horaire).',
      'Contenu que tu crées : trades (réels et de backtest), habitudes, routines et agenda, notes de journal, captures d’écran importées, stratégies, sauvegardes de backtest, analyses fondamentales enregistrées.',
      'Connexion d’un courtier (optionnelle) : identifiant de compte, serveur et libellé sont stockés par Tempo. Le mot de passe investisseur (lecture seule) est transmis à MetaApi, qui le conserve sur ses serveurs tant que la connexion est active afin de lire ton historique ; Tempo ne le stocke jamais dans sa base de données. Déconnecter le compte de courtier (Réglages) demande à MetaApi la suppression du compte de connexion et de ces identifiants.',
      'Données techniques minimales de fonctionnement (journaux d’erreurs). Tempo n’utilise aucun traceur publicitaire.',
    ]},
    { t: '3. Finalités et bases légales', p: [
      'Fournir le service (exécution du contrat) : stocker et afficher ton journal, tes statistiques, tes backtests.',
      'Sécurité et prévention des abus (intérêt légitime).',
      'Aucune donnée n’est vendue ni utilisée à des fins publicitaires.',
    ]},
    { t: '4. Sous-traitants et hébergement', p: [
      'Supabase (base de données, authentification, stockage de fichiers) et Cloudflare (hébergement du site, services de synchronisation et de calendrier économique).',
      'MetaApi (Agiliumtrade) uniquement si tu connectes un compte MetaTrader 5 : la connexion au courtier est établie via leur infrastructure.',
      'Ces prestataires agissent comme sous-traitants au sens du RGPD.',
      'Sources de marché appelées depuis ton navigateur : pour l’analyse fondamentale, ton appareil interroge directement des services publics tiers indépendants (Binance, Kraken, Frankfurter). Ces services reçoivent ton adresse IP et l’identifiant de ton navigateur, mais aucune donnée de ton compte. Certains sont situés hors de l’Union européenne ; ils ne sont pas des sous-traitants de Tempo et appliquent leurs propres conditions. Les actualités et les cotes d’indices (Cboe) sont lues par le service de calendrier économique de Tempo, hébergé chez Cloudflare : ces sources ne reçoivent aucune donnée te concernant.',
      'Au chargement de l’application, ton navigateur récupère aussi des bibliothèques et des polices depuis des serveurs de diffusion tiers (Google Fonts, unpkg, jsDelivr, amCharts). Ces services reçoivent ton adresse IP et l’identifiant de ton navigateur, mais aucune donnée de ton compte.',
    ]},
    { t: '5. Durée de conservation', p: [
      'Tes données sont conservées tant que ton compte est actif. La suppression du compte (Réglages → Données → Supprimer le compte) efface définitivement trades, habitudes, agenda, notes, captures, stratégies, sauvegardes de backtest, analyses fondamentales et connexions de courtier.',
      `L’enregistrement d’authentification résiduel (email) peut être purgé sur demande à ${LEGAL_CONTACT}.`,
      'Données techniques : si tu as renseigné un calendrier externe, son contenu est mis en cache 10 minutes sur nos serveurs Cloudflare ; les compteurs anti-abus (adresse IP hachée) expirent après 10 minutes ; les journaux techniques de nos sous-traitants (connexions, erreurs) sont conservés par eux pour la durée nécessaire à la sécurité, typiquement quelques semaines à quelques mois.',
      'Comptes inactifs : un compte sans aucune connexion pendant 24 mois peut être supprimé, après un email d’avertissement envoyé à l’adresse du compte au moins 30 jours avant.',
    ]},
    { t: '6. Tes droits (RGPD)', p: [
      'Tu disposes des droits d’accès, de rectification, d’effacement, de portabilité et d’opposition sur tes données.',
      'La plupart s’exercent directement dans l’application (Réglages : profil éditable, réinitialisation du journal, suppression du compte).',
      `La portabilité (copie de tes données dans un format structuré, CSV/JSON) et toute autre demande s’exercent par email à ${LEGAL_CONTACT} ; réponse sous un mois. Tu peux également saisir la CNIL (cnil.fr).`,
    ]},
    { t: '7. Stockage sur ton appareil', p: [
      'Tempo enregistre sur ton appareil (stockage local du navigateur, jamais dans la base) : des préférences d’affichage (thème, catégories sélectionnées, réglages de backtest), des caches de données publiques (analyses, calendrier économique), tes notes « Mon plan » liées aux événements économiques et — si tu l’as renseigné — le lien privé de ton calendrier externe, qui ne transite par nos serveurs que pour lire ce calendrier. Ces éléments sont effacés à la déconnexion et à la suppression du compte (seuls le thème et quelques réglages d’affichage restent sur l’appareil), ou en vidant les données du site dans ton navigateur. Aucun cookie de suivi tiers n’est déposé.',
    ]},
    { t: '8. Sécurité', p: [
      'Chiffrement en transit (HTTPS), isolation des données par utilisateur au niveau de la base (chaque compte ne peut lire et modifier que ses propres données), accès au courtier en lecture seule via le mot de passe investisseur.',
    ]},
  ],
};

// Conditions générales de vente : abonnement Pro vendu à des consommateurs
// (France / UE). Complètent les CGU ; consultées via LegalLinks, Réglages,
// landing.html (./index.html#cgv) et LegalModal kind 'cgv'.
// Identité du vendeur (§1, avec téléphone), garant de la conformité (§8),
// destinataire du formulaire de rétractation (§7), régime de TVA (§1),
// prestataire de paiement (§5) et médiateur (§14) : tous lus dans LEGAL_IDENTITY
// (voir l’en-tête). Faire relire avant activation du paiement.
// À reprendre TELS QUELS dans le futur écran de paiement :
// le texte de la case « accès immédiat » (§7 — demande expresse d’exécution avant
// la fin du délai de rétractation, L221-25 : le droit de rétractation est CONSERVÉ,
// seul un prorata est dû) et le libellé du bouton « Payer et m’abonner » (§5, L221-14).
const LEGAL_CGV = {
  title: 'Conditions générales de vente',
  sections: [
    { t: '1. Vendeur', p: [
      `L’abonnement Tempo Pro est vendu par l’éditeur de Tempo${LEGAL_SELLER ? ' : ' + LEGAL_SELLER : ''}.`,
      `Contact : ${LEGAL_CONTACT}. Cette adresse sert à toute question sur ton abonnement, ta facturation ou une réclamation.`,
      LEGAL_IDENTITY.tva ? `Régime de TVA : ${LEGAL_IDENTITY.tva}.` : null,
    ]},
    { t: '2. Objet et champ d’application', p: [
      'Les présentes conditions générales de vente (CGV) régissent les abonnements à Tempo souscrits depuis tempo-trading.com par des consommateurs, c’est-à-dire des personnes physiques agissant à des fins qui n’entrent pas dans le cadre de leur activité professionnelle.',
      'Elles complètent les conditions générales d’utilisation (CGU), qui restent applicables à l’usage du service, et la politique de confidentialité. En cas de contradiction sur un point relatif à la vente, ce sont les CGV qui s’appliquent.',
      'Tu acceptes les CGV au moment de la souscription d’un abonnement payant, en cochant la case prévue à cet effet sur l’écran de paiement. Les CGV applicables sont celles en vigueur à cette date ; leur version est indiquée en bas de ce document.',
    ]},
    { t: '3. Offres', p: [
      'Starter — gratuit, sans limite de durée et sans carte bancaire. Comprend le journal de trading (saisie, import de fichier, captures, notes), le tableau de bord, le bilan hebdomadaire et les statistiques, les routines et les vérifications avant trade, le calendrier économique et les actualités.',
      'Pro — 9 € TTC par mois, tarif de lancement, sans engagement. Comprend tout le plan Starter ainsi que les modules listés dans le présent article et sur la page Tarifs de tempo-trading.com, notamment le backtest en replay (bougie par bougie, avec sauvegardes) et l’analyse fondamentale Jour et Semaine. Les fonctions signalées « bêta » sont fournies à titre expérimental et peuvent être modifiées ou retirées.',
      'Période de lancement : tant que le paiement n’est pas activé dans l’application, toutes les fonctions — y compris celles du plan Pro — sont ouvertes gratuitement à tous les comptes, et aucun paiement n’est prélevé. Tu seras prévenu dans l’application avant toute mise en place d’un abonnement payant. Le passage au plan Pro payant ne sera jamais automatique : aucun prélèvement ne peut avoir lieu sans une souscription explicite de ta part.',
      'Tempo peut faire évoluer le contenu des plans dans les conditions de l’article L224-25-25 du code de la consommation ; une modification ayant une incidence négative non négligeable sur ton accès au plan Pro ou son utilisation te sera annoncée par email au moins 30 jours à l’avance et t’ouvrira le droit de résilier sans frais dans les 30 jours suivant l’information.',
      'Compatibilité : Tempo est une application web accessible sans installation depuis un navigateur récent à jour (Safari, Chrome, Firefox, Edge) sur ordinateur, tablette et smartphone, avec une connexion internet ; elle peut être ajoutée à l’écran d’accueil (application web progressive), le mode hors ligne se limitant à l’interface.',
    ]},
    { t: '4. Prix', p: [
      'Les prix sont indiqués en euros, toutes taxes comprises (TTC). Le prix applicable est celui affiché au moment de ta souscription.',
      'Le tarif de 9 € TTC par mois est un tarif de lancement. Toute modification du prix te sera annoncée par email ou dans l’application au moins 30 jours avant son entrée en vigueur ; si tu ne l’acceptes pas, tu peux résilier ton abonnement avant cette date, sans frais. Sans résiliation de ta part, le nouveau prix s’applique au prochain renouvellement suivant le délai de 30 jours.',
      'Aucun frais supplémentaire (frais de dossier, de connexion, de résiliation) n’est facturé par Tempo. Les frais éventuels de ton opérateur télécom ou de ta banque restent à ta charge.',
    ]},
    { t: '5. Souscription et paiement', p: [
      'Pour souscrire au plan Pro, tu dois disposer d’un compte Tempo, être majeur et avoir accepté les CGU. La souscription se fait en ligne depuis l’application (Réglages → Abonnement) : choix du plan, récapitulatif de la commande (prix TTC, périodicité, date du prochain prélèvement), acceptation des CGV, puis validation par le bouton « Payer et m’abonner » (commande avec obligation de paiement, article L221-14 du code de la consommation).',
      `Le paiement s’effectue par carte bancaire, via un prestataire de paiement sécurisé${LEGAL_IDENTITY.paiement ? ' : ' + LEGAL_IDENTITY.paiement : ''}. Tes données de carte sont saisies et conservées uniquement chez ce prestataire ; Tempo n’y a jamais accès et ne les stocke pas.`,
      'Le premier mois est prélevé à la souscription, puis chaque mois à la date anniversaire de celle-ci (prélèvement mensuel). Un reçu ou une facture t’est envoyé par email à chaque paiement et reste consultable depuis Réglages → Abonnement.',
      'En cas d’échec de paiement (carte expirée, refus de la banque…), tu es prévenu par email et une nouvelle tentative est effectuée dans les jours qui suivent. Si le paiement reste impossible pendant 10 jours, ton compte repasse au plan Starter ; tes données sont intégralement conservées et tu peux souscrire à nouveau à tout moment.',
      'La confirmation de souscription t’est adressée par email et récapitule les CGV acceptées, le prix, la périodicité et les modalités de résiliation, ainsi que, le cas échéant, ta demande expresse d’accès immédiat (article L221-13).',
    ]},
    { t: '6. Durée, renouvellement et résiliation', p: [
      'L’abonnement Pro est conclu pour une durée d’un mois, renouvelée tacitement de mois en mois. Conformément à l’article L215-1 du code de la consommation, tu es informé que ton abonnement se renouvelle automatiquement à chaque échéance tant que tu ne l’as pas résilié.',
      'Tu peux résilier à tout moment, sans motif ni frais, directement en ligne depuis Réglages → Abonnement → « Résilier mon abonnement » (résiliation en quelques clics, article L215-1-1 du code de la consommation). Une confirmation te parvient par email avec la date à laquelle la résiliation prend effet.',
      `Tu peux également résilier en écrivant à ${LEGAL_CONTACT} depuis l’adresse email de ton compte ; la résiliation est enregistrée à réception.`,
      'La résiliation prend effet à la fin de la période mensuelle déjà payée : tu conserves l’accès au plan Pro jusqu’à cette date, puis ton compte repasse au plan Starter. La période entamée n’est pas remboursée, sauf exercice du droit de rétractation (article 7) ou résiliation à l’initiative de Tempo sans faute de ta part (article 13).',
      'Le retour au plan Starter ne supprime aucune donnée : tes trades, notes, stratégies et sauvegardes de backtest restent accessibles, et la suppression du compte reste possible à tout moment depuis Réglages → Données.',
    ]},
    { t: '7. Droit de rétractation', p: [
      'Conformément à l’article L221-18 du code de la consommation, tu disposes d’un délai de 14 jours à compter de la souscription pour te rétracter, sans avoir à justifier de motif ni à payer de pénalité.',
      'Exécution immédiate (articles L221-25 et L221-28 1° du code de la consommation) : l’abonnement Pro est un service fourni en continu. Si tu souhaites accéder au plan Pro dès la souscription, sans attendre la fin du délai de 14 jours, tu dois le demander expressément en cochant la case prévue à cet effet sur l’écran de paiement (non cochée par défaut). Tu conserves alors ton droit de rétractation pendant 14 jours ; si tu l’exerces, tu dois uniquement payer les jours d’accès déjà fournis, calculés au prorata du prix mensuel (9 € × nombre de jours écoulés ÷ nombre de jours de la période), et le reste te sera remboursé.',
      'Texte exact de la case à cocher affichée au moment du paiement : « Je demande expressément que mon accès au plan Pro commence immédiatement, avant la fin du délai de rétractation de 14 jours. Je comprends que si je me rétracte pendant ce délai, je devrai payer les jours d’accès déjà fournis, au prorata du prix mensuel (article L221-25 du code de la consommation). »',
      'Si tu ne coches pas cette case, ton accès au plan Pro débute à l’expiration du délai de 14 jours ; la première période mensuelle et la date anniversaire du prélèvement courent à compter de ce début d’accès. Pendant ces 14 jours tu peux te rétracter et être intégralement remboursé.',
      `Pour te rétracter, envoie une déclaration claire à ${LEGAL_CONTACT} depuis l’adresse email de ton compte. Tu peux utiliser le formulaire type suivant : « À l’attention de ${LEGAL_POSTAL || 'l’éditeur de Tempo'}, ${LEGAL_CONTACT} — Je vous notifie par la présente ma rétractation du contrat portant sur la prestation de service ci-dessous : abonnement Tempo Pro, souscrit le [date], pour le compte [adresse email]. Nom du consommateur : […]. Adresse du consommateur : […]. Date : […]. Signature (uniquement en cas de notification sur papier). » Un accusé de réception te sera envoyé par email.`,
      'En cas de rétractation valable, tu es remboursé de la totalité des sommes versées — déduction faite, si tu avais demandé l’accès immédiat, du montant proportionnel aux jours d’accès déjà fournis — au plus tard 14 jours après réception de ta demande, par le même moyen de paiement que celui utilisé lors de la souscription.',
    ]},
    { t: '8. Garantie légale de conformité', p: [
      'Tempo est un service numérique au sens des articles L224-25-1 et suivants du code de la consommation. Tu bénéficies de la garantie légale de conformité : le service doit correspondre à sa description, être fourni avec les mises à jour nécessaires à son maintien en conformité et présenter les fonctionnalités qu’un consommateur peut légitimement attendre.',
      `Garant de la conformité : le vendeur désigné à l’article 1${LEGAL_POSTAL ? ' (' + LEGAL_POSTAL + ')' : ''}.`,
      'Le consommateur a droit à la mise en œuvre de la garantie légale de conformité en cas d’apparition d’un défaut de conformité durant toute la période de fourniture du service numérique. Durant cette période, le consommateur n’est tenu d’établir que l’existence du défaut de conformité et non la date d’apparition de celui-ci. La garantie légale de conformité emporte obligation de fournir toutes les mises à jour nécessaires au maintien de la conformité du service numérique.',
      'La garantie légale de conformité donne au consommateur droit à la mise en conformité du service numérique sans retard injustifié suivant sa demande, sans frais et sans inconvénient majeur pour lui. Le consommateur peut obtenir une réduction du prix en conservant le service numérique, ou mettre fin au contrat en se faisant rembourser intégralement contre renoncement au service numérique, si : 1° le professionnel refuse de mettre le service numérique en conformité ; 2° la mise en conformité est retardée de manière injustifiée ; 3° la mise en conformité ne peut avoir lieu sans frais imposés au consommateur ; 4° la mise en conformité occasionne un inconvénient majeur pour le consommateur ; 5° la non-conformité persiste en dépit de la tentative de mise en conformité effectuée sans succès. Le consommateur a également droit à une réduction du prix ou à la résolution du contrat lorsque le défaut de conformité est si grave qu’il justifie que la réduction du prix ou la résolution soit immédiate ; il n’est alors pas tenu de demander la mise en conformité au préalable. Toute période d’indisponibilité du service numérique en vue de sa remise en conformité suspend la garantie qui restait à courir jusqu’à la fourniture du service de nouveau conforme.',
      `Ces droits résultent des articles L224-25-1 à L224-25-31 du code de la consommation. Le professionnel qui fait obstacle de mauvaise foi à la mise en œuvre de la garantie légale de conformité encourt une amende civile d’un montant maximal de 300 000 euros, pouvant être porté jusqu’à 10 % du chiffre d’affaires moyen annuel (article L242-18-1 du code de la consommation). Toute demande s’adresse à ${LEGAL_CONTACT}.`,
      'Cette garantie s’applique sans frais pendant toute la durée de fourniture du service. Elle ne couvre pas les défauts résultant de ton propre équipement, de ta connexion internet ou d’une utilisation non conforme aux CGU.',
    ]},
    { t: '9. Disponibilité et maintenance', p: [
      'Tempo est accessible en ligne 24 h/24 et 7 j/7, dans la limite des opérations de maintenance et des incidents. L’éditeur fait ses meilleurs efforts pour assurer la continuité du service, mais ne garantit pas une disponibilité ininterrompue.',
      'Des interruptions planifiées (mises à jour, maintenance) peuvent avoir lieu ; les interruptions de plus d’une heure prévues à l’avance sont annoncées dans l’application. Le service dépend également de prestataires techniques (hébergement, base de données) et de sources de données tierces qui peuvent connaître leurs propres indisponibilités.',
      'Une indisponibilité prolongée du plan Pro imputable à Tempo (hors force majeure) et dépassant 72 heures consécutives donne droit à une prolongation gratuite de l’abonnement d’une durée équivalente.',
    ]},
    { t: '10. Responsabilité', p: [
      'Le trading comporte un risque élevé de perte en capital. Tempo est un outil de journalisation et d’analyse — il ne fournit aucun conseil en investissement, aucune recommandation d’achat ou de vente et aucun signal de trading. L’avertissement sur les risques figurant dans les CGU (article 4) fait partie intégrante des présentes CGV.',
      'Aucune garantie de résultat n’est donnée : les statistiques, analyses, indicateurs et résultats de backtest sont fournis à titre informatif et pédagogique. Toute décision d’investissement relève de ta seule responsabilité, et l’éditeur ne saurait être tenu responsable des pertes financières liées à tes opérations de trading.',
      'L’éditeur est responsable de plein droit de la bonne exécution de l’abonnement, y compris lorsqu’elle est confiée à ses prestataires techniques (article L221-15 du code de la consommation). Il n’est pas responsable des pertes liées à tes décisions de trading, qui relèvent de ta seule responsabilité, ni des dommages résultant de ta propre faute, du fait imprévisible et insurmontable d’un tiers étranger à la fourniture du service, ou d’un cas de force majeure. Aucune clause des présentes ne limite les droits que tu tiens des garanties légales.',
    ]},
    { t: '11. Données personnelles', p: [
      'Le traitement de tes données personnelles est décrit dans la politique de confidentialité, accessible depuis l’application et le site. Les données de paiement (numéro de carte) sont traitées exclusivement par le prestataire de paiement, qui agit comme responsable de traitement indépendant pour cette opération ; Tempo ne conserve que l’identifiant de l’abonnement, son statut et l’historique de facturation, nécessaires à l’exécution du contrat et à nos obligations comptables.',
    ]},
    { t: '12. Propriété intellectuelle', p: [
      'L’abonnement te confère un droit d’utilisation personnel, non exclusif et non transférable du service, pour la durée de l’abonnement. L’interface, le code, les analyses produites par Tempo et la marque Tempo restent la propriété de l’éditeur ; toute reproduction, revente ou extraction massive est interdite.',
      `Tes données (trades, notes, captures, stratégies, sauvegardes de backtest) restent les tiennes, quel que soit ton plan. Tu peux les supprimer à tout moment depuis Réglages et en demander une copie dans un format structuré (CSV/JSON) en écrivant à ${LEGAL_CONTACT}.`,
    ]},
    { t: '13. Suspension et résiliation par Tempo', p: [
      'Tempo peut suspendre ou résilier ton abonnement en cas de manquement grave aux CGU (article 6 : perturbation du service, tentative d’accès aux données d’autres utilisateurs, extraction massive, revente), de fraude au paiement ou d’impayé. Sauf urgence (sécurité du service, fraude), tu es prévenu par email et disposes de 10 jours pour régulariser (délai identique à celui de l’article 5 en cas d’échec de paiement) avant toute mesure.',
      'Si Tempo met fin à ton abonnement sans faute de ta part (par exemple en cas d’arrêt du plan Pro), la période déjà payée et non consommée t’est remboursée au prorata. En cas d’arrêt définitif du service, tu en es informé au moins 2 mois à l’avance afin de pouvoir récupérer tes données.',
    ]},
    { t: '14. Réclamations et médiation', p: [
      `Pour toute réclamation, écris d’abord à ${LEGAL_CONTACT} ; nous nous engageons à te répondre sous 15 jours ouvrés.`,
      `Si le désaccord persiste, tu peux saisir gratuitement le médiateur de la consommation dont relève Tempo, conformément aux articles L612-1 et suivants du code de la consommation${LEGAL_IDENTITY.mediateur ? ' : ' + LEGAL_IDENTITY.mediateur : ' ; ses coordonnées seront indiquées ici avant l’activation du paiement'}. La saisine du médiateur n’est possible qu’après avoir tenté de résoudre le litige directement avec nous, par réclamation écrite, dans un délai d’un an à compter de cette réclamation.`,
      'Tu restes libre de saisir la justice à tout moment.',
    ]},
    { t: '15. Droit applicable, langue et tribunaux', p: [
      'Les présentes CGV sont régies par le droit français. Elles sont rédigées en français ; en cas de traduction, seule la version française fait foi. Le contrat est conclu en français.',
      'En cas de litige non résolu à l’amiable, tu peux saisir, à ton choix, la juridiction du lieu où tu résidais au moment de la conclusion du contrat ou de la survenance du fait dommageable, ou toute autre juridiction territorialement compétente (article R631-3 du code de la consommation). Si tu résides dans un autre État membre de l’Union européenne, tu peux saisir les juridictions de ton État de résidence.',
      'Si tu résides dans un autre État membre de l’Union européenne, tu bénéficies en outre des dispositions impératives de protection des consommateurs de ton pays de résidence.',
    ]},
    { t: '16. Modifications et version', p: [
      `Les présentes CGV sont datées du ${LEGAL_VERSION}. Tempo peut les modifier ; toute modification substantielle te sera annoncée par email ou dans l’application au moins 30 jours avant son entrée en vigueur. Si tu ne l’acceptes pas, tu peux résilier ton abonnement avant cette date ; à défaut, la nouvelle version s’applique au renouvellement suivant. La version acceptée lors de ta souscription reste consultable sur demande.`,
    ]},
  ],
};

// ─── Rendu d’un paragraphe ───────────────────────────────────────────
// L’adresse de contact devient un lien mailto insécable : elle ne se coupe
// plus sur son trait d’union en fin de ligne (feuille mobile).
function legalRichText(text) {
  const parts = String(text).split(LEGAL_CONTACT);
  if (parts.length === 1) return text;
  const out = [];
  parts.forEach((part, k) => {
    if (k > 0) out.push(<a key={'m' + k} href={'mailto:' + LEGAL_CONTACT} style={{ color: 'var(--blue-600)', whiteSpace: 'nowrap' }}>{LEGAL_CONTACT}</a>);
    if (part) out.push(<React.Fragment key={'t' + k}>{part}</React.Fragment>);
  });
  return out;
}

// ─── Modale légale ────────────────────────────────────────────────────
// Comportement commun des modales (useModalBehavior, core.jsx — charte §8) :
// le fond ne ferme que sur mousedown hors de la carte (une sélection de texte
// relâchée sur le fond ne ferme plus rien), Échap ferme la modale du dessus
// seulement, le focus est piégé puis rendu au déclencheur. Sous 900 px (même
// seuil que useIsMobile), feuille pleine largeur avec un padding de 12 px.
// Lecture au clavier : la zone de texte est focalisable (tabIndex 0) et reçoit
// le focus à l’ouverture. Sans cela le focus irait au bouton « Fermer », hors
// de la zone défilante, et ni les flèches ni Espace ne feraient défiler un
// document de plusieurs écrans. useModalBehavior respecte un focus déjà placé
// dans la modale et a mémorisé le déclencheur au rendu : le retour du focus au
// lien d’origine n’est pas affecté. La zone fait partie du cycle de Tab.
// Arrivée par l’adresse (#cgv depuis la page de vente) : il n’y a pas de
// déclencheur et le navigateur afficherait d’office l’anneau de focus autour de
// tout le texte, y compris au doigt. Il est donc masqué pour ce premier focus
// seulement, et revient dès que le focus a quitté la zone (retour par Tab).
function LegalModal({ kind, onClose }) {
  const doc = kind === 'privacy' ? LEGAL_PRIVACY : kind === 'cgv' ? LEGAL_CGV : LEGAL_CGU;
  const isMobile = typeof useIsMobile === 'function' ? useIsMobile() : (typeof window !== 'undefined' && window.innerWidth < 900);
  const modal = useModalBehavior({ open: true, onRequestClose: onClose, labelledBy: 'legal-modal-title' });
  const padX = isMobile ? 12 : 20;
  const scrollRef = React.useRef(null);
  const [quietFocus, setQuietFocus] = React.useState(() => !document.activeElement || document.activeElement === document.body);
  React.useLayoutEffect(() => {
    const node = scrollRef.current;
    if (!node) return;
    node.scrollTop = 0; // changement de document sans démontage : repartir du début
    node.focus({ preventScroll: true });
  }, [kind]);
  return (
    <div {...modal.backdropProps} style={{
      position: 'fixed', inset: 0, zIndex: 10000, background: 'rgba(15,23,42,.45)',
      display: 'flex', alignItems: isMobile ? 'flex-end' : 'center', justifyContent: 'center',
      padding: isMobile ? 0 : 18,
    }}>
      <div {...modal.dialogProps} className="card" style={{
        width: isMobile ? '100%' : 640, maxWidth: '100%', maxHeight: isMobile ? '92dvh' : '86vh',
        borderRadius: isMobile ? '16px 16px 0 0' : 12,
        display: 'flex', flexDirection: 'column', padding: 0, overflow: 'hidden', outline: 'none',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, padding: isMobile ? `14px ${padX}px 12px` : `16px ${padX}px`, borderBottom: '1px solid var(--line)' }}>
          <div style={{ minWidth: 0 }}>
            <div id="legal-modal-title" style={{ fontSize: 15.5, fontWeight: 700, letterSpacing: '-.015em', color: 'var(--fg)' }}>{doc.title}</div>
            <div style={{ fontSize: 11, color: 'var(--fg-3)', marginTop: 2 }}>{`Version du ${LEGAL_VERSION}`}</div>
          </div>
          <button type="button" onClick={modal.requestClose} className="tap tap-44" aria-label="Fermer" title="Fermer" style={{ width: 30, height: 30, borderRadius: 8, border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--fg-2)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>{Ico.x}</button>
        </div>
        {/* outlineOffset négatif : la carte est en overflow hidden, l’anneau de focus (index.html) serait rogné à +2 px. */}
        <div ref={scrollRef} className="scroll" tabIndex={0} role="document" aria-labelledby="legal-modal-title" onBlur={() => { if (quietFocus) setQuietFocus(false); }} style={{ overflow: 'auto', outline: quietFocus ? 'none' : undefined, outlineOffset: -2, padding: isMobile ? `14px ${padX}px calc(20px + env(safe-area-inset-bottom))` : `18px ${padX}px 24px` }}>
          {doc.sections.map((s, i) => (
            <div key={i} style={{ marginBottom: 16 }}>
              <div style={{ fontSize: 13, fontWeight: 700, marginBottom: 6, letterSpacing: '-.01em', color: 'var(--fg)' }}>{s.t}</div>
              {s.p.filter(Boolean).map((p, j) => (
                <p key={j} style={{ fontSize: 12.5, lineHeight: 1.6, color: 'var(--fg-2)', margin: '0 0 8px' }}>{legalRichText(p)}</p>
              ))}
            </div>
          ))}
          <div style={{ fontSize: 11, color: 'var(--fg-3)', paddingTop: 8, borderTop: '1px solid var(--line)' }}>
            {legalRichText(`Version du ${LEGAL_VERSION} · Contact : ${LEGAL_CONTACT}`)}
          </div>
        </div>
      </div>
    </div>
  );
}

// ─── Liens auto-gérés (Réglages, pieds de page) ──────────────────────
// Mêmes libellés que le pied de page de landing.html (« CGU · CGV ·
// Confidentialité ») : ils tiennent sur une ligne, même dans la carte de
// connexion sur mobile. Le nom complet du document est donné au survol (title,
// lu aussi comme description par les lecteurs d’écran).
const LEGAL_LINKS = [
  { kind: 'cgu', label: 'CGU', full: LEGAL_CGU.title },
  { kind: 'cgv', label: 'CGV', full: LEGAL_CGV.title },
  { kind: 'privacy', label: 'Confidentialité', full: LEGAL_PRIVACY.title },
];
function LegalLinks({ compact }) {
  const [kind, setKind] = React.useState(null);
  const linkStyle = { background: 'transparent', border: 'none', padding: 0, cursor: 'pointer', color: 'var(--blue-600)', fontSize: compact ? 11 : 11.5, fontWeight: 500, fontFamily: 'inherit', whiteSpace: 'nowrap' };
  return (
    <React.Fragment>
      <span style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6, flexWrap: 'wrap' }}>
        {LEGAL_LINKS.map((l, i) => (
          <React.Fragment key={l.kind}>
            {i > 0 && <span aria-hidden="true" style={{ color: 'var(--fg-4)', fontSize: compact ? 11 : 11.5 }}>·</span>}
            {/* .tap-44 : 44 px de côté au moins sous 900 px de large (les trois liens
                sont alors bien séparés), texte inchangé. */}
            <button type="button" className="tap tap-44" style={linkStyle} title={l.full} onClick={() => setKind(l.kind)}>{l.label}</button>
          </React.Fragment>
        ))}
      </span>
      {kind && <LegalModal kind={kind} onClose={() => setKind(null)}/>}
    </React.Fragment>
  );
}

// ─── Avertissement trading global ────────────────────────────────────
// Texte lisible : var(--fg-3) (contraste ≥ 4,5:1) ; --fg-4 est réservé au décoratif.
function TradingDisclaimer({ compact }) {
  return (
    <div style={{ fontSize: compact ? 10.5 : 11, color: 'var(--fg-3)', lineHeight: 1.5, textAlign: 'center' }}>
      Le trading comporte un risque élevé de perte en capital. Tempo est un outil de journalisation
      et d’analyse — il ne fournit aucun conseil en investissement.
    </div>
  );
}

Object.assign(window, { LegalModal, LegalLinks, TradingDisclaimer, LEGAL_VERSION, LEGAL_CONTACT, LEGAL_IDENTITY, LEGAL_CGV });
