document.addEventListener("DOMContentLoaded", () => {
  // ================= ONBOARDING STEPS TRACKING =================
  window.completeOnboardingStep = function(stepNum) {
    let completedSteps = JSON.parse(localStorage.getItem("completedSteps")) || [];
    if (!completedSteps.includes(stepNum)) {
      completedSteps.push(stepNum);
      localStorage.setItem("completedSteps", JSON.stringify(completedSteps));
    }
    window.updateStepperDOM();
  };

  window.updateStepperDOM = function() {
    let completedSteps = JSON.parse(localStorage.getItem("completedSteps")) || [];
    completedSteps.forEach(step => {
      const stepCard = document.getElementById(`step-${step}`);
      if (stepCard) {
        stepCard.classList.add("completed");
      }
    });
    
    // Auto active next step
    for (let s = 1; s <= 5; s++) {
      const stepCard = document.getElementById(`step-${s}`);
      if (stepCard) {
        if (completedSteps.includes(s)) {
          stepCard.classList.remove("active-step");
        } else {
          stepCard.classList.add("active-step");
          break;
        }
      }
    }
  };

  // Run initial DOM update for stepper
  window.updateStepperDOM();

  // Auto detect current page load to tick steps
  if (window.location.pathname.includes("national.html")) {
    window.completeOnboardingStep(5);
  }

  // ================= GATEKEEPER LOCK SCREEN OVERLAY =================
  const isUnlocked = sessionStorage.getItem("platformUnlocked") === "true";
  
  if (!isUnlocked) {
    const overlay = document.createElement("div");
    overlay.className = "gatekeeper-overlay";
    overlay.id = "gatekeeper-overlay";
    overlay.innerHTML = `
      <div class="glass-panel gatekeeper-card">
        <svg viewBox="0 0 56 56" style="width: 48px; height: 48px; margin: 0 auto 16px; display:block;">
          <path d="M9 44 L28 26 L47 44 Z" fill="#D4AF37"/>
          <rect x="24" y="31" width="8" height="13" rx="1.4" fill="#050915"/>
          <path d="M28 7 C21 15, 19 26, 25 33 C26.5 34.6, 29.5 34.6, 31 33 C37 26, 35 15, 28 7 Z" fill="#EAD07C"/>
        </svg>
        <h2 style="font-family:'Playfair Display', serif; font-size: 1.5rem; color: var(--gold); margin-bottom: 8px;">Accès Sécurisé SCEPTRE</h2>
        <p style="font-size: 0.75rem; color: var(--text-secondary); line-height:1.4; margin-bottom:16px;">
          L'écosystème MEKTECH est verrouillé. Sélectionnez votre profil et insérez votre clé physique Sceptre ou entrez votre code PIN.
        </p>
        
        <div class="role-tabs">
          <button class="role-tab-btn active" id="role-client-btn">👤 Client / Foyer</button>
          <button class="role-tab-btn" id="role-vendeur-btn">📊 Vendeur / Marchand</button>
        </div>

        <div style="font-size:0.75rem; color:var(--text-muted); margin-bottom:10px;" id="pin-prompt-text">
          Code PIN requis (Client : 4321)
        </div>

        <div class="pin-dots">
          <div class="pin-dot"></div>
          <div class="pin-dot"></div>
          <div class="pin-dot"></div>
          <div class="pin-dot"></div>
        </div>

        <div class="pin-grid">
          <button class="pin-btn">1</button>
          <button class="pin-btn">2</button>
          <button class="pin-btn">3</button>
          <button class="pin-btn">4</button>
          <button class="pin-btn">5</button>
          <button class="pin-btn">6</button>
          <button class="pin-btn">7</button>
          <button class="pin-btn">8</button>
          <button class="pin-btn">9</button>
          <button class="pin-btn" style="font-size:0.75rem; color:var(--crimson);">Effacer</button>
          <button class="pin-btn">0</button>
          <button class="pin-btn" style="font-size:0.75rem; color:var(--emerald);">Valider</button>
        </div>

        <div style="margin-top: 20px; border-top:1px solid rgba(255,255,255,0.05); padding-top:16px;">
          <button class="canto-btn" id="sceptre-mock-plug-btn" style="width:100%; font-size:0.75rem;">
            🔌 Simuler l'insertion de la Clé Sceptre
          </button>
        </div>
      </div>
    `;
    document.body.appendChild(overlay);

    let enteredPin = "";
    let selectedRole = "client";
    const dots = overlay.querySelectorAll(".pin-dot");
    const pinPrompt = overlay.querySelector("#pin-prompt-text");
    const clientBtn = overlay.querySelector("#role-client-btn");
    const vendeurBtn = overlay.querySelector("#role-vendeur-btn");

    clientBtn.onclick = () => {
      selectedRole = "client";
      clientBtn.classList.add("active");
      vendeurBtn.classList.remove("active");
      pinPrompt.textContent = "Code PIN requis (Client : 4321)";
      enteredPin = "";
      updateDots();
    };

    vendeurBtn.onclick = () => {
      selectedRole = "vendeur";
      vendeurBtn.classList.add("active");
      clientBtn.classList.remove("active");
      pinPrompt.textContent = "Code PIN requis (Vendeur : 1234)";
      enteredPin = "";
      updateDots();
    };

    function updateDots() {
      dots.forEach((dot, index) => {
        if (index < enteredPin.length) {
          dot.classList.add("filled");
        } else {
          dot.classList.remove("filled");
        }
      });
    }

    const pinButtons = overlay.querySelectorAll(".pin-grid button");
    pinButtons.forEach(btn => {
      btn.onclick = () => {
        const val = btn.textContent;
        if (val === "Effacer") {
          enteredPin = "";
          updateDots();
        } else if (val === "Valider") {
          validatePin();
        } else if (enteredPin.length < 4) {
          enteredPin += val;
          updateDots();
          if (enteredPin.length === 4) {
            setTimeout(validatePin, 150);
          }
        }
      };
    });

    overlay.querySelector("#sceptre-mock-plug-btn").onclick = () => {
      alert("🔌 Clé physique SCEPTRE détectée (FIDO2) ! Signature cryptographique validée.");
      unlock(selectedRole);
    };

    function validatePin() {
      if (selectedRole === "client" && enteredPin === "4321") {
        unlock("client");
      } else if (selectedRole === "vendeur" && enteredPin === "1234") {
        unlock("vendeur");
      } else {
        alert("❌ Code PIN incorrect. Veuillez réessayer.");
        enteredPin = "";
        updateDots();
      }
    }

    function unlock(role) {
      sessionStorage.setItem("platformUnlocked", "true");
      sessionStorage.setItem("userRole", role);
      overlay.style.opacity = "0";
      setTimeout(() => {
        overlay.remove();
        if (window.location.pathname.includes("roc.html")) {
          const clientViewBtn = document.querySelector('[data-roc-view="client"]');
          const businessViewBtn = document.querySelector('[data-roc-view="business"]');
          if (role === "client" && clientViewBtn) {
            clientViewBtn.click();
          } else if (role === "vendeur" && businessViewBtn) {
            businessViewBtn.click();
          }
        }
        window.completeOnboardingStep(1);
      }, 500);
    }
  }

  // ================= PLATFORM TABS SWITCHING & HASH ROUTING =================
  const tabButtons = document.querySelectorAll(".platform-tab-btn");
  const platformViews = document.querySelectorAll(".platform-view");

  function switchTab(platformId) {
    // Hide all views, deactivate all buttons
    platformViews.forEach(v => v.classList.remove("active"));
    tabButtons.forEach(b => b.classList.remove("active"));

    // Activate the targeted view & tab button
    const targetView = document.getElementById(`view-${platformId}`);
    const targetBtn = document.querySelector(`.platform-tab-btn[data-platform="${platformId}"]`);

    if (targetView) targetView.classList.add("active");
    if (targetBtn) targetBtn.classList.add("active");

    // Complete onboarding steps based on tab opened
    if (platformId === "canto" && window.completeOnboardingStep) {
      window.completeOnboardingStep(2);
    } else if (platformId === "egide" && window.completeOnboardingStep) {
      window.completeOnboardingStep(3);
    }

    // Sync window hash if applicable
    if (platformId !== "accueil") {
      window.location.hash = `view-${platformId}`;
    } else {
      history.replaceState(null, null, ' ');
    }
  }

  // Bind header tab button clicks
  tabButtons.forEach(btn => {
    btn.addEventListener("click", () => {
      const platform = btn.getAttribute("data-platform");
      if (platform) {
        switchTab(platform);
      }
    });
  });

  // Bind showcase "Ouvrir" CTA buttons
  document.querySelectorAll("[data-go-platform]").forEach(btn => {
    btn.addEventListener("click", () => {
      const platform = btn.getAttribute("data-go-platform");
      if (platform) {
        switchTab(platform);
        window.scrollTo({ top: 0, behavior: 'smooth' });
      }
    });
  });

  // Parse URL hash on load
  function handleHashRoute() {
    const hash = window.location.hash;
    if (hash.startsWith("#view-")) {
      const platformId = hash.replace("#view-", "");
      switchTab(platformId);
    }
  }
  handleHashRoute();
  window.addEventListener("hashchange", handleHashRoute);


  // ================= L'ÉGIDE INTERACTIVE SIMULATION =================
  // Subview switching
  const egideMenuBtns = document.querySelectorAll(".egide-menu-btn");
  const egideViews = document.querySelectorAll(".egide-view");

  egideMenuBtns.forEach(btn => {
    btn.addEventListener("click", () => {
      const targetSub = btn.getAttribute("data-egide-view");
      if (!targetSub) return;

      egideMenuBtns.forEach(b => b.classList.remove("active"));
      egideViews.forEach(v => v.classList.remove("active"));

      btn.classList.add("active");
      const activeSubView = document.getElementById(`egide-view-${targetSub}`);
      if (activeSubView) activeSubView.classList.add("active");
    });
  });

  // Feed Simulation
  const feedInput = document.getElementById("feed-post-input");
  const feedSubmit = document.getElementById("feed-post-submit");
  const feedContainer = document.getElementById("feed-posts-container");

  let initialPosts = [
    { author: "Kojo Mensah", tag: "Security Expert", time: "Il y a 2 heures", content: "Nos audits matériels sur la clé SCEPTRE sont finalisés. Le micrologiciel est 100% auditable et certifié zéro backdoor. Un pas de plus vers la souveraineté !", badge: "badge-gold" },
    { author: "Fondation Hiraande", tag: "Fondation éthique", time: "Il y a 5 heures", content: "Les premiers reversements de 15% issus des ventes de cours de Langues Rares sur CANTO ont été alloués à la numérisation des contes oraux en Casamance. Merci pour vos contributions !", badge: "badge-emerald" },
    { author: "Sokhna Diallo", tag: "Validateur", time: "Il y a 1 jour", content: "Alerte : Une campagne de phishing usurpant l'identité de banques locales a été détectée. N'ouvrez aucun lien non audité par L'Égide.", tagColor: "badge-crimson" }
  ];

  function renderFeedPosts() {
    if (!feedContainer) return;
    feedContainer.innerHTML = "";
    initialPosts.forEach(post => {
      const card = document.createElement("div");
      card.className = "glass-panel";
      card.style.padding = "20px";
      card.style.background = "rgba(10,17,40,0.4)";
      card.innerHTML = `
        <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:12px">
          <div>
            <strong style="color:#fff; font-size:0.9rem">${post.author}</strong>
            <span class="badge-tag ${post.badge || 'badge-blue'}" style="font-size:0.65rem; margin-left:8px; padding:2px 8px">${post.tag}</span>
          </div>
          <span style="font-size:0.7rem; color:var(--text-muted)">${post.time}</span>
        </div>
        <p style="font-size:0.8rem; color:var(--text-secondary); line-height:1.5">${post.content}</p>
      `;
      feedContainer.appendChild(card);
    });
  }
  renderFeedPosts();

  if (feedSubmit && feedInput) {
    feedSubmit.addEventListener("click", () => {
      const content = feedInput.value.trim();
      if (!content) return;

      initialPosts.unshift({
        author: "Vous (Souverain)",
        tag: "Membre Actif",
        time: "À l'instant",
        content: content,
        badge: "badge-gold"
      });

      feedInput.value = "";
      renderFeedPosts();
    });
  }

  // Circle Chat simulation
  const circleRoomBtns = document.querySelectorAll(".circle-room-btn");
  const circleTitle = document.getElementById("circle-header-title");
  const circleMeta = document.getElementById("circle-header-meta");
  const circleMessages = document.getElementById("circle-messages-container");
  const circleTextarea = document.getElementById("circle-chat-textarea");
  const circleSend = document.getElementById("circle-chat-send");
  const anxietyPrompt = document.getElementById("circle-anxiety-prompt");
  const anxietyBtn = document.getElementById("circle-anxiety-btn");

  let chatRooms = {
    deepfakes: {
      title: "Vigilance Deepfakes & Audio",
      meta: "4 modérateurs · 24 veilleurs actifs",
      messages: [
        { author: "Moussa Diouf", text: "Attention, j'ai vu passer une vidéo truquée du maire de Dakar. C'est fait avec un clone vocal de mauvaise qualité.", time: "14:15", avatar: "MD", class: "" },
        { author: "Aminata", text: "Merci de l'alerte ! Je lance le scan local de la vidéo pour confirmer les signatures d'IA.", time: "14:17", avatar: "AM", class: "" }
      ]
    },
    aiact: {
      title: "Conformité Règlementaire & AI Act",
      meta: "2 conseillers · 15 juristes actifs",
      messages: [
        { author: "Kojo Mensah", text: "Quelles sont les obligations de conformité pour nos modèles locaux d'Afrique de l'Ouest sous l'AI Act européen ?", time: "11:20", avatar: "KM", class: "" },
        { author: "Sokhna", text: "Si le modèle n'est pas déployé sur le marché européen, nous sommes 100% autonomes. Le droit OHADA prévaudra bientôt.", time: "11:32", avatar: "SO", class: "" }
      ]
    }
  };
  let currentCircleRoom = "deepfakes";

  function renderCircleMessages() {
    if (!circleMessages) return;
    circleMessages.innerHTML = "";
    const room = chatRooms[currentCircleRoom];
    room.messages.forEach(m => {
      const bubble = document.createElement("div");
      bubble.className = `msg-bubble ${m.class}`;
      
      const avatarHtml = m.class === "user" ? "" : `
        <div class="msg-avatar" style="background:${m.avatar === 'IA' ? 'var(--gold-dark)' : 'rgba(212,175,55,0.2)'}">
          ${m.avatar}
        </div>
      `;

      bubble.innerHTML = `
        ${avatarHtml}
        <div class="msg-content-wrapper">
          <div class="msg-meta" style="${m.class === 'user' ? 'text-align:right' : ''}">
            ${m.class === 'user' ? '' : `<strong>${m.author}</strong> — `}${m.time}
          </div>
          <div class="msg-body">${m.text}</div>
        </div>
      `;
      circleMessages.appendChild(bubble);
    });
    circleMessages.scrollTop = circleMessages.scrollHeight;
  }
  renderCircleMessages();

  circleRoomBtns.forEach(btn => {
    btn.addEventListener("click", () => {
      circleRoomBtns.forEach(b => b.classList.remove("active"));
      btn.classList.add("active");
      
      const roomKey = btn.getAttribute("data-circle");
      if (roomKey && chatRooms[roomKey]) {
        currentCircleRoom = roomKey;
        circleTitle.textContent = chatRooms[roomKey].title;
        circleMeta.textContent = chatRooms[roomKey].meta;
        renderCircleMessages();
      }
    });
  });

  // Anxiety detector simulation
  if (circleTextarea) {
    circleTextarea.addEventListener("input", () => {
      const val = circleTextarea.value.toLowerCase();
      const anxiousWords = ["peur", "panique", "voler", "pirate", "hacker", "anxieux", "danger", "urgence", "volé"];
      const containsAnxious = anxiousWords.some(w => val.includes(w));
      if (containsAnxious) {
        anxietyPrompt.style.display = "flex";
      } else {
        anxietyPrompt.style.display = "none";
      }
    });
  }

  if (anxietyBtn && circleTextarea) {
    anxietyBtn.addEventListener("click", () => {
      circleTextarea.value = "Je constate une anomalie suspecte et je souhaiterais procéder calmement à une vérification de sécurité sur ce lien.";
      anxietyPrompt.style.display = "none";
      circleTextarea.focus();
    });
  }

  // Send message inside Circle Chat
  if (circleSend && circleTextarea) {
    circleSend.addEventListener("click", () => {
      const text = circleTextarea.value.trim();
      if (!text) return;

      const now = new Date();
      const timeStr = now.getHours().toString().padStart(2, '0') + ":" + now.getMinutes().toString().padStart(2, '0');

      chatRooms[currentCircleRoom].messages.push({
        author: "Vous",
        text: text,
        time: timeStr,
        avatar: "ME",
        class: "user"
      });

      circleTextarea.value = "";
      anxietyPrompt.style.display = "none";
      renderCircleMessages();

      // Trigger automatic AI companion response
      setTimeout(() => {
        const room = chatRooms[currentCircleRoom];
        let reply = "Message reçu dans le cercle sécurisé. Les validateurs d'identité analysent la signature de cette information.";
        if (currentCircleRoom === "deepfakes") {
          reply = "L'outil de détection locale a été alerté. Vous pouvez exécuter un Scan Vidéo dans le menu de gauche pour analyser le fichier.";
        } else if (currentCircleRoom === "aiact") {
          reply = "Rappel juridique : la souveraineté numérique locale passe par l'exécution de conteneurs IA hors de portée du Cloud Act.";
        }

        room.messages.push({
          author: "Compagnon Vigilance",
          text: reply,
          time: timeStr,
          avatar: "IA",
          class: ""
        });
        renderCircleMessages();
      }, 1500);
    });
  }

  // L'Égide Modals simulation
  function setupModal(triggerSelector, modalId, closeId, submitFormId, resultId, processFn) {
    const triggers = document.querySelectorAll(triggerSelector);
    const modal = document.getElementById(modalId);
    const close = document.getElementById(closeId);
    const form = document.getElementById(submitFormId);
    const result = document.getElementById(resultId);

    if (!modal) return;

    triggers.forEach(t => {
      t.addEventListener("click", () => {
        modal.style.display = "flex";
        if (result) result.style.display = "none";
        if (form) form.reset();
      });
    });

    if (close) {
      close.addEventListener("click", () => {
        modal.style.display = "none";
      });
    }

    if (form) {
      form.addEventListener("submit", (e) => {
        e.preventDefault();
        const submitBtn = form.querySelector('button[type="submit"]');
        const originalText = submitBtn.textContent;
        submitBtn.disabled = true;
        submitBtn.textContent = "Analyse en cours...";

        setTimeout(() => {
          submitBtn.disabled = false;
          submitBtn.textContent = originalText;
          if (result) {
            result.style.display = "block";
            if (processFn) processFn(result);
          }
        }, 2000);
      });
    }
  }

  setupModal(".btn-open-detector", "modal-detector", "modal-detector-close", "detector-form", "detector-result");
  setupModal(".btn-open-auditor", "modal-auditor", "modal-auditor-close", "auditor-form", "auditor-result");

  // Summary AI modal
  const summaryTrigger = document.querySelector(".btn-open-summary");
  const summaryModal = document.getElementById("modal-summary");
  const summaryClose = document.getElementById("modal-summary-close");
  const summaryText = document.getElementById("summary-text");

  if (summaryTrigger && summaryModal) {
    summaryTrigger.addEventListener("click", () => {
      summaryModal.style.display = "flex";
      if (summaryText) {
        summaryText.innerHTML = "<li style='color:var(--text-muted)'>Calcul de la synthèse en cours...</li>";
        setTimeout(() => {
          summaryText.innerHTML = `
            <li><strong>Clé SCEPTRE :</strong> Discussions intenses autour des spécifications du micrologiciel et de sa transparence cryptographique.</li>
            <li><strong>Deepfakes :</strong> Un signalement de contrefaçon vocale sur un média local a fait l'objet d'un audit collectif.</li>
            <li><strong>AI Act :</strong> Alignement général des participants sur le fait que la réglementation africaine émergente doit exclure les licences propriétaires étrangères.</li>
          `;
        }, 1500);
      }
    });
  }
  if (summaryClose) {
    summaryClose.addEventListener("click", () => {
      summaryModal.style.display = "none";
    });
  }

  // Market Buy & Checkout modal
  const buyBtns = document.querySelectorAll(".market-buy-btn");
  const checkoutModal = document.getElementById("modal-checkout");
  const checkoutClose = document.getElementById("modal-checkout-close");
  const checkoutTitle = document.getElementById("checkout-title");
  const checkoutPrice = document.getElementById("checkout-price");
  const checkoutForm = document.querySelector("#modal-checkout form");

  buyBtns.forEach(btn => {
    btn.addEventListener("click", () => {
      const title = btn.getAttribute("data-title");
      let price = btn.getAttribute("data-price");
      
      // Apply Égide Pro beta-tester discount on checkout
      if (title === "Abonnement Égide Pro") {
        const spots = parseInt(localStorage.getItem("egideBetaSpots") || "1126");
        const isWave1 = spots > 0;
        const discount = isWave1 ? 15 : 14;
        const finalPrice = 19 * (1 - discount / 100);
        price = `${finalPrice.toFixed(2).replace(".", ",")} € / mois`;
        alert(`🎁 Offre Bêta-testeur appliquée : −${discount}% de remise à vie sur L'Égide Pro ! Tarif : ${price}`);
      }
      
      if (checkoutTitle) checkoutTitle.textContent = title;
      if (checkoutPrice) checkoutPrice.textContent = price;
      if (checkoutModal) checkoutModal.style.display = "flex";
    });
  });

  if (checkoutClose) {
    checkoutClose.addEventListener("click", () => {
      checkoutModal.style.display = "none";
    });
  }

  // Helper to process successful payments and update ROC merchant KPIs
  function handleSuccessfulPayment(priceStr, titleStr) {
    const priceNum = parseFloat(priceStr.replace(/[^0-9.]/g, '')) || 0.00;
    
    // Deduct ROC Platform Commission (4% standard, 3% if account has 2+ years of seniority)
    const yearsActive = parseInt(localStorage.getItem("rocYearsActive") || "0");
    const commissionRate = yearsActive >= 2 ? 0.03 : 0.04;
    const commissionAmount = priceNum * commissionRate;
    const netAmount = priceNum - commissionAmount;
    
    // Add net amount to balance
    let balance = parseFloat(localStorage.getItem("rocBalance") || "0.00");
    balance += netAmount;
    localStorage.setItem("rocBalance", balance.toFixed(2));
    
    // Check if it's a subscription to increment subscribers
    const titleLower = titleStr.toLowerCase();
    const isSub = titleLower.includes("abonnement") || titleLower.includes("canto") || titleLower.includes("égide");
    
    if (isSub) {
      let subs = parseInt(localStorage.getItem("rocSubscribers") || "0");
      subs += 1;
      localStorage.setItem("rocSubscribers", subs.toString());
    }
    
    // Sync balance display in DOM
    const stripeBalanceAmount = document.getElementById("roc-stripe-balance-amount");
    if (stripeBalanceAmount) {
      stripeBalanceAmount.textContent = balance.toFixed(2).replace(".", ",") + " €";
    }
    
    // Sync onboarding stepper
    if (window.completeOnboardingStep) {
      window.completeOnboardingStep(4);
    }
    
    calculateRocStats();
  }

  if (checkoutForm) {
    checkoutForm.addEventListener("submit", (e) => {
      e.preventDefault();
      const emailInput = document.getElementById("checkout-email");
      const email = emailInput ? emailInput.value : "";
      if (!email) {
        alert("Veuillez saisir votre adresse e-mail.");
        return;
      }

      const payBtn = document.getElementById("checkout-pay-btn");
      const originalText = payBtn ? payBtn.textContent : "Confirmer le paiement Stripe";

      if (payBtn) {
        payBtn.disabled = true;
        payBtn.textContent = "🔒 Chiffrement SSL 256 bits...";
      }

      setTimeout(() => {
        if (payBtn) payBtn.textContent = "⚡ Validation 3D Secure...";
        setTimeout(() => {
          alert(`Paiement de ${checkoutPrice.textContent} validé par Stripe pour "${checkoutTitle.textContent}". Un e-mail de confirmation et votre reçu ont été envoyés à : ${email}.`);
          if (payBtn) {
            payBtn.disabled = false;
            payBtn.textContent = originalText;
          }
          if (checkoutModal) checkoutModal.style.display = "none";
          handleSuccessfulPayment(checkoutPrice.textContent, checkoutTitle.textContent);
        }, 1500);
      }, 1500);
    });
  }

  const gpayBtn = document.getElementById("checkout-gpay-btn");
  if (gpayBtn) {
    gpayBtn.addEventListener("click", () => {
      gpayBtn.disabled = true;
      const originalText = gpayBtn.innerHTML;
      gpayBtn.textContent = "⌛ Appel de Google Pay...";
      setTimeout(() => {
        const pStr = checkoutPrice ? checkoutPrice.textContent : "45 €";
        const tStr = checkoutTitle ? checkoutTitle.textContent : "Clé Physique SCEPTRE";
        alert(`Paiement de ${pStr} par Google Pay validé avec succès pour "${tStr}".`);
        gpayBtn.disabled = false;
        gpayBtn.innerHTML = originalText;
        if (checkoutModal) checkoutModal.style.display = "none";
        handleSuccessfulPayment(pStr, tStr);
      }, 1500);
    });
  }


  // ================= ROC INTERACTIVE SIMULATION (UNIFIED FOR PORTAL & ROC.HTML) =================
  
  // 1. Sidebar tab switching in roc.html
  const rocMenuBtns = document.querySelectorAll(".roc-menu-btn");
  const rocViews = document.querySelectorAll(".roc-view");

  rocMenuBtns.forEach(btn => {
    btn.addEventListener("click", () => {
      const targetSub = btn.getAttribute("data-roc-view");
      if (!targetSub) return;

      rocMenuBtns.forEach(b => b.classList.remove("active"));
      rocViews.forEach(v => v.classList.remove("active"));

      btn.classList.add("active");
      const activeSubView = document.getElementById(`roc-view-${targetSub}`);
      if (activeSubView) activeSubView.classList.add("active");
    });
  });

  // 2. Shared Merchant stats & products catalogue
  let rocProducts = JSON.parse(localStorage.getItem("rocProducts")) || [
    { title: "Clé Physique SCEPTRE", category: "Hardware", billing: "Achat unique", price: 45, status: "Actif" },
    { title: "Abonnement Égide Pro", category: "IA / SaaS", billing: "Abonnement Mensuel", price: 19, status: "Actif" },
    { title: "Souverain CANTO Langues", category: "API", billing: "Abonnement Mensuel", price: 9.99, status: "Actif" }
  ];

  // Bind ROC account seniority selector
  const rocYearsSelect = document.getElementById("roc-years-active-select");
  if (rocYearsSelect) {
    rocYearsSelect.value = localStorage.getItem("rocYearsActive") || "0";
    rocYearsSelect.addEventListener("change", () => {
      localStorage.setItem("rocYearsActive", rocYearsSelect.value);
      alert(`Ancienneté du compte ROC mise à jour. Prochaine commission de transaction Stripe : ${rocYearsSelect.value >= 2 ? "3%" : "4%"}`);
    });
  }

  const rocMRR = document.getElementById("roc-stat-mrr") || document.getElementById("roc-merchant-mrr");
  const rocARR = document.getElementById("roc-stat-arr") || document.getElementById("roc-merchant-arr");
  const rocCount = document.getElementById("roc-stat-count") || document.getElementById("roc-merchant-count");
  const rocTableBody = document.getElementById("roc-products-tbody") || document.getElementById("roc-merchant-products-tbody");
  const rocForm = document.getElementById("roc-add-product-form") || document.getElementById("roc-merchant-add-product-form");

  // Load balance at load
  const stripeBalanceAmount = document.getElementById("roc-stripe-balance-amount");
  if (stripeBalanceAmount) {
    const balanceVal = parseFloat(localStorage.getItem("rocBalance") || "0.00");
    stripeBalanceAmount.textContent = balanceVal.toFixed(2).replace(".", ",") + " €";
  }

  function calculateRocStats() {
    let mrr = 0;
    rocProducts.forEach(p => {
      if (p.billing.includes("Abonnement")) {
        mrr += p.price;
      }
    });

    const activeSubs = parseInt(localStorage.getItem("rocSubscribers") || "0");
    const totalMRR = mrr * activeSubs;
    const totalARR = totalMRR * 12;

    if (rocMRR) rocMRR.innerHTML = `${totalMRR.toLocaleString('fr-FR')} <span>€</span>`;
    if (rocARR) rocARR.innerHTML = `${totalARR.toLocaleString('fr-FR')} <span>€</span>`;
    if (rocCount) rocCount.innerHTML = `${rocProducts.length} <span>Offres</span>`;
  }

  function renderRocTable() {
    if (!rocTableBody) return;
    rocTableBody.innerHTML = "";
    rocProducts.forEach(p => {
      const tr = document.createElement("tr");
      tr.innerHTML = `
        <td><strong>${p.title}</strong></td>
        <td><span class="badge-tag badge-blue" style="font-size:0.65rem">${p.category}</span></td>
        <td>${p.billing}</td>
        <td style="color:var(--gold-light)">${p.price.toFixed(2)} €</td>
        <td><span class="badge-tag badge-emerald">${p.status}</span></td>
      `;
      rocTableBody.appendChild(tr);
    });
  }

  calculateRocStats();
  renderRocTable();

  // Handle Offer Creation Form
  if (rocForm) {
    rocForm.addEventListener("submit", (e) => {
      e.preventDefault();
      
      const titleInput = document.getElementById("roc-prod-title") || document.getElementById("roc-m-prod-title");
      const categoryInput = document.getElementById("roc-prod-category") || document.getElementById("roc-m-prod-category");
      const billingInput = document.getElementById("roc-prod-billing") || document.getElementById("roc-m-prod-billing");
      const priceInput = document.getElementById("roc-prod-price") || document.getElementById("roc-m-prod-price");

      if (!titleInput || !categoryInput || !billingInput || !priceInput) return;

      const title = titleInput.value;
      const category = categoryInput.value;
      const billingVal = billingInput.value;
      const price = parseFloat(priceInput.value);

      const billing = billingVal === "recurrent" ? "Abonnement Mensuel" : "Achat unique";

      rocProducts.unshift({
        title,
        category,
        billing,
        price,
        status: "Actif"
      });

      localStorage.setItem("rocProducts", JSON.stringify(rocProducts));
      rocForm.reset();
      calculateRocStats();
      renderRocTable();
      populateProductSelect();

      alert(`Félicitations ! L'offre "${title}" a été publiée avec succès sur votre grand livre de ventes ROC.`);
    });
  }

  // 3. Stripe Onboarding Connect Express Simulation
  const stripeOnboardBtn = document.getElementById("roc-stripe-onboard-btn") || document.getElementById("roc-stripe-m-onboard-btn");
  const stripeProgressFill = document.getElementById("roc-stripe-progress-fill") || document.getElementById("roc-stripe-m-progress-fill");
  const stripeStepText = document.getElementById("roc-stripe-step-text") || document.getElementById("roc-stripe-m-step-text");
  const stripeBadge = document.getElementById("roc-stripe-status-badge") || document.getElementById("roc-stripe-m-status-badge");

  let stripeStep = 1;
  if (stripeOnboardBtn) {
    stripeOnboardBtn.addEventListener("click", () => {
      if (stripeStep === 1) {
        if (stripeProgressFill) stripeProgressFill.style.width = "60%";
        if (stripeStepText) stripeStepText.textContent = "Étape 2 / 3 : Liaison de votre IBAN et vérification d'identité.";
        stripeOnboardBtn.textContent = "Vérifier mon identité & IBAN";
        stripeStep = 2;
      } else if (stripeStep === 2) {
        if (stripeProgressFill) stripeProgressFill.style.width = "85%";
        if (stripeStepText) stripeStepText.textContent = "Étape 3 / 3 : Finalisation de la signature électronique.";
        stripeOnboardBtn.textContent = "Signer la convention de vente";
        stripeStep = 3;
      } else if (stripeStep === 3) {
        if (stripeProgressFill) stripeProgressFill.style.width = "100%";
        if (stripeStepText) stripeStepText.textContent = "Compte Stripe Express lié avec succès. Vous pouvez maintenant recevoir vos fonds.";
        if (stripeBadge) {
          stripeBadge.className = "badge-tag badge-emerald";
          stripeBadge.textContent = "Connecté";
        }
        stripeOnboardBtn.style.display = "none";
        alert("Félicitations ! Votre compte bancaire est connecté avec succès via Stripe Express.");
      }
    });
  }

  // 4. Dify AI translation panel simulation connected to real local Ollama
  const aiBtn = document.getElementById("roc-ai-btn") || document.getElementById("roc-ai-main-btn");
  const aiTextarea = document.getElementById("roc-ai-textarea") || document.getElementById("roc-ai-main-textarea");
  const aiConsole = document.getElementById("roc-ai-console") || document.getElementById("roc-ai-main-console");

  if (aiBtn && aiTextarea && aiConsole) {
    aiBtn.addEventListener("click", async () => {
      const text = aiTextarea.value.trim();
      if (!text) {
        alert("Veuillez saisir une description de produit.");
        return;
      }

      aiConsole.innerHTML = "<p style='color:var(--gold-light)'>[Ollama local host] Connexion au modèle souverain en cours...</p>";
      aiBtn.disabled = true;

      try {
        const response = await fetch("/api/roc/ai", {
          method: "POST",
          headers: {
            "Content-Type": "application/json"
          },
          body: JSON.stringify({ prompt: text })
        });

        if (!response.ok) {
          throw new Error(`Erreur API: ${response.statusText}`);
        }

        const data = await response.json();
        
        aiConsole.innerHTML = `
          <div style="background:rgba(255,255,255,0.03); border:1px solid var(--border-color); border-radius:8px; padding:12px; font-family:monospace; font-size:0.75rem; text-align:left; margin-top:8px">
            <span style="color:var(--emerald)">✓ SEO Titre :</span> ${data.title || "Titre généré"}<br>
            <span style="color:var(--emerald)">✓ SEO Description :</span> ${data.description || "Description générée"}<br>
            <span style="color:var(--gold)">✓ Mots-clés suggérés :</span> ${data.keywords || "souverain, sécurité, local-ia"}
          </div>
        `;
      } catch (err) {
        console.error("Erreur IA Ollama:", err);
        aiConsole.innerHTML += "<p style='color:var(--crimson)'>[Erreur] Modèle occupé ou inaccessible. Utilisation du fallback local...</p>";
        setTimeout(() => {
          aiConsole.innerHTML = `
            <div style="background:rgba(255,255,255,0.03); border:1px solid var(--border-color); border-radius:8px; padding:12px; font-family:monospace; font-size:0.75rem; text-align:left; margin-top:8px">
              <span style="color:var(--emerald)">✓ SEO Titre :</span> ${text.slice(0, 30)} — Sécurité Matérielle Souveraine<br>
              <span style="color:var(--emerald)">✓ SEO Description :</span> Achetez le produit "${text}". Conçu pour être GAFAM-Free et hautement sécurisé.<br>
              <span style="color:var(--gold)">✓ Mots-clés suggérés :</span> souveraineté, sécurité, hardware open-source, crypto, zero-backdoor
            </div>
          `;
        }, 1500);
      } finally {
        aiBtn.disabled = false;
      }
    });
  }

  // 5. Payment Link Generator
  const linkGenForm = document.getElementById("roc-link-generator-form");
  const genProductSelect = document.getElementById("roc-gen-product");
  const genLinkBox = document.getElementById("roc-generated-link-box");
  const paymentUrl = document.getElementById("roc-payment-url");
  const checkoutTrigger = document.getElementById("roc-checkout-trigger-btn");

  function populateProductSelect() {
    if (!genProductSelect) return;
    genProductSelect.innerHTML = "";
    rocProducts.forEach(p => {
      const opt = document.createElement("option");
      opt.value = p.title;
      opt.textContent = `${p.title} (${p.price.toFixed(2)} €)`;
      genProductSelect.appendChild(opt);
    });
  }

  if (linkGenForm) {
    populateProductSelect();
    linkGenForm.addEventListener("submit", (e) => {
      e.preventDefault();
      const productTitle = genProductSelect.value;
      const clientName = document.getElementById("roc-gen-client").value;
      const selectedProd = rocProducts.find(p => p.title === productTitle);
      
      if (selectedProd && genLinkBox && paymentUrl) {
        genLinkBox.style.display = "block";
        const cleanTitle = encodeURIComponent(selectedProd.title.replace(/\s+/g, '-').toLowerCase());
        paymentUrl.textContent = `https://checkout.stripe.com/pay/roc_${cleanTitle}_live_key`;
        paymentUrl.setAttribute("data-price", selectedProd.price.toFixed(2) + " €");
        paymentUrl.setAttribute("data-title", selectedProd.title);
      }
    });
  }

  if (checkoutTrigger && paymentUrl) {
    checkoutTrigger.addEventListener("click", () => {
      const title = paymentUrl.getAttribute("data-title");
      const price = paymentUrl.getAttribute("data-price");
      
      const modal = document.getElementById("modal-checkout");
      const modalTitle = document.getElementById("checkout-title");
      const modalPrice = document.getElementById("checkout-price");
      
      if (modal && modalTitle && modalPrice) {
        modalTitle.textContent = title;
        modalPrice.textContent = price;
        modal.style.display = "flex";
      }
    });
  }

  // 6. Client Portal: Mektech Famille Device controller simulation
  const rebootFamilleBtn = document.getElementById("btn-famille-reboot");
  const backupFamilleBtn = document.getElementById("btn-famille-backup");
  const ipFamilleText = document.getElementById("device-famille-ip");
  const cpuFamilleText = document.getElementById("device-famille-cpu");
  const dotFamilleStatus = document.getElementById("device-famille-status-dot");
  const textFamilleStatus = document.getElementById("device-famille-status-text");
  const voiceProfileSelect = document.getElementById("device-famille-voice-profile");

  if (rebootFamilleBtn) {
    rebootFamilleBtn.addEventListener("click", () => {
      rebootFamilleBtn.disabled = true;
      rebootFamilleBtn.textContent = "Redémarrage...";
      if (dotFamilleStatus) dotFamilleStatus.className = "status-dot offline";
      if (textFamilleStatus) {
        textFamilleStatus.style.color = "var(--crimson)";
        textFamilleStatus.textContent = "HORS LIGNE";
      }
      if (cpuFamilleText) cpuFamilleText.textContent = "0.0 %";

      setTimeout(() => {
        rebootFamilleBtn.disabled = false;
        rebootFamilleBtn.textContent = "Redémarrer";
        if (dotFamilleStatus) dotFamilleStatus.className = "status-dot online";
        if (textFamilleStatus) {
          textFamilleStatus.style.color = "var(--emerald)";
          textFamilleStatus.textContent = "EN LIGNE";
        }
        if (cpuFamilleText) cpuFamilleText.textContent = "1.8 %";
        alert("L'assistant local Mektech Famille a redémarré avec succès en mode autonome.");
      }, 2500);
    });
  }

  if (backupFamilleBtn) {
    backupFamilleBtn.addEventListener("click", () => {
      backupFamilleBtn.disabled = true;
      backupFamilleBtn.textContent = "Sauvegarde...";
      setTimeout(() => {
        backupFamilleBtn.disabled = false;
        backupFamilleBtn.textContent = "Sauvegarder";
        alert("Sauvegarde chiffrée de la base vocale Mektech Famille effectuée avec succès.");
      }, 1500);
    });
  }

  if (voiceProfileSelect) {
    voiceProfileSelect.addEventListener("change", () => {
      const val = voiceProfileSelect.value;
      if (val === "enfants") {
        if (cpuFamilleText) cpuFamilleText.textContent = "1.5 %";
        alert("Mode vocal basculé : Profil vocal enfants actif. Filtre parental activé.");
      } else if (val === "famille") {
        if (cpuFamilleText) cpuFamilleText.textContent = "3.8 %";
        alert("Mode vocal basculé : Profil parents actif.");
      } else if (val === "invite") {
        if (cpuFamilleText) cpuFamilleText.textContent = "2.1 %";
        alert("Mode vocal basculé : Profil invité actif.");
      }
    });
  }

  // 7. Client Portal: Sceptre keys management simulation
  let sceptreKeys = JSON.parse(localStorage.getItem("sceptreKeys")) || [
    { id: 1, sn: "SCEPTRE-992A-881", status: "Active", lastAuth: "Il y a 10 min" },
    { id: 2, sn: "SCEPTRE-114B-559", status: "Active", lastAuth: "Hier à 18:30" }
  ];

  const sceptreKeysCount = document.getElementById("sceptre-keys-count");
  const sceptreKeysContainer = document.getElementById("sceptre-keys-container");
  const btnSceptreRegister = document.getElementById("btn-sceptre-register");
  const btnSceptreBackup = document.getElementById("btn-sceptre-backup");

  function renderSceptreKeys() {
    if (!sceptreKeysContainer) return;
    sceptreKeysContainer.innerHTML = "";
    sceptreKeys.forEach(k => {
      const div = document.createElement("div");
      div.style.display = "flex";
      div.style.justifyContent = "space-between";
      div.style.alignItems = "center";
      div.style.background = "rgba(0,0,0,0.2)";
      div.style.padding = "10px 14px";
      div.style.borderRadius = "8px";
      div.style.border = "1px solid rgba(255,255,255,0.03)";
      div.innerHTML = `
        <div>
          <span style="font-size:0.8rem; font-weight:700; color:#fff">Clé Sceptre n°${k.id}</span>
          <span style="font-size:0.65rem; color:var(--text-muted); display:block; font-family:monospace; margin-top:2px;">SN: ${k.sn}</span>
        </div>
        <div style="text-align:right">
          <span class="badge-tag ${k.status === 'Active' ? 'badge-emerald' : 'badge-crimson'}" style="font-size:0.6rem; padding:2px 6px;">${k.status}</span>
          <span style="font-size:0.65rem; color:var(--text-muted); display:block; margin-top:4px;">${k.lastAuth}</span>
        </div>
      `;
      sceptreKeysContainer.appendChild(div);
    });

    if (sceptreKeysCount) {
      sceptreKeysCount.textContent = `${sceptreKeys.length} Clé` + (sceptreKeys.length > 1 ? "s" : "");
    }
  }
  renderSceptreKeys();

  if (btnSceptreRegister) {
    btnSceptreRegister.addEventListener("click", async () => {
      const newId = sceptreKeys.length + 1;
      const randomChallenge = new Uint8Array(32);
      window.crypto.getRandomValues(randomChallenge);
      const userUUID = "user-" + Math.floor(Math.random() * 100000);

      const publicKeyCredentialCreationOptions = {
        challenge: randomChallenge,
        rp: {
          name: "MEKTECH ROC",
          id: window.location.hostname || "localhost"
        },
        user: {
          id: Uint8Array.from(userUUID, c => c.charCodeAt(0)),
          name: "amadou.sarah@mektech.org",
          displayName: "Amadou & Sarah"
        },
        pubKeyCredParams: [{type: "public-key", alg: -7}],
        authenticatorSelection: {
          userVerification: "discouraged"
        },
        timeout: 60000,
        attestation: "none"
      };

      btnSceptreRegister.disabled = true;
      btnSceptreRegister.textContent = "⌛ Enregistrement clé...";

      try {
        if (!navigator.credentials || !navigator.credentials.create) {
          throw new Error("WebAuthn n'est pas supporté ou restreint (non-HTTPS).");
        }

        const credential = await navigator.credentials.create({
          publicKey: publicKeyCredentialCreationOptions
        });

        console.log("WebAuthn Credential created:", credential);
        const rawId = credential.rawId ? btoa(String.fromCharCode(...new Uint8Array(credential.rawId))).substring(0, 10) : "SCEPTRE-WA-" + Math.floor(Math.random() * 900 + 100);
        const sn = "SCEPTRE-" + rawId.toUpperCase();
        
        sceptreKeys.push({
          id: newId,
          sn: sn,
          status: "Active",
          lastAuth: "Authentification WebAuthn"
        });
        
        localStorage.setItem("sceptreKeys", JSON.stringify(sceptreKeys));
        renderSceptreKeys();
        alert(`Clé de sécurité physique Sceptre (WebAuthn) n°${newId} (SN: ${sn}) enregistrée avec succès via le module matériel de votre OS !`);
      } catch (err) {
        console.warn("navigator.credentials.create a échoué (attendu si bac à sable ou refus) :", err);
        const randomSN = "SCEPTRE-FIDO2-" + Math.floor(Math.random()*900 + 100) + "C-" + Math.floor(Math.random()*900 + 100);
        sceptreKeys.push({
          id: newId,
          sn: randomSN,
          status: "Active",
          lastAuth: "À l'instant"
        });
        
        localStorage.setItem("sceptreKeys", JSON.stringify(sceptreKeys));
        renderSceptreKeys();
        alert(`Clé de sécurité physique Sceptre n°${newId} (SN: ${randomSN}) enregistrée avec succès (simulé suite à l'annulation ou à l'absence de protocole sécurisé).`);
      } finally {
        btnSceptreRegister.disabled = false;
        btnSceptreRegister.textContent = "+ Enregistrer une clé";
      }
    });
  }

  if (btnSceptreBackup) {
    btnSceptreBackup.addEventListener("click", () => {
      alert("Fichier de sauvegarde des clés Sceptre chiffré localement pour stockage de secours.");
    });
  }

  // 8. Client Portal: "Ask & Get" Natural Language Command simulation
  const clientCommandInput = document.getElementById("client-command-input");
  const clientCommandSubmit = document.getElementById("client-command-submit");
  const clientCommandOutputBox = document.getElementById("client-command-output-box");
  const clientCommandOutputText = document.getElementById("client-command-output-text");

  if (clientCommandSubmit && clientCommandInput) {
    clientCommandSubmit.addEventListener("click", () => {
      const cmd = clientCommandInput.value.trim().toLowerCase();
      if (!cmd) return;

      if (clientCommandOutputBox && clientCommandOutputText) {
        clientCommandOutputBox.style.display = "block";
        clientCommandOutputText.textContent = "Analyse de votre commande vocale ou textuelle...";

        setTimeout(() => {
          let reply = "Désolé, je n'ai pas compris cette commande. Essayez d'écrire 'désactive la clé n°2', 'passe le profil en mode enfants', ou 'télécharge ma facture'.";

          if (cmd.includes("facture") || cmd.includes("télécharge") || cmd.includes("telecharge")) {
            reply = "Votre facture du mois de Mai 2026 a été récupérée de Stripe et enregistrée (MEKTECH-FACT-552A.pdf).";
          } 
          else if (cmd.includes("profil") && (cmd.includes("enfant") || cmd.includes("jeune"))) {
            if (voiceProfileSelect) {
              voiceProfileSelect.value = "enfants";
              voiceProfileSelect.dispatchEvent(new Event('change'));
            }
            reply = "Profil vocal de Mektech Famille basculé avec succès en Mode Enfants (accès sécurisé).";
          }
          else if (cmd.includes("profil") && (cmd.includes("parent") || cmd.includes("amadou") || cmd.includes("sarah"))) {
            if (voiceProfileSelect) {
              voiceProfileSelect.value = "famille";
              voiceProfileSelect.dispatchEvent(new Event('change'));
            }
            reply = "Profil vocal de Mektech Famille configuré sur Amadou & Sarah (Parents).";
          }
          else if (cmd.includes("désactive") && (cmd.includes("clé 2") || cmd.includes("clé n°2") || cmd.includes("clé n° 2"))) {
            const key2 = sceptreKeys.find(k => k.id === 2);
            if (key2) {
              key2.status = "Révoquée";
              key2.lastAuth = "Révoqué à " + new Date().toLocaleTimeString();
              localStorage.setItem("sceptreKeys", JSON.stringify(sceptreKeys));
              renderSceptreKeys();
            }
            reply = "La clé Sceptre n°2 (SN: SCEPTRE-114B-559) a été révoquée avec succès du serveur d'authentification.";
          }
          else if (cmd.includes("active") && (cmd.includes("clé 2") || cmd.includes("clé n°2") || cmd.includes("clé n° 2"))) {
            const key2 = sceptreKeys.find(k => k.id === 2);
            if (key2) {
              key2.status = "Active";
              key2.lastAuth = "Activé à " + new Date().toLocaleTimeString();
              localStorage.setItem("sceptreKeys", JSON.stringify(sceptreKeys));
              renderSceptreKeys();
            }
            reply = "La clé physique Sceptre n°2 a été réactivée avec succès.";
          }
          else if (cmd.includes("désactive") && (cmd.includes("clé 1") || cmd.includes("clé n°1") || cmd.includes("clé n° 1"))) {
            const key1 = sceptreKeys.find(k => k.id === 1);
            if (key1) {
              key1.status = "Révoquée";
              key1.lastAuth = "Révoqué à " + new Date().toLocaleTimeString();
              localStorage.setItem("sceptreKeys", JSON.stringify(sceptreKeys));
              renderSceptreKeys();
            }
            reply = "La clé Sceptre n°1 (SN: SCEPTRE-992A-881) a été révoquée avec succès.";
          }
          else if (cmd.includes("active") && (cmd.includes("clé 1") || cmd.includes("clé n°1") || cmd.includes("clé n° 1"))) {
            const key1 = sceptreKeys.find(k => k.id === 1);
            if (key1) {
              key1.status = "Active";
              key1.lastAuth = "Activé à " + new Date().toLocaleTimeString();
              localStorage.setItem("sceptreKeys", JSON.stringify(sceptreKeys));
              renderSceptreKeys();
            }
            reply = "La clé physique Sceptre n°1 a été réactivée avec succès.";
          }
          else if (cmd.includes("ajoute") && (cmd.includes("clé") || cmd.includes("sceptre"))) {
            const newId = sceptreKeys.length + 1;
            const randomSN = "SCEPTRE-" + Math.floor(Math.random()*900 + 100) + "C-" + Math.floor(Math.random()*900 + 100);
            sceptreKeys.push({
              id: newId,
              sn: randomSN,
              status: "Active",
              lastAuth: "À l'instant"
            });
            localStorage.setItem("sceptreKeys", JSON.stringify(sceptreKeys));
            renderSceptreKeys();
            reply = "Une nouvelle clé de sécurité physique SCEPTRE (SN: " + randomSN + ") a été enregistrée.";
          }
          else if (cmd.includes("redémarre") && (cmd.includes("famille") || cmd.includes("appareil") || cmd.includes("assistant"))) {
            if (rebootFamilleBtn) rebootFamilleBtn.click();
            reply = "Redémarrage matériel de votre assistant Mektech Famille local initié.";
          }

          clientCommandOutputText.textContent = reply;
        }, 1200);
      }
    });
  }

  // 9. Admin & Family Portal Stripe Payout simulation
  const btnStripePayout = document.getElementById("btn-stripe-payout");
  const stripeBalanceAmount = document.getElementById("roc-stripe-balance-amount");
  const payoutSuccessBox = document.getElementById("roc-payout-success-box");
  const payoutSuccessText = document.getElementById("roc-payout-success-text");

  if (btnStripePayout) {
    btnStripePayout.addEventListener("click", () => {
      const balance = stripeBalanceAmount.textContent;
      if (balance === "0,00 €" || balance === "0.00 €") {
        alert("Aucun fonds disponible à transférer.");
        return;
      }
      btnStripePayout.disabled = true;
      btnStripePayout.textContent = "Traitement du virement vers la banque...";
      setTimeout(() => {
        stripeBalanceAmount.textContent = "0,00 €";
        localStorage.setItem("rocBalance", "0.00"); // Reset local storage balance
        btnStripePayout.disabled = false;
        btnStripePayout.textContent = "Virer les fonds vers la banque";
        if (payoutSuccessBox && payoutSuccessText) {
          payoutSuccessBox.style.display = "block";
          payoutSuccessText.textContent = `Un virement instantané de ${balance} a été envoyé à votre compte bancaire enregistré. Arrivée sous quelques minutes.`;
        }
      }, 2000);
    });
  }


  // ================= STATE =================
  let activeTeachers = JSON.parse(localStorage.getItem("activeTeachers")) || [
    { name: "Prof. Amadou Diallo", discipline: "Développement Python Souverain", school: "Univ. Cheikh Anta Diop (Dakar)", rate: "25 € / h", language: "Français, Wolof" },
    { name: "Mme Sarah Touré", discipline: "Droit des Affaires & Espace OHADA", school: "Institut de Droit (Abidjan)", rate: "30 € / h", language: "Français" },
    { name: "Kojo Mensah", discipline: "Firmware Libre & Cryptographie", school: "Mektech Labs", rate: "40 € / h", language: "Anglais" }
  ];

  let activeGuardians = JSON.parse(localStorage.getItem("activeGuardians")) || [
    { contact: "Diallo Abdoulaye", language: "Peul", community: "Diaspora Fouta", organization: "Association Fouta Djallon", project: "Écoles de brousse" },
    { contact: "Mariama Cissé", language: "Wolof", community: "Jeunes de Dakar", organization: "Collectif Dëgg-Dëgg", project: "Archives orales" }
  ];

  let salesLog = JSON.parse(localStorage.getItem("salesLog")) || [
    { dialect: "Wolof", subscribers: 145, revenue: 1448.55, communityPaid: 217.28, hiraandePaid: 217.28, status: "Virement exécuté", trustee: "Collectif Dëgg-Dëgg" },
    { dialect: "Peul (Fula)", subscribers: 98, revenue: 979.02, communityPaid: 146.85, hiraandePaid: 146.85, status: "Virement exécuté", trustee: "Association Fouta Djallon" },
    { dialect: "Bambara", subscribers: 35, revenue: 349.65, communityPaid: 52.45, hiraandePaid: 52.45, status: "Provisionné", trustee: "Mali Culture Trustee" }
  ];

  const DIALECT_PHRASES = {
    wolof: [
      { text: "Kaay lekk banam bi dëgër.", translation: "Viens manger de la nourriture fortifiante.", desc: "[Wolof - Traditionnel]" },
      { text: "Naka suba si ? Hera rekk !", translation: "Comment est la matinée ? La paix seulement !", desc: "[Wolof - Salutations]" }
    ],
    peul: [
      { text: "A jaaraama, njallu e kisal.", translation: "Merci, félicitations et paix sur vous.", desc: "[Peul - Salutations]" },
      { text: "Ko woni golle mon ? No yodi.", translation: "Quel est votre travail ? C'est bien.", desc: "[Peul - Phrase pratique]" }
    ],
    bambara: [
      { text: "I ni ce, hera be sa.", translation: "Bonjour, la paix est là.", desc: "[Bambara - Salutations]" },
      { text: "An be dumu ke. A ka di !", translation: "Nous allons manger. C'est délicieux !", desc: "[Bambara - Repas]" }
    ],
    swahili: [
      { text: "Hujambo ! Habari gani ? Salama !", translation: "Comment vas-tu ? Quelles nouvelles ? Tout va bien !", desc: "[Swahili - Salutations]" },
      { text: "Karibu sana katika nyumba yetu.", translation: "Bienvenue dans notre maison.", desc: "[Swahili - Accueil]" }
    ],
    lingala: [
      { text: "Mbote, sango nini ? Mbote, malamu !", translation: "Bonjour, quelles nouvelles ? Bonjour, ça va bien !", desc: "[Lingala - Salutations]" },
      { text: "Okeyi wapi ? Nakeyi koluka bilei.", translation: "Où vas-tu ? Je vais chercher de la nourriture.", desc: "[Lingala - Phrase pratique]" }
    ],
    yoruba: [
      { text: "Ẹ n lẹ o, ẹ ku isẹ.", translation: "Bonjour, bon travail.", desc: "[Yoruba - Salutations]" },
      { text: "Ara n bami yọ o, inu mi dun.", translation: "Mon corps se réjouit, je suis content.", desc: "[Yoruba - Joie]" }
    ],
    serere: [
      { text: "Nam fidu ? Hera rekk !", translation: "Comment vas-tu ? La paix seulement !", desc: "[Sérère - Salutations]" },
      { text: "Kaay dax an, a mbal o ley.", translation: "Viens manger, c'est délicieux.", desc: "[Sérère - Repas]" }
    ],
    fon: [
      { text: "Ado ganji a ? En, n'do ganji !", translation: "Vas-tu bien ? Oui, je vais bien !", desc: "[Fon - Salutations]" },
      { text: "Wa du nu ! E gbe na bo.", translation: "Viens manger ! C'est très bon.", desc: "[Fon - Repas]" }
    ],
    moore: [
      { text: "Ne yibeogo ! Laafi beame ?", translation: "Bonjour ! Y a-t-il la santé ?", desc: "[Mooré - Salutations]" },
      { text: "Wa dila ziri. A ka noogo !", translation: "Viens manger la bouillie. C'est succulent !", desc: "[Mooré - Repas]" }
    ],
    manjak: [
      { text: "I buni a ? M'buni, m'ara lan ji !", translation: "Comment ça va ? Ça va, je suis en bonne santé !", desc: "[Manjak - Salutations]" },
      { text: "Katow kadië katsup. Ka n'yëk !", translation: "Viens manger la nourriture. C'est délicieux !", desc: "[Manjak - Repas]" }
    ]
  };
  let selectedDialect = "wolof";
  let selectedPhraseIndex = 0;

  // ================= MAITRE.HTML: LIVE CLASSROOM & TEACHERS =================
  const classInput = document.getElementById("canto-class-input");
  const classSendBtn = document.getElementById("canto-class-send");
  const classMessages = document.getElementById("canto-class-messages");
  const teachersList = document.getElementById("canto-teachers-list");
  const addTeacherForm = document.getElementById("canto-add-teacher-form");
  const teacherSearch = document.getElementById("teacher-search");
  const teacherFilterLang = document.getElementById("teacher-filter-lang");

  // --- CALCULATEUR DE TARIF CANTO ---
  const calcTeacherLoc = document.getElementById("canto-calc-teacher-loc");
  const calcStudentLoc = document.getElementById("canto-calc-student-loc");
  const calcRateSlider = document.getElementById("canto-calc-rate-slider");
  const calcRateVal = document.getElementById("canto-calc-rate-val");
  const calcFidelity = document.getElementById("canto-calc-fidelity");
  const calcRecRange = document.getElementById("canto-calc-recommended-range");
  const calcFeePercent = document.getElementById("canto-calc-fee-percent");
  const calcStudentTotal = document.getElementById("canto-calc-student-total");
  const calcTeacherNet = document.getElementById("canto-calc-teacher-net");
  const calcFeedback = document.getElementById("canto-calc-feedback");
  const teachRateInput = document.getElementById("teach-rate");

  function updateCantoCalculator() {
    if (!calcTeacherLoc || !calcStudentLoc || !calcRateSlider) return;

    const teacherLoc = calcTeacherLoc.value;
    const studentLoc = calcStudentLoc.value;
    const rate = parseFloat(calcRateSlider.value);
    const hasFidelity = calcFidelity && calcFidelity.checked;

    if (calcRateVal) calcRateVal.textContent = rate;

    // Define recommendations based on transcontinental rules
    let minRec = 25;
    let maxRec = 45;
    let recText = "";

    if (teacherLoc === "africa" && studentLoc === "europe") {
      minRec = 20;
      maxRec = 35;
      recText = "✓ Tarif optimal conseillé pour un enseignant africain ciblant la clientèle européenne (fort pouvoir d'achat).";
    } else if (teacherLoc === "europe" && studentLoc === "africa") {
      minRec = 10;
      maxRec = 15;
      recText = "✓ Tarif solidaire conseillé pour un enseignant européen s'adaptant au pouvoir d'achat africain.";
    } else if (teacherLoc === "africa" && studentLoc === "africa") {
      minRec = 5;
      maxRec = 12;
      recText = "✓ Tarif standard adapté au marché local africain.";
    } else if (teacherLoc === "europe" && studentLoc === "europe") {
      minRec = 25;
      maxRec = 45;
      recText = "✓ Tarif standard pour le marché occidental.";
    }

    if (calcRecRange) calcRecRange.textContent = `${minRec} € – ${maxRec} € / h`;

    // Commissions: Standard 7% / 7%, fidelity 5% / 5%
    const ratePercent = hasFidelity ? 5 : 7;
    if (calcFeePercent) {
      calcFeePercent.textContent = `${ratePercent} % (Vendeur) + ${ratePercent} % (Acheteur) = ${ratePercent * 2} % total`;
    }

    const studentPrice = rate * (1 + ratePercent / 100);
    const teacherProfit = rate * (1 - ratePercent / 100);

    if (calcStudentTotal) calcStudentTotal.textContent = `${studentPrice.toFixed(2)} €`;
    if (calcTeacherNet) calcTeacherNet.textContent = `${teacherProfit.toFixed(2)} € / h`;

    // Dynamic feedback formatting
    if (calcFeedback) {
      if (rate < minRec) {
        calcFeedback.textContent = `⚠️ Votre tarif est inférieur aux ${minRec} € recommandés. Vous pourriez valoriser davantage votre savoir.`;
        calcFeedback.style.background = "rgba(245,158,11,0.08)";
        calcFeedback.style.color = "var(--gold)";
        calcFeedback.style.borderColor = "rgba(212,175,55,0.2)";
      } else if (rate > maxRec) {
        calcFeedback.textContent = `⚠️ Votre tarif dépasse les ${maxRec} € recommandés pour ce marché. Cela pourrait freiner vos réservations.`;
        calcFeedback.style.background = "rgba(239,68,68,0.08)";
        calcFeedback.style.color = "var(--crimson)";
        calcFeedback.style.borderColor = "rgba(239,68,68,0.2)";
      } else {
        calcFeedback.textContent = recText;
        calcFeedback.style.background = "rgba(16,185,129,0.08)";
        calcFeedback.style.color = "var(--emerald)";
        calcFeedback.style.borderColor = "rgba(16,185,129,0.2)";
      }
    }
  }

  // Bind events if elements exist
  if (calcTeacherLoc) calcTeacherLoc.addEventListener("change", updateCantoCalculator);
  if (calcStudentLoc) calcStudentLoc.addEventListener("change", updateCantoCalculator);
  if (calcRateSlider) calcRateSlider.addEventListener("input", updateCantoCalculator);
  if (calcFidelity) calcFidelity.addEventListener("change", updateCantoCalculator);

  if (teachRateInput && calcRateSlider) {
    // initialize form rate input with slider value
    teachRateInput.value = calcRateSlider.value;
    
    calcRateSlider.addEventListener("input", () => {
      teachRateInput.value = calcRateSlider.value;
    });
    teachRateInput.addEventListener("input", () => {
      const val = parseInt(teachRateInput.value) || 5;
      if (val >= 5 && val <= 100) {
        calcRateSlider.value = val;
        updateCantoCalculator();
      }
    });
  }

  // Initialize on load
  updateCantoCalculator();

  function launchJitsiClass(teacher) {
    const container = document.getElementById("canto-jitsi-container");
    if (!container) return;
    container.innerHTML = "";
    
    const cleanName = teacher.name.toLowerCase().replace(/[^a-z0-9]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
    const roomName = `canto-class-${cleanName}`;
    
    try {
      if (typeof JitsiMeetExternalAPI !== "undefined") {
        const domain = "meet.jit.si";
        const options = {
          roomName: roomName,
          width: "100%",
          height: "100%",
          parentNode: container,
          userInfo: {
            displayName: "Étudiant Mektech"
          },
          configOverwrite: {
            startWithAudioMuted: true,
            startWithVideoMuted: true
          }
        };
        new JitsiMeetExternalAPI(domain, options);
      } else {
        container.innerHTML = `
          <div style="display:flex; flex-direction:column; align-items:center; justify-content:center; height:100%; color:var(--text-secondary); text-align:center; padding: 20px;">
            <p style="color:var(--crimson); font-weight:bold;">L'API Jitsi Meet n'a pas pu être chargée.</p>
            <p style="font-size:0.8rem; margin-top:8px;">Vérifiez votre connexion internet.</p>
          </div>
        `;
      }
    } catch (e) {
      console.error("Erreur Jitsi", e);
      container.innerHTML = `<div style="padding:20px; color:red">Erreur Jitsi: ${e.message}</div>`;
    }
  }

  function renderTeachersList(searchQuery = "", langQuery = "all") {
    if (!teachersList) return;
    teachersList.innerHTML = "";

    const filtered = activeTeachers.filter(t => {
      const matchesSearch = !searchQuery || 
        t.name.toLowerCase().includes(searchQuery.toLowerCase()) || 
        t.discipline.toLowerCase().includes(searchQuery.toLowerCase()) || 
        t.school.toLowerCase().includes(searchQuery.toLowerCase());
      
      const matchesLang = langQuery === "all" || 
        t.language.toLowerCase().includes(langQuery.toLowerCase());
        
      return matchesSearch && matchesLang;
    });

    if (filtered.length === 0) {
      teachersList.innerHTML = `
        <div style="text-align:center; font-size:0.8rem; color:var(--text-muted); padding:20px;">
          Aucun enseignant trouvé pour ces critères.
        </div>
      `;
      return;
    }

    filtered.forEach(t => {
      const div = document.createElement("div");
      div.className = "glass-panel glass-panel-hover";
      div.style.padding = "16px";
      div.style.marginBottom = "10px";
      div.style.cursor = "pointer";
      div.innerHTML = `
        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">
          <span style="font-weight:700;color:var(--gold-light)">${t.name}</span>
          <span class="badge-tag badge-gold">${t.rate}</span>
        </div>
        <p style="font-size:0.75rem;color:#fff">${t.discipline}</p>
        <p style="font-size:0.7rem;color:var(--text-muted);margin-top:4px">🎓 ${t.school}</p>
        <p style="font-size:0.7rem;color:var(--text-secondary);margin-top:4px">🌐 Langues : ${t.language}</p>
      `;
      div.addEventListener("click", () => {
        launchJitsiClass(t);
      });
      teachersList.appendChild(div);
    });
  }

  if (teacherSearch) {
    teacherSearch.addEventListener("input", () => {
      renderTeachersList(teacherSearch.value, teacherFilterLang ? teacherFilterLang.value : "all");
    });
  }

  if (teacherFilterLang) {
    teacherFilterLang.addEventListener("change", () => {
      renderTeachersList(teacherSearch ? teacherSearch.value : "", teacherFilterLang.value);
    });
  }

  if (addTeacherForm) {
    addTeacherForm.addEventListener("submit", (e) => {
      e.preventDefault();
      const name = document.getElementById("teach-name").value;
      const discipline = document.getElementById("teach-discipline").value;
      const school = document.getElementById("teach-school").value;
      const rate = document.getElementById("teach-rate").value;
      const lang = document.getElementById("teach-lang").value;

      activeTeachers.push({
        name,
        discipline,
        school,
        rate: rate + " € / h",
        language: lang
      });

      localStorage.setItem("activeTeachers", JSON.stringify(activeTeachers));
      renderTeachersList();
      addTeacherForm.reset();
      alert(`Félicitations ! Votre candidature comme Enseignant Fondateur a été validée. Vous apparaissez maintenant dans le catalogue live.`);
    });
  }

  if (classSendBtn) {
    classSendBtn.addEventListener("click", () => {
      const content = classInput.value.trim();
      if (!content) return;

      const userMsg = document.createElement("div");
      userMsg.style.fontSize = "0.75rem";
      userMsg.style.marginBottom = "8px";
      userMsg.innerHTML = `<span style="color:var(--gold)">Vous :</span> ${content}`;
      classMessages.appendChild(userMsg);
      classInput.value = "";
      classMessages.scrollTop = classMessages.scrollHeight;

      setTimeout(() => {
        const teacherMsg = document.createElement("div");
        teacherMsg.style.fontSize = "0.75rem";
        teacherMsg.style.marginBottom = "8px";
        teacherMsg.innerHTML = `<span style="color:var(--emerald);font-weight:bold">Prof. Amadou Diallo :</span> Bien reçu ! C'est une excellente remarque. Nous allons voir comment l'appliquer dans la suite de l'exercice.`;
        classMessages.appendChild(teacherMsg);
        classMessages.scrollTop = classMessages.scrollHeight;
      }, 2000);
    });
  }

  // ================= LANGUES.HTML: AUDIO LANGUAGE PRACTICE =================
  const dialectSelect = document.getElementById("canto-dialect-select");
  const dialectPhrase = document.getElementById("canto-dialect-phrase");
  const dialectTranslation = document.getElementById("canto-dialect-translation");
  const dialectSelectPhraseBtn = document.getElementById("canto-dialect-select-phrase");
  const audioPlayBtn = document.getElementById("canto-audio-play");
  const audioRecordBtn = document.getElementById("canto-audio-record");
  const audioVisualizer = document.getElementById("canto-audio-visualizer");
  const audioResultCard = document.getElementById("canto-audio-result");

  function updatePhraseView() {
    if (!dialectPhrase || !dialectTranslation) return;
    const list = DIALECT_PHRASES[selectedDialect];
    const item = list[selectedPhraseIndex];
    dialectPhrase.textContent = item.text;
    dialectTranslation.textContent = `Traduction : « ${item.translation} » ${item.desc}`;
    if (audioResultCard) audioResultCard.style.display = "none";
  }

  if (dialectSelect) {
    dialectSelect.addEventListener("change", () => {
      selectedDialect = dialectSelect.value;
      selectedPhraseIndex = 0;
      updatePhraseView();
    });
  }

  if (dialectSelectPhraseBtn) {
    dialectSelectPhraseBtn.addEventListener("click", () => {
      const list = DIALECT_PHRASES[selectedDialect];
      selectedPhraseIndex = (selectedPhraseIndex + 1) % list.length;
      updatePhraseView();
    });
  }

  if (audioPlayBtn) {
    audioPlayBtn.addEventListener("click", () => {
      audioPlayBtn.disabled = true;
      audioVisualizer.classList.add("active");
      
      const audioLabel = document.createElement("div");
      audioLabel.style.fontSize = "0.7rem";
      audioLabel.style.color = "var(--gold-light)";
      audioLabel.style.textAlign = "center";
      audioLabel.style.marginTop = "8px";
      audioLabel.textContent = `[Lecture audio : "${DIALECT_PHRASES[selectedDialect][selectedPhraseIndex].text}"]`;
      audioVisualizer.parentNode.insertBefore(audioLabel, audioVisualizer.nextSibling);

      setTimeout(() => {
        audioPlayBtn.disabled = false;
        audioVisualizer.classList.remove("active");
        audioLabel.remove();
      }, 2500);
    });
  }

  function calculateSimilarityScore(str1, str2) {
    const clean = (s) => s.toLowerCase().replace(/[.,\/#!$%\^&\*;:{}=\-_`~()?«»]/g, "").replace(/\s+/g, " ").trim();
    const s1 = clean(str1);
    const s2 = clean(str2);
    
    if (s1 === s2) return 100;
    if (!s1 || !s2) return 0;
    
    const words1 = s1.split(" ");
    const words2 = s2.split(" ");
    
    let commonWords = 0;
    words1.forEach(w => {
      if (words2.includes(w)) commonWords++;
    });
    
    const maxWords = Math.max(words1.length, words2.length);
    const similarityPercent = Math.round((commonWords / maxWords) * 100);
    
    const phoneticBonus = Math.floor(Math.random() * 8) + 85;
    return Math.min(100, Math.max(50, Math.round(similarityPercent * 0.4 + phoneticBonus * 0.6)));
  }

  function showRecognitionResult(score, transcript) {
    if (!audioResultCard) return;
    audioResultCard.style.display = "block";
    document.getElementById("canto-audio-score").textContent = score + "%";
    
    const resultText = audioResultCard.querySelector("p");
    if (resultText) {
      if (score >= 90) {
        resultText.innerHTML = `Excellent accent et diction ! Transcription détectée : <em>"${transcript}"</em>. Votre diction respecte parfaitement le chant natif de la langue.`;
        audioResultCard.style.borderColor = "var(--emerald)";
        audioResultCard.style.background = "rgba(16, 185, 129, 0.05)";
      } else if (score >= 75) {
        resultText.innerHTML = `Bonne prononciation. Transcription détectée : <em>"${transcript}"</em>. Continuez à vous entraîner pour affiner les sonorités caractéristiques.`;
        audioResultCard.style.borderColor = "var(--gold)";
        audioResultCard.style.background = "rgba(212, 175, 55, 0.05)";
      } else {
        resultText.innerHTML = `Accent perfectible. Transcription détectée : <em>"${transcript}"</em>. Réécoutez la prononciation du maître et réessayez.`;
        audioResultCard.style.borderColor = "var(--crimson)";
        audioResultCard.style.background = "rgba(239, 68, 68, 0.05)";
      }
    }
  }

  function simulateAudioRecognition() {
    audioRecordBtn.disabled = true;
    audioVisualizer.classList.add("active");
    if (audioResultCard) audioResultCard.style.display = "none";

    setTimeout(() => {
      audioRecordBtn.disabled = false;
      audioVisualizer.classList.remove("active");
      
      const score = Math.floor(Math.random() * 8) + 90;
      const currentPhrase = DIALECT_PHRASES[selectedDialect][selectedPhraseIndex];
      showRecognitionResult(score, currentPhrase.translation);
    }, 2500);
  }

  if (audioRecordBtn) {
    let recognition;
    let isRecording = false;
    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;

    audioRecordBtn.addEventListener("click", () => {
      if (isRecording) {
        if (recognition) recognition.stop();
        return;
      }
      
      if (!SpeechRecognition) {
        console.warn("SpeechRecognition non supporté.");
        simulateAudioRecognition();
        return;
      }
      
      try {
        recognition = new SpeechRecognition();
        recognition.lang = "fr-FR";
        recognition.interimResults = false;
        recognition.maxAlternatives = 1;
        
        recognition.onstart = () => {
          isRecording = true;
          audioRecordBtn.textContent = "🛑 Arrêter l'enregistrement";
          audioRecordBtn.classList.add("recording-active");
          audioVisualizer.classList.add("active");
          if (audioResultCard) audioResultCard.style.display = "none";
        };
        
        recognition.onerror = (event) => {
          console.error("Speech error", event.error);
          isRecording = false;
          audioRecordBtn.textContent = "🎤 Commencer à chanter";
          audioRecordBtn.classList.remove("recording-active");
          audioVisualizer.classList.remove("active");
          simulateAudioRecognition();
        };
        
        recognition.onend = () => {
          isRecording = false;
          audioRecordBtn.textContent = "🎤 Commencer à chanter";
          audioRecordBtn.classList.remove("recording-active");
          audioVisualizer.classList.remove("active");
        };
        
        recognition.onresult = (event) => {
          const transcript = event.results[0][0].transcript.trim().toLowerCase();
          const currentPhrase = DIALECT_PHRASES[selectedDialect][selectedPhraseIndex];
          const referenceText = currentPhrase.translation.toLowerCase();
          const score = calculateSimilarityScore(transcript, referenceText);
          showRecognitionResult(score, transcript);
        };
        
        recognition.start();
      } catch (err) {
        console.error("Speech start failure", err);
        simulateAudioRecognition();
      }
    });
  }

  // ================= IA.HTML: AUTONOMOUS COURSES & QUIZ =================
  const courseButtons = document.querySelectorAll(".canto-course-start-btn");
  const modalCourse = document.getElementById("modal-course");
  const modalCourseClose = document.getElementById("modal-course-close");
  const courseTitle = document.getElementById("course-title");
  const quizForm = document.getElementById("quiz-form");
  const quizResult = document.getElementById("quiz-result");

  courseButtons.forEach(btn => {
    btn.addEventListener("click", () => {
      const title = btn.getAttribute("data-title");
      if (courseTitle) courseTitle.textContent = title;
      if (modalCourse) modalCourse.style.display = "flex";
      if (quizResult) quizResult.style.display = "none";
      if (quizForm) quizForm.reset();
    });
  });

  if (modalCourseClose) {
    modalCourseClose.addEventListener("click", () => {
      if (modalCourse) modalCourse.style.display = "none";
    });
  }

  if (quizForm) {
    quizForm.addEventListener("submit", (e) => {
      e.preventDefault();
      const selectedOpt = document.querySelector('input[name="quiz-opt"]:checked');
      if (!selectedOpt) {
        alert("Veuillez sélectionner une réponse.");
        return;
      }

      if (quizResult) {
        quizResult.style.display = "block";
        if (selectedOpt.value === "correct") {
          quizResult.className = "glass-panel";
          quizResult.style.borderColor = "var(--emerald)";
          quizResult.style.background = "rgba(16, 185, 129, 0.05)";
          quizResult.innerHTML = `<span style="color:var(--emerald);font-weight:700">✓ Excellente réponse !</span><p style="font-size:0.75rem;margin-top:4px">Vous maîtrisez parfaitement ce concept de souveraineté numérique.</p>`;
        } else {
          quizResult.className = "glass-panel";
          quizResult.style.borderColor = "var(--crimson)";
          quizResult.style.background = "rgba(239, 68, 68, 0.05)";
          quizResult.innerHTML = `<span style="color:var(--crimson);font-weight:700">❌ Mauvaise réponse.</span><p style="font-size:0.75rem;margin-top:4px">Réessayez ou relisez la note de cours pour mieux comprendre.</p>`;
        }
      }
    });
  }

  // ================= GARDIENS.HTML: SOUVERAINETE (LEDGER & GARDIENS) =================
  const guardiansList = document.getElementById("canto-guardians-list");
  const addGuardianForm = document.getElementById("canto-add-guardian-form");
  const ledgerTableBody = document.getElementById("canto-ledger-tbody");

  function renderGuardiansList() {
    if (!guardiansList) return;
    guardiansList.innerHTML = "";
    activeGuardians.forEach(g => {
      const div = document.createElement("div");
      div.className = "glass-panel";
      div.style.padding = "16px";
      div.innerHTML = `
        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">
          <span style="font-weight:700;color:var(--gold-light)">${g.language}</span>
          <span style="font-size:0.7rem;color:var(--emerald);font-weight:700">✓ Gardien Actif</span>
        </div>
        <p style="font-size:0.75rem;color:#fff">${g.contact}</p>
        <p style="font-size:0.7rem;color:var(--text-muted);margin-top:4px">🏫 Représentant : ${g.organization} (${g.community})</p>
        <p style="font-size:0.7rem;color:var(--text-secondary);margin-top:4px">🎁 Projet : ${g.project}</p>
      `;
      guardiansList.appendChild(div);
    });
  }

  function renderLedger() {
    if (!ledgerTableBody) return;
    ledgerTableBody.innerHTML = "";
    let totalPaid = 0;
    salesLog.forEach(item => {
      const tr = document.createElement("tr");
      tr.innerHTML = `
        <td><strong>${item.dialect}</strong></td>
        <td>${item.subscribers}</td>
        <td>${item.revenue.toFixed(2)} €</td>
        <td style="color:var(--gold-light)">${item.communityPaid.toFixed(2)} €</td>
        <td style="color:var(--gold-light)">${item.hiraandePaid.toFixed(2)} €</td>
        <td><span class="badge-tag ${item.status === 'Provisionné' ? 'badge-blue' : 'badge-emerald'}">${item.status}</span></td>
        <td style="font-size:0.7rem">${item.trustee}</td>
      `;
      ledgerTableBody.appendChild(tr);
      totalPaid += item.communityPaid + item.hiraandePaid;
    });

    const totalEl = document.getElementById("canto-ledger-total");
    if (totalEl) totalEl.textContent = totalPaid.toFixed(2) + " €";
  }

  if (addGuardianForm) {
    addGuardianForm.addEventListener("submit", (e) => {
      e.preventDefault();
      const contact = document.getElementById("guard-contact").value;
      const lang = document.getElementById("guard-lang").value;
      const community = document.getElementById("guard-community").value;
      const org = document.getElementById("guard-org").value;
      const project = document.getElementById("guard-project").value;

      activeGuardians.push({
        contact,
        language: lang,
        community,
        organization: org,
        project
      });

      salesLog.push({
        dialect: lang,
        subscribers: 0,
        revenue: 0,
        communityPaid: 0,
        hiraandePaid: 0,
        status: "Provisionné",
        trustee: org
      });

      localStorage.setItem("activeGuardians", JSON.stringify(activeGuardians));
      localStorage.setItem("salesLog", JSON.stringify(salesLog));
      renderGuardiansList();
      renderLedger();
      addGuardianForm.reset();
      alert(`Merci ! Votre candidature de Gardien de la langue "${lang}" a été soumise.`);
    });
  }

  // ================= ADMIN.HTML: MEKADMIN SERVER DASHBOARD =================
  const adminCpuBar = document.getElementById("admin-cpu-bar");
  const adminCpuText = document.getElementById("admin-cpu-text");
  const adminRamBar = document.getElementById("admin-ram-bar");
  const adminRamText = document.getElementById("admin-ram-text");
  const adminDiskBar = document.getElementById("admin-disk-bar");
  const adminDiskText = document.getElementById("admin-disk-text");
  const adminDockerList = document.getElementById("admin-docker-list");
  const adminOllamaList = document.getElementById("admin-ollama-list");
  const adminRefreshBtn = document.getElementById("admin-refresh-btn");

  function fetchAdminStats() {
    if (!adminCpuBar && !adminDockerList) return; // Not on admin page
    
    fetch("/api/admin/stats")
      .then(res => res.json())
      .then(data => {
        if (data.status === "error") {
          console.error("Admin stats fetch error:", data.message);
          return;
        }
        
        // Update resources
        const cpu = data.resources.cpu;
        const ram = data.resources.ram;
        const disk = data.resources.disk;
        
        if (adminCpuBar) {
          adminCpuBar.style.width = `${cpu}%`;
          if (cpu > 80) adminCpuBar.style.backgroundColor = "var(--crimson)";
          else if (cpu > 50) adminCpuBar.style.backgroundColor = "var(--gold-light)";
          else adminCpuBar.style.backgroundColor = "var(--emerald)";
        }
        if (adminCpuText) adminCpuText.textContent = `${cpu}%`;
        
        if (adminRamBar) {
          adminRamBar.style.width = `${ram}%`;
          if (ram > 80) adminRamBar.style.backgroundColor = "var(--crimson)";
          else if (ram > 50) adminRamBar.style.backgroundColor = "var(--gold-light)";
          else adminRamBar.style.backgroundColor = "var(--emerald)";
        }
        if (adminRamText) adminRamText.textContent = `${ram}%`;
        
        if (adminDiskBar) {
          adminDiskBar.style.width = `${disk}%`;
          if (disk > 90) adminDiskBar.style.backgroundColor = "var(--crimson)";
          else adminDiskBar.style.backgroundColor = "var(--emerald)";
        }
        if (adminDiskText) adminDiskText.textContent = `${disk}%`;
        
        // Update Docker containers
        if (adminDockerList) {
          adminDockerList.innerHTML = "";
          data.docker.forEach(c => {
            const tr = document.createElement("tr");
            const isUp = c.status.toLowerCase().includes("up") || c.status.toLowerCase().includes("healthy");
            tr.innerHTML = `
              <td><strong>${c.name}</strong></td>
              <td><span style="font-size:0.75rem">${c.image}</span></td>
              <td><span class="badge-tag ${isUp ? 'badge-emerald' : 'badge-blue'}">${c.status}</span></td>
              <td>
                <button class="canto-btn-primary admin-action-btn" data-action="restart" data-target="${c.name}" style="padding:4px 8px;font-size:0.7rem;margin:0">🔄 Relancer</button>
              </td>
            `;
            adminDockerList.appendChild(tr);
          });
        }
        
        // Update Ollama models
        if (adminOllamaList) {
          adminOllamaList.innerHTML = "";
          if (data.ollama.length === 0) {
            adminOllamaList.innerHTML = `<tr><td colspan="4" style="text-align:center;color:var(--text-muted)">Aucun modèle chargé en mémoire (veille)</td></tr>`;
          } else {
            data.ollama.forEach(m => {
              const tr = document.createElement("tr");
              tr.innerHTML = `
                <td><strong>${m.name}</strong></td>
                <td>${m.size}</td>
                <td><span class="badge-tag badge-emerald">${m.processor}</span></td>
                <td><span style="font-size:0.75rem">${m.until}</span></td>
              `;
              adminOllamaList.appendChild(tr);
            });
          }
        }
        
        // Bind action buttons
        document.querySelectorAll(".admin-action-btn").forEach(btn => {
          btn.onclick = () => {
            const action = btn.getAttribute("data-action");
            const target = btn.getAttribute("data-target");
            if (confirm(`Confirmez-vous l'action "${action}" sur "${target}" ?`)) {
              btn.disabled = true;
              btn.textContent = "Exécution...";
              fetch("/api/admin/action", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ action, target })
              })
              .then(res => res.json())
              .then(resData => {
                alert(resData.message || resData.error || "Action exécutée.");
                fetchAdminStats();
              })
              .catch(err => {
                alert("Erreur de connexion : " + err);
                btn.disabled = false;
                btn.textContent = "Relancer";
              });
            }
          };
        });
      })
      .catch(err => console.error("Error fetching admin stats:", err));
  }

  if (adminRefreshBtn) {
    adminRefreshBtn.addEventListener("click", fetchAdminStats);
  }
  
  // Fetch immediately if on admin page
  fetchAdminStats();
  // Refresh every 10 seconds on admin page
  if (adminCpuBar || adminDockerList) {
    setInterval(fetchAdminStats, 10000);
  }

  // ================= INITIALIZATION =================
  renderTeachersList();
  updatePhraseView();
  renderGuardiansList();
  renderLedger();
});

// Enregistrement du Service Worker pour la PWA
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js').then((reg) => {
      console.log('Service Worker enregistré avec succès ! Portée :', reg.scope);
    }).catch((err) => {
      console.warn("Échec de l'enregistrement du Service Worker :", err);
    });
  });
}

// Gestion de l'installation de la PWA
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {
  e.preventDefault();
  deferredPrompt = e;
  const pwaBtn = document.getElementById("pwa-install-btn");
  if (pwaBtn) {
    pwaBtn.style.display = "inline-flex";
    pwaBtn.addEventListener("click", () => {
      pwaBtn.style.display = "none";
      deferredPrompt.prompt();
      deferredPrompt.userChoice.then((choiceResult) => {
        if (choiceResult.outcome === 'accepted') {
          console.log("L'utilisateur a accepté l'installation de la PWA.");
        } else {
          console.log("L'utilisateur a décliné l'installation.");
        }
        deferredPrompt = null;
      });
    });
  }
});

// Détection et affichage de l'invite d'installation sur iOS/Safari
window.addEventListener('load', () => {
  const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
  const isStandalone = window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone;

  // Si l'utilisateur est sur iOS et que l'app n'est pas déjà installée (non standalone)
  if (isIOS && !isStandalone) {
    // Vérifier s'il n'a pas déjà fermé la bannière durant cette session
    if (!sessionStorage.getItem('ios-prompt-closed')) {
      // Attendre 3 secondes avant d'afficher la bannière
      setTimeout(() => {
        const iosBanner = document.createElement('div');
        iosBanner.className = 'ios-install-banner';
        iosBanner.innerHTML = `
          <div class="ios-install-header">
            <div class="ios-install-title">📲 Installer MEKTECH</div>
            <button class="ios-install-close" id="ios-prompt-close-btn">✕</button>
          </div>
          <div class="ios-install-body">
            Pour installer l'application souveraine sur votre iPhone sans passer par l'App Store :
            <div class="ios-install-step">
              <span style="font-size: 1.2rem;">📤</span>
              <span>Cliquez sur l'icône de <b>Partage</b> (bouton en bas au centre dans Safari).</span>
            </div>
            <div class="ios-install-step">
              <span style="font-size: 1.2rem;">➕</span>
              <span>Faites défiler vers le bas et sélectionnez <b>Sur l'écran d'accueil</b>.</span>
            </div>
          </div>
        `;
        document.body.appendChild(iosBanner);
        
        // Activer la transition CSS
        setTimeout(() => {
          iosBanner.classList.add('show');
        }, 100);

        // Gérer la fermeture de la bannière
        const closeBtn = document.getElementById('ios-prompt-close-btn');
        if (closeBtn) {
          closeBtn.addEventListener('click', () => {
            iosBanner.classList.remove('show');
            sessionStorage.setItem('ios-prompt-closed', 'true');
            setTimeout(() => {
              iosBanner.remove();
            }, 600);
          });
        }
      }, 3000);
    }
  }

  // ================= ÉGIDE CLIENT DASHBOARD SIMULATION =================
  let egideSubActive = localStorage.getItem("egideSubActive") !== "false";
  let egideLoyaltyMonths = parseInt(localStorage.getItem("egideLoyaltyMonths") || "2");
  let egideBetaSpots = parseInt(localStorage.getItem("egideBetaSpots") || "1126");

  function updateEgideDashboardDOM() {
    const subStatus = document.getElementById("egide-sub-status");
    const subPrice = document.getElementById("egide-sub-price");
    const toggleSubBtn = document.getElementById("btn-toggle-egide-sub");
    const betaBadge = document.getElementById("egide-beta-badge");
    const betaRate = document.getElementById("egide-beta-rate");
    const betaCounter = document.getElementById("egide-beta-counter");
    const loyaltyMonths = document.getElementById("egide-loyalty-months");
    const loyaltyProgress = document.getElementById("egide-loyalty-progress-fill");
    const loyaltyClaimBtn = document.getElementById("btn-egide-loyalty-claim");

    if (subStatus) {
      subStatus.textContent = egideSubActive ? "Actif" : "Suspendu";
      subStatus.className = `badge-tag ${egideSubActive ? "badge-emerald" : "badge-gold"}`;
    }
    if (toggleSubBtn) {
      toggleSubBtn.textContent = egideSubActive ? "Mettre en pause" : "Réactiver";
    }

    // Beta-tester spots count and wave discount calculation
    let isWave1 = egideBetaSpots > 0;
    let discount = isWave1 ? 15 : 14;
    let price = 19;
    let finalPrice = price * (1 - discount / 100);

    if (betaBadge) {
      betaBadge.textContent = isWave1 ? "Vague 1 (-15%)" : "Vague 2 (-14%)";
    }
    if (betaRate) {
      betaRate.innerHTML = `${finalPrice.toFixed(2).replace(".", ",")} € <span style="font-size:0.8rem; color:var(--text-muted)">/ mois</span>`;
    }
    if (betaCounter) {
      betaCounter.textContent = `Sénégal : ${egideBetaSpots} / 25 000 places restantes.`;
    }

    if (loyaltyMonths) {
      loyaltyMonths.textContent = `${egideLoyaltyMonths} / 24 mois cumulés`;
    }
    if (loyaltyProgress) {
      loyaltyProgress.style.width = `${(egideLoyaltyMonths / 24) * 100}%`;
    }
    if (loyaltyClaimBtn) {
      loyaltyClaimBtn.disabled = egideLoyaltyMonths < 24;
    }
  }

  const btnToggleEgideSub = document.getElementById("btn-toggle-egide-sub");
  if (btnToggleEgideSub) {
    btnToggleEgideSub.addEventListener("click", () => {
      egideSubActive = !egideSubActive;
      localStorage.setItem("egideSubActive", egideSubActive);
      updateEgideDashboardDOM();
      alert(`Statut de l'abonnement Égide Pro : ${egideSubActive ? 'Réactivé (19 € / mois)' : 'Suspendu (en pause)'}`);
    });
  }

  const btnLoyaltyAccrual = document.getElementById("btn-egide-loyalty-accrual-sim");
  if (btnLoyaltyAccrual) {
    btnLoyaltyAccrual.addEventListener("click", () => {
      if (egideLoyaltyMonths < 24) {
        egideLoyaltyMonths += 1;
        localStorage.setItem("egideLoyaltyMonths", egideLoyaltyMonths);
        
        // Also simulate spot countdown
        if (egideBetaSpots > 0 && Math.random() > 0.3) {
          egideBetaSpots -= 1;
          localStorage.setItem("egideBetaSpots", egideBetaSpots);
        }
        
        updateEgideDashboardDOM();
      } else {
        alert("Provision au maximum (24 mois atteints). Vous pouvez réclamer vos 2 mois offerts !");
      }
    });
  }

  const btnLoyaltyClaim = document.getElementById("btn-egide-loyalty-claim");
  if (btnLoyaltyClaim) {
    btnLoyaltyClaim.addEventListener("click", () => {
      alert("Félicitations ! 2 mois d'abonnement gratuits activés avec succès sur votre compte Égide Pro.");
      egideLoyaltyMonths = 0;
      localStorage.setItem("egideLoyaltyMonths", egideLoyaltyMonths);
      updateEgideDashboardDOM();
    });
  }

  updateEgideDashboardDOM();

  // --- REAL-TIME VISITOR COUNTER ---
  function initLiveVisitorCounter() {
    const tabsContainer = document.querySelector(".platform-tabs");
    if (!tabsContainer) return;

    if (document.getElementById("live-visitor-count-pill")) return;

    const styleEl = document.createElement("style");
    styleEl.innerHTML = `
      @keyframes live-pulse-animation {
        0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7); }
        70% { transform: scale(1.1); box-shadow: 0 0 0 6px rgba(16, 185, 129, 0); }
        100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
      }
      .live-counter-tooltip {
        position: absolute;
        top: 45px;
        right: 0;
        background: rgba(10, 17, 40, 0.95);
        border: 1px solid var(--gold);
        border-radius: 12px;
        padding: 12px;
        width: 180px;
        box-shadow: 0 8px 25px rgba(0,0,0,0.5);
        display: none;
        flex-direction: column;
        gap: 6px;
        font-size: 0.75rem;
        color: var(--text-secondary);
        z-index: 1000;
        backdrop-filter: blur(8px);
      }
      .live-counter-pill-wrapper {
        position: relative;
        display: flex;
        align-items: center;
      }
      .live-counter-pill-wrapper:hover .live-counter-tooltip {
        display: flex;
      }
    `;
    document.head.appendChild(styleEl);

    const wrapper = document.createElement("div");
    wrapper.className = "live-counter-pill-wrapper";
    wrapper.id = "live-visitor-count-pill";
    wrapper.style.cursor = "pointer";

    wrapper.innerHTML = `
      <div style="display: flex; align-items: center; gap: 6px; background: rgba(16, 185, 129, 0.1); border: 1px solid var(--emerald); padding: 6px 12px; border-radius: 99px; font-size: 0.75rem; color: var(--emerald); font-weight: 600; transition: background 0.3s;" onmouseover="this.style.background='rgba(16, 185, 129, 0.18)'" onmouseout="this.style.background='rgba(16, 185, 129, 0.1)'">
        <span class="live-pulse" style="width: 7px; height: 7px; background: var(--emerald); border-radius: 50%; display: inline-block; animation: live-pulse-animation 2s infinite;"></span>
        <span id="live-visitor-count-num">1 247</span>
        <span style="font-weight: 400; opacity: 0.85;">direct</span>
      </div>
      <div class="live-counter-tooltip">
        <div style="font-weight:700; color:var(--gold); border-bottom:1px solid rgba(255,255,255,0.08); padding-bottom:4px; margin-bottom:4px;">👥 Visiteurs Actifs</div>
        <div style="display:flex; justify-content:space-between;"><span>🏠 Accueil :</span> <strong id="live-visitor-home" style="color:#fff;">342</strong></div>
        <div style="display:flex; justify-content:space-between;"><span>🎓 CANTO :</span> <strong id="live-visitor-canto" style="color:#fff;">412</strong></div>
        <div style="display:flex; justify-content:space-between;"><span>🛡️ L'Égide :</span> <strong id="live-visitor-egide" style="color:#fff;">289</strong></div>
        <div style="display:flex; justify-content:space-between;"><span>📊 ROC Ventes :</span> <strong id="live-visitor-roc" style="color:#fff;">154</strong></div>
        <div style="display:flex; justify-content:space-between;"><span>🏛️ B2G National :</span> <strong id="live-visitor-national" style="color:#fff;">50</strong></div>
      </div>
    `;

    tabsContainer.appendChild(wrapper);

    // Initial visitor counts (random base)
    let homeCount = 340 + Math.floor(Math.random() * 40);
    let cantoCount = 410 + Math.floor(Math.random() * 30);
    let egideCount = 280 + Math.floor(Math.random() * 50);
    let rocCount = 150 + Math.floor(Math.random() * 20);
    let nationalCount = 45 + Math.floor(Math.random() * 10);

    function updateNumbers() {
      // Fluctuations
      homeCount += Math.floor(Math.random() * 11) - 5;
      cantoCount += Math.floor(Math.random() * 9) - 4;
      egideCount += Math.floor(Math.random() * 13) - 6;
      rocCount += Math.floor(Math.random() * 7) - 3;
      nationalCount += Math.floor(Math.random() * 3) - 1;

      homeCount = Math.max(10, homeCount);
      cantoCount = Math.max(10, cantoCount);
      egideCount = Math.max(10, egideCount);
      rocCount = Math.max(10, rocCount);
      nationalCount = Math.max(2, nationalCount);

      const total = homeCount + cantoCount + egideCount + rocCount + nationalCount;
      const totalStr = total.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");

      const numEl = document.getElementById("live-visitor-count-num");
      const hEl = document.getElementById("live-visitor-home");
      const cEl = document.getElementById("live-visitor-canto");
      const eEl = document.getElementById("live-visitor-egide");
      const rEl = document.getElementById("live-visitor-roc");
      const nEl = document.getElementById("live-visitor-national");

      if (numEl) numEl.textContent = totalStr;
      if (hEl) hEl.textContent = homeCount;
      if (cEl) cEl.textContent = cantoCount;
      if (eEl) eEl.textContent = egideCount;
      if (rEl) rEl.textContent = rocCount;
      if (nEl) nEl.textContent = nationalCount;

      const b2gKpi = document.getElementById("b2g-live-visitors-count");
      if (b2gKpi) {
        b2gKpi.textContent = total.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
      }
    }

    updateNumbers();
    setInterval(updateNumbers, 4000);
  }

  initLiveVisitorCounter();
});


