Click&Fit

Module Click&Fit avec upload topographies et autres fonctionnalités V4

// ==UserScript==
// @name         Click&Fit
// @namespace    https://precilens.com/
// @version      4.9
// @description  Module Click&Fit avec upload topographies et autres fonctionnalités V4
// @author       Precilens
// @match        https://click-fit.precilens.com/*
// @icon         https://www.precilens.fr/favicon.ico
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  // Double clique sur la consultation
  document.addEventListener('dblclick', function(e) {
    let el = e.target;
    while (el && el !== document && (!el.id || !el.id.startsWith('file-'))) {
      el = el.parentElement;
    }
    if (el && el.id && el.id.startsWith('file-')) {
          const openBtn = document.querySelector(
            '#wrapper > main > app-home > div > div:nth-child(3) > app-file-preview > div > div > amds-button.file-open-btn.hydrated > button'
          );
          if (openBtn) {
            openBtn.click();

          } else {

          }
        }
      });

  // Style CSS du fichier
  function injectStyles() {
    const styleId = 'click-fit-custom-styles';
    if (document.getElementById(styleId)) return;

    const style = document.createElement('style');
    style.id = styleId;
    style.textContent = `
      .modal textarea#input-content {
        min-height: 150px !important;
      }

      /* CORRECTIF: Agrandir la zone d'édition des notes existantes */
      textarea#input-editContent {
        min-height: 200px !important;
        max-height: 500px !important;
        resize: vertical !important;
        font-size: 14px !important;
        line-height: 1.4 !important;
        padding: 12px !important;
        border: 2px solid #e0e0e0 !important;
        border-radius: 8px !important;
        transition: border-color 0.3s ease, height 0.2s ease !important;
        overflow: hidden !important;
        box-sizing: border-box !important;
      }

      textarea#input-editContent:focus {
        border-color: #2196f3 !important;
        outline: none !important;
        box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1) !important;
      }

      /* CORRECTIF: Centrage parfait des modals */
      .modal.modal--size-medium {
        position: fixed !important;
        margin: 0 !important;
        z-index: 1050 !important;
        transform: none !important;
      }


      /* BOUTON FLOTTANT ET MENU */
      .clickfit-fab {
        position: fixed;
        bottom: 20px;
        right: 20px;
        width: 60px;
        height: 60px;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        border-radius: 50%;
        box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 9999;
        transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
      }

      .clickfit-fab:hover {
        transform: scale(1.1);
        box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
      }

      .clickfit-fab.active {
        transform: rotate(45deg);
        background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
      }

      .clickfit-fab-icon {
        color: white;
        font-size: 28px;
        font-weight: bold;
        transition: transform 0.3s ease;
      }

      .clickfit-fab-menu {
        position: fixed;
        bottom: 90px;
        right: 20px;
        display: flex;
        flex-direction: column;
        gap: 15px;
        opacity: 0;
        visibility: hidden;
        transition: all 0.3s ease;
      }

      .clickfit-fab-menu.active {
        opacity: 1;
        visibility: visible;
      }

      .clickfit-fab-option {
        background: white;
        border-radius: 30px;
        padding: 12px 20px;
        box-shadow: 0 3px 12px rgba(0, 0, 0, 0.15);
        cursor: pointer;
        display: flex;
        align-items: center;
        gap: 10px;
        white-space: nowrap;
        transform: translateX(20px);
        opacity: 0;
        transition: all 0.3s ease;
      }

      .clickfit-fab-menu.active .clickfit-fab-option {
        transform: translateX(0);
        opacity: 1;
      }

      .clickfit-fab-menu.active .clickfit-fab-option:nth-child(1) {
        transition-delay: 0.1s;
      }

      .clickfit-fab-menu.active .clickfit-fab-option:nth-child(2) {
        transition-delay: 0.15s;
      }

      .clickfit-fab-menu.active .clickfit-fab-option:nth-child(3) {
        transition-delay: 0.2s;
      }

      .clickfit-fab-menu.active .clickfit-fab-option:nth-child(4) {
        transition-delay: 0.25s;
      }

      .clickfit-fab-menu.active .clickfit-fab-option:nth-child(5) {
        transition-delay: 0.3s;
      }

      .clickfit-fab-menu.active .clickfit-fab-option:nth-child(6) {
        transition-delay: 0.35s;
      }

      .clickfit-fab-option:hover {
        transform: translateX(-5px);
        box-shadow: 0 5px 20px rgba(0, 0, 0, 0.2);
      }

      .clickfit-fab-option-icon {
        width: 24px;
        height: 24px;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        color: white;
        font-size: 14px;
      }

      .clickfit-fab-option-text {
        color: #333;
        font-size: 14px;
        font-weight: 500;
        font-family: "Fira Sans", -apple-system, BlinkMacSystemFont;
      }

      /* Toast notifications */
      .clickfit-toast {
        position: fixed;
        bottom: 20px;
        left: 50%;
        transform: translateX(-50%) translateY(100px);
        background: #333;
        color: white;
        padding: 12px 24px;
        border-radius: 25px;
        box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
        opacity: 0;
        transition: all 0.3s ease;
        z-index: 10000;
      }

      .clickfit-toast.show {
        transform: translateX(-50%) translateY(0);
        opacity: 1;
      }

      /* INDICATEUR TOPOGRAPHIES */
      .topo-indicator {
        position: fixed;
        bottom: 100px;
        right: 20px;
        width: 60px;
        height: 60px;
        background: #17a2b8;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 24px;
        cursor: pointer;
        transition: all 0.3s;
        box-shadow: 0 4px 15px rgba(23, 162, 184, 0.3);
        z-index: 9998;
      }

      .topo-indicator:hover {
        transform: scale(1.1);
        box-shadow: 0 6px 20px rgba(23, 162, 184, 0.5);
      }

      .topo-indicator.has-files {
        background: #28a745;
        animation: pulse 2s infinite;
      }

      @keyframes pulse {
        0% { box-shadow: 0 4px 15px rgba(40, 167, 69, 0.4); }
        50% { box-shadow: 0 4px 25px rgba(40, 167, 69, 0.6); }
        100% { box-shadow: 0 4px 15px rgba(40, 167, 69, 0.4); }
      }

      .topo-badge {
        position: absolute;
        top: -5px;
        right: -5px;
        background: #dc3545;
        color: white;
        border-radius: 50%;
        width: 22px;
        height: 22px;
        display: none;
        align-items: center;
        justify-content: center;
        font-size: 12px;
        font-weight: bold;
      }

      .topo-indicator.has-files .topo-badge {
        display: flex;
      }

      /* DIALOG TOPOGRAPHIES */
      .topo-dialog {
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background: white;
        border-radius: 15px;
        box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
        z-index: 10001;
        min-width: 500px;
        max-width: 90vw;
        max-height: 80vh;
        overflow: hidden;
        display: none;
      }

      .topo-dialog.show {
        display: block;
        animation: dialogSlideIn 0.3s ease;
      }

      @keyframes dialogSlideIn {
        from {
          opacity: 0;
          transform: translate(-50%, -45%);
        }
        to {
          opacity: 1;
          transform: translate(-50%, -50%);
        }
      }

      .topo-dialog-header {
        background: linear-gradient(135deg, #17a2b8 0%, #138496 100%);
        color: white;
        padding: 20px;
        display: flex;
        justify-content: space-between;
        align-items: center;
      }

      .topo-dialog-header h3 {
        margin: 0;
        font-size: 20px;
      }

      .topo-dialog-close {
        background: none;
        border: none;
        color: white;
        font-size: 24px;
        cursor: pointer;
        width: 40px;
        height: 40px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 50%;
        transition: background 0.3s;
      }

      .topo-dialog-close:hover {
        background: rgba(255, 255, 255, 0.2);
      }

      .topo-dialog-body {
        padding: 20px;
        max-height: 60vh;
        overflow-y: auto;
      }

      .topo-file-list {
        margin: 15px 0;
      }

      .topo-file-item {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 12px 15px;
        margin: 8px 0;
        background: #f8f9fa;
        border-radius: 8px;
        border: 1px solid #dee2e6;
        transition: all 0.3s;
      }

      .topo-file-item:hover {
        background: #e9ecef;
        border-color: #17a2b8;
      }

      .topo-file-info {
        display: flex;
        align-items: center;
        gap: 12px;
      }

      .topo-file-icon {
        font-size: 24px;
      }

      .topo-file-details {
        display: flex;
        flex-direction: column;
      }

      .topo-file-name {
        font-weight: 600;
        color: #333;
      }

      .topo-file-meta {
        font-size: 12px;
        color: #6c757d;
      }

      .topo-file-status {
        padding: 4px 12px;
        border-radius: 15px;
        font-size: 12px;
        font-weight: 500;
      }

      .topo-file-status.pending {
        background: #fff3cd;
        color: #856404;
      }

      .topo-file-status.processing {
        background: #cce5ff;
        color: #004085;
      }

      .topo-file-status.success {
        background: #d4edda;
        color: #155724;
      }

      .topo-file-status.error {
        background: #f8d7da;
        color: #721c24;
      }

      .topo-actions {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-top: 20px;
        padding-top: 20px;
        border-top: 1px solid #dee2e6;
      }

      .topo-actions-left {
        display: flex;
        align-items: center;
        gap: 10px;
      }

      .topo-btn {
        padding: 10px 20px;
        border: none;
        border-radius: 8px;
        font-size: 14px;
        font-weight: 500;
        cursor: pointer;
        transition: all 0.3s;
      }

      .topo-btn-primary {
        background: #17a2b8;
        color: white;
      }

      .topo-btn-primary:hover {
        background: #138496;
        transform: translateY(-1px);
        box-shadow: 0 4px 12px rgba(23, 162, 184, 0.3);
      }

      .topo-btn-secondary {
        background: #6c757d;
        color: white;
      }

      .topo-btn-secondary:hover {
        background: #5a6268;
      }

      .topo-connection-status {
        display: flex;
        align-items: center;
        gap: 8px;
        font-size: 13px;
        color: #6c757d;
      }

      .topo-connection-dot {
        width: 10px;
        height: 10px;
        border-radius: 50%;
        background: #dc3545;
      }

      .topo-connection-dot.connected {
        background: #28a745;
      }

      /* Modal medium: resize and overflow */
      .modal.modal--size-medium {
        resize: both !important;
        overflow: auto !important;
        min-width: 400px;
        min-height: 200px;
        max-width: 95vw !important;
        max-height: 90vh !important;
      }

      /* Indicateur d'œil détecté */
.topo-file-item[data-eye="od"] {
  border-left: 4px solid #17a2b8;
}

.topo-file-item[data-eye="og"] {
  border-left: 4px solid #28a745;
}

.topo-file-item[data-eye="both"] {
  border-left: 4px solid #ffc107;
}

.eye-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 12px;
  font-size: 11px;
  font-weight: bold;
  margin-left: 8px;
}

.eye-badge.od {
  background: #e3f2fd;
  color: #1976d2;
}

.eye-badge.og {
  background: #e8f5e9;
  color: #388e3c;
}

.eye-badge.both {
  background: #fff3e0;
  color: #f57c00;
}
    `;
    document.head.appendChild(style);
    console.log('Styles personnalisés injectés');
  }

  // État de l'auto-save
  let autoSaveEnabled = true;


  // Afficher une notification
  function showToast(message) {
    const toast = document.createElement('div');
    toast.className = 'clickfit-toast';
    toast.textContent = message;
    document.body.appendChild(toast);

    setTimeout(() => toast.classList.add('show'), 10);
    setTimeout(() => {
      toast.classList.remove('show');
      setTimeout(() => toast.remove(), 300);
    }, 3000);
  }

  // Menu bouton flottant en bas à droite
  function toggleMenu() {
    const fab = document.querySelector('.clickfit-fab');
    const menu = document.querySelector('.clickfit-fab-menu');
    fab.classList.toggle('active');
    menu.classList.toggle('active');
  }


  // Passage de l'astigmatisme en rouge si > 1,00 Dioptrie
   function recolorAstigmatisme() {
  // Chercher TOUS les éléments contenant "Astigmatisme interne"
  const allElements = document.querySelectorAll('amds-text div, .amds-text div');

  allElements.forEach(el => {
    const txt = el.textContent.trim();

    // Vérifier que c'est bien l'astigmatisme interne
    if (!/Astigmatisme interne/i.test(txt)) return;

    console.log('Astigmatisme trouvé:', txt);

    // Regex plus flexible pour extraire la valeur
    // Accepte différents formats : "1.25", "1,25", "+1.25", "-1.25", "1.25 /", etc.
    const patterns = [
      /Astigmatisme interne\s*[::]?\s*([-+−]?\d+[.,]\d+)/i,
      /Astigmatisme interne\s*[::]?\s*([-+−]?\d+)/i,
      /([-+−]?\d+[.,]\d+)\s*(?:D|dioptries)?/i
    ];

    let value = null;
    for (let pattern of patterns) {
      const match = txt.match(pattern);
      if (match) {
        value = parseFloat(match[1].replace(',', '.').replace('−', '-'));
        break;
      }
    }

    console.log('Valeur extraite:', value);

    if (value !== null && Math.abs(value) > 1.00) {
      el.style.color = 'red';
      el.style.fontWeight = 'bold';
      console.log('→ Mise en rouge (>', 1.00);
    } else {
      el.style.color = '';
      el.style.fontWeight = '';
    }
  });
}

// Observer avec debounce
let debounceTimer;
const observer = new MutationObserver(() => {
  clearTimeout(debounceTimer);
  debounceTimer = setTimeout(() => {
    recolorAstigmatisme();
  }, 100); // Réduit le délai à 100ms
});

// Observer
observer.observe(document.body, {
  childList: true,
  subtree: true,
  characterData: true
});

// Exécution
recolorAstigmatisme();
setInterval(recolorAstigmatisme, 2000);



  // Bouton flottant
  function createFloatingButton() {
    if (document.querySelector('.clickfit-fab')) return;

    const fab = document.createElement('div');
    fab.className = 'clickfit-fab';
    fab.innerHTML = '<span class="clickfit-fab-icon">+</span>';

    const menu = document.createElement('div');
    menu.className = 'clickfit-fab-menu';

    const menuOptions = [
      {
        icon: '📄',
        text: 'Copier les paramètres',
        action: copyParametersToClipboard
      },

       // Split View
      {
        icon: '🖥️',
        text: 'Split View',
        action: () => {
          activateSplitView();
          toggleMenu();
        }
      },
      {
        icon: '🔭',
        text: 'Calcul LRPG (F4)',
        action: performLRPGCalculation
      },
       {
        icon: '🔬',
        text: 'Calcul OrthoK (F3) ',
        action: performOrthoKCalculation
      },
      {
        icon: '📋',
        text: 'Dupliquer OD→OG (F2)',
        action: duplicateODtoOG
      },
      {
        icon: '👓',
        text: 'Coller réfraction (F1)',
        action: pasteRefractionFromClipboard
      },
      // Import Topographie
      {
        icon: '🖥️',
        text: 'Import Topographies',
        action: () => {
          if (window.DesktopImportModule) {
            window.DesktopImportModule.showDesktopImportModal();
          } else {
            showToast('❌ Module d\'import non chargé');
          }
          toggleMenu();
        }
      },

      // Créer un client
      // {
      //   icon: '👤',
      //   text: 'Créer un client',
      //   action: () => {
      //     automateClientCreation();
      //     toggleMenu();
      //   }
      // }
    ];

    menuOptions.forEach(option => {
      const optionEl = document.createElement('div');
      optionEl.className = 'clickfit-fab-option';
      optionEl.innerHTML = `
        <div class="clickfit-fab-option-icon">${option.icon}</div>
        <div class="clickfit-fab-option-text">${option.text}</div>
      `;
      optionEl.addEventListener('click', () => {
        option.action();
        // Éviter double-toggle

      });
      menu.appendChild(optionEl);
    });

    document.body.appendChild(fab);
    document.body.appendChild(menu);

    fab.addEventListener('click', toggleMenu);

    document.addEventListener('click', (e) => {
      if (!fab.contains(e.target) && !menu.contains(e.target)) {
        fab.classList.remove('active');
        menu.classList.remove('active');
      }
    });
  }

  // Création automatique de client
  function automateClientCreation() {
    // Cliquer sur "Liste des clients"
    const listeBtn = document.querySelector('header nav ul li:nth-child(2) button');
    if (!listeBtn) return alert("Bouton 'Liste des clients' introuvable");
    listeBtn.click();

    setTimeout(() => {
      // Cliquer sur "Ajouter un client"
      const ajouterBtn = document.querySelector('main app-list amds-button:nth-child(2) button');
      if (!ajouterBtn) return alert("Bouton 'Ajouter un client' introuvable");
      ajouterBtn.click();

      setTimeout(() => {
        // Récupérer texte du presse-papiers
        navigator.clipboard.readText().then(text => {
          const lines = text.split(/\n|<br>|,/).map(l => l.trim()).filter(Boolean);

          let compte = lines.find(l => /\d{8}/.test(l))?.match(/\d{8}/)?.[0] ?? '';
          let mail = lines.find(l => /@/.test(l)) ?? '';
          let tel = lines.find(l => /\d{9,}/.test(l)) ?? '';

          // Remplir les champs
          document.querySelector('#input-accountNumber')?.focus();
          if (document.querySelector('#input-accountNumber')) document.querySelector('#input-accountNumber').value = compte;

          document.querySelector('#input-phoneNumber')?.focus();
          if (document.querySelector('#input-phoneNumber')) document.querySelector('#input-phoneNumber').value = tel;

          document.querySelector('#input-email')?.focus();
          if (document.querySelector('#input-email')) document.querySelector('#input-email').value = mail;
        }).catch(() => {
          alert("Impossible de lire le presse-papiers");
        });
      }, 500);
    }, 500);
  }

  // Auto-consultation sur clic porteur

  (function setupAutoConsultationClick() {
    function waitAndClick(selector, maxWait = 4000) {
      return new Promise((resolve, reject) => {
        const start = Date.now();
        const interval = setInterval(() => {
          const el = document.querySelector(selector);
          if (el) {
            el.click();
            clearInterval(interval);
            resolve(true);
          } else if (Date.now() - start > maxWait) {
            clearInterval(interval);
            reject(`Timeout: ${selector} non trouvé`);
          }
        }, 100);
      });
    }

    document.body.addEventListener('click', function(e) {
      const tr = e.target.closest('#wearer-list-table tr.selectable');
      if (!tr) return;

      // Éviter double-trigger
      if (tr.dataset.autoConsulting) return;
      tr.dataset.autoConsulting = "1";

      // Attendre Angular
      setTimeout(async () => {
        // Vérifier sélection
        if (!tr.classList.contains('selected')) {
          delete tr.dataset.autoConsulting;
          return;
        }

        try {
          await waitAndClick(
            '#wrapper > main > app-home > div > div:nth-child(2) > app-files-list > div.files.hide-scrollbars.ng-star-inserted > app-file-card:nth-child(1)'
          );
          // showToast('Consultation ouverte !');
        } catch (err) {
          console.warn('[AutoConsultation]', err);
        } finally {
          // Reset
          delete tr.dataset.autoConsulting;
        }
      }, 400);
    }, true);


  })();

    // Copier paramètres
  function copyParametersToClipboard() {


    try {
      const nameElement = document.querySelector('#wrapper > header > div.header__team-selector.ng-star-inserted > app-file-header-info > div > amds-text.file-wearer-name.hydrated > div');
      const name = nameElement ? nameElement.textContent.trim() : 'Non renseigné';

      const dateOfBirth = '02/01/2015';

      const getValue = (selector) => {
        const element = document.querySelector(selector);
        return element ? element.value : null;
      };

      const getSelectedText = (selector) => {
        const element = document.querySelector(selector);
        if (!element) return null;
        const selectedOption = element.options[element.selectedIndex];
        return selectedOption ? selectedOption.textContent.trim() : null;
      };

      const formatMaterial = (material) => {
        if (!material) return '';
        let formatted = material.replace(/^(Boston|Contamac)\s*/i, '');
        if (formatted === 'XO 100') {
          formatted = 'XO';
        }
        return formatted;
      };

      const formatModel = (model) => {
        if (!model) return 'Non renseigné';
        const parts = model.split(':');
        const lastPart = parts[parts.length - 1];
        return lastPart.toUpperCase();
      };

      const buildEyeParameters = (side) => {
        const prefix = side === 'right' ? 'right' : 'left';

        const diameter = getValue(`#input-${prefix}totalDiameter`);
        const k = getValue(`#input-${prefix}kParameter`);
        const kp = getValue(`#input-${prefix}steepKParameter`);
        const m = getValue(`#input-${prefix}mParameter`);
        const h = getValue(`#input-${prefix}hParameter`);
        const c = getValue(`#input-${prefix}cParameter`);
        const p = getValue(`#input-${prefix}pParameter`);
        const pp = getValue(`#input-${prefix}steepPParameter`);

        let zof = getValue(`#input-${prefix}backFlatOpticalComplementaryDiameter`);
        let zos = getValue(`#input-${prefix}backSteepOpticalComplementaryDiameter`);

        if (!zof) {
          zof = getValue(`#input-${prefix}backOpticalZoneDiameter`);
        }

        let params = [];

        if (diameter) params.push(`ØT ${diameter}`);
        if (k) params.push(`K ${k}`);
        if (kp && parseFloat(kp) !== 0) params.push(`Kp ${kp}`);
        if (m) {
          params.push(`M ${m}`);
        } else if (h) {
          params.push(`H ${h}`);
        }
        if (c && parseFloat(c) !== 0) params.push(`C ${c}`);
        if (p) params.push(`P ${p}`);
        if (pp && parseFloat(pp) !== 0) params.push(`P' ${pp}`);

        if (zof && parseFloat(zof) !== 0) {
          let myopicParams = [`Zof ${zof}`];
          const zosValue = (zos && parseFloat(zos) !== 0) ? zos : zof;
          myopicParams.push(`Zos ${zosValue}`);
          params.push(`Contrôle myopique : ${myopicParams.join(', ')}`);
        }

        return params.join(', ');
      };

      const rightModel = formatModel(getValue('#input-rightmodel'));
      const rightMaterial = formatMaterial(getSelectedText('#input-rightmaterial'));
      const rightColor = getSelectedText('#input-rightcolor') || '';
      const rightParams = buildEyeParameters('right');

      let rightModelDesc = rightModel;
      if (rightMaterial) rightModelDesc += ` - ${rightMaterial}`;
      if (rightColor) rightModelDesc += ` ${rightColor}`;

      const leftModel = formatModel(getValue('#input-leftmodel'));
      const leftMaterial = formatMaterial(getSelectedText('#input-leftmaterial'));
      const leftColor = getSelectedText('#input-leftcolor') || '';
      const leftParams = buildEyeParameters('left');

      let leftModelDesc = leftModel;
      if (leftMaterial) leftModelDesc += ` - ${leftMaterial}`;
      if (leftColor) leftModelDesc += ` ${leftColor}`;

      const textToCopy = `Porteur
Nom = ${name}
Date de naissance = ${dateOfBirth}

Œil droit
Modèle = ${rightModelDesc}
Paramètres = ${rightParams || 'Non renseignés'}

Œil gauche
Modèle = ${leftModelDesc}
Paramètres = ${leftParams || 'Non renseignés'}`;

      navigator.clipboard.writeText(textToCopy).then(() => {
        showToast('📄 Paramètres copiés dans le presse-papier !');
        console.log('Texte copié :', textToCopy);
      }).catch(err => {
        console.error('Erreur lors de la copie :', err);
        showToast('❌ Erreur lors de la copie');
      });

    } catch (error) {
      console.error('Erreur lors de la récupération des paramètres :', error);
      showToast('❌ Erreur lors de la récupération des paramètres');
    }
  }

  // Module Import Topographies
  const DesktopImportModule = {
      apiUrl: 'http://localhost:8765/api',
      currentGroups: [],

      init() {
          console.log('🖥️ Module Import Topo initialisé');
          this.injectModalStyles();
          // Debug
          window.DIM = this;
      },

      injectModalStyles() {
          if (document.getElementById('desktop-import-styles')) return;

          const style = document.createElement('style');
          style.id = 'desktop-import-styles';
          style.textContent = `
              /* Overlay pour bloquer l'arrière-plan */
              .dim-overlay {
                  position: fixed;
                  top: 0;
                  left: 0;
                  width: 100vw;
                  height: 100vh;
                  background: rgba(0, 0, 0, 0.5);
                  z-index: 999998;
              }

              .dim-modal {
                  position: fixed;
                  top: 50%;
                  left: 50%;
                  transform: translate(-50%, -50%);
                  background: white;
                  border-radius: 12px;
                  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
                  z-index: 999999;
                  min-width: 500px;
                  max-width: 80vw;
                  max-height: 80vh;
                  overflow: hidden;
              }

              .dim-header {
                  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                  color: white;
                  padding: 15px 20px;
                  display: flex;
                  justify-content: space-between;
                  align-items: center;
              }

              .dim-close {
                  background: none;
                  border: none;
                  color: white;
                  font-size: 24px;
                  cursor: pointer;
                  padding: 0;
                  width: 30px;
                  height: 30px;
              }

              .dim-body {
                  padding: 20px;
                  max-height: 60vh;
                  overflow-y: auto;
              }

              .dim-group {
                  background: #f8f9fa;
                  border: 2px solid #dee2e6;
                  border-radius: 8px;
                  padding: 15px;
                  margin-bottom: 15px;
              }

              .dim-group.selected-od {
                  border-color: #2196f3;
                  background: #e3f2fd;
              }

              .dim-group.selected-og {
                  border-color: #4caf50;
                  background: #e8f5e9;
              }

              .dim-buttons {
                  display: flex;
                  gap: 10px;
                  margin-top: 10px;
              }

              .dim-btn {
                  flex: 1;
                  padding: 8px;
                  border: 1px solid #ddd;
                  background: white;
                  border-radius: 4px;
                  cursor: pointer;
              }

              .dim-btn:hover {
                  background: #f0f0f0;
              }

              .dim-btn.active-od {
                  background: #2196f3;
                  color: white;
              }

              .dim-btn.active-og {
                  background: #4caf50;
                  color: white;
              }

              .dim-footer {
                  padding: 15px 20px;
                  border-top: 1px solid #ddd;
                  text-align: center;
              }

              .dim-import-btn {
                  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                  color: white;
                  border: none;
                  padding: 12px 30px;
                  border-radius: 6px;
                  font-size: 16px;
                  cursor: pointer;
              }

              .dim-import-btn:disabled {
                  opacity: 0.5;
                  cursor: not-allowed;
              }
          `;
          document.head.appendChild(style);
      },

      async showDesktopImportModal() {
          console.log('🔍 Début scan bureau...');

          try {
              // Test connexion
              const testResponse = await fetch(`${this.apiUrl}/status`);
              if (!testResponse.ok) {
                  throw new Error('Scanner non accessible');
              }

              // Scanner bureau
              const response = await fetch(`${this.apiUrl}/scan-desktop`);
              const data = await response.json();

              console.log('📊 Réponse scan:', data);

              if (!data.success) {
                  throw new Error(data.error || 'Erreur scan');
              }

              if (!data.groups || data.groups.length === 0) {
                  alert('📭 Aucune topographie trouvée sur le bureau');
                  return;
              }

              // Stocker groupes
              this.currentGroups = data.groups;

              // Créer modal
              this.createSimpleModal();

          } catch (error) {
              console.error('❌ Erreur:', error);
              alert('❌ Erreur: Vérifiez que le scanner Python est lancé\n\n' + error.message);
          }
      },

      createSimpleModal() {
          // Nettoyer modal
          this.closeModal();

          // Overlay
          const overlay = document.createElement('div');
          overlay.className = 'dim-overlay';
          overlay.id = 'dim-overlay';

          // Modal
          const modal = document.createElement('div');
          modal.className = 'dim-modal';
          modal.id = 'dim-modal';

          // HTML
          let groupsHtml = '';
          this.currentGroups.forEach((group, index) => {
              groupsHtml += `
                  <div class="dim-group" data-index="${index}">
                      <strong>${group.icon} ${group.topographer_name}</strong>
                      <div style="font-size: 12px; color: #666; margin: 5px 0;">
                          ${group.files.map(f => '• ' + f.split('\\').pop()).join('<br>')}
                      </div>
                      <div class="dim-buttons">
                          <button class="dim-btn dim-select-od" data-index="${index}" data-eye="od">
                              OD
                          </button>
                          <button class="dim-btn dim-select-og" data-index="${index}" data-eye="og">
                              OG
                          </button>
                          <button class="dim-btn dim-select-skip" data-index="${index}" data-eye="skip">
                              Ignorer
                          </button>
                      </div>
                  </div>
              `;
          });

          modal.innerHTML = `
              <div class="dim-header">
                  <h3>Import depuis le bureau (${this.currentGroups.length} groupes)</h3>
                  <button class="dim-close" id="dim-close">×</button>
              </div>
              <div class="dim-body">

                  ${groupsHtml}
              </div>
              <div class="dim-footer">
                  <button class="dim-import-btn" id="dim-import">
                      Lancer l'import
                  </button>
              </div>
          `;

          // Ajouter DOM
          document.body.appendChild(overlay);
          document.body.appendChild(modal);

          // Attacher événements
          this.attachEvents();

          console.log('✅ Modal créé avec', this.currentGroups.length, 'groupes');
      },

      attachEvents() {
          const modal = document.getElementById('dim-modal');
          if (!modal) {
              console.error('Modal non trouvé !');
              return;
          }

          // Fermer modal
          document.getElementById('dim-close')?.addEventListener('click', () => {
              console.log('Fermeture modal');
              this.closeModal();
          });

          document.getElementById('dim-overlay')?.addEventListener('click', () => {
              this.closeModal();
          });

          // Sélection
          modal.querySelectorAll('.dim-btn').forEach(btn => {
              btn.addEventListener('click', (e) => {
                  const index = parseInt(btn.dataset.index);
                  const eye = btn.dataset.eye;
                  console.log(`Clic: Groupe ${index} → ${eye}`);
                  this.selectGroupEye(index, eye);
              });
          });

          // Tout OD
          document.getElementById('dim-all-od')?.addEventListener('click', () => {
              console.log('Tout en OD');
              this.currentGroups.forEach((g, i) => this.selectGroupEye(i, 'od'));
          });

          // Tout OG
          document.getElementById('dim-all-og')?.addEventListener('click', () => {
              console.log('Tout en OG');
              this.currentGroups.forEach((g, i) => this.selectGroupEye(i, 'og'));
          });

          // Import
          document.getElementById('dim-import')?.addEventListener('click', () => {
              console.log('Lancement import');
              this.startImport();
          });

          // ESC
          document.addEventListener('keydown', this.escHandler = (e) => {
              if (e.key === 'Escape') this.closeModal();
          });
      },

      selectGroupEye(index, eye) {
          const group = this.currentGroups[index];
          if (!group) return;

          // Mettre à jour
          group.selectedEye = eye;

          // UI
          const groupEl = document.querySelector(`.dim-group[data-index="${index}"]`);
          if (groupEl) {
              // Reset
              groupEl.classList.remove('selected-od', 'selected-og');
              groupEl.querySelectorAll('.dim-btn').forEach(b => {
                  b.classList.remove('active-od', 'active-og');
              });

              // Classes
              if (eye === 'od') {
                  groupEl.classList.add('selected-od');
                  groupEl.querySelector('.dim-select-od').classList.add('active-od');
              } else if (eye === 'og') {
                  groupEl.classList.add('selected-og');
                  groupEl.querySelector('.dim-select-og').classList.add('active-og');
              }
          }

          console.log(`✅ Groupe ${group.topographer_name} → ${eye}`);
      },

      closeModal() {
          document.getElementById('dim-modal')?.remove();
          document.getElementById('dim-overlay')?.remove();
          if (this.escHandler) {
              document.removeEventListener('keydown', this.escHandler);
          }
      },

    async startImport() {
        const toImport = this.currentGroups.filter(g => g.selectedEye && g.selectedEye !== 'skip');

        if (toImport.length === 0) {
            alert('⚠️ Sélectionnez au moins un œil pour l\'import');
            return;
        }

        console.log(`🚀 Import séquentiel de ${toImport.length} groupe(s)...`);

        // Fermer modal
        this.closeModal();

        // Toast
        if (window.showToast) {
            window.showToast(`🚀 Import de ${toImport.length} groupe(s) en cours...`);
        }

        let successCount = 0;
        let errorCount = 0;

        // Import séquentiel
        for (let i = 0; i < toImport.length; i++) {
            const group = toImport[i];

            try {
                console.log(`📦 Import ${i + 1}/${toImport.length}: ${group.topographer_name} → ${group.selectedEye.toUpperCase()}`);

                // Progression
                if (window.showToast) {
                    window.showToast(`Import ${i + 1}/${toImport.length}: ${group.topographer_name} → ${group.selectedEye.toUpperCase()}`);
                }

                // Attendre import
                await this.performRealImport(group, group.selectedEye);

                successCount++;

                // Pause
                if (i < toImport.length - 1) {
                    console.log('⏳ Pause avant le prochain import...');
                    await new Promise(r => setTimeout(r, 2000));
                }

            } catch (error) {
                console.error(`❌ Erreur import ${group.topographer_name}:`, error);
                errorCount++;
            }
        }

        // Résultat
        // const message = `Terminé: ${successCount} importé(s)` +
        //                 (errorCount > 0 ? `, ${errorCount} erreur(s)` : '');

        // if (window.showToast) {
        //     window.showToast(message);
        // } else {
        //     alert(message);
        // }

        // Rafraîchir
        if (window.TopographyModule) {
            window.TopographyModule.checkForFiles();
        }
    },

    async performRealImport(group, eye) {
      console.log(`🎯 Import: ${group.topographer_name} vers ${eye.toUpperCase()}`);

      try {
          // Bouton download
          let uploadButton;

          if (eye === 'od') {
              uploadButton = document.querySelector('app-file-information-eye:nth-child(1) button i.ri-download-2-fill')?.parentElement?.parentElement;
              if (!uploadButton) {
                  uploadButton = document.querySelector('app-file-information-eye:nth-child(1) button:has(i.ri-download-2-fill)');
              }
          } else {
              uploadButton = document.querySelector('app-file-information-eye:nth-child(2) button i.ri-download-2-fill')?.parentElement?.parentElement;
              if (!uploadButton) {
                  uploadButton = document.querySelector('app-file-information-eye:nth-child(2) button:has(i.ri-download-2-fill)');
              }
          }

          if (!uploadButton) {
              const allButtons = document.querySelectorAll('button');
              const downloadButtons = Array.from(allButtons).filter(b =>
                  b.querySelector('i.ri-download-2-fill')
              );

              if (eye === 'od' && downloadButtons[0]) {
                  uploadButton = downloadButtons[0];
              } else if (eye === 'og' && downloadButtons[1]) {
                  uploadButton = downloadButtons[1];
              }
          }

          if (!uploadButton) {
              console.error(`❌ Bouton ${eye} non trouvé`);
              alert(`Bouton d'import ${eye.toUpperCase()} non trouvé`);
              return;
          }

          console.log('✅ Bouton trouvé, clic...');
          uploadButton.click();

          // Attendre modal
          await new Promise(r => setTimeout(r, 1500));

          // Sélection topographe
          const topographerSelect = document.querySelector('#input-topographer');
          if (topographerSelect) {
              console.log(`🔍 Sélection du topographe: ${group.topographer_name}`);

              const topographerMapping = {
                  'tms4': 'tms_4',
                  'tms5': 'tms_5',
                  'medmont': 'medmont_6',
                  'pentacam': 'oculus_pentacam',
                  'keratron': 'keratron_scout',
                  'atlas': 'atlas9000',
                  'phoenix': 'sirius_phoenix',
                  'ca200': 'ca200',
                  'opd_scan': 'opdscan',
                  'orbscan': 'orbscan',
                  'keratograph': 'oculus_keratograph',
                  'easygraph': 'oculus_easygraph'
              };

              const selectValue = topographerMapping[group.topographer];

              if (selectValue) {
                  topographerSelect.value = selectValue;
                  topographerSelect.dispatchEvent(new Event('change', { bubbles: true }));
                  topographerSelect.dispatchEvent(new Event('input', { bubbles: true }));
                  console.log(`✅ Topographe sélectionné: ${selectValue}`);
                  await new Promise(r => setTimeout(r, 500));
              } else {
                  console.log(`⚠️ Pas de mapping pour: ${group.topographer}`);

                  // Recherche par nom
                  const options = topographerSelect.querySelectorAll('option');
                  options.forEach(option => {
                      const optionText = option.textContent.trim().toLowerCase();
                      const groupName = group.topographer_name.toLowerCase();

                      if (optionText.includes(groupName) || groupName.includes(optionText)) {
                          topographerSelect.value = option.value;
                          topographerSelect.dispatchEvent(new Event('change', { bubbles: true }));
                          console.log(`✅ Topographe trouvé par nom: ${option.value}`);
                      }
                  });
              }
          }

          // Input file
          const fileInput = document.querySelector('input[type="file"]');
          if (!fileInput) {
              console.error('❌ Input file non trouvé');
              return;
          }

          console.log('✅ Modal d\'upload ouvert');

          // Charger fichiers
          const files = [];
          for (const filepath of group.files) {
              const filename = filepath.split('/').pop().split('\\').pop();
              console.log(`Téléchargement: ${filename}`);

              try {
                  const response = await fetch(`${this.apiUrl}/file/${filename}`);

                  if (!response.ok) {
                      console.error(`Fichier non trouvé: ${filename}`);
                      continue;
                  }

                  const blob = await response.blob();
                  console.log(`Fichier reçu: ${filename} (${blob.size} octets)`);

                  const file = new File([blob], filename, {
                      type: blob.type || 'application/octet-stream',
                      lastModified: Date.now()
                  });

                  files.push(file);

              } catch (error) {
                  console.error(`❌ Erreur téléchargement ${filename}:`, error);
              }
          }

          if (files.length === 0) {
              console.error('❌ Aucun fichier chargé');
              return;
          }

          console.log(`📊 ${files.length} fichiers prêts`);

          // Assigner fichiers
          const dt = new DataTransfer();
          files.forEach(file => dt.items.add(file));

          try {
              fileInput.files = dt.files;
          } catch(e) {
              Object.defineProperty(fileInput, 'files', {
                  value: dt.files,
                  writable: false,
                  configurable: true
              });
          }

          fileInput.dispatchEvent(new Event('change', { bubbles: true }));
          console.log('Fichiers assignés à l\'input');

          // Attendre un peu
          await new Promise(r => setTimeout(r, 800));

          // Bouton Importer
          const importBtn = Array.from(document.querySelectorAll('button')).find(btn =>
              btn.textContent.includes('Importer') && !btn.disabled
          );

          if (importBtn) {
              console.log('✅ Clic sur Importer');
              importBtn.click();

              // Marquer importé
              await this.markAsImported(group.files, group);

              // Marquer serveur
              await this.markAsImported(group.files);

              await new Promise(r => setTimeout(r, 2000));
              console.log(' Import terminé');
          } else {
              console.error(' Bouton Importer non trouvé dans le modal');
          }

      } catch (error) {
          console.error(' Erreur import:', error);
      }
    },

    async loadFilesFromServer(group) {
          const files = [];

          for (const filepath of group.files) {
              try {
                  // Extraire nom fichier
                  const filename = filepath.split('/').pop().split('\\').pop();
                  console.log(` Chargement: ${filename}`);

                  // Appeler API
                  const response = await fetch(`${this.apiUrl}/file/${encodeURIComponent(filename)}`);

                  if (!response.ok) {
                      console.error(` Erreur chargement ${filename}: ${response.status}`);
                      continue;
                  }

                  const blob = await response.blob();
                  console.log(` Fichier reçu: ${filename} (${blob.size} octets)`);

                  // Créer File
                  const file = new File([blob], filename, {
                      type: this.getMimeType(filename)
                  });

                  files.push(file);

              } catch (error) {
                  console.error(` Erreur chargement fichier:`, error);
              }
          }

          console.log(`📊 Total: ${files.length} fichiers chargés`);
          return files;
    },

    getMimeType(filename) {
          const ext = filename.split('.').pop().toLowerCase();
          const mimeTypes = {
              'tgl': 'application/octet-stream',
              'hgt': 'application/octet-stream',
              'dst': 'application/octet-stream',
              'csv': 'text/csv',
              'txt': 'text/plain',
              'xml': 'text/xml',
              'dat': 'application/octet-stream'
          };
          return mimeTypes[ext] || 'application/octet-stream';
      },

    async waitForUploadModal(maxWait = 5000) {
        const startTime = Date.now();

        while (Date.now() - startTime < maxWait) {
            const modal = document.querySelector('.modal, app-modal, [role="dialog"]');
            if (modal) {
                console.log(' Modal d\'upload trouvée');
                await new Promise(r => setTimeout(r, 500));
                return modal;
            }
            await new Promise(r => setTimeout(r, 100));
        }

        throw new Error('Timeout: Modal non trouvée');
    },

    async findDropzone() {
        // Sélecteurs
        const selectors = [
            '.dropzone.visible',
            '.dropzone',
            'app-files-dropzone .dropzone',
            '[class*="drop"][class*="zone"]',
            '.modal input[type="file"]'
        ];

        for (const selector of selectors) {
            const element = document.querySelector(selector);
            if (element) {
                console.log(` Dropzone trouvée: ${selector}`);
                return element;
            }
        }

        // Input file parent
        const fileInput = document.querySelector('input[type="file"]');
        if (fileInput) {
            return fileInput.parentElement;
        }

        return null;
    },

    async findValidateButton() {
        // Sélecteurs bouton
        const selectors = [
            '.modal__footer button[type="submit"]',
            '.modal__footer button.modal-submit-btn',
            '.modal button:last-child',
            'button[class*="submit"]',
            'button[class*="import"]'
        ];

        for (const selector of selectors) {
            const button = document.querySelector(selector);
            if (button && !button.disabled) {
                // Vérifier bouton
                const text = button.textContent.toLowerCase();
                if (text.includes('import') || text.includes('valid') || text.includes('ok')) {
                    return button;
                }
            }
        }

        // Recherche texte
        const allButtons = document.querySelectorAll('.modal button, app-modal button');
        for (const button of allButtons) {
            const text = button.textContent.toLowerCase();
            if ((text.includes('import') || text.includes('valid')) && !button.disabled) {
                return button;
            }
        }

        return null;
    },

    async waitForModalClose(maxWait = 5000) {
        const startTime = Date.now();

        while (Date.now() - startTime < maxWait) {
            const modal = document.querySelector('.modal, app-modal');
            if (!modal) {
                console.log(' Modal fermée');
                return;
            }
            await new Promise(r => setTimeout(r, 100));
        }
    },

    async markAsImported(files, groupInfo = null) {
    try {
        // Vérifier TMS-4
        const keepXref = groupInfo && groupInfo.topographer === 'tms4' && groupInfo.multiple_eyes;

        await fetch(`${this.apiUrl}/mark-imported`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                files: files,
                move: true,
                keep_xref: keepXref
            })
        });
        console.log('Fichiers marqués comme importés' + (keepXref ? ' (XREF conservé)' : ''));
    } catch (error) {
        console.error('Erreur marquage:', error);
    }
  }
  };

  // Global
  window.DesktopImportModule = DesktopImportModule;

  // Auto-init
  setTimeout(() => {
      if (window.DesktopImportModule) {
          window.DesktopImportModule.init();
          console.log('Module Import Topographie prêt');
      }
  }, 2000);



  // Dupliquer OD vers OG
  function duplicateODtoOG() {
    console.log('Début de la duplication OD→OG');

    const mappings = [
      {
        from: '#input-rightsphere',
        to: '#input-leftsphere',
        name: 'Sphère'
      },
      {
        from: '#input-rightcylinder',
        to: '#input-leftcylinder',
        name: 'Cylindre'
      },
      {
        from: '#input-rightrefractionAxis',
        to: '#input-leftrefractionAxis',
        name: 'Axe'
      }
    ];

    let copiedCount = 0;
    let errorMessages = [];

    mappings.forEach(mapping => {
      const fromInput = document.querySelector(mapping.from);
      const toInput = document.querySelector(mapping.to);

      if (fromInput && toInput) {
        const value = fromInput.value;

        if (value && value !== '') {
          toInput.value = value;
          toInput.dispatchEvent(new Event('input', { bubbles: true }));
          toInput.dispatchEvent(new Event('change', { bubbles: true }));

          if (mapping.name === 'Sphère' || mapping.name === 'Cylindre') {
            const numValue = parseFloat(value);
            if (!isNaN(numValue)) {
              toInput.value = numValue.toFixed(2);
            }
          }

          console.log(` ${mapping.name}: ${value} copié de OD vers OG`);
          copiedCount++;
        }
      } else {
        if (!fromInput) {
          errorMessages.push(`Input source ${mapping.from} introuvable`);
        }
        if (!toInput) {
          errorMessages.push(`Input destination ${mapping.to} introuvable`);
        }
      }
    });

    if (copiedCount > 0) {
      showToast(` ${copiedCount} valeur(s) copiée(s) de OD vers OG`);
    } else if (errorMessages.length > 0) {
      showToast(' Erreur lors de la duplication');
      console.error('Erreurs de duplication:', errorMessages);
    } else {
      showToast(' Aucune valeur à copier');
    }
  }

  // Calcul OrthoK
  async function performOrthoKCalculation() {
    showToast('🔬 Démarrage du calcul OrthoK...');
    console.log('🔬 Début du calcul OrthoK');

    try {
      // Onglet lentille
      const lensTab = document.querySelector('#wrapper > main > app-file-layout > div > app-tabs-list > div.tabs-container.has-actions > div.tabs.theme--classic.has-separators > div.tab.lens-0-tab.clickable.ng-star-inserted');
      if (lensTab) {
        lensTab.click();
        console.log(' Clic sur l\'onglet lentille');
        await new Promise(resolve => setTimeout(resolve, 1000));
      } else {
        console.warn('Onglet lentille non trouvé, on continue...');
      }

      // Sélection OrthoK pour OD
      const rightTypeSelect = document.querySelector('#input-righttype');
      if (rightTypeSelect) {
        rightTypeSelect.value = 'lens:type:orthok';
        rightTypeSelect.dispatchEvent(new Event('change', { bubbles: true }));
        rightTypeSelect.dispatchEvent(new Event('input', { bubbles: true }));
        console.log(' OrthoK sélectionné pour OD');
      } else {
        console.error(' Select OD non trouvé');
      }
      await new Promise(resolve => setTimeout(resolve, 500));

      // Sélection OrthoK pour OG
      const leftTypeSelect = document.querySelector('#input-lefttype');
      if (leftTypeSelect) {
        leftTypeSelect.value = 'lens:type:orthok';
        leftTypeSelect.dispatchEvent(new Event('change', { bubbles: true }));
        leftTypeSelect.dispatchEvent(new Event('input', { bubbles: true }));
        console.log(' OrthoK sélectionné pour OG');
      } else {
        console.error(' Select OG non trouvé');
      }
      await new Promise(resolve => setTimeout(resolve, 500));

      // Déclencher calcul
      if (rightTypeSelect) rightTypeSelect.blur();
      if (leftTypeSelect) leftTypeSelect.blur();

      // Bouton validation
      const validateBtn = document.querySelector('.modal__footer button.modal-submit-btn, .modal__footer button[type="submit"]');
      if (validateBtn && !validateBtn.disabled) {
        validateBtn.click();
        console.log(' Validation du calcul OrthoK');
      }

      showToast(' Calcul OrthoK terminé avec succès !');
      console.log(' Calcul OrthoK complété');
    } catch (error) {
      console.error(' Erreur lors du calcul OrthoK:', error);
      showToast(' Erreur lors du calcul OrthoK');
    }
  }

  // Calcul LRPG
  async function performLRPGCalculation() {
    showToast('Démarrage du calcul LRPG...');
    console.log('Début du calcul LRPG');

    try {
      const lensTab = document.querySelector('#wrapper > main > app-file-layout > div > app-tabs-list > div.tabs-container.has-actions > div.tabs.theme--classic.has-separators > div.tab.lens-0-tab.clickable.ng-star-inserted');

      if (!lensTab) {
        showToast('Onglet lentille introuvable');
        console.error('Onglet lentille non trouvé');
        return;
      }

      lensTab.click();
      console.log('Clic sur l\'onglet lentille');

      await new Promise(resolve => setTimeout(resolve, 1000));

      const rightTypeSelect = document.querySelector('#input-righttype');
      if (rightTypeSelect) {
        rightTypeSelect.value = 'lens:type:rigid';
        rightTypeSelect.dispatchEvent(new Event('change', { bubbles: true }));
        console.log('LRPG (Rigide) sélectionné pour OD');
      } else {
        console.error('Select OD non trouvé');
      }

      await new Promise(resolve => setTimeout(resolve, 500));

      const leftTypeSelect = document.querySelector('#input-lefttype');
      if (leftTypeSelect) {
        leftTypeSelect.value = 'lens:type:rigid';
        leftTypeSelect.dispatchEvent(new Event('change', { bubbles: true }));
        console.log('LRPG (Rigide) sélectionné pour OG');
      } else {
        console.error(' Select OG non trouvé');
      }

      await new Promise(resolve => setTimeout(resolve, 500));

      showToast(' Calcul LRPG terminé avec succès !');
      console.log(' Calcul LRPG complété');

    } catch (error) {
      console.error(' Erreur lors du calcul LRPG:', error);
      showToast(' Erreur lors du calcul LRPG');
    }
  }

  // Coller réfraction
  async function pasteRefractionFromClipboard() {
    console.log('👓 Tentative de collage de réfraction...');

    try {
      const clipboardText = await navigator.clipboard.readText();
      console.log('Contenu du presse-papier:', clipboardText);

      const patterns = {
        compactFormat: /([+-]?\d+[.,]\d{2})\s*\(([+-]?\d+[.,]\d{2})\)\s*(\d+)[°]?/g,
        altFormat: /([+-]?\d+[.,]\d{2})\s*\(\s*([+-]?\d+[.,]\d{2})\s*[àa]\s*(\d+)[°]?\s*\)/g,
        cylinder: /([+-]?\d+[.,]\d{2})\s*[x×]\s*(\d+)[°]?/g,
        sphere: /([+-]?\d+[.,]\d{2})(?!\s*[°])/g
      };

      const cleanValue = (value) => {
        if (!value) return '';
        return value.replace(',', '.').trim();
      };

      const isEyeEmpty = (side) => {
        const sphereSelector = side === 'od' ? '#input-rightsphere' : '#input-leftsphere';
        const cylinderSelector = side === 'od' ? '#input-rightcylinder' : '#input-leftcylinder';
        const axisSelector = side === 'od' ? '#input-rightrefractionAxis' : '#input-leftrefractionAxis';

        const sphereInput = document.querySelector(sphereSelector);
        const cylinderInput = document.querySelector(cylinderSelector);
        const axisInput = document.querySelector(axisSelector);

        const isEmpty = (input) => {
          if (!input || !input.value || input.value === '') return true;
          const numValue = parseFloat(input.value);
          return numValue === 0;
        };

        return isEmpty(sphereInput) && isEmpty(cylinderInput) && isEmpty(axisInput);
      };

      let detectedValues = {
        od: { sphere: null, cylinder: null, axis: null },
        og: { sphere: null, cylinder: null, axis: null }
      };

      const lines = clipboardText.split('\n').map(l => l.trim()).filter(l => l);

      let currentEye = null;

      for (let i = 0; i < lines.length; i++) {
        const line = lines[i];

        if (/\b(OD|RE|Œil\s*droit|Oeil\s*droit|Right)/i.test(line)) {
          currentEye = 'od';
          console.log('👁️ Détection OD à la ligne', i);
        } else if (/\b(OG|OS|LE|Œil\s*gauche|Oeil\s*gauche|Left)/i.test(line)) {
          currentEye = 'og';
          console.log('👁️ Détection OG à la ligne', i);
        }

        patterns.compactFormat.lastIndex = 0;
        patterns.altFormat.lastIndex = 0;
        patterns.cylinder.lastIndex = 0;
        patterns.sphere.lastIndex = 0;

        const compactMatch = patterns.compactFormat.exec(line);
        if (compactMatch && currentEye) {
          detectedValues[currentEye].sphere = cleanValue(compactMatch[1]);
          detectedValues[currentEye].cylinder = cleanValue(compactMatch[2]);
          detectedValues[currentEye].axis = compactMatch[3];
          console.log(`✅ Format compact détecté pour ${currentEye}:`, detectedValues[currentEye]);
          continue;
        }

        patterns.altFormat.lastIndex = 0;

        const altMatch = patterns.altFormat.exec(line);
        if (altMatch && currentEye) {
          detectedValues[currentEye].sphere = cleanValue(altMatch[1]);
          detectedValues[currentEye].cylinder = cleanValue(altMatch[2]);
          detectedValues[currentEye].axis = altMatch[3];
          console.log(`✅ Format alternatif détecté pour ${currentEye}:`, detectedValues[currentEye]);
          continue;
        }

        patterns.cylinder.lastIndex = 0;

        const cylMatch = patterns.cylinder.exec(line);
        if (cylMatch && currentEye) {
          detectedValues[currentEye].cylinder = cleanValue(cylMatch[1]);
          detectedValues[currentEye].axis = cylMatch[2];
          console.log(`📐 Cylindre détecté pour ${currentEye}:`, cylMatch[1], 'x', cylMatch[2]);
        }

        patterns.sphere.lastIndex = 0;

        const sphereMatches = line.match(patterns.sphere);
        if (sphereMatches && currentEye) {
          for (const match of sphereMatches) {
            const cleanMatch = cleanValue(match);
            if (cleanMatch !== detectedValues[currentEye].cylinder) {
              detectedValues[currentEye].sphere = cleanMatch;
              console.log(`🔵 Sphère détectée pour ${currentEye}:`, cleanMatch);
              break;
            }
          }
        }
      }

      if (!detectedValues.od.sphere && !detectedValues.og.sphere &&
          !detectedValues.od.cylinder && !detectedValues.og.cylinder) {
        console.log('⚠️ Pas d\'identification OD/OG, tentative par ordre...');

        const refractionLines = lines.filter(line => {
          return /([+-]?\d+[.,]\d+)/.test(line);
        });

        console.log(`📊 Nombre de lignes de réfraction trouvées: ${refractionLines.length}`);

        if (refractionLines.length >= 1) {
          const firstLine = refractionLines[0];
          console.log('📝 Analyse première ligne:', firstLine);

          patterns.compactFormat.lastIndex = 0;
          patterns.altFormat.lastIndex = 0;
          patterns.cylinder.lastIndex = 0;
          patterns.sphere.lastIndex = 0;

          let compactMatch = patterns.compactFormat.exec(firstLine);
          if (compactMatch) {
            detectedValues.od.sphere = cleanValue(compactMatch[1]);
            detectedValues.od.cylinder = cleanValue(compactMatch[2]);
            detectedValues.od.axis = compactMatch[3];
            console.log('✅ Format compact détecté pour OD (par ordre):', detectedValues.od);
          } else {
            patterns.altFormat.lastIndex = 0;
            let altMatch = patterns.altFormat.exec(firstLine);
            if (altMatch) {
              detectedValues.od.sphere = cleanValue(altMatch[1]);
              detectedValues.od.cylinder = cleanValue(altMatch[2]);
              detectedValues.od.axis = altMatch[3];
            } else {
              patterns.sphere.lastIndex = 0;
              let sphereMatch = patterns.sphere.exec(firstLine);
              if (sphereMatch) detectedValues.od.sphere = cleanValue(sphereMatch[1]);

              patterns.cylinder.lastIndex = 0;
              let cylMatch = patterns.cylinder.exec(firstLine);
              if (cylMatch) {
                detectedValues.od.cylinder = cleanValue(cylMatch[1]);
                detectedValues.od.axis = cylMatch[2];
              }
            }
          }
        }

        if (refractionLines.length >= 2) {
          const secondLine = refractionLines[1];
          console.log('📝 Analyse deuxième ligne:', secondLine);

          patterns.compactFormat.lastIndex = 0;
          patterns.altFormat.lastIndex = 0;
          patterns.cylinder.lastIndex = 0;
          patterns.sphere.lastIndex = 0;

          let compactMatch = patterns.compactFormat.exec(secondLine);
          if (compactMatch) {
            detectedValues.og.sphere = cleanValue(compactMatch[1]);
            detectedValues.og.cylinder = cleanValue(compactMatch[2]);
            detectedValues.og.axis = compactMatch[3];
            console.log('✅ Format compact détecté pour OG (par ordre):', detectedValues.og);
          } else {
            patterns.altFormat.lastIndex = 0;
            let altMatch = patterns.altFormat.exec(secondLine);
            if (altMatch) {
              detectedValues.og.sphere = cleanValue(altMatch[1]);
              detectedValues.og.cylinder = cleanValue(altMatch[2]);
              detectedValues.og.axis = altMatch[3];
            } else {
              patterns.sphere.lastIndex = 0;
              let sphereMatch = patterns.sphere.exec(secondLine);
              if (sphereMatch) detectedValues.og.sphere = cleanValue(sphereMatch[1]);

              patterns.cylinder.lastIndex = 0;
              let cylMatch = patterns.cylinder.exec(secondLine);
              if (cylMatch) {
                detectedValues.og.cylinder = cleanValue(cylMatch[1]);
                detectedValues.og.axis = cylMatch[2];
              }
            }
          }
        }
      }

      let fieldsUpdated = 0;

      const fillField = async (selector, value, fieldName) => {
        console.log(`� Tentative de remplissage: ${fieldName} avec la valeur "${value}"`);

        if (!value || value === 'null' || value === 'undefined') {
          console.log(`⚠ Valeur vide ou invalide pour ${fieldName}`);
          return false;
        }

        const input = document.querySelector(selector);
        if (!input) {
          console.error(`❌ Champ non trouvé: ${selector}`);
          return false;
        }

        let cleanedValue = value.toString().replace(',', '.').replace(/^\+/, '').trim();

        if (fieldName.includes('Axe')) {
          cleanedValue = parseInt(cleanedValue).toString();
        } else {
          const numValue = parseFloat(cleanedValue);
          if (isNaN(numValue)) {
            console.log(`⚠️ Valeur non numérique pour ${fieldName}: ${cleanedValue}`);
            return false;
          }
          cleanedValue = numValue.toFixed(2);
        }

        try {
          input.focus();
          await new Promise(r => setTimeout(r, 50));

          input.value = '';

          const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
            window.HTMLInputElement.prototype,
            'value'
          ).set;
          nativeInputValueSetter.call(input, cleanedValue);

          const inputEvent = new Event('input', { bubbles: true, cancelable: true });
          input.dispatchEvent(inputEvent);

          await new Promise(r => setTimeout(r, 50));

          const changeEvent = new Event('change', { bubbles: true, cancelable: true });
          input.dispatchEvent(changeEvent);

          input.blur();
          await new Promise(r => setTimeout(r, 50));
          input.focus();

          console.log(` ${fieldName}: ${value} → ${cleanedValue} (valeur finale: ${input.value})`);
          return true;

        } catch (error) {
          console.error(`❌ Erreur lors du remplissage de ${fieldName}:`, error);
          return false;
        }
      };

      if ((detectedValues.od.sphere || detectedValues.od.cylinder) &&
          (detectedValues.og.sphere || detectedValues.og.cylinder)) {


        if (await fillField('#input-rightsphere', detectedValues.od.sphere, 'Sphère OD')) fieldsUpdated++;
        await new Promise(r => setTimeout(r, 100));
        if (await fillField('#input-rightcylinder', detectedValues.od.cylinder, 'Cylindre OD')) fieldsUpdated++;
        await new Promise(r => setTimeout(r, 100));
        if (await fillField('#input-rightrefractionAxis', detectedValues.od.axis, 'Axe OD')) fieldsUpdated++;

        await new Promise(r => setTimeout(r, 200));

        if (await fillField('#input-leftsphere', detectedValues.og.sphere, 'Sphère OG')) fieldsUpdated++;
        await new Promise(r => setTimeout(r, 100));
        if (await fillField('#input-leftcylinder', detectedValues.og.cylinder, 'Cylindre OG')) fieldsUpdated++;
        await new Promise(r => setTimeout(r, 100));
        if (await fillField('#input-leftrefractionAxis', detectedValues.og.axis, 'Axe OG')) fieldsUpdated++;
      }
      else if (detectedValues.od.sphere || detectedValues.od.cylinder ||
               detectedValues.og.sphere || detectedValues.og.cylinder) {
        console.log('👁️ Un seul œil détecté ou pas d\'indication');

        const values = (detectedValues.od.sphere || detectedValues.od.cylinder) ?
                       detectedValues.od : detectedValues.og;

        if (isEyeEmpty('od')) {

          if (await fillField('#input-rightsphere', values.sphere, 'Sphère OD')) fieldsUpdated++;
          await new Promise(r => setTimeout(r, 100));
          if (await fillField('#input-rightcylinder', values.cylinder, 'Cylindre OD')) fieldsUpdated++;
          await new Promise(r => setTimeout(r, 100));
          if (await fillField('#input-rightrefractionAxis', values.axis, 'Axe OD')) fieldsUpdated++;
        }
        else if (isEyeEmpty('og')) {
          if (await fillField('#input-leftsphere', values.sphere, 'Sphère OG')) fieldsUpdated++;
          await new Promise(r => setTimeout(r, 100));
          if (await fillField('#input-leftcylinder', values.cylinder, 'Cylindre OG')) fieldsUpdated++;
          await new Promise(r => setTimeout(r, 100));
          if (await fillField('#input-leftrefractionAxis', values.axis, 'Axe OG')) fieldsUpdated++;
        }
        else {
          showToast('⚠️ Les deux yeux sont déjà remplis');
          return;
        }
      }

      if (fieldsUpdated > 0) {
        showToast(`✅ ${fieldsUpdated} valeur(s) collée(s) avec succès !`);
        console.log('📊 Résumé du collage:', detectedValues);
      } else {
        showToast('❌ Aucune valeur de réfraction détectée');

      }

    } catch (error) {
      console.error('❌ Erreur lors du collage:', error);
      showToast('❌ Erreur lors de la lecture du presse-papier');
    }
  }

  const selectors = [
    "#wrapper > main > app-file-layout > div > app-file-tab-information > div.eyes-container > div > app-file-information-eye:nth-child(1) > div > div.header > div.header__actions > amds-button > button", // OD
    "#wrapper > main > app-file-layout > div > app-file-tab-information > div.eyes-container > div > app-file-information-eye:nth-child(2) > div > div.header > div.header__actions > amds-button > button", // OG
    "#wrapper > main > app-file-layout > div > app-file-tab-first-lens > div.lens-container > form > div > amds-button > button", // Prescripteur
    "#wrapper > main > app-file-layout > div > app-file-tab-first-lens > div.lens-container > div > app-file-first-lens:nth-child(1) > div > div.header > div.header__actions > amds-button > button", // Lentille OD
    "#wrapper > main > app-file-layout > div > app-file-tab-first-lens > div.lens-container > div > app-file-first-lens:nth-child(2) > div > div.header > div.header__actions > amds-button > button" // Lentille OG
  ];

  const alreadyObserved = new WeakSet();

  // Raccourci Double Alt
  function setupDoubleAltShortcut() {
    console.log('⌨️ Configuration du raccourci Double Alt pour enregistrer et ouvrir les notes...');

    let lastAltTime = 0;
    const doubleAltDelay = 500;

    document.addEventListener('keydown', (e) => {
      // Vérifier Alt
      if (e.key === 'Alt') {
        const currentTime = Date.now();
        const timeDiff = currentTime - lastAltTime;

        // Double Alt
        if (timeDiff < doubleAltDelay) {
          console.log('⌨️ Double Alt détecté - Enregistrement + Ouverture des notes');

          // Empêcher défaut
          e.preventDefault();
          e.stopPropagation();

          // Enregistrer
          console.log('💾 Enregistrement des données...');

          // Boutons enregistrement
          const saveButtons = document.querySelectorAll('amds-button button');
          let savedCount = 0;

          saveButtons.forEach((btn, index) => {
            if (!btn.disabled && btn.textContent && btn.textContent.includes('Enregistr')) {
              console.log(`💾 Clic sur bouton enregistrer ${index + 1}`);

              // Montrer bouton
              const wasHidden = btn.style.display === 'none';
              if (wasHidden) {
                btn.style.display = '';
              }

              btn.click();
              savedCount++;

              // Re-cacher si nécessaire
              if (wasHidden) {
                setTimeout(() => {
                  btn.style.display = 'none';
                }, 100);
              }
            }
          });

          // Attendre
          setTimeout(() => {
            console.log('📝 Ouverture des notes après enregistrement...');

            // Bouton Notes
            const notesButtons = document.querySelectorAll('button');
            let notesButton = null;

            notesButtons.forEach(btn => {
              if (btn.textContent && btn.textContent.includes('Notes') &&
                  btn.closest('.header__actions')) {
                notesButton = btn;
              }
            });

            if (notesButton) {
              console.log('📝 Bouton Notes trouvé - Ouverture du modal');
              notesButton.click();
            } else {
              console.log('⚠️ Bouton Notes non trouvé');
              showToast('❌ Bouton Notes non trouvé');
            }
          }, 300);
        } else {
          // Premier Alt
          lastAltTime = currentTime;
        }
      }
    });
  }

  // Init raccourci
  setupDoubleAltShortcut();

  // Notification
  setTimeout(() => {
    showToast('⌨️ Nouveau raccourci : Double Alt pour enregistrer et ouvrir les notes !');
  }, 2000);

  // Agrandir zone notes
  function setupNotesEditAreaEnlargement() {
    console.log('📝 Configuration de l\'agrandissement de la zone d\'édition des notes...');

    // Observer textarea
    const editObserver = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        mutation.addedNodes.forEach((node) => {
          if (node.nodeType === Node.ELEMENT_NODE) {
            // Chercher textarea
            const textarea = node.querySelector ?
              node.querySelector('textarea#input-editContent') : null;

            // Vérifier nœud
            const isEditTextarea = node.tagName === 'TEXTAREA' && node.id === 'input-editContent';

            if (textarea || isEditTextarea) {
              const targetTextarea = textarea || node;
              console.log('📝 Zone d\'édition détectée - Application des styles d\'agrandissement');

              // Appliquer styles
              targetTextarea.style.minHeight = '200px';
              targetTextarea.style.resize = 'vertical';
              targetTextarea.style.fontSize = '14px';
              targetTextarea.style.lineHeight = '1.4';
              targetTextarea.style.padding = '12px';
              targetTextarea.style.border = '2px solid #e0e0e0';
              targetTextarea.style.borderRadius = '8px';
              targetTextarea.style.transition = 'border-color 0.3s ease';
              targetTextarea.style.overflow = 'hidden';

              // Ajuster hauteur
              function autoResizeTextarea(textarea) {
                // Réinitialiser hauteur
                textarea.style.height = 'auto';

                // Calculer hauteur
                const scrollHeight = textarea.scrollHeight;
                const minHeight = 200;
                const maxHeight = 500;

                // Appliquer hauteur
                const newHeight = Math.max(minHeight, Math.min(scrollHeight, maxHeight));
                textarea.style.height = newHeight + 'px';

                console.log(`📝 Hauteur ajustée automatiquement: ${newHeight}px`);
              }

              // Hauteur initiale
              autoResizeTextarea(targetTextarea);

              // Ajuster contenu
              targetTextarea.addEventListener('input', () => {
                autoResizeTextarea(targetTextarea);
              });

              // Ajuster focus
              targetTextarea.addEventListener('focus', () => {
                autoResizeTextarea(targetTextarea);
              });
            }
          }
        });
      });
    });

    // Observer tout le document
    editObserver.observe(document.body, {
      childList: true,
      subtree: true
    });
  }

  // Init agrandissement
  setupNotesEditAreaEnlargement();

  // Centrage et déplacement modals
  function setupModalCentering() {
    console.log('🎯 Configuration du centrage et déplacement unifié des modals...');

    // Centrer modal
    function centerModal(modal) {
      if (!modal || !modal.classList.contains('modal--size-medium')) return;

      // Centrage CSS
      modal.style.position = 'fixed';
      modal.style.margin = '0';
      modal.style.zIndex = '1050';

      // Largeur
      if (!modal.dataset.cfDefaultWidthSet) {
        modal.style.width = '70vw';
        modal.dataset.cfDefaultWidthSet = 'true';
      }

      // Centrer position
      const rect = modal.getBoundingClientRect();
      const winW = window.innerWidth;
      const winH = window.innerHeight;

      modal.style.left = Math.max(0, (winW - rect.width) / 2) + 'px';
      modal.style.top = Math.max(0, (winH - rect.height) / 2) + 'px';
      modal.style.transform = 'none';

      console.log('🎯 Modal centré:', modal);
    }

    // Rendre déplaçable
    function makeModalDraggable(modal) {
      if (!modal || modal.dataset.cfDraggable === 'true') return;

      const header = modal.querySelector('.modal__header');
      if (!header) return;

      modal.dataset.cfDraggable = 'true';

      let isDragging = false;
      let startX, startY, startLeft, startTop;

      // Style header
      header.style.cursor = 'move';
      header.style.userSelect = 'none';

      // Drag events
      header.addEventListener('mousedown', (e) => {
        if (e.target.closest('.cf-modal-grip')) return;

        isDragging = true;
        startX = e.clientX;
        startY = e.clientY;

        // Récupérer la position actuelle
        const rect = modal.getBoundingClientRect();
        startLeft = rect.left;
        startTop = rect.top;

        // S'assurer qu'il n'y a pas de transform
        modal.style.transform = 'none';

        e.preventDefault();
      });

      document.addEventListener('mousemove', (e) => {
        if (!isDragging) return;

        const deltaX = e.clientX - startX;
        const deltaY = e.clientY - startY;

        const newLeft = Math.max(0, Math.min(window.innerWidth - modal.offsetWidth, startLeft + deltaX));
        const newTop = Math.max(0, Math.min(window.innerHeight - modal.offsetHeight, startTop + deltaY));

        modal.style.left = newLeft + 'px';
        modal.style.top = newTop + 'px';
      });

      document.addEventListener('mouseup', () => {
        isDragging = false;
      });

      console.log('🎯 Modal rendu déplaçable:', modal);
    }


    // Observer pour détecter l'ouverture de nouveaux modals
    const modalObserver = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        mutation.addedNodes.forEach((node) => {
          if (node.nodeType === Node.ELEMENT_NODE) {
            // Chercher les modals dans le nouveau nœud
            const modals = node.querySelectorAll ?
              node.querySelectorAll('.modal.modal--size-medium') : [];

            // Ou vérifier si le nœud lui-même est un modal
            if (node.classList && node.classList.contains('modal') &&
                node.classList.contains('modal--size-medium')) {
              modals.push(node);
            }

            modals.forEach(modal => {
              if (!modal.dataset.cfCentered) {
                modal.dataset.cfCentered = 'true';

                // Attendre que le modal soit complètement rendu
                setTimeout(() => {
                  centerModal(modal);
                  makeModalDraggable(modal);
                }, 100);
              }
            });
          }
        });
      });
    });

    // Observer tout le document
    modalObserver.observe(document.body, {
      childList: true,
      subtree: true
    });

    // Centrer et rendre déplaçables les modals existants
    document.querySelectorAll('.modal.modal--size-medium').forEach(modal => {
      if (!modal.dataset.cfCentered) {
        modal.dataset.cfCentered = 'true';
        centerModal(modal);
        makeModalDraggable(modal);
      }
    });

    // Re-centrer lors du redimensionnement de la fenêtre
    window.addEventListener('resize', () => {
      document.querySelectorAll('.modal.modal--size-medium').forEach(modal => {
        centerModal(modal);
      });
    });

    // Gestionnaire global unique pour fermer les modals avec Échap
    let escapeHandlerAdded = false;

    function addEscapeHandler() {
      if (escapeHandlerAdded) return;
      escapeHandlerAdded = true;

      document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape') {
          // Trouver tous les modals visibles
          const visibleModals = Array.from(document.querySelectorAll('.modal.modal--size-medium')).filter(modal => {
            const rect = modal.getBoundingClientRect();
            return modal.offsetParent !== null &&
                   modal.style.display !== 'none' &&
                   rect.width > 0 &&
                   rect.height > 0;
          });

          if (visibleModals.length > 0) {
            const modal = visibleModals[visibleModals.length - 1]; // Le plus récent
            console.log('⌨️ Échap détecté, fermeture du modal:', modal);

            // Essayer de fermer le modal
            const closeButton = modal.querySelector('amds-button button[type="button"]');
            const closeIcon = modal.querySelector('[name="ri-close-fill"], .ri-close-fill');
            const overlay = modal.querySelector('.modal-overlay, .modal__overlay');

            if (closeButton) {
              console.log('✅ Fermeture via bouton');
              closeButton.click();
            } else if (closeIcon) {
              console.log('✅ Fermeture via icône');
              closeIcon.click();
            } else if (overlay) {
              console.log('✅ Fermeture via overlay');
              overlay.click();
            } else {
              console.log('⚠️ Fermeture forcée');
              modal.style.display = 'none';
            }

            e.preventDefault();
            e.stopPropagation();
          }
        }
      });

      console.log('⌨️ Gestionnaire Échap global activé');
    }

    // Activer le gestionnaire
    addEscapeHandler();
  }

  // Initialiser le centrage des modals
  setupModalCentering();

  // Observation des boutons
  function observeAndAutoClick(selector, buttonLabel) {
    const btn = document.querySelector(selector);
    if (!btn || alreadyObserved.has(btn)) return;
    btn.style.display = "none";

    // Délai spécifique pour les boutons "Lentille OD" et "Lentille OG"
    const needsDelay = buttonLabel.includes("Lentille");
    const clickDelay = needsDelay ? 1500 : 0; // 1.5 secondes pour les lentilles

    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === 'attributes' && mutation.attributeName === 'disabled') {
          if (!btn.disabled && autoSaveEnabled) { // Vérifier si auto-save est activé
            if (clickDelay > 0) {
              console.log(`Bouton ${buttonLabel} actif → attente de ${clickDelay}ms pour le rendu WebGL...`);

              // Vérifier si le canvas existe et attendre qu'il soit prêt
              const checkCanvasAndClick = () => {
                const canvas = document.querySelector('#webgl-canvas');
                if (canvas) {
                  // Attendre un peu plus pour être sûr que le rendu est fait
                  setTimeout(() => {
                    console.log(`Bouton ${buttonLabel} → clic automatique après délai`);
                    btn.click();
                  }, clickDelay);
                } else {
                  // Si pas de canvas, cliquer quand même après le délai
                  setTimeout(() => {
                    console.log(`Bouton ${buttonLabel} → clic automatique (sans canvas)`);
                    btn.click();
                  }, clickDelay);
                }
              };

              checkCanvasAndClick();
            } else {
              console.log(`Bouton ${buttonLabel} actif → clic automatique immédiat`);
              btn.click();
            }
          }
        }
      });
    });
    observer.observe(btn, { attributes: true });
    alreadyObserved.add(btn);
    console.log(`Observation activée pour ${buttonLabel}`);
  }

  // Fonction pour scanner et observer tous les boutons
  function scanAndObserveButtons() {
    const labels = ["OD", "OG", "Prescripteur", "Lentille OD", "Lentille OG"];

    selectors.forEach((sel, i) => {
      const btn = document.querySelector(sel);
      if (btn && !alreadyObserved.has(btn)) {
        observeAndAutoClick(sel, labels[i]);
      }
    });
  }

  // Observation pour détecter l'apparition de nouveaux boutons
  function setupButtonObserver() {
    console.log('🔍 Configuration de l\'observateur de boutons...');

    // Observer spécifique pour les boutons, pas global
    const buttonObserver = new MutationObserver((mutations) => {
      let shouldScan = false;

      mutations.forEach((mutation) => {
        // Vérifier si des boutons ont pu être ajoutés
        if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
          mutation.addedNodes.forEach((node) => {
            if (node.nodeType === 1) { // Element node
              // Vérifier si c'est un bouton ou contient des boutons
              if (node.tagName === 'BUTTON' ||
                  node.querySelector && node.querySelector('button')) {
                shouldScan = true;
              }
            }
          });
        }
      });

      if (shouldScan) {
        scanAndObserveButtons();
      }
    });

    // Observer seulement les zones où les boutons peuvent apparaître
    const targetZones = [
      document.querySelector('#wrapper > main'),
      document.querySelector('.eyes-container'),
      document.querySelector('.lens-container')
    ].filter(el => el !== null);

    targetZones.forEach(zone => {
      buttonObserver.observe(zone, {
        childList: true,
        subtree: true
      });
    });

    // Si aucune zone trouvée, observer le body mais avec plus de restrictions
    if (targetZones.length === 0) {
      buttonObserver.observe(document.body, {
        childList: true,
        subtree: true
      });
    }
  }

  function setupLensPageObserver() {
  console.log('Configuration de l\'observateur de page lentilles...');

  const lensPageObserver = new MutationObserver((mutations) => {
    let shouldCheckForLensPage = false;

    mutations.forEach((mutation) => {
      if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
        mutation.addedNodes.forEach((node) => {
          if (node.nodeType === 1) {
            if (node.textContent &&
                (node.textContent.includes('Œil droit') ||
                 node.textContent.includes('Œil gauche') ||
                 node.textContent.includes('Oeil droit') ||
                 node.textContent.includes('Oeil gauche'))) {
              shouldCheckForLensPage = true;
            }

            if (node.querySelector &&
                (node.querySelector('div.amds-text.amds-font-headline-h6') ||
                 node.querySelector('[class*="lens"]'))) {
              shouldCheckForLensPage = true;
            }
          }
        });
      }
    });

    if (shouldCheckForLensPage) {
      console.log('👁️ Page lentilles potentielle détectée, vérification...');
      setTimeout(() => {
        if (window.displayRefractionOnLensPage) {
          window.displayRefractionOnLensPage();
        }
      }, 500);
    }
  });

  const targetZones = [
    document.querySelector('#wrapper > main'),
    document.querySelector('.lens-container'),
    document.querySelector('[class*="lens"]')
  ].filter(el => el !== null);

  targetZones.forEach(zone => {
    lensPageObserver.observe(zone, {
      childList: true,
      subtree: true
    });
  });

  if (targetZones.length === 0 && document.querySelector('main')) {
    lensPageObserver.observe(document.querySelector('main'), {
      childList: true,
      subtree: true
    });
  }


  }

  // Force le step à 0.25 sur un input donné
  function forceCustomStep(inputSelector, inputName) {
    const input = document.querySelector(inputSelector);
    if (!input || input.dataset.customStepApplied === 'true') return;

    console.log(`Application du step personnalisé sur ${inputName}...`);

    // Fonction helper pour vérifier si un input doit avoir le step 0.25
    function shouldHaveCustomStep(inputElement) {
      const stepInputs = [
        '#input-rightsphere',
        '#input-rightcylinder',
        '#input-leftsphere',
        '#input-leftcylinder',
        '#input-rightaddition',
        '#input-leftaddition'
      ];

      return stepInputs.some(selector => {
        return inputElement.matches(selector) || inputElement.id === selector.replace('#', '');
      });
    }

    // Vérifier si cet input doit avoir le comportement personnalisé
    if (!shouldHaveCustomStep(input)) {
      console.log(`⏭️ ${inputName} n'est pas dans la liste - garde son comportement natif`);
      return;
    }

    // Marquer comme traité
    input.dataset.customStepApplied = 'true';

    // Forcer les attributs
    input.setAttribute('step', '0.25');

    // Fonction pour arrondir au multiple de 0.25 le plus proche
    function roundToStep(value, step = 0.25) {
      return Math.round(value / step) * step;
    }

    // Fonction pour mettre à jour la valeur
    function updateValue(newValue, keepFocus = false) {
      const rounded = roundToStep(newValue, 0.25);
      const formatted = rounded.toFixed(2);

      // Sauvegarder l'état du focus et la position du curseur
      const hasFocus = document.activeElement === input;
      const selectionStart = input.selectionStart;
      const selectionEnd = input.selectionEnd;

      // Forcer la mise à jour de plusieurs façons
      input.value = formatted;
      input.setAttribute('value', formatted);

      // Déclencher tous les événements possibles
      ['input', 'change'].forEach(eventType => {
        input.dispatchEvent(new Event(eventType, { bubbles: true, cancelable: true }));
      });

      // Forcer si comp Angular utilsé
      if (input._valueTracker) {
        input._valueTracker.setValue(formatted);
      }

      // Restaurer le focus si nécessaire
      if ((hasFocus || keepFocus) && document.activeElement !== input) {
        input.focus();
        // Restaurer la position du curseur
        if (selectionStart !== null && selectionEnd !== null) {
          input.setSelectionRange(selectionStart, selectionEnd);
        }
      }
    }

    // Intercepter et modifier le step natif
    let isUpdating = false;

    // Observer les changements de valeur
    const valueObserver = new MutationObserver((mutations) => {
      if (isUpdating) return;

      mutations.forEach((mutation) => {
        if (mutation.type === 'attributes' && mutation.attributeName === 'value') {
          const currentValue = parseFloat(input.value) || 0;
          const roundedValue = roundToStep(currentValue, 0.25);

          if (Math.abs(currentValue - roundedValue) > 0.001) {
            isUpdating = true;
            updateValue(roundedValue);
            setTimeout(() => { isUpdating = false; }, 100);
          }
        }
      });
    });

    valueObserver.observe(input, {
      attributes: true,
      attributeFilter: ['value']
    });

    // Intercepter les événements de changement
    input.addEventListener('change', (e) => {
      if (isUpdating) return;
      const currentValue = parseFloat(e.target.value) || 0;
      const roundedValue = roundToStep(currentValue, 0.25);

      if (Math.abs(currentValue - roundedValue) > 0.001) {
        e.preventDefault();
        e.stopPropagation();
        isUpdating = true;
        updateValue(roundedValue);
        setTimeout(() => { isUpdating = false; }, 100);
      }
    }, true);

    // Gérer la molette
    input.addEventListener('wheel', (e) => {
      e.preventDefault();
      e.stopPropagation();
      const current = parseFloat(input.value) || 0;
      const delta = e.deltaY < 0 ? 0.25 : -0.25;
      updateValue(current + delta, true);
    }, { passive: false, capture: true });

    // Gérer les flèches du clavier
    input.addEventListener('keydown', (e) => {
      if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
        e.preventDefault();
        e.stopPropagation();
        const current = parseFloat(input.value) || 0;
        const delta = e.key === 'ArrowUp' ? 0.25 : -0.25;
        updateValue(current + delta, true);
      }
    }, true);

    // Intercepter le clic sur les boutons de step natifs (si présents)
    const interceptStepButtons = () => {
      const parent = input.parentElement;
      if (!parent) return;


      parent.addEventListener('click', (e) => {
        // Si c'est un clic sur un bouton de step
        if (e.target.matches('button, [role="button"]') && e.target !== input) {
          e.preventDefault();
          e.stopPropagation();

          // Déterminer la direction
          const rect = input.getBoundingClientRect();
          const isUp = e.clientY < rect.top + rect.height / 2;
          const current = parseFloat(input.value) || 0;
          const delta = isUp ? 0.25 : -0.25;
          updateValue(current + delta, true);
        }
      }, true);


      setTimeout(() => {
        // Chercher la div .arrows qui contient les boutons
        const arrowsContainer = parent.querySelector('.arrows');
        if (arrowsContainer) {
          console.log(`🎯 Flèches custom trouvées pour ${inputName} (step 0.25)`);

          const buttons = arrowsContainer.querySelectorAll('button');
          buttons.forEach((button, index) => {
            // Remplacer complètement le comportement du bouton
            const newButton = button.cloneNode(true);
            button.parentNode.replaceChild(newButton, button);

            newButton.addEventListener('click', (e) => {
              e.preventDefault();
              e.stopPropagation();
              e.stopImmediatePropagation();

              const current = parseFloat(input.value) || 0;
              // Index 0 = bouton du haut (augmenter), Index 1 = bouton du bas (diminuer)
              const delta = index === 0 ? 0.25 : -0.25;
              updateValue(current + delta, true);

              console.log(`🔺 Clic sur flèche ${index === 0 ? 'haut' : 'bas'}: ${current} → ${current + delta}`);
            });
          });
        }
      }, 100);


      const arrowObserver = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
          mutation.addedNodes.forEach((node) => {
            if (node.classList && node.classList.contains('arrows')) {
              console.log(`🆕 Nouvelles flèches détectées pour ${inputName} (step 0.25)`);

              const buttons = node.querySelectorAll('button');
              buttons.forEach((button, index) => {
                button.addEventListener('click', (e) => {
                  e.preventDefault();
                  e.stopPropagation();
                  e.stopImmediatePropagation();

                  const current = parseFloat(input.value) || 0;
                  const delta = index === 0 ? 0.25 : -0.25;
                  updateValue(current + delta, true);
                }, true);
              });
            }
          });
        });
      });

      arrowObserver.observe(parent, {
        childList: true,
        subtree: true
      });
    };

    interceptStepButtons();

    // Vérification périodiquement que le step est toujours à 0.25
    setInterval(() => {
      if (input.getAttribute('step') !== '0.25') {
        input.setAttribute('step', '0.25');
      }
    }, 1000);

    console.log(`✅ Step personnalisé 0.25 forcé pour ${inputName}`);
  }

  // Liste des inputs qui doivent avoir le step 0.25
  const stepInputs = [
    '#input-rightsphere',
    '#input-rightcylinder',
    '#input-leftsphere',
    '#input-leftcylinder',
    '#input-rightaddition',
    '#input-leftaddition'
  ];

  // Appliquer le step custom à tous les inputs
  function applyCustomStepToAll() {
    const inputNames = {
      '#input-rightsphere': 'Sphère OD',
      '#input-rightcylinder': 'Cylindre OD',
      '#input-leftsphere': 'Sphère OG',
      '#input-leftcylinder': 'Cylindre OG'
    };

    stepInputs.forEach(selector => {
      forceCustomStep(selector, inputNames[selector] || selector);
    });
  }


  function patchColorAutoChange() {
      const materialSelectors = ['#input-leftmaterial', '#input-rightmaterial'];

      materialSelectors.forEach(selector => {
        const materialSelect = document.querySelector(selector);
        if (!materialSelect) return;

        // Déterminer si c'est pour l'œil gauche ou droit
        const isLeft = selector.includes('left');
        const colorSelector = isLeft ? '#input-leftcolor' : '#input-rightcolor';

        // Sauvegarder la couleur actuelle avant le changement
        materialSelect.addEventListener('mousedown', () => {
          const colorSelect = document.querySelector(colorSelector);
          if (colorSelect && colorSelect.value !== 'null') {
            colorSelect.dataset.savedColor = colorSelect.value;
            console.log(`Couleur sauvegardée: ${colorSelect.value}`);
          }
        });

        // Restaurer la couleur après le changement de matériau
        materialSelect.addEventListener('change', () => {
          setTimeout(() => {
            const colorSelect = document.querySelector(colorSelector);
            if (colorSelect && colorSelect.dataset.savedColor) {
              const savedColor = colorSelect.dataset.savedColor;
              if (colorSelect.value !== savedColor) {
                console.log(`Restauration de la couleur: ${savedColor}`);
                colorSelect.value = savedColor;
                colorSelect.dispatchEvent(new Event('change', { bubbles: true }));
              }
              delete colorSelect.dataset.savedColor;
            }
          }, 100); // Petit délai pour laisser l'application faire son changement automatique
        });
      });

      // Observer l'apparition de nouveaux sélecteurs (pour les pages chargées dynamiquement)
      const observer = new MutationObserver(() => {
        materialSelectors.forEach(selector => {
          const select = document.querySelector(selector);
          if (select && !select.dataset.colorPatchApplied) {
            select.dataset.colorPatchApplied = 'true';
            patchColorAutoChange();
          }
        });
      });

      observer.observe(document.body, {
        childList: true,
        subtree: true
      });
  }

  // Remplissage France automatique pour le prescripteur
  function autoFillPrescripteurCountry() {
      console.log('Activation de l\'auto-remplissage du pays prescripteur...');

      // Observer l'apparition du modal
      const modalObserver = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
          // Vérifier si des nœuds ont été ajoutés
          if (mutation.addedNodes.length > 0) {
            mutation.addedNodes.forEach((node) => {
              // Vérifier si c'est un élément DOM
              if (node.nodeType === 1) {
                // Chercher le titre du modal dans le noeud ou ses enfants
                let hasTitle = false;

                // Vérifier le texte du noeud lui-même
                if (node.textContent && node.textContent.includes('Création d\'un prescripteur')) {
                  hasTitle = true;
                }

                // Vérifier les enfants
                if (!hasTitle && node.querySelectorAll) {
                  const titles = node.querySelectorAll('.modal_header, .modal-title, h1, h2, h3, h4, h5, h6');
                  titles.forEach(title => {
                    if (title.textContent.includes('Création d\'un prescripteur')) {
                      hasTitle = true;
                    }
                  });
                }

                if (hasTitle && !node.dataset.countryFilled) {
                  console.log('Modal prescripteur détecté');
                  node.dataset.countryFilled = 'true';

                  // Attendre que le modal soit complètement rendu
                  setTimeout(() => {
                    autoFillCountry();
                  }, 500);
                }
              }
            });
          }
        });
      });

      // Fonction pour remplir automatiquement le pays
      async function autoFillCountry() {
        console.log('Recherche du champ pays...');

        // Chercher le champ pays par son label
        let countryInput = null;


        countryInput = document.querySelector('#input-country');


        if (!countryInput) {
          const labels = document.querySelectorAll('label');
          labels.forEach(label => {
            if (label.textContent.includes('Pays')) {
              const inputId = label.getAttribute('for');
              if (inputId) {
                countryInput = document.querySelector(`#${inputId}`);
              }
            }
          });
        }

        // Chercher un input avec placeholder contenant "Fra"
        if (!countryInput) {
          const inputs = document.querySelectorAll('input[placeholder*="Fra"]');
          if (inputs.length > 0) {
            countryInput = inputs[0];
          }
        }

        if (!countryInput) {
          console.log(' Champ pays non trouvé');
          return;
        }

        console.log('Champ pays trouvé:', countryInput);

        // Vérifier si le champ est vide ou contient "Fra"
        if (countryInput.value === '' || countryInput.value === 'Fra') {
          console.log('Début du remplissage...');

          // Focus sur le champ
          countryInput.focus();
          await delay(100);

          // Effacer et taper "Fra"
          countryInput.value = '';
          await delay(50);

          countryInput.value = 'Fra';
          countryInput.dispatchEvent(new Event('input', { bubbles: true }));
          countryInput.dispatchEvent(new Event('change', { bubbles: true }));

          console.log('Attente de l\'apparition de la suggestion...');
          await delay(300); // Attendre que la suggestion apparaisse


          let clicked = false;

          // Chercher spécifiquement les divs avec la classe de suggestion
          const suggestions = document.querySelectorAll('div.amds-text.amds-font-body-body1.amds-color-basic-900');

          for (const suggestion of suggestions) {
            if (suggestion.textContent.trim() === 'France') {
              console.log(' Suggestion "France" trouvée !');

              // Essayer de cliquer sur la suggestion
              suggestion.click();

              // Si ça ne marche pas, essayer de cliquer sur le parent
              if (suggestion.parentElement) {
                suggestion.parentElement.click();
              }

              clicked = true;
              console.log('Clic sur "France" effectué');
              break;
            }
          }

          // Si pas trouvé avec la classe exacte, chercher plus largement
          if (!clicked) {
            console.log(' Recherche élargie...');
            const allDivs = document.querySelectorAll('div');

            for (const div of allDivs) {
              // Vérifier que c'est visible et contient exactement "France"
              if (div.textContent.trim() === 'France' &&
                  div.offsetParent !== null &&
                  !div.querySelector('*')) { // S'assurer que c'est une feuille de l'arbre DOM

                console.log('Suggestion alternative trouvée');
                div.click();

                // Essayer aussi le parent au cas où
                if (div.parentElement && div.parentElement.tagName !== 'BODY') {
                  div.parentElement.click();
                }

                clicked = true;
                break;
              }
            }
          }

          if (clicked) {
            console.log('Pays "France" sélectionné avec succès !');
            // showToast(' Pays défini sur France');
          } else {
            console.log('Impossible de cliquer sur la suggestion');

            // Fallback: essayer de mettre France directement
            countryInput.value = 'France';
            countryInput.dispatchEvent(new Event('change', { bubbles: true }));
            countryInput.blur();
          }
        }
      }

      // Helper pour les délais
      function delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
      }

      // Observer aussi spécifiquement l'apparition du texte "France" après avoir tapé
      const franceObserver = new MutationObserver((mutations) => {
        // Ne réagir que si on a tapé "Fra" dans le champ
        const countryInput = document.querySelector('#input-country');
        if (!countryInput || countryInput.value !== 'Fra') return;

        mutations.forEach((mutation) => {
          if (mutation.addedNodes.length > 0) {
            mutation.addedNodes.forEach((node) => {
              if (node.nodeType === 1) {
                // Chercher France dans le nouveau noeud
                if (node.textContent && node.textContent.trim() === 'France') {
                  console.log('🎯 Auto-détection de la suggestion France');
                  setTimeout(() => {
                    node.click();
                  }, 50);
                }

                // Chercher aussi dans les enfants
                if (node.querySelectorAll) {
                  const franceDivs = node.querySelectorAll('div');
                  franceDivs.forEach(div => {
                    if (div.textContent.trim() === 'France' && !div.querySelector('*')) {
                      console.log('Auto-détection de France dans les enfants');
                      setTimeout(() => {
                        div.click();
                      }, 50);
                    }
                  });
                }
              }
            });
          }
        });
      });

      // Démarrer les observateurs
      modalObserver.observe(document.body, {
        childList: true,
        subtree: true
      });

      franceObserver.observe(document.body, {
        childList: true,
        subtree: true
      });

      console.log('Auto-remplissage du pays prescripteur activé');
  }

  // Fonction pour réorganiser les champs de kératométrie
  function reorderKeratometryFields() {

    // Sélectionner les deux sections de kératométrie (OD et OG)
    const eyeContainers = document.querySelectorAll('app-file-information-eye');

    eyeContainers.forEach((eyeContainer, eyeIndex) => {
      const eyeName = eyeIndex === 0 ? 'OD' : 'OG';

      // Trouver la section kératométrie
      const keratometrySection = eyeContainer.querySelector('app-file-information-eye-keratometry');
      if (!keratometrySection) {
        console.log(`⚠️ Section kératométrie non trouvée pour ${eyeName}`);
        return;
      }

      // Trouver le conteneur des champs (.fields ou app-file-form-group selon la structure)
      const fieldsContainer = keratometrySection.querySelector('.fields app-file-form-group') ||
                            keratometrySection.querySelector('app-file-form-group:last-of-type') ||
                            keratometrySection.querySelector('.form app-file-form-group:last-of-type');

      if (!fieldsContainer) {
        console.log(`⚠️ Conteneur des champs non trouvé pour ${eyeName}`);
        return;
      }

      // Identifier les champs par leur data-field ou leur ID
      const fieldMapping = {
        kFlat: fieldsContainer.querySelector('[data-field="kParameter"], [id*="kParameter"]:not([id*="steep"])')?.closest('app-store-field'),
        excFlat: fieldsContainer.querySelector('[data-field="eccentricity"], [id*="eccentricity"]:not([id*="steep"])')?.closest('app-store-field'),
        axisFlat: fieldsContainer.querySelector('[data-field="keratometryAxis"], [id*="keratometryAxis"]')?.closest('app-store-field'),
        kSteep: fieldsContainer.querySelector('[data-field="steepKParameter"], [id*="steepKParameter"]')?.closest('app-store-field'),
        excSteep: fieldsContainer.querySelector('[data-field="steepEccentricity"], [id*="steepEccentricity"]')?.closest('app-store-field'),
        div30: fieldsContainer.querySelector('[data-field="visibleIrisDiameterAt30"], [id*="visibleIrisDiameterAt30"]')?.closest('app-store-field')
      };

      // Vérifier que tous les champs sont trouvés
      const foundFields = Object.entries(fieldMapping).filter(([key, el]) => el !== null);
      console.log(`📍 ${eyeName}: ${foundFields.length}/6 champs trouvés`);

      if (foundFields.length === 0) {
        console.log(`❌ Aucun champ trouvé pour ${eyeName}`);
        return;
      }

      // Ordre  : Ligne 1: K plat, K serré, Axe | Ligne 2: Exc plat, Exc serré, DIV 30
      const desiredOrder = ['kFlat', 'kSteep', 'axisFlat', 'excFlat', 'excSteep', 'div30'];

      // Créer un fragment pour réorganiser
      const fragment = document.createDocumentFragment();

      // Ajouter les champs dans l'ordre souhaité
      desiredOrder.forEach(fieldName => {
        const field = fieldMapping[fieldName];
        if (field) {
          fragment.appendChild(field);
        }
      });

      // Vider et remplir le conteneur
      while (fieldsContainer.firstChild) {
        fieldsContainer.removeChild(fieldsContainer.firstChild);
      }
      fieldsContainer.appendChild(fragment);

      console.log(`✅ Champs réorganisés pour ${eyeName}`);
    });

    // Ajuster le style pour une meilleure présentation
    injectKeratometryStyles();
  }

  // Styles pour améliorer la présentation
  function injectKeratometryStyles() {
    if (document.getElementById('keratometry-reorder-styles')) return;

    const styles = `
      <style id="keratometry-reorder-styles">
        /* Améliorer l'espacement des champs de kératométrie */
        app-file-information-eye-keratometry .fields app-file-form-group,
        app-file-information-eye-keratometry .form > app-file-form-group:last-of-type {
          display: grid !important;
          grid-template-columns: repeat(3, 1fr) !important;
          gap: 0.8rem !important;
        }

        /* LIGNE 1 : K plat, K serré, Axe */
        app-file-information-eye-keratometry [data-field="kParameter"] {
          grid-column: 1;
          grid-row: 1;
        }

        app-file-information-eye-keratometry [data-field="steepKParameter"] {
          grid-column: 2;
          grid-row: 1;
        }

        app-file-information-eye-keratometry [data-field="keratometryAxis"] {
          grid-column: 3;
          grid-row: 1;
        }

        /* LIGNE 2 : Exc plat, Exc serré, DIV 30 */
        app-file-information-eye-keratometry [data-field="eccentricity"] {
          grid-column: 1;
          grid-row: 2;
        }

        app-file-information-eye-keratometry [data-field="steepEccentricity"] {
          grid-column: 2;
          grid-row: 2;
        }

        app-file-information-eye-keratometry [data-field="visibleIrisDiameterAt30"] {
          grid-column: 3;
          grid-row: 2;
        }

        /* Couleurs douces pour différencier plat et serré */
        /* Bleu doux pour les champs "plat" */
        app-file-information-eye-keratometry [data-field="kParameter"] .amds-input,
        app-file-information-eye-keratometry [data-field="eccentricity"] .amds-input {
          background-color: rgba(59, 130, 246, 0.05) !important;
          border: 1px solid rgba(59, 130, 246, 0.2) !important;
        }

        app-file-information-eye-keratometry [data-field="kParameter"] .amds-input:hover,
        app-file-information-eye-keratometry [data-field="eccentricity"] .amds-input:hover {
          background-color: rgba(59, 130, 246, 0.08) !important;
          border-color: rgba(59, 130, 246, 0.3) !important;
        }

        app-file-information-eye-keratometry [data-field="kParameter"] .amds-input:focus,
        app-file-information-eye-keratometry [data-field="eccentricity"] .amds-input:focus {
          background-color: rgba(59, 130, 246, 0.1) !important;
          border-color: rgba(59, 130, 246, 0.4) !important;
        }

        /* Rouge doux pour les champs "serré" */
        app-file-information-eye-keratometry [data-field="steepKParameter"] .amds-input,
        app-file-information-eye-keratometry [data-field="steepEccentricity"] .amds-input {
          background-color: rgba(239, 68, 68, 0.05) !important;
          border: 1px solid rgba(239, 68, 68, 0.2) !important;
        }

        app-file-information-eye-keratometry [data-field="steepKParameter"] .amds-input:hover,
        app-file-information-eye-keratometry [data-field="steepEccentricity"] .amds-input:hover {
          background-color: rgba(239, 68, 68, 0.08) !important;
          border-color: rgba(239, 68, 68, 0.3) !important;
        }

        app-file-information-eye-keratometry [data-field="steepKParameter"] .amds-input:focus,
        app-file-information-eye-keratometry [data-field="steepEccentricity"] .amds-input:focus {
          background-color: rgba(239, 68, 68, 0.1) !important;
          border-color: rgba(239, 68, 68, 0.4) !important;
        }

        /* Style neutre pour l'axe */
        app-file-information-eye-keratometry [data-field="keratometryAxis"] .amds-input {
          background-color: rgba(107, 114, 128, 0.05) !important;
          border: 1px solid rgba(107, 114, 128, 0.2) !important;
        }

        app-file-information-eye-keratometry [data-field="keratometryAxis"] .amds-input:hover {
          background-color: rgba(107, 114, 128, 0.08) !important;
          border-color: rgba(107, 114, 128, 0.3) !important;
        }

        app-file-information-eye-keratometry [data-field="keratometryAxis"] .amds-input:focus {
          background-color: rgba(107, 114, 128, 0.1) !important;
          border-color: rgba(107, 114, 128, 0.4) !important;
        }

        /* Style vert doux pour DIV 30 */
        app-file-information-eye-keratometry [data-field="visibleIrisDiameterAt30"] .amds-input {
          background-color: rgba(34, 197, 94, 0.05) !important;
          border: 1px solid rgba(34, 197, 94, 0.2) !important;
        }

        app-file-information-eye-keratometry [data-field="visibleIrisDiameterAt30"] .amds-input:hover {
          background-color: rgba(34, 197, 94, 0.08) !important;
          border-color: rgba(34, 197, 94, 0.3) !important;
        }

        app-file-information-eye-keratometry [data-field="visibleIrisDiameterAt30"] .amds-input:focus {
          background-color: rgba(34, 197, 94, 0.1) !important;
          border-color: rgba(34, 197, 94, 0.4) !important;
        }

        /* Améliorer la lisibilité des labels */
        app-file-information-eye-keratometry .amds-form-element label {
          font-weight: 500;
        }



        /* Transition douce sur tous les inputs */
        app-file-information-eye-keratometry .amds-input {
          transition: all 0.2s ease;
        }

        /* S'assurer que les inputs ont la même hauteur */
        app-file-information-eye-keratometry .amds-input input {
          height: 38px;
        }
      </style>
    `;

    document.head.insertAdjacentHTML('beforeend', styles);
  }

  // Réorganisation des champs de kératométrie avec observation des changements
  function setupKeratometryReorder() {
    console.log('🎨 Configuration du réorganisateur de kératométrie...');

    // Application initiale
    setTimeout(() => {
      if (window.location.pathname.includes('/file/')) {
        reorderKeratometryFields();
      }
    }, 2500); // Un peu après la réorganisation des sections

    // Observer les changements
    const observer = new MutationObserver((mutations) => {
      // Vérifier si des champs de kératométrie sont ajoutés
      for (const mutation of mutations) {
        if (mutation.addedNodes.length > 0) {
          for (const node of mutation.addedNodes) {
            if (node.nodeType === 1 && // Element node
                (node.matches && node.matches('app-file-information-eye-keratometry')) ||
                (node.querySelector && node.querySelector('app-file-information-eye-keratometry'))) {
              setTimeout(reorderKeratometryFields, 500);
              return;
            }
          }
        }
      }
    });

    // Observer le body pour les changements
    observer.observe(document.body, {
      childList: true,
      subtree: true
    });
  }

  // Fonction de raccourcis clavier
  function setupKeyboardShortcuts() {
    console.log('Activation des raccourcis F1-F4...');

    document.addEventListener('keydown', async (event) => {
      // F1 - Coller réfraction depuis le presse-papier
      if (event.key === 'F1') {
        console.log('Raccourci F1 détecté - Collage réfraction');
        event.preventDefault();
        event.stopPropagation();
        await pasteRefractionFromClipboard();
      }

      // F2 - Dupliquer OD→OG
      else if (event.key === 'F2') {
        console.log('Raccourci F2 détecté - Duplication OD→OG');
        event.preventDefault();
        event.stopPropagation();

        // Vérifier qu'on est sur une page avec les champs
        const odSphere = document.querySelector('#input-rightsphere');
        const ogSphere = document.querySelector('#input-leftsphere');

        if (odSphere && ogSphere) {
          duplicateODtoOG();
        } else {
          console.log('Champs de réfraction non trouvés sur cette page');
          showToast('⚠️ Champs de réfraction non disponibles');
        }
      }

      // F3 - Calcul OrthoK
      else if (event.key === 'F3') {
        console.log('Raccourci F3 détecté - Calcul OrthoK');
        event.preventDefault();
        event.stopPropagation();
        await performOrthoKCalculation();
      }

      // F4 - Calcul LRPG
      else if (event.key === 'F4') {
        console.log('Raccourci F4 détecté - Calcul LRPG');
        event.preventDefault();
        event.stopPropagation();
        await performLRPGCalculation();
      }

    }, true); // Capture phase pour intercepter avant tout autre handler

    console.log('✅ Raccourcis activés :');
    console.log('  F1 : Coller réfraction depuis presse-papier');
    console.log('  F2 : Dupliquer OD→OG');
    console.log('  F3 : Calcul OrthoK');
    console.log('  F4 : Calcul LRPG');
    }

  // Fonction pour capturer et mémoriser les données de réfraction/kératométrie
  function captureRefractionData() {

    const data = {
      od: {
        sphere: null,
        cylinder: null,
        axis: null,
        kerato: {
          kFlat: null,
          kSteep: null,
          axisFlat: null
        }
      },
      og: {
        sphere: null,
        cylinder: null,
        axis: null,
        kerato: {
          kFlat: null,
          kSteep: null,
          axisFlat: null
        }
      }
    };

    // Capturer les valeurs de réfraction OD
    const odSphere = document.querySelector('#input-rightsphere');
    const odCylinder = document.querySelector('#input-rightcylinder');
    const odAxis = document.querySelector('#input-rightrefractionAxis');

    if (odSphere && odSphere.value) data.od.sphere = odSphere.value;
    if (odCylinder && odCylinder.value) data.od.cylinder = odCylinder.value;
    if (odAxis && odAxis.value) data.od.axis = odAxis.value;

    // Capturer les valeurs de kératométrie OD
    const odKFlat = document.querySelector('#input-rightkParameter');
    const odKSteep = document.querySelector('#input-rightsteepKParameter');
    const odAxisFlat = document.querySelector('#input-rightkeratometryAxis');

    if (odKFlat && odKFlat.value) data.od.kerato.kFlat = odKFlat.value;
    if (odKSteep && odKSteep.value) data.od.kerato.kSteep = odKSteep.value;
    if (odAxisFlat && odAxisFlat.value) data.od.kerato.axisFlat = odAxisFlat.value;

    // Capturer les valeurs de réfraction OG
    const ogSphere = document.querySelector('#input-leftsphere');
    const ogCylinder = document.querySelector('#input-leftcylinder');
    const ogAxis = document.querySelector('#input-leftrefractionAxis');

    if (ogSphere && ogSphere.value) data.og.sphere = ogSphere.value;
    if (ogCylinder && ogCylinder.value) data.og.cylinder = ogCylinder.value;
    if (ogAxis && ogAxis.value) data.og.axis = ogAxis.value;

    // Capturer les valeurs de kératométrie OG
    const ogKFlat = document.querySelector('#input-leftkParameter');
    const ogKSteep = document.querySelector('#input-leftsteepKParameter');
    const ogAxisFlat = document.querySelector('#input-leftkeratometryAxis');

    if (ogKFlat && ogKFlat.value) data.og.kerato.kFlat = ogKFlat.value;
    if (ogKSteep && ogKSteep.value) data.og.kerato.kSteep = ogKSteep.value;
    if (ogAxisFlat && ogAxisFlat.value) data.og.kerato.axisFlat = ogAxisFlat.value;

    // Stocker dans sessionStorage
    sessionStorage.setItem('clickfit_refraction_data', JSON.stringify(data));
    console.log(' Données capturées:', data);

    return data;
  }

  // Fonction pour formater les données complètes (réfraction + kérato)
  function formatCompleteData(eye) {
    let result = '';

    // Partie réfraction : sphère (cylindre) axe°
    if (eye.sphere || eye.cylinder) {
      // Sphère
      if (eye.sphere) {
        const sphere = parseFloat(eye.sphere);
        result += sphere > 0 ? '+' : '';
        result += sphere.toFixed(2);
      } else {
        result += 'Plan';
      }

      // Cylindre et axe
      if (eye.cylinder && parseFloat(eye.cylinder) !== 0) {
        const cylinder = parseFloat(eye.cylinder);
        result += ' (';
        result += cylinder > 0 ? '+' : '';
        result += cylinder.toFixed(2);
        result += ')';

        if (eye.axis) {
          result += ' ' + parseInt(eye.axis) + '°';
        }
      }
    } else {
      result += 'Non renseigné';
    }

    // Partie kératométrie : Kérato plate x Kérato serrée @ Axe plat°
    if (eye.kerato.kFlat && eye.kerato.kSteep) {
      result += ' / ';
      result += eye.kerato.kFlat + ' x ' + eye.kerato.kSteep;

      if (eye.kerato.axisFlat) {
        result += ' @ ' + eye.kerato.axisFlat + '°';
      }
    }

    return result;
  }

  // Fonction pour afficher les données sur la page des lentilles avec encadré et légende
  function displayRefractionOnLensPage() {
    console.log('� Tentative d\'affichage des données de réfraction...');

    // Récupérer les données depuis sessionStorage
    const storedData = sessionStorage.getItem('clickfit_refraction_data');
    if (!storedData) {
      console.log(' Aucune donnée de réfraction en mémoire');
      return;
    }

    const data = JSON.parse(storedData);
    console.log('� Données récupérées:', data);

    // Chercher les divs contenant "Œil droit" et "Œil gauche"
    const findEyeContainers = () => {
      console.log('🔍 Recherche des conteneurs œil droit/gauche...');

      // Chercher par classe spécifique
      const allDivs = document.querySelectorAll('div.amds-text.amds-font-headline-h6.amds-color-basic-900');
      console.log(`📊 ${allDivs.length} divs trouvés avec la classe`);

      let odContainer = null;
      let ogContainer = null;

      for (let div of allDivs) {
        // Nettoyage du texte
        const text = div.textContent.replace(/\s+/g, ' ').trim();
        console.log(`Texte trouvé: "${text}"`);

        if (text === 'Œil droit' || text === 'Oeil droit') {
          odContainer = div;
          console.log(' Œil droit trouvé:', div);
        } else if (text === 'Œil gauche' || text === 'Oeil gauche') {
          ogContainer = div;
          console.log(' Œil gauche trouvé:', div);
        }
      }

      console.log('📊 Résultat recherche:', { odContainer, ogContainer });
      return { odContainer, ogContainer };
    };

    const { odContainer, ogContainer } = findEyeContainers();

    // Fonction pour créer un encadré formaté avec légende (version horizontale)
  const createInfoBox = (data, eye) => {
    const eyeData = eye === 'od' ? data.od : data.og;
    const isOD = eye === 'od';

    // Couleurs différenciées OD (violet) / OG (bleu)
    const colors = isOD ? {
      background: '#faf8ff',  // Violet très clair
      border: '#d4c5e8',      // Bordure violet doux
      shadow: 'rgba(146, 75, 146, 0.08)',  // Ombre violette douce
      textPrimary: '#4a1e7c', // Texte violet foncé
      textSecondary: '#6c4a8d', // Violet moyen pour les labels
      separator: '#e4d5f0'    // Séparateur violet clair
    } : {
      background: '#f8fbff',  // Bleu clair (actuel pour OG)
      border: '#d0d7e5',      // Bordure bleue
      shadow: 'rgba(30, 75, 146, 0.08)',  // Ombre bleue
      textPrimary: '#1a3d7c', // Texte bleu foncé
      textSecondary: '#1e4b92', // Bleu moyen pour les labels
      separator: '#d0d7e5'    // Séparateur bleu clair
    };

    // Formater la réfraction
    let refractionText = '';
    if (eyeData.sphere || eyeData.cylinder) {
      // Sphère
      if (eyeData.sphere) {
        const sphere = parseFloat(eyeData.sphere);
        refractionText += sphere > 0 ? '+' : '';
        refractionText += sphere.toFixed(2).replace('.', ',');
      } else {
        refractionText += 'Plan';
      }

      // Cylindre et axe
      if (eyeData.cylinder && parseFloat(eyeData.cylinder) !== 0) {
        const cylinder = parseFloat(eyeData.cylinder);
        refractionText += ' (';
        refractionText += cylinder > 0 ? '+' : '';
        refractionText += cylinder.toFixed(2).replace('.', ',');
        refractionText += ')';

        if (eyeData.axis) {
          refractionText += ' ' + parseInt(eyeData.axis) + '°';
        }
      }
    } else {
      refractionText = 'Non renseignée';
    }

    // Formater la kératométrie
    let keratoText = '';
    if (eyeData.kerato.kFlat && eyeData.kerato.kSteep) {
      keratoText = eyeData.kerato.kFlat.replace('.', ',') + ' × ' + eyeData.kerato.kSteep.replace('.', ',');
      if (eyeData.kerato.axisFlat) {
        keratoText += ' @ ' + eyeData.kerato.axisFlat + '°';
      }
    } else {
      keratoText = 'Non renseignée';
    }

    // Créer l'élément encadré
    const infoBox = document.createElement('div');
    infoBox.className = `refraction-info refraction-info-${eye}`;
    infoBox.style.cssText = `
      border: 1px solid ${colors.border};
      border-radius: 6px;
      padding: 10px 14px;
      margin: 8px 15px 8px 0;
      background-color: ${colors.background};
      box-shadow: 0 1px 3px ${colors.shadow};
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
      font-size: 14px;
      max-width: 700px;
    `;

    infoBox.innerHTML = `
      <div style="
        font-weight: 600;
        color: #6c757d;
        text-transform: uppercase;
        font-size: 11px;
        letter-spacing: 0.5px;
        margin-bottom: 6px;
        display: flex;
        align-items: center;
        gap: 6px;
      ">
        <span>📋</span>
        <span>Données initiales</span>
      </div>

      <div style="
        color: ${colors.textSecondary};
        display: flex;
        align-items: center;
        gap: 20px;
        flex-wrap: wrap;
      ">
        <div style="display: flex; align-items: center; gap: 6px;">
          <span style="font-weight: 500;">Réfraction :</span>
          <span style="font-weight: 600; color: ${colors.textPrimary};">${refractionText}</span>
        </div>

        <span style="color: ${colors.separator}; font-weight: 300;">|</span>

        <div style="display: flex; align-items: center; gap: 6px;">
          <span style="font-weight: 500;">Kératométrie :</span>
          <span style="font-weight: 600; color: ${colors.textPrimary};">${keratoText}</span>
        </div>
      </div>
    `;

    return infoBox;
  };

    // Ajouter les informations pour OD
    if (odContainer) {
      // Chercher si l'info existe déjà dans le parent ou à côté
      const parent = odContainer.parentElement;
      let existingInfo = null;

      // Chercher plus largement dans le parent du parent
      const grandParent = parent ? parent.parentElement : null;
      if (grandParent) {
        existingInfo = grandParent.querySelector('.refraction-info-od');
      }

      if (!existingInfo) {
        const odInfoBox = createInfoBox(data, 'od');

        // Insérer après le parent du titre pour que ce soit bien en dessous
        if (parent && parent.parentElement) {
          parent.parentElement.insertBefore(odInfoBox, parent.nextSibling);
        } else if (odContainer.nextSibling) {
          odContainer.parentNode.insertBefore(odInfoBox, odContainer.nextSibling);
        } else {
          odContainer.appendChild(odInfoBox);
        }

        console.log(' Info OD ajoutée avec encadré');
      } else {
        // Remplacer complètement l'info existante
        const newInfoBox = createInfoBox(data, 'od');
        existingInfo.replaceWith(newInfoBox);
        console.log('🔄 Info OD mise à jour avec encadré');
      }
    } else {
      console.log('Conteneur OD non trouvé');
    }

    // Ajouter les informations pour OG
    if (ogContainer) {
      // Chercher si l'info existe déjà dans le parent ou à côté
      const parent = ogContainer.parentElement;
      let existingInfo = null;

      // Chercher plus largement dans le parent du parent
      const grandParent = parent ? parent.parentElement : null;
      if (grandParent) {
        existingInfo = grandParent.querySelector('.refraction-info-og');
      }

      if (!existingInfo) {
        const ogInfoBox = createInfoBox(data, 'og');

        // Insérer après le parent du titre pour que ce soit bien en dessous
        if (parent && parent.parentElement) {
          parent.parentElement.insertBefore(ogInfoBox, parent.nextSibling);
        } else if (ogContainer.nextSibling) {
          ogContainer.parentNode.insertBefore(ogInfoBox, ogContainer.nextSibling);
        } else {
          ogContainer.appendChild(ogInfoBox);
        }

        console.log('✅ Info OG ajoutée avec encadré');
      } else {
        // Remplacer complètement l'info existante
        const newInfoBox = createInfoBox(data, 'og');
        existingInfo.replaceWith(newInfoBox);
        console.log('🔄 Info OG mise à jour avec encadré');
      }
    } else {
      console.log(' Conteneur OG non trouvé');
    }
  }

  function setupRefractionPolling() {
  console.log('🔄 Activation du polling mémoire réfraction (robuste)');
  window.captureRefractionData = captureRefractionData;
  window.displayRefractionOnLensPage = displayRefractionOnLensPage;

  // Reset à chaque changement de fiche patient (via l’URL)
  let lastPatientId = null;
  setInterval(() => {
    const match = location.pathname.match(/\/file\/([A-Za-z0-9]+)/);
    const patientId = match ? match[1] : null;
    if (patientId !== lastPatientId) {
      sessionStorage.removeItem('clickfit_refraction_data');
      lastPatientId = patientId;
      console.log('Nouvelle fiche patient détectée, reset mémoire');
    }
  }, 500);

  // Polling toutes les 500ms sur la page info patient pour capture
  setInterval(() => {
    // Teste la présence de TOUS les champs nécessaires (OD + OG)
    const odSphere = document.querySelector('#input-rightsphere');
    const odCyl = document.querySelector('#input-rightcylinder');
    const odAxis = document.querySelector('#input-rightrefractionAxis');
    const ogSphere = document.querySelector('#input-leftsphere');
    const ogCyl = document.querySelector('#input-leftcylinder');
    const ogAxis = document.querySelector('#input-leftrefractionAxis');


    if (odSphere && odCyl && odAxis && ogSphere && ogCyl && ogAxis) {

      const hasAnyValue = [odSphere.value, odCyl.value, odAxis.value, ogSphere.value, ogCyl.value, ogAxis.value]
        .some(val => val && val.trim() !== '');

      if (hasAnyValue) {
        // Capture et sauvegarde si changement
        const data = captureRefractionData();
        const oldData = sessionStorage.getItem('clickfit_refraction_data');
        if (JSON.stringify(data) !== oldData) {
          sessionStorage.setItem('clickfit_refraction_data', JSON.stringify(data));
          console.log('Données de réfraction mises à jour');
        }
      }
    }
  }, 500);

  // Affichage automatique sur la page lentilles
  setInterval(() => {
    if (typeof window.displayRefractionOnLensPage === 'function') {
      window.displayRefractionOnLensPage();
    }
  }, 1500);
  }

  // Module protection tabulation

  // ========================================
// FIX ANTI-DÉFOCUS ET NAVIGATION TAB POUR PREMIÈRES LENTILLES
// ========================================

function fixLensPageAutoSaveAndTab() {
  console.log('🛡️ Activation du fix anti-défocus pour Premières lentilles...');

  // Variables globales pour le module
  let currentFocusedElement = null;
  let shouldMaintainFocus = false;
  let focusProtectionActive = false;
  let lastInputTime = 0;
  const DEBOUNCE_DELAY = 300; // Délai avant auto-save

  // Fonction pour détecter si on est sur la page lentilles
  function isLensPage() {
    const indicators = [
      document.querySelector('.tab.lens-0-tab.active'),
      document.querySelector('app-file-first-lens'),
      document.querySelector('#input-righttype'),
      document.querySelector('.lenses')
    ];
    return indicators.some(el => el !== null);
  }

  if (!isLensPage()) {
    console.log('❌ Pas sur la page Premières lentilles');
    return;
  }

  // Éviter la double activation
  if (window.lensAutoSaveFixActive) {
    console.log('🔄 Fix anti-défocus déjà actif');
    return;
  }

  console.log('✅ Fix anti-défocus activé pour la page lentilles');
  window.lensAutoSaveFixActive = true;

  // ========================================
  // PARTIE 1: NEUTRALISATION DE L'AUTO-SAVE
  // ========================================

  // Intercepter et bloquer les blur causés par l'auto-save
  function protectFocus() {
    if (focusProtectionActive) return;
    focusProtectionActive = true;

    // Sauvegarder les méthodes originales
    const originalBlur = HTMLElement.prototype.blur;
    const originalFocus = HTMLElement.prototype.focus;

    // Override de blur pour empêcher le défocus non désiré
    HTMLElement.prototype.blur = function() {
      // Si on est dans un input de la page lentilles et qu'on veut maintenir le focus
      if (shouldMaintainFocus && this === currentFocusedElement) {
        console.log('🛡️ Blur bloqué sur:', this.id || this.className);
        // Ne pas exécuter le blur
        return;
      }
      // Sinon, exécuter normalement
      return originalBlur.apply(this, arguments);
    };

    // Intercepter les événements blur au niveau document
    document.addEventListener('blur', function(e) {
      if (!shouldMaintainFocus) return;

      const target = e.target;

      // Vérifier si c'est un input de la page lentilles
      if (target && target === currentFocusedElement &&
          (target.tagName === 'INPUT' || target.tagName === 'SELECT')) {

        console.log('🔄 Tentative de défocus détectée, restauration...');

        // Empêcher la propagation
        e.stopImmediatePropagation();
        e.preventDefault();

        // Restaurer le focus immédiatement
        setTimeout(() => {
          if (currentFocusedElement && currentFocusedElement !== document.activeElement) {
            currentFocusedElement.focus();

            // Pour les inputs numériques, resélectionner le contenu
            if (currentFocusedElement.type === 'number' || currentFocusedElement.type === 'text') {
              currentFocusedElement.select();
            }
          }
        }, 0);
      }
    }, true); // Capture phase

    console.log('✅ Protection focus activée');
  }

  // Tracker le focus actuel
  function trackFocus() {
    document.addEventListener('focusin', function(e) {
      const target = e.target;

      // Si c'est un input/select de la page lentilles
      if (isLensPage() &&
          (target.tagName === 'INPUT' || target.tagName === 'SELECT')) {

        currentFocusedElement = target;
        shouldMaintainFocus = true;

        console.log('🎯 Focus tracké sur:', target.id || target.className);

        // Désactiver la protection après un délai (pour permettre la navigation normale)
        clearTimeout(window.focusProtectionTimeout);
        window.focusProtectionTimeout = setTimeout(() => {
          shouldMaintainFocus = false;
        }, 5000); // 5 secondes de protection
      }
    }, true);

    // Détecter les changements d'input pour réactiver la protection
    document.addEventListener('input', function(e) {
      if (isLensPage() && e.target === currentFocusedElement) {
        shouldMaintainFocus = true;
        lastInputTime = Date.now();

        // Réactiver la protection
        clearTimeout(window.focusProtectionTimeout);
        window.focusProtectionTimeout = setTimeout(() => {
          shouldMaintainFocus = false;
        }, 2000); // 2 secondes après la dernière frappe
      }
    }, true);
  }

  // ========================================
  // PARTIE 2: AMÉLIORATION DE LA NAVIGATION TAB
  // ========================================

  function enhanceTabNavigation() {
    let isNavigating = false;

    document.addEventListener('keydown', function(e) {
      if (e.key !== 'Tab' || !isLensPage()) return;

      const activeElement = document.activeElement;
      if (!activeElement || activeElement.tagName === 'BODY') return;

      // Marquer qu'on est en navigation pour ne pas interférer
      isNavigating = true;
      shouldMaintainFocus = false; // Permettre le changement de focus

      // Obtenir tous les inputs/selects visibles
      const allInputs = getAllNavigableElements();
      const currentIndex = allInputs.indexOf(activeElement);

      if (currentIndex === -1) {
        isNavigating = false;
        return;
      }

      e.preventDefault();
      e.stopPropagation();

      // Calculer l'index suivant
      let nextIndex;
      if (e.shiftKey) {
        nextIndex = currentIndex - 1;
        if (nextIndex < 0) nextIndex = allInputs.length - 1;
      } else {
        nextIndex = currentIndex + 1;
        if (nextIndex >= allInputs.length) nextIndex = 0;
      }

      // Naviguer vers le prochain élément
      const nextElement = allInputs[nextIndex];
      if (nextElement) {
        console.log(`➡️ Navigation vers:`, nextElement.id || nextElement.className);

        // Désactiver temporairement la protection
        shouldMaintainFocus = false;

        setTimeout(() => {
          nextElement.focus();

          // Réactiver la protection sur le nouvel élément
          currentFocusedElement = nextElement;
          shouldMaintainFocus = true;

          // Sélectionner le contenu pour les inputs
          if (nextElement.tagName === 'INPUT' &&
              (nextElement.type === 'text' || nextElement.type === 'number')) {
            nextElement.select();
          }

          isNavigating = false;

          // Protection pendant 3 secondes
          clearTimeout(window.focusProtectionTimeout);
          window.focusProtectionTimeout = setTimeout(() => {
            shouldMaintainFocus = false;
          }, 3000);
        }, 10);
      }
    }, true);
  }

  // Obtenir tous les éléments navigables dans l'ordre
  function getAllNavigableElements() {
    const allElements = [];

    // IMPORTANT: D'abord TOUS les inputs OD, puis TOUS les inputs OG

    // 1. Récupérer TOUS les inputs OD (pas les selects)
    const odContainer = document.querySelector('app-file-first-lens:nth-child(1)');
    if (odContainer) {
      const odInputs = odContainer.querySelectorAll(`
        input:not([type="hidden"]):not([type="radio"]):not([type="checkbox"]):not([disabled]):not([readonly])
      `);

      const visibleOdInputs = [];
      odInputs.forEach(input => {
        if (input.offsetParent !== null && input.tabIndex !== -1) {
          visibleOdInputs.push(input);
        }
      });

      // Trier par position verticale puis horizontale
      visibleOdInputs.sort((a, b) => {
        const rectA = a.getBoundingClientRect();
        const rectB = b.getBoundingClientRect();

        // D'abord par position verticale
        if (Math.abs(rectA.top - rectB.top) > 10) {
          return rectA.top - rectB.top;
        }
        // Puis par position horizontale
        return rectA.left - rectB.left;
      });

      allElements.push(...visibleOdInputs);
      console.log(`📊 OD: ${visibleOdInputs.length} inputs trouvés`);

      // Log pour debug
      visibleOdInputs.forEach((el, index) => {
        const label = el.getAttribute('aria-label') || el.id || el.placeholder || 'inconnu';
        console.log(`  OD ${index + 1}: ${label}`);
      });
    }

    // 2. Récupérer TOUS les inputs OG (pas les selects)
    const ogContainer = document.querySelector('app-file-first-lens:nth-child(2)');
    if (ogContainer) {
      const ogInputs = ogContainer.querySelectorAll(`
        input:not([type="hidden"]):not([type="radio"]):not([type="checkbox"]):not([disabled]):not([readonly])
      `);

      const visibleOgInputs = [];
      ogInputs.forEach(input => {
        if (input.offsetParent !== null && input.tabIndex !== -1) {
          visibleOgInputs.push(input);
        }
      });

      // Trier par position verticale puis horizontale
      visibleOgInputs.sort((a, b) => {
        const rectA = a.getBoundingClientRect();
        const rectB = b.getBoundingClientRect();

        // D'abord par position verticale
        if (Math.abs(rectA.top - rectB.top) > 10) {
          return rectA.top - rectB.top;
        }
        // Puis par position horizontale
        return rectA.left - rectB.left;
      });

      allElements.push(...visibleOgInputs);
      console.log(`📊 OG: ${visibleOgInputs.length} inputs trouvés`);

      // Log pour debug
      visibleOgInputs.forEach((el, index) => {
        const label = el.getAttribute('aria-label') || el.id || el.placeholder || 'inconnu';
        console.log(`  OG ${index + 1}: ${label}`);
      });
    }

    console.log(`📋 Total: ${allElements.length} inputs navigables (selects exclus)`);
    return allElements;
  }

  // ========================================
  // PARTIE 3: INTERCEPTION DES SAVES ANGULAR
  // ========================================

  function interceptAngularSaves() {
    // Intercepter les requêtes XHR pour détecter les saves
    const originalXHRSend = XMLHttpRequest.prototype.send;

    XMLHttpRequest.prototype.send = function() {
      // Si c'est une requête de save sur la page lentilles
      if (this.responseURL && this.responseURL.includes('/api/') && isLensPage()) {

        // Sauvegarder l'élément actuellement focus
        const elementToRestore = currentFocusedElement;

        this.addEventListener('loadend', function() {
          // Après la requête, restaurer le focus
          if (elementToRestore && shouldMaintainFocus) {
            console.log('🔄 Restauration focus post-save');
            setTimeout(() => {
              if (elementToRestore !== document.activeElement) {
                elementToRestore.focus();
                if (elementToRestore.type === 'number' || elementToRestore.type === 'text') {
                  elementToRestore.select();
                }
              }
            }, 100);
          }
        });
      }

      return originalXHRSend.apply(this, arguments);
    };
  }

  // ========================================
  // PARTIE 4: OBSERVER POUR RÉACTIVATION
  // ========================================

  function observePageChanges() {
    const observer = new MutationObserver(() => {
      // Vérifier si on a changé de page
      if (!isLensPage() && window.lensAutoSaveFixActive) {
        console.log('📤 Sortie de la page lentilles');
        window.lensAutoSaveFixActive = false;
        shouldMaintainFocus = false;
        currentFocusedElement = null;
      } else if (isLensPage() && !window.lensAutoSaveFixActive) {
        console.log('📥 Retour sur la page lentilles');
        fixLensPageAutoSaveAndTab();
      }
    });

    observer.observe(document.body, {
      childList: true,
      subtree: true
    });
  }

  // ========================================
  // INITIALISATION
  // ========================================

  protectFocus();
  trackFocus();
  enhanceTabNavigation();
  interceptAngularSaves();
  observePageChanges();

  console.log('✨ Fix anti-défocus et navigation Tab activé avec succès !');
  console.log('📝 Instructions:');
  console.log('   - Tab/Shift+Tab pour naviguer');
  console.log('   - Le focus est maintenu pendant la frappe');
  console.log('   - Protection auto pendant 2-3 secondes après chaque action');
}

// ========================================
// ACTIVATION AUTOMATIQUE
// ========================================

// Vérifier et activer toutes les secondes
setInterval(() => {
  const lensTab = document.querySelector('.tab.lens-0-tab.active');
  if (lensTab && !window.lensAutoSaveFixActive) {
    console.log('📍 Page Premières lentilles détectée - activation du fix');
    fixLensPageAutoSaveAndTab();
  }
}, 1000);

// Activation initiale si déjà sur la page
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', () => {
    setTimeout(fixLensPageAutoSaveAndTab, 1000);
  });
} else {
  setTimeout(fixLensPageAutoSaveAndTab, 1000);
}

console.log('🚀 Module Anti-Défocus pour Premières Lentilles chargé');


  // ========== MODULE VIDEO EXPLICATIVE ==========
  const VideoExplanationModule = {
    // Configuration des vidéos par modèle
    videos: {
      'expert prog': {
        url: 'https://www.youtube.com/embed/P9Kmm2fg6wk?si=YTkBsPOXq50fzJAI',
        title: 'Guide Expert Prog'
      }
      // Ajout d'autres modèles/vidéos ici si besoin
    },

    // État du module
    currentButtons: new Map(),
    modalOpen: false,

    // Initialisation
    init() {
      console.log('📹 Initialisation du module vidéo explicative');
      this.injectStyles();
      this.setupObservers();
      this.checkExistingSelects();
    },

    // Injection des styles CSS
    injectStyles() {
      if (document.getElementById('video-explanation-styles')) return;

      const styles = `
        /* Bouton vidéo */
        .video-help-button {
          display: inline-flex;
          align-items: center;
          gap: 6px;
          margin-left: 12px;
          padding: 6px 12px;
          background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
          color: white;
          border: none;
          border-radius: 20px;
          font-size: 13px;
          font-weight: 500;
          cursor: pointer;
          transition: all 0.3s ease;
          box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
          vertical-align: middle;
        }

        .video-help-button:hover {
          transform: translateY(-2px);
          box-shadow: 0 4px 12px rgba(102, 126, 234, 0.5);
        }

        .video-help-button.pulse {
          animation: pulse-video 2s infinite;
        }

        @keyframes pulse-video {
          0% { box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); }
          50% { box-shadow: 0 2px 16px rgba(102, 126, 234, 0.6); }
          100% { box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); }
        }

        /* Modal vidéo */
        .video-modal-overlay {
          position: fixed;
          top: 0;
          left: 0;
          width: 100vw;
          height: 100vh;
          background: rgba(0, 0, 0, 0.85);
          display: flex;
          align-items: center;
          justify-content: center;
          z-index: 100000;
          opacity: 0;
          transition: opacity 0.3s ease;
          backdrop-filter: blur(5px);
        }

        .video-modal-overlay.show {
          opacity: 1;
        }

        .video-modal-container {
          position: relative;
          width: 90%;
          max-width: 900px;
          background: #1a1a1a;
          border-radius: 12px;
          overflow: hidden;
          box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
          transform: scale(0.9);
          transition: transform 0.3s ease;
        }

        .video-modal-overlay.show .video-modal-container {
          transform: scale(1);
        }

        .video-modal-header {
          background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
          padding: 16px 20px;
          display: flex;
          justify-content: space-between;
          align-items: center;
        }

        .video-modal-title {
          color: white;
          font-size: 18px;
          font-weight: 600;
          margin: 0;
        }

        .video-modal-close {
          background: rgba(255, 255, 255, 0.2);
          border: none;
          color: white;
          width: 32px;
          height: 32px;
          border-radius: 50%;
          font-size: 20px;
          cursor: pointer;
          display: flex;
          align-items: center;
          justify-content: center;
          transition: background 0.3s;
        }

        .video-modal-close:hover {
          background: rgba(255, 255, 255, 0.3);
        }

        .video-modal-body {
          position: relative;
          padding-bottom: 56.25%; /* Ratio 16:9 */
          height: 0;
          background: #000;
        }

        .video-modal-body iframe {
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          border: none;
        }
      `;

      const styleEl = document.createElement('style');
      styleEl.id = 'video-explanation-styles';
      styleEl.textContent = styles;
      document.head.appendChild(styleEl);
    },

    // Vérifier si un modèle nécessite une vidéo
    needsVideo(modelText) {
      if (!modelText) return null;

      const lowerText = modelText.toLowerCase();

      // Chercher dans la config des vidéos
      for (const [key, videoData] of Object.entries(this.videos)) {
        if (lowerText.includes(key)) {
          return videoData;
        }
      }

      return null;
    },

    // Créer le bouton vidéo
    createVideoButton(videoData) {
      const button = document.createElement('button');
      button.className = 'video-help-button pulse';
      button.innerHTML = `
        <span>📹</span>
        <span>Aide vidéo</span>
      `;

      button.addEventListener('click', (e) => {
        e.preventDefault();
        e.stopPropagation();
        this.openVideoModal(videoData);
        button.classList.remove('pulse');
      });

      return button;
    },

    // Ouvrir le modal vidéo
    openVideoModal(videoData) {
      if (this.modalOpen) return;

      this.modalOpen = true;

      // Créer l'overlay et le modal
      const overlay = document.createElement('div');
      overlay.className = 'video-modal-overlay';

      overlay.innerHTML = `
        <div class="video-modal-container">
          <div class="video-modal-header">
            <h3 class="video-modal-title">${videoData.title}</h3>
            <button class="video-modal-close">×</button>
          </div>
          <div class="video-modal-body">
            <iframe
              src="${videoData.url}"
              title="${videoData.title}"
              frameborder="0"
              allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
              referrerpolicy="strict-origin-when-cross-origin"
              allowfullscreen>
            </iframe>
          </div>
        </div>
      `;

      document.body.appendChild(overlay);

      // Animation d'ouverture
      setTimeout(() => overlay.classList.add('show'), 10);

      // Fermeture
      const closeModal = () => {
        overlay.classList.remove('show');
        setTimeout(() => {
          overlay.remove();
          this.modalOpen = false;
        }, 300);
      };

      // Event listeners pour fermer
      overlay.querySelector('.video-modal-close').addEventListener('click', closeModal);

      // Fermer en cliquant en dehors
      overlay.addEventListener('click', (e) => {
        if (e.target === overlay) {
          closeModal();
        }
      });

      // Fermer avec Echap
      const escHandler = (e) => {
        if (e.key === 'Escape') {
          closeModal();
          document.removeEventListener('keydown', escHandler);
        }
      };
      document.addEventListener('keydown', escHandler);

      console.log(`📹 Vidéo ouverte: ${videoData.title}`);
    },

    // Gérer l'ajout/suppression du bouton
    handleSelectChange(selectElement) {
      const selectId = selectElement.id;
      const selectedOption = selectElement.options[selectElement.selectedIndex];
      const modelText = selectedOption ? selectedOption.textContent : '';

      // Retirer l'ancien bouton s'il existe
      const existingButton = this.currentButtons.get(selectId);
      if (existingButton) {
        existingButton.remove();
        this.currentButtons.delete(selectId);
      }

      // Vérifier si on doit ajouter un bouton
      const videoData = this.needsVideo(modelText);
      if (videoData) {
        // Créer et ajouter le nouveau bouton
        const button = this.createVideoButton(videoData);

        // Trouver où insérer le bouton (après le select ou son conteneur)
        const container = selectElement.closest('.amds-form-element') ||
                        selectElement.closest('.form-group') ||
                        selectElement.parentElement;

        if (container) {
          container.appendChild(button);
          this.currentButtons.set(selectId, button);

          // Retirer l'animation après 5 secondes
          setTimeout(() => button.classList.remove('pulse'), 5000);
        }
      }
    },

    // Observer les changements sur les selects
    setupObservers() {
      // Observer les changements de valeur
      const observeSelect = (selectId) => {
        const select = document.querySelector(selectId);
        if (select && !select.dataset.videoObserved) {
          select.dataset.videoObserved = 'true';

          // Écouter les changements
          select.addEventListener('change', () => {
            this.handleSelectChange(select);
          });

          // Vérification initiale
          this.handleSelectChange(select);
        }
      };

      // Observer les deux selects
      setInterval(() => {
        observeSelect('#input-rightmodel');
        observeSelect('#input-leftmodel');
      }, 1000);
    },

    // Vérifier les selects existants au chargement
    checkExistingSelects() {
      setTimeout(() => {
        const rightSelect = document.querySelector('#input-rightmodel');
        const leftSelect = document.querySelector('#input-leftmodel');

        if (rightSelect) this.handleSelectChange(rightSelect);
        if (leftSelect) this.handleSelectChange(leftSelect);
      }, 2000);
    }
  };

  // Barre d'espace pour navigation "Suivant"
  function setupSpaceNext() {
      console.log('Activation espace = suivant');

      document.addEventListener('keydown', (e) => {
        // Si c'est la barre espace
        if (e.key === ' ' || e.code === 'Space') {

          // Si on est dans un input, on ne fait rien
          if (document.activeElement.tagName === 'INPUT' ||
              document.activeElement.tagName === 'TEXTAREA') {
            return;
          }

          // Chercher le bouton suivant
          const nextButton = document.querySelector('#input-nextstep > button');

          if (nextButton) {
            e.preventDefault(); // Empêcher le scroll
            nextButton.click();
            console.log('Clic sur Suivant');
          }
        }
      });
  }

  // Système de fix pour la navigation Tab avec auto-save
  // Remplacer la fonction fixTabNavigationWithAutoSave existante (ligne ~3570)
function fixTabNavigationWithAutoSave() {
  console.log('✅ Activation du fix de navigation Tab avec détection de page...');

  // Variables pour tracker le focus
  let lastFocusedElement = null;
  let lastFocusedSelector = null;
  let isAutoSaving = false;
  let tabQueue = [];

  const fieldsOrder = [
    // Réfraction OD
    '#input-rightsphere',
    '#input-rightcylinder',
    '#input-rightrefractionAxis',
    '#input-rightaddition',
    // Réfraction OG
    '#input-leftsphere',
    '#input-leftcylinder',
    '#input-leftrefractionAxis',
    '#input-leftaddition',
    // Kératométrie OD
    '#input-rightkParameter',
    '#input-rightsteepKParameter',
    '#input-rightkeratometryAxis',
    '#input-righteccentricity',
    '#input-rightsteepEccentricity',
    '#input-rightvisibleIrisDiameterAt30',
    // Kératométrie OG
    '#input-leftkParameter',
    '#input-leftsteepKParameter',
    '#input-leftkeratometryAxis',
    '#input-lefteccentricity',
    '#input-leftsteepEccentricity',
    '#input-leftvisibleIrisDiameterAt30'
  ];

  // NOUVELLE FONCTION : Vérifier si on est sur la page information
  function isOnInformationPage() {
    return !!document.querySelector('#wrapper > main > app-file-layout > div > app-file-tab-information');
  }

  // NOUVELLE FONCTION : Vérifier si on est sur la page first-lens
  function isOnFirstLensPage() {
    return !!document.querySelector('#wrapper > main > app-file-layout > div > app-file-tab-first-lens');
  }

  // Fonctions helper existantes
  function getElementSelector(element) {
    if (element.id) return `#${element.id}`;
    let selector = element.tagName.toLowerCase();
    if (element.className) {
      selector += '.' + element.className.split(' ').join('.');
    }
    const siblings = element.parentElement?.querySelectorAll(selector);
    if (siblings && siblings.length > 1) {
      const index = Array.from(siblings).indexOf(element);
      selector += `:nth-of-type(${index + 1})`;
    }
    return selector;
  }

  function saveCurrentFocus() {
    const activeElement = document.activeElement;
    if (activeElement && activeElement.tagName === 'INPUT') {
      lastFocusedElement = activeElement;
      lastFocusedSelector = getElementSelector(activeElement);
      if (activeElement.selectionStart !== undefined) {
        lastFocusedElement.dataset.lastCursorPos = activeElement.selectionStart;
      }
    }
  }

  function restoreFocus() {
    if (lastFocusedSelector) {
      const element = document.querySelector(lastFocusedSelector);
      if (element && element !== document.activeElement) {
        console.log(`🎯 Restauration du focus sur ${lastFocusedSelector}`);
        setTimeout(() => {
          element.focus();
          if (element.dataset.lastCursorPos) {
            const pos = parseInt(element.dataset.lastCursorPos);
            element.setSelectionRange(pos, pos);
            delete element.dataset.lastCursorPos;
          }
        }, 50);
      }
    }
  }

  // Override de la navigation Tab MODIFIÉ
  function overrideTabNavigation() {
    document.addEventListener('keydown', (e) => {
      // NOUVEAU : Vérifier qu'on est sur la page information
      if (isOnFirstLensPage()) {
        // Sur la page first-lens, ne PAS intercepter Tab
        console.log('🚫 Page first-lens détectée - navigation Tab native');
        return;
      }

      if (!isOnInformationPage()) {
        // Si on n'est pas sur la page information, ne rien faire
        return;
      }

      // Ne traiter que Tab sans Shift (navigation avant)
      if (e.key === 'Tab' && !e.shiftKey) {
        const activeElement = document.activeElement;

        // Vérifier si on est dans un champ de notre liste
        const currentIndex = fieldsOrder.findIndex(selector =>
          activeElement === document.querySelector(selector)
        );

        if (currentIndex !== -1) {
          // On est dans un champ géré
          e.preventDefault();
          e.stopPropagation();

          console.log(`📍 Navigation depuis: ${fieldsOrder[currentIndex]}`);
          saveCurrentFocus();

          // Trouver le prochain champ
          let nextIndex = currentIndex + 1;
          let nextElement = null;

          // Chercher le prochain élément disponible
          while (nextIndex < fieldsOrder.length && !nextElement) {
            nextElement = document.querySelector(fieldsOrder[nextIndex]);
            if (!nextElement || nextElement.disabled || nextElement.readOnly) {
              console.log(`⭕ ${fieldsOrder[nextIndex]} non disponible`);
              nextElement = null;
              nextIndex++;
            }
          }

          // Si on est à la fin, boucler au début
          if (!nextElement && nextIndex >= fieldsOrder.length) {
            console.log('🔄 Fin de la liste, retour au début');
            nextIndex = 0;
            while (nextIndex < currentIndex && !nextElement) {
              nextElement = document.querySelector(fieldsOrder[nextIndex]);
              if (!nextElement || nextElement.disabled || nextElement.readOnly) {
                nextElement = null;
                nextIndex++;
              }
            }
          }

          if (nextElement) {
            console.log(`➡️ Navigation vers: ${fieldsOrder[nextIndex]}`);
            setTimeout(() => {
              nextElement.focus();
              nextElement.select();
            }, isAutoSaving ? 100 : 0);
          }
        }
      }
      // Gérer aussi Shift+Tab (navigation arrière)
      else if (e.key === 'Tab' && e.shiftKey) {
        // NOUVEAU : Même vérification pour Shift+Tab
        if (isOnFirstLensPage() || !isOnInformationPage()) {
          return;
        }

        const activeElement = document.activeElement;
        const currentIndex = fieldsOrder.findIndex(selector =>
          activeElement === document.querySelector(selector)
        );

        if (currentIndex !== -1) {
          e.preventDefault();
          e.stopPropagation();

          // Navigation arrière
          let prevIndex = currentIndex - 1;
          let prevElement = null;

          while (prevIndex >= 0 && !prevElement) {
            prevElement = document.querySelector(fieldsOrder[prevIndex]);
            if (!prevElement || prevElement.disabled || prevElement.readOnly) {
              prevElement = null;
              prevIndex--;
            }
          }

          if (!prevElement && prevIndex < 0) {
            prevIndex = fieldsOrder.length - 1;
            while (prevIndex > currentIndex && !prevElement) {
              prevElement = document.querySelector(fieldsOrder[prevIndex]);
              if (!prevElement || prevElement.disabled || prevElement.readOnly) {
                prevElement = null;
                prevIndex--;
              }
            }
          }

          if (prevElement) {
            console.log(`⬅️ Navigation arrière vers: ${fieldsOrder[prevIndex]}`);
            setTimeout(() => {
              prevElement.focus();
              prevElement.select();
            }, isAutoSaving ? 100 : 0);
          }
        }
      }
    }, true);
  }

  // Détection de l'autoSave
  function detectAutoSave() {
    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === 'attributes' && mutation.target.tagName === 'BUTTON') {
          const button = mutation.target;
          if (button.textContent?.includes('Enregistrer') ||
              button.className?.includes('save')) {
            console.log('💾 Auto-save détecté');
            isAutoSaving = true;
            saveCurrentFocus();
            setTimeout(() => {
              isAutoSaving = false;
              restoreFocus();
            }, 500);
          }
        }
      });
    });

    observer.observe(document.body, {
      attributes: true,
      subtree: true,
      attributeFilter: ['disabled', 'class']
    });
  }

  // Initialisation
  detectAutoSave();
  overrideTabNavigation();

  console.log('✅ Fix de navigation Tab activé avec détection de page');
  console.log(`📊 ${fieldsOrder.length} champs dans l'ordre de navigation`);
  console.log('📄 Actif uniquement sur app-file-tab-information');
}

  // Fonction pour forcer l'enregistrement de tous les yeux
  async function forceAutoSaveAllEyes() {
      console.log('🔄 Forçage de l\'enregistrement pour les deux yeux...');

      // Sélecteurs des boutons d'enregistrement
      const saveButtonSelectors = [
          // OD
          "#wrapper > main > app-file-layout > div > app-file-tab-information > div.eyes-container > div > app-file-information-eye:nth-child(1) > div > div.header > div.header__actions > amds-button > button",
          // OG
          "#wrapper > main > app-file-layout > div > app-file-tab-information > div.eyes-container > div > app-file-information-eye:nth-child(2) > div > div.header > div.header__actions > amds-button > button"
      ];

      let savedCount = 0;

      for (const selector of saveButtonSelectors) {
          const btn = document.querySelector(selector);
          if (btn && !btn.disabled) {
              console.log(`💾 Clic sur bouton enregistrer ${savedCount === 0 ? 'OD' : 'OG'}`);

              // Montrer temporairement si caché
              const wasHidden = btn.style.display === 'none';
              if (wasHidden) btn.style.display = '';

              btn.click();

              // Re-cacher si nécessaire
              if (wasHidden) {
                  setTimeout(() => btn.style.display = 'none', 100);
              }

              savedCount++;

              // Attendre que l'enregistrement se fasse
              await new Promise(resolve => setTimeout(resolve, 500));
          }
      }

      if (savedCount > 0) {
          console.log(`✅ ${savedCount} œil(x) enregistré(s)`);
          // Attendre un peu plus pour être sûr
          await new Promise(resolve => setTimeout(resolve, 1000));
      }

      return savedCount;
  }

  // Modifier les fonctions de calcul OrthoK et LRPG
  async function performOrthoKCalculation() {
        showToast('🔬 Démarrage du calcul OrthoK...');
        console.log('🔬 Début du calcul OrthoK');

        try {
            // Forcer l'enregistrement d'abord
            await forceAutoSaveAllEyes();

            // Aller sur l'onglet lentille
            const lensTab = document.querySelector('#wrapper > main > app-file-layout > div > app-tabs-list > div.tabs-container.has-actions > div.tabs.theme--classic.has-separators > div.tab.lens-0-tab.clickable.ng-star-inserted');
            if (lensTab) {
                lensTab.click();
                console.log('✅ Clic sur l\'onglet lentille');
                await new Promise(resolve => setTimeout(resolve, 1000));
            }

            // Sélection OrthoK pour OD
            const rightTypeSelect = document.querySelector('#input-righttype');
            if (rightTypeSelect) {
                rightTypeSelect.value = 'lens:type:orthok';
                rightTypeSelect.dispatchEvent(new Event('change', { bubbles: true }));
                rightTypeSelect.dispatchEvent(new Event('input', { bubbles: true }));
                console.log('✅ OrthoK sélectionné pour OD');
            }

            await new Promise(resolve => setTimeout(resolve, 500));

            // Sélection OrthoK pour OG
            const leftTypeSelect = document.querySelector('#input-lefttype');
            if (leftTypeSelect) {
                leftTypeSelect.value = 'lens:type:orthok';
                leftTypeSelect.dispatchEvent(new Event('change', { bubbles: true }));
                leftTypeSelect.dispatchEvent(new Event('input', { bubbles: true }));
                console.log('✅ OrthoK sélectionné pour OG');
            }

            await new Promise(resolve => setTimeout(resolve, 500));

            showToast('✅ Calcul OrthoK terminé avec succès !');
            console.log('✅ Calcul OrthoK complété');

        } catch (error) {
            console.error('❌ Erreur lors du calcul OrthoK:', error);
            showToast('❌ Erreur lors du calcul OrthoK');
        }
    }

  // Ajout styles split view
  function injectSplitViewStyles() {
    if (document.getElementById('clickfit-splitview-styles')) return;
    const style = document.createElement('style');
    style.id = 'clickfit-splitview-styles';
    style.textContent = `
      .clickfit-splitview-overlay {
        position: fixed;
        top: 0;
        left: 0;
        width: 100vw;
        height: 100vh;
        z-index: 100000;
        background: #181a1b;
        display: flex;
        align-items: stretch;
        justify-content: stretch;
        transition: opacity 0.3s;
      }
      .clickfit-splitview-iframe {
        flex: 1 1 0;
        border: none;
        width: 50vw;
        height: 100vh;
        min-width: 0;
        min-height: 0;
        background: white;
      }
      .clickfit-splitview-close {
        position: absolute;
        top: 14px;
        right: 18px;
        z-index: 100001;
        background: rgba(255,255,255,0.8);
        border: none;
        border-radius: 50%;
        width: 36px;
        height: 36px;
        font-size: 24px;
        color: #181a1b;
        cursor: pointer;
        box-shadow: 0 2px 6px rgba(0,0,0,0.12);
        transition: background 0.2s;
        opacity: 0.8;
      }
      .clickfit-splitview-close:hover {
        background: #fff;
        opacity: 1;
      }
    `;
    document.head.appendChild(style);
  }

  // Cache le body sauf split view
  let splitViewHiddenNodes = [];
  function activateSplitView() {
    if (document.querySelector('.clickfit-splitview-overlay')) return;
    injectSplitViewStyles();

    // Masquer tout le contenu du body sauf split view
    splitViewHiddenNodes = [];
    Array.from(document.body.children).forEach(node => {
      if (
        node.classList &&
        node.classList.contains('clickfit-splitview-overlay')
      ) {
        // ne rien faire
      } else if (
        node.tagName === 'SCRIPT' ||
        node.tagName === 'STYLE' ||
        node.id === 'clickfit-splitview-styles'
      ) {
        // laisser styles/scripts
      } else {
        // masquer
        splitViewHiddenNodes.push({
          node: node,
          prevDisplay: node.style.display
        });
        node.style.display = 'none';
      }
    });

    // Créer le panneau split view
    const overlay = document.createElement('div');
    overlay.className = 'clickfit-splitview-overlay';

    // Bouton fermer
    const closeBtn = document.createElement('button');
    closeBtn.className = 'clickfit-splitview-close';
    closeBtn.innerHTML = '×';
    closeBtn.title = 'Fermer Split View';
    closeBtn.addEventListener('click', deactivateSplitView);
    overlay.appendChild(closeBtn);

    // 2 iframes côte à côte
    const url = window.location.href;
    const iframe1 = document.createElement('iframe');
    iframe1.className = 'clickfit-splitview-iframe';
    iframe1.src = url;
    iframe1.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-forms allow-popups allow-modals');
    const iframe2 = document.createElement('iframe');
    iframe2.className = 'clickfit-splitview-iframe';
    iframe2.src = url;
    iframe2.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-forms allow-popups allow-modals');
    overlay.appendChild(iframe1);
    overlay.appendChild(iframe2);

    document.body.appendChild(overlay);
  }

  function deactivateSplitView() {
    // Supprimer split view
    const overlay = document.querySelector('.clickfit-splitview-overlay');
    if (overlay) overlay.remove();
    // Restaurer le body
    if (splitViewHiddenNodes && splitViewHiddenNodes.length > 0) {
      splitViewHiddenNodes.forEach(({node, prevDisplay}) => {
        node.style.display = prevDisplay || '';
      });
      splitViewHiddenNodes = [];
    }
  }

  // Modal dragable et redimensionnable
  function makeModalDraggableAndResizable() {
    // Ajoute le style CSS pour le grip (coin bas droit)
    if (!document.getElementById('cf-modal-draggable-resizable-style')) {
      const style = document.createElement('style');
      style.id = 'cf-modal-draggable-resizable-style';
      style.textContent = `
        .modal.modal--size-medium {
          position: fixed !important;
          /* Pour éviter le scroll du parent */
        }
        .modal.modal--size-medium .modal__header {
          cursor: move;
          user-select: none;
        }
        .modal.modal--size-medium .cf-modal-grip {
          position: absolute;
          width: 22px;
          height: 22px;
          right: 0;
          bottom: 0;
          cursor: nwse-resize;
          z-index: 10;
        }
        .modal.modal--size-medium .cf-modal-grip::after {
          content: "";
          display: block;
          width: 100%;
          height: 100%;
          background:
            linear-gradient(135deg, transparent 65%, #bbb 70%, #bbb 100%);
          opacity: 0.7;
          border-bottom-right-radius: 6px;
        }
        .modal.modal--size-medium.cf-draggable-resizing {
          pointer-events: none;
          /* Empêche les clics pendant le resize */
        }
      `;
      document.head.appendChild(style);
    }

    // Pour chaque modal medium natif Angular
    document.querySelectorAll('.modal.modal--size-medium').forEach(modal => {
      // Éviter de patcher deux fois
      if (modal.dataset.cfDraggableResized === 'true') return;
      modal.dataset.cfDraggableResized = 'true';

      // --- DRAG ---
      const header = modal.querySelector('.modal__header');
      if (header && !header.dataset.cfDraggablePatched) {
        header.dataset.cfDraggablePatched = 'true';
        let dragging = false, offsetX = 0, offsetY = 0, startX = 0, startY = 0;
        let origLeft, origTop;

        const onMouseDown = (e) => {
          // Ne draguer que bouton gauche
          if (e.button !== 0) return;
          dragging = true;
          startX = e.clientX;
          startY = e.clientY;
          // Calcul de la position initiale
          const rect = modal.getBoundingClientRect();
          origLeft = rect.left;
          origTop = rect.top;
          document.body.style.userSelect = 'none';
          window.addEventListener('mousemove', onMouseMove);
          window.addEventListener('mouseup', onMouseUp);
        };
        const onMouseMove = (e) => {
          if (!dragging) return;
          const dx = e.clientX - startX;
          const dy = e.clientY - startY;
          modal.style.left = (origLeft + dx) + 'px';
          modal.style.top = (origTop + dy) + 'px';
          modal.style.margin = '0';
        };
        const onMouseUp = () => {
          dragging = false;
          document.body.style.userSelect = '';
          window.removeEventListener('mousemove', onMouseMove);
          window.removeEventListener('mouseup', onMouseUp);
        };
        header.addEventListener('mousedown', onMouseDown);
      }

      // --- RESIZE ---
      if (!modal.querySelector('.cf-modal-grip')) {
        const grip = document.createElement('div');
        grip.className = 'cf-modal-grip';
        modal.appendChild(grip);
        let resizing = false, startWidth = 0, startHeight = 0, startX = 0, startY = 0;

        const minWidth = 400, minHeight = 200;

        const onGripMouseDown = (e) => {
          if (e.button !== 0) return;
          e.stopPropagation();
          resizing = true;
          modal.classList.add('cf-draggable-resizing');
          const rect = modal.getBoundingClientRect();
          startWidth = rect.width;
          startHeight = rect.height;
          startX = e.clientX;
          startY = e.clientY;
          document.body.style.userSelect = 'none';
          window.addEventListener('mousemove', onGripMouseMove);
          window.addEventListener('mouseup', onGripMouseUp);
        };
        const onGripMouseMove = (e) => {
          if (!resizing) return;
          let newW = Math.max(minWidth, startWidth + (e.clientX - startX));
          let newH = Math.max(minHeight, startHeight + (e.clientY - startY));
          modal.style.width = newW + 'px';
          modal.style.height = newH + 'px';
          modal.style.maxWidth = 'none';
          modal.style.maxHeight = 'none';
        };
        const onGripMouseUp = () => {
          resizing = false;
          modal.classList.remove('cf-draggable-resizing');
          document.body.style.userSelect = '';
          window.removeEventListener('mousemove', onGripMouseMove);
          window.removeEventListener('mouseup', onGripMouseUp);
        };
        grip.addEventListener('mousedown', onGripMouseDown);
      }

      // --- Initial position: center if not already positioned
      if (!modal.style.left && !modal.style.top) {
        // Centrer à l'ouverture
        const rect = modal.getBoundingClientRect();
        const winW = window.innerWidth, winH = window.innerHeight;
        modal.style.left = Math.max(0, (winW - rect.width) / 2) + 'px';
        modal.style.top = Math.max(0, (winH - rect.height) / 2) + 'px';
        modal.style.margin = '0';
      }
    });
  }

function autoCheckObservanceDefaults() {
  console.log('🔍 Recherche de la page observance...');

  // Garde-fou : vérifier qu'on est sur la bonne page
  const observanceTitle = document.querySelector('h1, h2, h3, .title');
  const isObservancePage = observanceTitle && observanceTitle.textContent.includes('Commun aux 2 yeux');

  // Vérifier aussi la présence du composant observance
  const observanceComponent = document.querySelector('app-observance');

  if (!isObservancePage && !observanceComponent) {
    console.log('❌ Pas sur la page observance');
    return;
  }

  console.log('✅ Page observance détectée');

  // Définir les options par défaut à cocher
  const defaultSelections = [
    {
      name: 'Oxydant',
      selector: 'app-store-field:nth-child(1) .input-radio-group > div:nth-child(1) input[type="radio"]'
    },
    {
      name: 'Hebdomadaire',
      selector: 'app-store-field:nth-child(2) .input-radio-group > div:nth-child(1) input[type="radio"]'
    },
    {
      name: 'Aquadrop',
      selector: 'app-store-field:nth-child(3) .input-radio-group > div:nth-child(1) input[type="radio"]'
    },
    {
      name: 'Ventouse',
      selector: 'app-store-field:nth-child(4) .input-radio-group > div:nth-child(2) input[type="radio"]'
    }
  ];

  // Pour chaque option par défaut
  defaultSelections.forEach(selection => {
    const radioButton = document.querySelector(`app-observance ${selection.selector}`);

    if (radioButton && !radioButton.checked) {
      // Cocher uniquement si pas déjà coché
      radioButton.checked = true;
      radioButton.dispatchEvent(new Event('change', { bubbles: true }));
      console.log(`✅ ${selection.name} coché`);
    }
  });
}

// Observer pour détecter l'apparition de la page
const observanceObserver = new MutationObserver(() => {
  // Vérifier si on trouve le texte caractéristique
  const hasObservanceText = Array.from(document.querySelectorAll('*')).some(el =>
    el.textContent && el.textContent.includes('Commun aux 2 yeux') &&
    el.textContent.includes('Produit utilisé')
  );

  if (hasObservanceText) {
    // Attendre un peu que tous les éléments soient chargés
    setTimeout(() => {
      autoCheckObservanceDefaults();
    }, 500);
  }
});

// Lancer l'observation
observanceObserver.observe(document.body, {
  childList: true,
  subtree: true
});

// Vérifier aussi immédiatement au cas où la page est déjà chargée
autoCheckObservanceDefaults();


//Sauvagarde dans la page Calcule lentilles
function interceptNextButton() {
    // Observer pour détecter quand le bouton Suivant apparaît
    const nextButtonObserver = new MutationObserver(() => {
      const nextButton = document.querySelector('#wrapper > main > app-file-layout > div > app-tabs-list > div.tabs-container.has-actions > div.actions.ng-star-inserted > amds-button > button');

      if (nextButton && !nextButton.dataset.intercepted) {
        setupNextButtonInterceptor(nextButton);
      }
    });

    // Observer le body pour détecter l'apparition du bouton
    nextButtonObserver.observe(document.body, {
      childList: true,
      subtree: true
    });

    // Vérifier aussi immédiatement
    const nextButton = document.querySelector('#wrapper > main > app-file-layout > div > app-tabs-list > div.tabs-container.has-actions > div.actions.ng-star-inserted > amds-button > button');
    if (nextButton) {
      setupNextButtonInterceptor(nextButton);
    }
  }

  function setupNextButtonInterceptor(nextButton) {
    // Marquer comme déjà intercepté
    nextButton.dataset.intercepted = 'true';

    // Sauvegarder la fonction click originale
    const originalClick = nextButton.onclick;

    // Créer notre propre handler
    const interceptedClick = async function(event) {
      console.log('🔄 Interception du clic sur Suivant...');

      // Empêcher l'action par défaut temporairement
      event.preventDefault();
      event.stopPropagation();

      // Chercher et cliquer sur les boutons Enregistrer des lentilles
      const saveButtons = await findAndClickLensSaveButtons();

      if (saveButtons.length > 0) {
        console.log(`⏳ Attente de l'enregistrement de ${saveButtons.length} lentille(s)...`);

        // Attendre un peu que les sauvegardes se fassent
        await new Promise(resolve => setTimeout(resolve, 1000));

        // Vérifier que les boutons sont redevenus disabled (signe que c'est sauvegardé)
        let allSaved = false;
        let attempts = 0;

        while (!allSaved && attempts < 10) {
          allSaved = saveButtons.every(btn => btn.disabled);
          if (!allSaved) {
            await new Promise(resolve => setTimeout(resolve, 500));
            attempts++;
          }
        }

        console.log('✅ Enregistrement terminé');
      }

      // Maintenant, exécuter le clic original
      console.log('➡️ Exécution du clic sur Suivant');

      // Retirer temporairement notre intercepteur pour éviter la boucle
      nextButton.removeEventListener('click', interceptedClick, true);

      // Cliquer pour de vrai
      nextButton.click();

      // Remettre l'intercepteur après un délai
      setTimeout(() => {
        nextButton.addEventListener('click', interceptedClick, true);
      }, 100);
    };

    // Ajouter notre intercepteur (en capture pour être sûr d'être appelé en premier)
    nextButton.addEventListener('click', interceptedClick, true);

    // Ajouter un indicateur visuel (optionnel)
    nextButton.title = 'Enregistrera automatiquement les lentilles avant de continuer';

    console.log('✅ Bouton Suivant intercepté avec succès');
  }

  async function findAndClickLensSaveButtons() {
    console.log('🔍 Recherche des boutons Enregistrer des lentilles...');

    const saveButtons = [];

    // Méthode 1 : Chercher par structure (page lentilles)
    const lensContainers = document.querySelectorAll('.lens-container .header__actions amds-button');

    lensContainers.forEach(amdsBtn => {
      const btn = amdsBtn.querySelector('button');
      if (btn && !btn.disabled) {
        // Vérifier que c'est bien un bouton Enregistrer
        const text = btn.textContent?.toLowerCase() || '';
        const ariaLabel = btn.getAttribute('aria-label')?.toLowerCase() || '';

        if (text.includes('enregistr') || ariaLabel.includes('save') || ariaLabel.includes('enregistr')) {
          saveButtons.push(btn);
        }
      }
    });

    // Méthode 2 : Chercher par texte si méthode 1 ne trouve rien
    if (saveButtons.length === 0) {
      document.querySelectorAll('amds-button button').forEach(btn => {
        if (!btn.disabled) {
          const text = btn.textContent?.toLowerCase() || '';
          if (text.includes('enregistr')) {
            // Vérifier que c'est dans un contexte de lentille
            const container = btn.closest('.lens-container, [class*="lens"]');
            if (container) {
              saveButtons.push(btn);
            }
          }
        }
      });
    }

    // Cliquer sur tous les boutons trouvés
    saveButtons.forEach((btn, index) => {
      console.log(`💾 Clic sur le bouton Enregistrer ${index + 1}`);

      // Montrer temporairement le bouton s'il est caché
      const wasHidden = btn.style.display === 'none';
      if (wasHidden) {
        btn.style.display = '';
      }

      btn.click();

      // Re-cacher si nécessaire
      if (wasHidden) {
        setTimeout(() => {
          btn.style.display = 'none';
        }, 100);
      }
    });

    return saveButtons;
  }

// Alternative : Intercepter aussi avec la touche Espace
function enhanceSpaceNext() {
  document.addEventListener('keydown', async (e) => {
    if (e.key === ' ' || e.code === 'Space') {
      // Si on n'est pas dans un input
      if (document.activeElement.tagName !== 'INPUT' &&
          document.activeElement.tagName !== 'TEXTAREA') {

        const nextButton = document.querySelector('#wrapper > main > app-file-layout > div > app-tabs-list > div.tabs-container.has-actions > div.actions.ng-star-inserted > amds-button > button');

        if (nextButton && !nextButton.disabled) {
          e.preventDefault();

          // Sauvegarder d'abord
          console.log('Espace détecté - Sauvegarde avant Suivant...');
          const saveButtons = await findAndClickLensSaveButtons();

          if (saveButtons.length > 0) {
            await new Promise(resolve => setTimeout(resolve, 1000));
          }

          // Puis cliquer sur Suivant
          nextButton.click();
        }
      }
    }
  });
}

// Fonction pour réorganiser les sections
function reorderSectionsOnly() {
  console.log('� Réorganisation simple des sections...');

  // Attendre que les sections soient chargées
  const eyeContainers = document.querySelectorAll('app-file-information-eye');

  if (eyeContainers.length < 2) {
    console.log('⚠ Les deux yeux ne sont pas encore chargés');
    return;
  }

  // Pour chaque œil
  eyeContainers.forEach((eyeContainer, eyeIndex) => {
    const eyeName = eyeIndex === 0 ? 'OD' : 'OG';
    console.log(`👁️ Réorganisation de l'œil ${eyeName}`);

    // Trouver le conteneur principal des sections
    const contentContainer = eyeContainer.querySelector('.eye > .content');
    if (!contentContainer) {
      console.log(`⚠️ Conteneur .content non trouvé pour ${eyeName}`);
      return;
    }

    // Identifier toutes les sections
    const sections = {
      refraction: contentContainer.querySelector('app-file-information-eye-refraction'),
      keratometry: contentContainer.querySelector('app-file-information-eye-keratometry'),
      visualAcuity: contentContainer.querySelector('app-file-information-eye-visual-acuity'),
      biometry: contentContainer.querySelector('app-file-information-eye-biometry')
    };

    // Vérifier que toutes les sections sont présentes
    const foundSections = Object.entries(sections).filter(([key, el]) => el !== null);
    console.log(`📍 ${eyeName}: ${foundSections.length}/4 sections trouvées`);

    if (foundSections.length === 0) {
      console.log(`❌ Aucune section trouvée pour ${eyeName}`);
      return;
    }

    // Créer un fragment pour réorganiser
    const fragment = document.createDocumentFragment();

    if (eyeIndex === 0) {
      // OD : Réfraction, Kératométrie, Acuité visuelle, Biométrie
      if (sections.refraction) fragment.appendChild(sections.refraction);
      if (sections.keratometry) fragment.appendChild(sections.keratometry);
      if (sections.visualAcuity) fragment.appendChild(sections.visualAcuity);
      if (sections.biometry) fragment.appendChild(sections.biometry);
    } else {
      // OG : Kératométrie, Réfraction, Biométrie, Acuité visuelle
      if (sections.keratometry) fragment.appendChild(sections.keratometry);
      if (sections.refraction) fragment.appendChild(sections.refraction);
      if (sections.biometry) fragment.appendChild(sections.biometry);
      if (sections.visualAcuity) fragment.appendChild(sections.visualAcuity);
    }

    // Vider et remplir le conteneur
    while (contentContainer.firstChild) {
      contentContainer.removeChild(contentContainer.firstChild);
    }
    contentContainer.appendChild(fragment);

    console.log(` Sections réorganisées pour ${eyeName}`);
  });

  // Ajouter un style minimal juste pour la grille si nécessaire
  if (!document.getElementById('simple-grid-fix')) {
    const style = document.createElement('style');
    style.id = 'simple-grid-fix';
    style.textContent = `
      /* Fix simple pour la grille sans changer le design */
      app-file-information-eye > .eye > .content {
        display: grid !important;
        grid-template-columns: 1fr 1fr;
        grid-template-rows: auto auto;
        gap: 16px;
      }

      /* Position dans la grille pour OD */
      app-file-information-eye:nth-child(1) app-file-information-eye-refraction {
        grid-column: 1;
        grid-row: 1;
        order: 1;
      }

      app-file-information-eye:nth-child(1) app-file-information-eye-keratometry {
        grid-column: 2;
        grid-row: 1;
        order: 2;
      }

      app-file-information-eye:nth-child(1) app-file-information-eye-visual-acuity {
        grid-column: 1;
        grid-row: 2;
        order: 3;
      }

      app-file-information-eye:nth-child(1) app-file-information-eye-biometry {
        grid-column: 2;
        grid-row: 2;
        order: 4;
      }

      /* Position dans la grille pour OG */
      app-file-information-eye:nth-child(2) app-file-information-eye-keratometry {
        grid-column: 1;
        grid-row: 1;
        order: 1;
      }

      app-file-information-eye:nth-child(2) app-file-information-eye-refraction {
        grid-column: 2;
        grid-row: 1;
        order: 2;
      }

      app-file-information-eye:nth-child(2) app-file-information-eye-biometry {
        grid-column: 1;
        grid-row: 2;
        order: 3;
      }

      app-file-information-eye:nth-child(2) app-file-information-eye-visual-acuity {
        grid-column: 2;
        grid-row: 2;
        order: 4;
      }

      /* Responsive : quand la fenêtre est réduite */
      @media (max-width: 1800px) {
        app-file-information-eye > .eye > .content {
          display: flex !important;
          flex-direction: column !important;
          gap: 16px;
        }

        /* Pour OD en mode mobile : Réfraction, Kératométrie, Biométrie, Acuité visuelle */
        app-file-information-eye:nth-child(1) app-file-information-eye-refraction {
          order: 1 !important;
        }

        app-file-information-eye:nth-child(1) app-file-information-eye-keratometry {
          order: 2 !important;
        }

        app-file-information-eye:nth-child(1) app-file-information-eye-biometry {
          order: 3 !important;
        }

        app-file-information-eye:nth-child(1) app-file-information-eye-visual-acuity {
          order: 4 !important;
        }

        /* Pour OG en mode mobile : même ordre que OD pour la cohérence */
        app-file-information-eye:nth-child(2) app-file-information-eye-refraction {
          order: 1 !important;
        }

        app-file-information-eye:nth-child(2) app-file-information-eye-keratometry {
          order: 2 !important;
        }

        app-file-information-eye:nth-child(2) app-file-information-eye-biometry {
          order: 3 !important;
        }

        app-file-information-eye:nth-child(2) app-file-information-eye-visual-acuity {
          order: 4 !important;
        }
      }
    `;
    document.head.appendChild(style);
  }
}
// Fonction pour réorganiser les champs de kératométrie
function setupSimpleSectionReorderSafe() {
  console.log('🔄 Configuration du réorganisateur intelligent v2...');

  let currentPatientId = null;


  function getCurrentPatientId() {
    const match = location.pathname.match(/\/file\/([A-Za-z0-9]+)/);
    return match ? match[1] : null;
  }

  // Fonction de réorganisation robuste
  async function performReorganization() {
    console.log('⏳ Tentative de réorganisation...');

    // Attendre que TOUTES les 8 sections soient présentes (4 par œil)
    let attempts = 0;
    const maxAttempts = 50; // 5 secondes max

    while (attempts < maxAttempts) {
      const sections = {
        odRefraction: document.querySelector('app-file-information-eye:nth-child(1) app-file-information-eye-refraction'),
        odKeratometry: document.querySelector('app-file-information-eye:nth-child(1) app-file-information-eye-keratometry'),
        odVisualAcuity: document.querySelector('app-file-information-eye:nth-child(1) app-file-information-eye-visual-acuity'),
        odBiometry: document.querySelector('app-file-information-eye:nth-child(1) app-file-information-eye-biometry'),
        ogRefraction: document.querySelector('app-file-information-eye:nth-child(2) app-file-information-eye-refraction'),
        ogKeratometry: document.querySelector('app-file-information-eye:nth-child(2) app-file-information-eye-keratometry'),
        ogVisualAcuity: document.querySelector('app-file-information-eye:nth-child(2) app-file-information-eye-visual-acuity'),
        ogBiometry: document.querySelector('app-file-information-eye:nth-child(2) app-file-information-eye-biometry')
      };

      const allSectionsLoaded = Object.values(sections).every(section => section !== null);

      if (allSectionsLoaded) {
        console.log('✅ Toutes les sections trouvées !');

        // Attendre un tout petit peu que Angular finisse le rendu
        await new Promise(resolve => setTimeout(resolve, 200));

        // Réorganiser
        reorderSectionsOnly();

        // Puis réorganiser les champs de kératométrie
        setTimeout(() => {
          reorderKeratometryFields();
        }, 100);

        console.log('✅ Réorganisation complétée');
        return true;
      }

      attempts++;
      await new Promise(resolve => setTimeout(resolve, 100));
    }

    console.log('⚠️ Timeout - toutes les sections non trouvées');
    return false;
  }

  // Surveiller les changements d'URL (navigation SPA)
  setInterval(async () => {
    const newPatientId = getCurrentPatientId();

    // Si on a changé de patient ou qu'on arrive sur un patient
    if (newPatientId && newPatientId !== currentPatientId) {
      console.log(`📋 Nouveau patient détecté: ${newPatientId}`);
      currentPatientId = newPatientId;

      // Lancer la réorganisation
      await performReorganization();
    }
  }, 250); // Check toutes les 250ms

  // Observer pour les changements dynamiques (au cas où)
  const observer = new MutationObserver(() => {
    // Si on est sur une fiche patient et qu'on n'a pas encore réorganisé
    const patientId = getCurrentPatientId();
    if (patientId && patientId === currentPatientId) {
      // Ne rien faire, déjà traité
    } else if (patientId) {
      currentPatientId = patientId;
      performReorganization();
    }
  });

  // Observer le conteneur principal avec SUBTREE
  const container = document.querySelector('#wrapper');
  if (container) {
    observer.observe(container, {
      childList: true,
      subtree: true
    });
  }

  // Tentative initiale si déjà sur une fiche
  if (getCurrentPatientId()) {
    currentPatientId = getCurrentPatientId();
    setTimeout(() => performReorganization(), 500);
  }
}


function makeSpecificSectionsCollapsible() {
  console.log('🔄 Patch sections rétractables...');

  // CSS pour les sections rétractables
  const styleId = 'simple-collapsible-patch';
  if (!document.getElementById(styleId)) {
    const style = document.createElement('style');
    style.id = styleId;
    style.textContent = `
      .collapsible-header {
        cursor: pointer !important;
        user-select: none !important;
        position: relative !important;
      }
      .section-chevron {
        position: absolute;
        right: 15px;
        top: 50%;
        transform: translateY(-50%);
        transition: transform 0.3s ease;
        font-size: 14px;
        color: #666;
        pointer-events: none;
      }
      .collapsed-section .section-chevron {
        transform: translateY(-50%) rotate(-90deg);
      }
      .collapsed-section .accordion > .content {
        display: none !important;
      }
    `;
    document.head.appendChild(style);
  }

  function makeCollapsible(sectionElement, sectionName, eyeName) {
    const accordion = sectionElement.querySelector('.accordion');
    if (!accordion) {
      console.log(`❌ Pas d'accordion trouvé pour ${sectionName} ${eyeName}`);
      return;
    }
    const header = accordion.querySelector('.header');
    if (!header || header.dataset.collapsible === 'true') {
      // log seulement si header absent
      if (!header) console.log(`❌ Header non trouvé pour ${sectionName} ${eyeName}`);
      return;
    }
    header.dataset.collapsible = 'true';
    header.classList.add('collapsible-header');
    const oldChevron = header.querySelector('.section-chevron');
    if (oldChevron) oldChevron.remove();
    const chevron = document.createElement('span');
    chevron.className = 'section-chevron';
    chevron.innerHTML = '▼';
    header.appendChild(chevron);


    const isCollapsed = GM_getValue(`${sectionName}_${eyeName}_collapsed`, false);
    if (isCollapsed) accordion.classList.add('collapsed-section');
    else accordion.classList.remove('collapsed-section');

    header.onclick = function(e) {
      e.stopPropagation();
      const wasCollapsed = accordion.classList.contains('collapsed-section');
      if (wasCollapsed) {
        accordion.classList.remove('collapsed-section');
      } else {
        accordion.classList.add('collapsed-section');
      }
      GM_setValue(`${sectionName}_${eyeName}_collapsed`, !wasCollapsed);
      console.log(`${sectionName} ${eyeName}: ${!wasCollapsed ? 'fermé' : 'ouvert'}`);
    };
    console.log(`✅ ${sectionName} ${eyeName} rendue rétractable`);
  }

  function applyToSpecificSections() {
    const eyeContainers = document.querySelectorAll('app-file-information-eye');
    if (eyeContainers.length === 0) {
      console.log('❌ Aucun conteneur œil trouvé');
      return;
    }
    eyeContainers.forEach((container, index) => {
      const eyeName = index === 0 ? 'OD' : 'OG';
      const biometry = container.querySelector('app-file-information-eye-biometry');
      if (biometry) makeCollapsible(biometry, 'biometry', eyeName);
      const visualAcuity = container.querySelector('app-file-information-eye-visual-acuity');
      if (visualAcuity) makeCollapsible(visualAcuity, 'visual-acuity', eyeName);
    });
  }

  // Appliquer maintenant
  applyToSpecificSections();

  // Observer les changements dynamiques
  if (!window._cfCollapsibleObserver) {
    window._cfCollapsibleObserver = new MutationObserver(() => {
      // Si aucune section rétractable n'est présente, réappliquer
      if (document.querySelectorAll('.collapsible-header').length === 0) {
        setTimeout(applyToSpecificSections, 300);
      }
    });
    window._cfCollapsibleObserver.observe(document.body, {
      childList: true,
      subtree: true
    });
  }
}


// Variable pour éviter les lancements multiples
let isLaunched = false;

// Lancement global
function launch() {

  if (isLaunched) return;
  isLaunched = true;

  console.log('Lancement du script ClickFit Assistant...');

  // Module navigation patients
  setTimeout(() => {
    if (typeof SimplePatientNav !== 'undefined') {
      SimplePatientNav.init();
    }
  }, 2000);

  //Eléments rétractables
  setTimeout(() => {
      makeSpecificSectionsCollapsible();

      // Réappliquer périodiquement pour les changements de page
      setInterval(() => {
        const needsReapply = document.querySelectorAll('.collapsible-header').length === 0;
        if (needsReapply && window.location.pathname.includes('/file/')) {
          makeSpecificSectionsCollapsible();
        }
      }, 2000);
    }, 2000); // Attendre 2s au lieu de 500ms

  // Module de réorganisation des sections
  setTimeout(() => {
    setupSectionReorganizer();
    console.log(' Module de réorganisation des sections activé');
  }, 2000);

  // Injecter les styles CSS
  if (typeof injectStyles === 'function') {
    injectStyles();
  }
  // Module Video
  if (typeof VideoExplanationModule !== 'undefined') {
    setTimeout(() => {
      VideoExplanationModule.init();
      console.log('📹 Module vidéo explicative activé');
    }, 2000);
  }

  // Autres initialisations
  if (typeof interceptNextButton === 'function') interceptNextButton();
  if (typeof enhanceSpaceNext === 'function') enhanceSpaceNext();
  if (typeof setupRefractionPolling === 'function') setupRefractionPolling();
  if (typeof setupSpaceNext === 'function') setupSpaceNext();
  if (typeof createFloatingButton === 'function') createFloatingButton();
  if (typeof setupKeyboardShortcuts === 'function') setupKeyboardShortcuts();
  if (typeof setupSimpleSectionReorderSafe === 'function') setupSimpleSectionReorderSafe();
  if (typeof reorderSectionsOnly === 'function') reorderSectionsOnly();
  if (typeof setupKeratometryReorder === 'function') setupKeratometryReorder();
  if (typeof fixTabNavigationWithAutoSave === 'function') fixTabNavigationWithAutoSave();
  if (typeof autoFillPrescripteurCountry === 'function') autoFillPrescripteurCountry();
  if (typeof autoCheckObservanceDefaults === 'function') autoCheckObservanceDefaults();
  if (typeof scanAndObserveButtons === 'function') {
    scanAndObserveButtons();
    setInterval(() => {
      scanAndObserveButtons();
    }, 2000);
  }
  if (typeof setupButtonObserver === 'function') setupButtonObserver();
  if (typeof setupLensPageObserver === 'function') setupLensPageObserver();
  if (typeof applyCustomStepToAll === 'function') {
    setTimeout(() => {
      applyCustomStepToAll();
      setInterval(() => {
        applyCustomStepToAll();
      }, 2000);
    }, 1000);
  }

  if (typeof patchColorAutoChange === 'function') patchColorAutoChange();

  console.log(' Tous les modules sont initialisés');
}

// Démarrage initial
if (document.readyState === "loading") {
  document.addEventListener("DOMContentLoaded", launch);
} else {
  setTimeout(launch, 1000);
}

})();