<script setup>
import { ref, computed, nextTick, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useCalibrationStore } from '../stores/calibration'
import { useUploadStore } from '../stores/upload'
import api from '../services/api'
import CalibrationArea from '@/components/CalibrationArea.vue'
import FootballField from '@/components/FootballField.vue'
import PlotlyChart from '@/components/PlotlyChart.vue'
import fieldTestImage from '@/assets/field_test_thumb.jpg'

const router = useRouter()
const calibrationStore = useCalibrationStore()
const uploadStore = useUploadStore()

// Refs pour les sections
const modeSection = ref(null)
const uploadSection = ref(null)
const videoTypeSection = ref(null)
const parametersSection = ref(null)
const processingSection = ref(null)
const errorSection = ref(null)
const resultsSection = ref(null)
const manualSection = ref(null)

// États locaux
const dragActive = ref(false)
const selectedTestImage = ref(null)

// Image de test
const testImageUrl = ref(fieldTestImage)

// États pour la vue manuelle
const thumbnail = ref(null)
const calibrationPoints = ref({})
const selectedFieldPoint = ref(null)
const calibrationLines = ref({})
const selectedFieldLine = ref(null)

// Refs pour les composants manuels
const calibrationArea = ref(null)
const footballField = ref(null)

// Computed
const showUpload = computed(() => calibrationStore.mode !== null && !uploadStore.isFileSelected)
const showVideoType = computed(() => uploadStore.isVideo && uploadStore.isFileSelected && uploadStore.videoType === null)
const showParameters = computed(() => uploadStore.needsParameters && !showManualCalibration.value)
const showProcessing = computed(() => calibrationStore.isProcessingStep)
const showResults = computed(() => calibrationStore.isResultsStep)
const showError = computed(() => calibrationStore.error !== null && !showManualCalibration.value)

// Computed pour afficher la vue manuelle
const showManualCalibration = computed(() => {
  return calibrationStore.isManualMode && 
         uploadStore.isFileSelected && 
         (uploadStore.isImage || (uploadStore.isVideo && uploadStore.videoType === 'static'))
})

// Watchers pour le scroll automatique
watch(() => calibrationStore.mode, async (newMode) => {
  if (newMode) {
    await nextTick()
    scrollToSection(uploadSection.value)
  }
})

watch(() => uploadStore.isVideo, async (isVideo) => {
  if (isVideo && uploadStore.isFileSelected) {
    await nextTick()
    scrollToSection(videoTypeSection.value)
  }
})

watch(() => uploadStore.videoType, async (videoType) => {
  if (calibrationStore.isManualMode) {
    if (videoType === 'static') {
      // Vidéo statique en mode manuel : charger la vue manuelle intégrée
      await loadThumbnail()
      await nextTick()
      scrollToSection(manualSection.value)
    } else if (videoType === 'dynamic') {
      // Vidéo dynamique en mode manuel : afficher message d'avertissement
      calibrationStore.setError("Le mode manuel pour les vidéos dynamiques n'est pas encore disponible. Cette fonctionnalité nécessite l'implémentation de nouvelles features. Veuillez utiliser le mode automatique ou sélectionner une vidéo statique.")
      await nextTick()
      scrollToSection(errorSection.value)
    }
  } else if (videoType === 'dynamic') {
    await nextTick()
    scrollToSection(parametersSection.value)
  }
  // Suppression du lancement automatique - sera géré par le watcher extractedFrame
})

// Watcher spécifique pour l'extraction de frame terminée
watch(() => uploadStore.extractedFrame, async (extractedFrame) => {
  // Lancement automatique quand la frame est extraite en mode auto + vidéo statique
  if (extractedFrame && 
      calibrationStore.isAutoMode && 
      uploadStore.isStaticVideo) {
    console.log('🔥 Frame extracted, starting automatic processing...')
    startProcessing()
  }
})

watch(() => calibrationStore.isProcessingStep, async (isProcessing) => {
  if (isProcessing) {
    await nextTick()
    scrollToSection(processingSection.value)
  }
})

watch(() => calibrationStore.isResultsStep, async (isResults) => {
  if (isResults) {
    await nextTick()
    scrollToSection(resultsSection.value)
  }
})

// Watcher spécial pour les résultats en mode manuel
watch(() => calibrationStore.results, async (results) => {
  if (results && calibrationStore.isManualMode) {
    await nextTick()
    scrollToSection(resultsSection.value)
  }
})

watch(() => calibrationStore.error, async (error) => {
  if (error) {
    await nextTick()
    scrollToSection(errorSection.value)
  }
})

// Méthodes
const scrollToSection = (element) => {
  if (element) {
    element.scrollIntoView({ behavior: 'smooth', block: 'start' })
  }
}

const selectMode = (mode) => {
  calibrationStore.setMode(mode)
}

const selectTestImage = async () => {
  try {
    selectedTestImage.value = 'test'
    
    // Créer un objet File à partir de l'URL de l'image de test
    const response = await fetch(testImageUrl.value)
    const blob = await response.blob()
    const file = new File([blob], 'field_test_thumb.jpg', { type: 'image/jpeg' })
    
    uploadStore.setFile(file)
    
    if (calibrationStore.isManualMode) {
      // En mode manuel avec image, charger la vue manuelle intégrée
      await loadThumbnail()
      await nextTick()
      scrollToSection(manualSection.value)
    } else if (calibrationStore.isAutoMode) {
      // En mode auto, lancement automatique pour les images
      startProcessing()
    }
  } catch (error) {
    console.error('Erreur lors du chargement de l\'image de test:', error)
    // Fallback: utiliser l'URL directement pour la preview
    uploadStore.filePreview = testImageUrl.value
    uploadStore.selectedFile = { name: 'test-image.jpg', size: 0 }
    uploadStore.fileType = 'image'
  }
}

const resetToStart = () => {
  // Réinitialiser tous les stores
  calibrationStore.reset()
  uploadStore.clearFile()
  
  // Scroll vers le haut
  scrollToSection(modeSection.value)
}

const handleFileSelect = async (event) => {
  const file = event.target.files[0]
  if (file) {
    uploadStore.setFile(file)
    
    if (calibrationStore.isManualMode) {
      if (uploadStore.isImage) {
        // En mode manuel avec image, charger la vue manuelle intégrée
        await loadThumbnail()
        await nextTick()
        scrollToSection(manualSection.value)
      } else if (uploadStore.isVideo) {
        // En mode manuel avec vidéo, aller au choix statique/dynamique
        await nextTick()
        scrollToSection(videoTypeSection.value)
      }
    } else if (calibrationStore.isAutoMode && uploadStore.isImage) {
      // En mode auto, lancement automatique pour les images
      startProcessing()
    }
    // Pour les vidéos en mode auto, on laisse le flow normal (choix statique/dynamique)
  }
}

const handleDrop = async (event) => {
  event.preventDefault()
  dragActive.value = false
  
  const files = event.dataTransfer.files
  if (files.length > 0) {
    uploadStore.setFile(files[0])
    
    if (calibrationStore.isManualMode) {
      if (uploadStore.isImage) {
        // En mode manuel avec image, charger la vue manuelle intégrée
        await loadThumbnail()
        await nextTick()
        scrollToSection(manualSection.value)
      } else if (uploadStore.isVideo) {
        // En mode manuel avec vidéo, aller au choix statique/dynamique
        await nextTick()
        scrollToSection(videoTypeSection.value)
      }
    } else if (calibrationStore.isAutoMode && uploadStore.isImage) {
      // En mode auto, lancement automatique pour les images
      startProcessing()
    }
    // Pour les vidéos en mode auto, on laisse le flow normal (choix statique/dynamique)
  }
}

const handleDragOver = (event) => {
  event.preventDefault()
  dragActive.value = true
}

const handleDragLeave = () => {
  dragActive.value = false
}

const selectVideoType = async (type) => {
  await uploadStore.setVideoType(type)
}

const updateParameter = (param, value) => {
  calibrationStore.setVideoParams({ [param]: value })
}

const startProcessing = async () => {
  calibrationStore.setProcessing(true, 'Initialisation...')
  
  try {
    let result
    
    if (uploadStore.isImage || uploadStore.isStaticVideo) {
      // Traitement d'image ou de frame extraite
      const fileToProcess = uploadStore.isImage ? 
        uploadStore.selectedFile : 
        uploadStore.extractedFrame
      
      // Vérification que le fichier existe
      if (!fileToProcess) {
        const errorMsg = uploadStore.isImage ? 
          'Aucun fichier image sélectionné' : 
          'Frame non extraite de la vidéo. Essayez de recharger la vidéo.'
        throw new Error(errorMsg)
      }
      
      // Logs détaillés pour debug
      console.log('🔥 File to process details:', {
        name: fileToProcess?.name,
        type: fileToProcess?.type,
        size: fileToProcess?.size,
        constructor: fileToProcess?.constructor?.name
      })
      
      console.log('🔥 Processing params:', {
        kpThreshold: calibrationStore.videoProcessingParams.kpThreshold,
        lineThreshold: calibrationStore.videoProcessingParams.lineThreshold,
        typeOfKp: typeof calibrationStore.videoProcessingParams.kpThreshold,
        typeOfLine: typeof calibrationStore.videoProcessingParams.lineThreshold
      })
      
      // Test de diagnostic si c'est une vidéo statique
      if (uploadStore.isStaticVideo && uploadStore.extractedFrame) {
        console.log('🔥 Testing extracted frame:', {
          isFile: fileToProcess instanceof File,
          isBlob: fileToProcess instanceof Blob,
          hasName: !!fileToProcess.name,
          hasType: !!fileToProcess.type
        })
      }
      
      result = await processWithProgress(() => 
        api.inferenceImage(fileToProcess, {
          kpThreshold: calibrationStore.videoProcessingParams.kpThreshold,
          lineThreshold: calibrationStore.videoProcessingParams.lineThreshold
        })
      )
    } else if (uploadStore.isDynamicVideo) {
      // Traitement de vidéo dynamique
      result = await processWithProgress(() =>
        api.inferenceVideo(uploadStore.selectedFile, calibrationStore.videoProcessingParams)
      )
    }
    
    // Console log de la réponse API
    console.log('🔥 Réponse API reçue:', result)
    
    if (result.status === 'success') {
      calibrationStore.setResults(result)
    } else if (result.status === 'failed') {
      throw new Error(result.message || "Échec de l'extraction des paramètres")
    } else {
      throw new Error(result.error || 'Erreur de traitement')
    }
    
  } catch (error) {
    console.error('❌ Erreur lors du traitement:', error)
    calibrationStore.setError(error.message)
  }
}

const processWithProgress = async (processFunction) => {
  // Activer le mode processing
  calibrationStore.setProcessing(true, 'Initialisation...')
  
  const tasks = [
    'Chargement du fichier...',
    'Détection des lignes du terrain...',
    'Analyse des points clés...',
    'Calcul des paramètres de caméra...',
    'Finalisation...'
  ]
  
  // Simulation du progrès
  for (let i = 0; i < tasks.length; i++) {
    calibrationStore.updateProgress((i / tasks.length) * 100, tasks[i])
    await new Promise(resolve => setTimeout(resolve, 500))
  }
  
  // Traitement réel
  const result = await processFunction()
  calibrationStore.updateProgress(100, 'Terminé !')
  
  return result
}

const goToManual = async () => {
  calibrationStore.switchToManual()
  await loadThumbnail()
  await nextTick()
  scrollToSection(manualSection.value)
}

const backToCalibration = async () => {
  // Réinitialiser les erreurs et résultats
  calibrationStore.setError(null)
  calibrationStore.setResults(null)
  calibrationStore.setProcessing(false)
  
  // Retourner à la section de calibration manuelle
  await nextTick()
  scrollToSection(manualSection.value)
}

const restart = () => {
  calibrationStore.reset()
  uploadStore.clearFile()
  scrollToSection(modeSection.value)
}

const exportResults = () => {
  // Encapsuler les données de calibration dans une clé "calibration"
  const data = {
    calibration: calibrationStore.results
  }
  
  // Générer le nom de fichier basé sur le fichier original
  let filename = 'football_vision_config.json'
  if (uploadStore.selectedFile && uploadStore.selectedFile.name) {
    // Enlever l'extension du fichier original et ajouter .json
    const originalName = uploadStore.selectedFile.name
    const nameWithoutExtension = originalName.substring(0, originalName.lastIndexOf('.')) || originalName
    filename = `${nameWithoutExtension}_calib.json`
  }
  
  const content = JSON.stringify(data, null, 2)
  
  const blob = new Blob([content], { type: 'application/json' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = filename
  a.click()
  URL.revokeObjectURL(url)
}

// Méthodes pour la vue manuelle
const loadThumbnail = async () => {
  try {
    thumbnail.value = null
    
    if (uploadStore.isImage) {
      // Pour les images, utiliser directement la preview
      thumbnail.value = uploadStore.filePreview
    } else if (uploadStore.isStaticVideo && uploadStore.extractedFrame) {
      // Pour les vidéos statiques, utiliser la frame déjà extraite
      console.log('Using extracted frame from static video:', uploadStore.selectedFile.name)
      thumbnail.value = URL.createObjectURL(uploadStore.extractedFrame)
    } else if (uploadStore.isVideo) {
      // Pour les autres vidéos, extraire la première frame
      console.log('Extracting first frame from video:', uploadStore.selectedFile.name)
      
      // Créer une URL pour le fichier vidéo
      const videoUrl = URL.createObjectURL(uploadStore.selectedFile)
      
      // Extraire la première frame avec un canvas
      const video = document.createElement('video')
      video.src = videoUrl
      video.muted = true // Important pour éviter les problèmes d'autoplay
      
      await new Promise((resolve, reject) => {
        video.addEventListener('loadedmetadata', () => {
          video.currentTime = 0 // Aller à la première frame
        })
        
        video.addEventListener('seeked', () => {
          try {
            const canvas = document.createElement('canvas')
            canvas.width = video.videoWidth
            canvas.height = video.videoHeight
            
            const ctx = canvas.getContext('2d')
            ctx.drawImage(video, 0, 0)
            
            thumbnail.value = canvas.toDataURL('image/jpeg', 0.9)
            URL.revokeObjectURL(videoUrl)
            resolve()
          } catch (err) {
            URL.revokeObjectURL(videoUrl)
            reject(err)
          }
        })
        
        video.addEventListener('error', (err) => {
          URL.revokeObjectURL(videoUrl)
          reject(err)
        })
      })
    }
  } catch (error) {
    console.error('Erreur lors du chargement du thumbnail:', error)
    thumbnail.value = null
  }
}

const handleFieldPointSelected = (pointData) => {
  selectedFieldLine.value = null
  selectedFieldPoint.value = pointData
}

const handleFieldLineSelected = (lineData) => {
  selectedFieldPoint.value = null
  selectedFieldLine.value = lineData
}

const updateThumbnail = (newThumbnail) => {
  thumbnail.value = newThumbnail
}

const updateCalibrationPoints = (newPoints) => {
  calibrationPoints.value = { ...newPoints }
}

const updateCalibrationLines = (newLines) => {
  calibrationLines.value = { ...newLines }
}

const updateSelectedFieldPoint = (newPoint) => {
  selectedFieldPoint.value = newPoint
}

const updateSelectedFieldLine = (newLine) => {
  selectedFieldLine.value = newLine
  if (footballField.value) {
    footballField.value.selectedLine = newLine ? newLine.id : null
  }
}

const clearCalibration = () => {
  calibrationPoints.value = {}
  calibrationLines.value = {}
  selectedFieldPoint.value = null
  selectedFieldLine.value = null
}

const processCalibration = async () => {
  if (!uploadStore.selectedFile || Object.keys(calibrationLines.value).length === 0) {
    alert('Veuillez créer au moins une ligne de calibration')
    return
  }

  // Scroll immédiat vers la section de processing
  scrollToSection(processingSection.value)
  await nextTick()

  try {
    // Utiliser le même système de progress que la version automatique
    const result = await processWithProgress(async () => {
      if (!calibrationArea.value) {
        throw new Error('CalibrationArea component is not mounted.')
      }

      const imageContainer = document.querySelector('.video-frame')
      const imageSize = calibrationArea.value.imageSize
      if (!imageSize) {
        throw new Error('Image size is not available.')
      }
      const containerWidth = imageContainer.clientWidth
      const containerHeight = imageContainer.clientHeight

      // Préparer les données des lignes pour l'API /calibrate
      const linesData = {}
      
      // Traitement des lignes - conversion des coordonnées container vers image
      for (const [lineName, line] of Object.entries(calibrationLines.value)) {
        linesData[lineName] = line.points.map(point => {
          return {
            x: point.x / containerWidth * imageSize.width,
            y: point.y / containerHeight * imageSize.height
          }
        })
      }

      console.log('🔥 Données de lignes pour calibration:', linesData)
      
      // Déterminer quel fichier envoyer à l'API
      let fileToSend
      if (uploadStore.isImage) {
        // Pour les images, utiliser le fichier original
        fileToSend = uploadStore.selectedFile
      } else if (uploadStore.isStaticVideo && uploadStore.extractedFrame) {
        // Pour les vidéos statiques, utiliser la frame extraite
        fileToSend = uploadStore.extractedFrame
      } else {
        throw new Error('Aucune image disponible pour la calibration')
      }
      
      console.log('🔥 Fichier envoyé pour calibration:', fileToSend.name || 'extracted_frame.jpg', 'Type:', fileToSend.type)
      
      // Appeler l'API /calibrate avec l'image et les lignes
      return await api.calibrateCamera(fileToSend, linesData)
    })
    
    // Console log de la réponse API
    console.log('🔥 Réponse API calibration reçue:', result)
    
    // Toujours afficher les résultats, même en cas d'erreur
    calibrationStore.setResults(result)
    
  } catch (error) {
    console.error('❌ Erreur lors du traitement manuel:', error)
    // En cas d'erreur de réseau ou autre, créer un objet de résultat d'erreur
    calibrationStore.setResults({
      status: 'failed',
      message: error.message,
      error: error.message
    })
  }
}

// Méthodes pour les événements du graphique Plotly
const onChartDataLoaded = (data) => {
  if (data.rows) {
    // Pour les données CSV
    console.log('📊 Données CSV chargées:', data.rows.length, 'points')
  } else {
    // Pour le terrain de football ou autres
    console.log('📊 Graphique chargé:', data.traces.length, 'éléments')
  }
}

const onChartError = (error) => {
  console.error('❌ Erreur dans le graphique:', error)
}
</script>

<template>



      <div class="home-container">    
    <!-- Bouton retour subtil (visible si on a déjà fait des actions) -->
    <button 
      v-if="showUpload || showResults || showError" 
      @click="resetToStart" 
      class="btn-back-home"
      title="Recommencer"
    >
      <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
        <path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/>
        <path d="M21 3v5h-5"/>
        <path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/>
        <path d="M3 21v-5h5"/>
      </svg>
    </button>

    <!-- Section 1: Choix du mode -->
    <section ref="modeSection" class="section mode-section">
      <div class="hero">
        <h1>Football Vision</h1>
        <p class="hero-subtitle">Analysez automatiquement les paramètres de caméra de vos vidéos de football</p>
      </div>

      <div class="mode-selection">        
        <div class="mode-cards">
          <div 
            class="mode-card auto" 
            :class="{ selected: calibrationStore.isAutoMode }"
            @click="selectMode('auto')"
          >
            <h3>Mode Automatique</h3>
            <p>Détection automatique des lignes du terrain</p>
            <ul>
              <li>Rapide et simple</li>
              <li>Précision élevée</li>
              <li>Recommandé</li>
            </ul>
          </div>

          <div 
            class="mode-card manual" 
            :class="{ selected: calibrationStore.isManualMode }"
            @click="selectMode('manual')"
          >
            <h3>Mode Manuel</h3>
            <p>Contrôle total sur la définition des lignes</p>
            <ul>
              <li>Contrôle précis</li>
              <li>Personnalisable</li>
              <li>Cas spéciaux</li>
            </ul>
          </div>
        </div>
      </div>
    </section>

        <!-- Section 2: Upload de fichier -->
    <section v-if="showUpload" ref="uploadSection" class="section upload-section">
      <div class="upload-grid">
        <!-- Côté gauche: Upload de fichier -->
        <div class="upload-left">
          <div 
            class="drop-zone"
            :class="{ 
              active: dragActive, 
              'has-file': uploadStore.isFileSelected,
              'processing': uploadStore.isUploading 
            }"
            @drop="handleDrop"
            @dragover="handleDragOver"
            @dragleave="handleDragLeave"
          >
            <div v-if="!uploadStore.isFileSelected" class="drop-content">
              <div class="upload-icon">+</div>
              <h4>Glissez-déposez votre fichier ici</h4>
              <p class="or-text">ou</p>
              <label class="file-input-label">
                <input 
                  type="file" 
                  accept="image/*,video/*" 
                  @change="handleFileSelect"
                  hidden
                >
                Choisir un fichier
              </label>
            </div>

            <div v-else class="file-preview">
              <div class="file-info">
                <h4>Fichier sélectionné</h4>
                <p class="file-name">{{ uploadStore.selectedFile.name }}</p>
                <p class="file-details">
                  <span>Type: {{ uploadStore.fileType === 'image' ? 'Image' : 'Vidéo' }}</span>
                  <span>Taille: {{ Math.round(uploadStore.selectedFile.size / 1024) }} KB</span>
                </p>
              </div>
              
              <div class="preview" v-if="uploadStore.filePreview">
                <img 
                  v-if="uploadStore.isImage" 
                  :src="uploadStore.filePreview" 
                  alt="Preview"
                  class="preview-media"
                >
                <video 
                  v-else 
                  :src="uploadStore.filePreview" 
                  controls
                  class="preview-media"
                >
                </video>
              </div>

              <button @click="uploadStore.clearFile()" class="btn-secondary">
                Changer de fichier
              </button>
            </div>
          </div>
        </div>

        <!-- Côté droit: Images de test -->
        <div class="upload-right">
          <div class="test-image-container">
            <div 
              class="test-image-card single"
              @click="selectTestImage"
              :class="{ selected: selectedTestImage === 'test' }"
            >
              <img :src="testImageUrl" :alt="'Test Image'" class="test-image-thumb">
              <div class="test-image-overlay">
                <div class="overlay-content">
                  <p>Vue Drone</p>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>

    <!-- Section 3: Type de vidéo (statique/dynamique) -->
    <section v-if="showVideoType" ref="videoTypeSection" class="section video-type-section">
      <h2>Type de vidéo</h2>
      
      <div class="video-type-cards">
        <div 
          class="type-card static" 
          :class="{ selected: uploadStore.videoType === 'static' }"
          @click="selectVideoType('static')"
        >
          <h3>Vidéo Statique</h3>
          <p>Caméra fixe, extraction de la première image</p>
          <ul>
            <li>Traitement rapide</li>
            <li>Analyse comme une image</li>
            <li>Recommandé pour caméra fixe</li>
          </ul>
        </div>

        <div 
          class="type-card dynamic" 
          :class="{ selected: uploadStore.videoType === 'dynamic' }"
          @click="selectVideoType('dynamic')"
        >
          <h3>Vidéo Dynamique</h3>
          <p>Caméra en mouvement, analyse de plusieurs frames</p>
          <ul>
            <li>Analyse complète</li>
            <li>Traitement avancé</li>
            <li>Plus de données collectées</li>
          </ul>
        </div>
      </div>
    </section>

    <!-- Section 4: Paramètres pour vidéo dynamique -->
    <section v-if="showParameters" ref="parametersSection" class="section parameters-section">
      <h2>Paramètres de traitement</h2>
      
      <div class="parameters-form">
        <div class="param-group">
          <label>Seuil de détection des points clés</label>
          <input 
            type="range" 
            min="0.1" 
            max="0.5" 
            step="0.05"
            :value="calibrationStore.videoProcessingParams.kpThreshold"
            @input="updateParameter('kpThreshold', parseFloat($event.target.value))"
          >
          <span class="param-value">{{ calibrationStore.videoProcessingParams.kpThreshold }}</span>
        </div>

        <div class="param-group">
          <label>Seuil de détection des lignes</label>
          <input 
            type="range" 
            min="0.1" 
            max="0.5" 
            step="0.05"
            :value="calibrationStore.videoProcessingParams.lineThreshold"
            @input="updateParameter('lineThreshold', parseFloat($event.target.value))"
          >
          <span class="param-value">{{ calibrationStore.videoProcessingParams.lineThreshold }}</span>
        </div>

        <div class="param-group">
          <label>Pas entre les frames (traiter 1 frame sur X)</label>
          <input 
            type="range" 
            min="1" 
            max="300" 
            step="1"
            :value="calibrationStore.videoProcessingParams.frameStep"
            @input="updateParameter('frameStep', parseInt($event.target.value))"
          >
          <span class="param-value">{{ calibrationStore.videoProcessingParams.frameStep }}</span>
        </div>

        <button @click="startProcessing" class="btn-primary launch-btn">
          Lancer le traitement
        </button>
      </div>
    </section>

    <!-- Section 5: Vue manuelle intégrée -->
    <section v-if="showManualCalibration" ref="manualSection" class="section manual-section">
      <div class="manual-container">
        <div class="manual-content">
          <div class="calibration-container">
            <CalibrationArea
              ref="calibrationArea"
              :thumbnail="thumbnail"
              :calibrationPoints="calibrationPoints"
              :calibrationLines="calibrationLines"
              :selectedFieldPoint="selectedFieldPoint"
              :selectedFieldLine="selectedFieldLine"
              @update:thumbnail="updateThumbnail"
              @update:calibrationPoints="updateCalibrationPoints"
              @update:calibrationLines="updateCalibrationLines"
              @update:selectedFieldPoint="updateSelectedFieldPoint"
              @update:selectedFieldLine="updateSelectedFieldLine"
              @clear-calibration="clearCalibration"
              @process-calibration="processCalibration"
            />
          </div>
          <div class="field-container">
            <FootballField 
              ref="footballField"
              @point-selected="handleFieldPointSelected"
              @line-selected="handleFieldLineSelected"
              :positionedPoints="calibrationPoints"
              :positionedLines="calibrationLines"
            />
          </div>
        </div>
      </div>
    </section>

    <!-- Section 6: Traitement en cours -->
    <section v-if="showProcessing" ref="processingSection" class="section processing-section">
      <h2>Traitement en cours</h2>
      
      <div class="processing-card">
        <div class="processing-spinner"></div>
        
        <h3>{{ calibrationStore.processingTask }}</h3>
        
        <div class="progress-container">
          <div class="progress-bar">
            <div 
              class="progress-fill"
              :style="{ width: calibrationStore.processingProgress + '%' }"
            ></div>
          </div>
          <span class="progress-text">{{ Math.round(calibrationStore.processingProgress) }}%</span>
        </div>
        
        <div class="processing-info">
          <div class="info-item">
            <span class="label">Fichier:</span>
            <span class="value">{{ uploadStore.selectedFile?.name }}</span>
          </div>
          <div class="info-item">
            <span class="label">Mode:</span>
            <span class="value">{{ calibrationStore.isAutoMode ? 'Automatique' : 'Manuel' }}</span>
          </div>
          <div class="info-item" v-if="uploadStore.isVideo">
            <span class="label">Type:</span>
            <span class="value">{{ uploadStore.videoType === 'static' ? 'Vidéo Statique' : 'Vidéo Dynamique' }}</span>
          </div>
        </div>
      </div>
    </section>

    <!-- Section 7: Erreur -->
    <section v-if="showError" ref="errorSection" class="section error-section">
      <h2 v-if="!calibrationStore.isManualMode">Mode manuel recommandé</h2>
      <h2 v-else>Échec de la calibration</h2>
      
      <div class="error-card">
        <p class="error-message">{{ calibrationStore.error }}</p>
        
        <div v-if="calibrationStore.isManualMode" class="manual-error-actions">
          <button @click="backToCalibration" class="btn-manual-primary">
            Modifier la calibration
          </button>
          <button @click="restart" class="btn-restart-small">
            Recommencer
          </button>
        </div>
        
        <div v-else class="auto-error-actions">
          <button @click="goToManual" class="btn-manual-primary">
            Passer en mode manuel
          </button>
          <button @click="restart" class="btn-restart-small">
            Ou essayer une autre image
          </button>
        </div>
      </div>
    </section>

    <!-- Section 8: Résultats -->
    <section v-if="showResults" ref="resultsSection" class="section results-section">
      <!-- Succès -->
      <div v-if="calibrationStore.results?.status === 'success'" class="results-container">
        <div class="result-status">
          <div class="status-success">
            <h2>Analyse réussie</h2>
          </div>
        </div>

        <div class="result-message">
          <p>{{ calibrationStore.results?.message || 'Paramètres de caméra extraits avec succès' }}</p>
        </div>

        <div class="result-actions">
          <button @click="exportResults()" class="btn-primary">
            Télécharger les résultats
          </button>
          
          <button v-if="calibrationStore.isManualMode" @click="backToCalibration" class="btn-secondary">
            Modifier la calibration
          </button>
          
          <button @click="restart" class="btn-tertiary">
            Nouvelle analyse
          </button>
        </div>

        <!-- Graphique 3D pour les images et vidéos statiques avec calibration réussie -->
        <div v-if="uploadStore.isImage || uploadStore.isStaticVideo" class="result-chart">
          <h3>Terrain de Football - Vue 3D</h3>
          <PlotlyChart 
            data-type="football-field"
            :height="550"
            :keypoints-data="calibrationStore.results?.detections?.keypoints || []"
            :camera-params="calibrationStore.results?.camera_parameters?.cam_params"
            :custom-layout="{
              title: {
                text: 'Visualisation 3D du terrain de football',
                font: { size: 16, color: 'white' }
              },
              paper_bgcolor: 'rgba(0,0,0,0)',
              plot_bgcolor: 'rgba(0,0,0,0)'
            }"
            @data-loaded="onChartDataLoaded"
            @error="onChartError"
          />
        </div>

        <details class="result-details">
          <summary>Données complètes</summary>
          <pre class="result-data">{{ JSON.stringify(calibrationStore.results, null, 2) }}</pre>
        </details>
      </div>

      <!-- Échec en mode manuel -->
      <div v-else-if="calibrationStore.isManualMode" class="error-card-simple">
        <h2>Calibration échouée</h2>
        
        <p class="error-message">Les lignes définies ne permettent pas de calculer les paramètres de caméra.</p>
        
        <div class="error-actions">
          <button 
            @click="backToCalibration" 
            class="btn-primary"
            title="Modifiez vos lignes de calibration : ajoutez plus de points, utilisez des lignes variées (droites, cercles), répartissez-les sur l'image"
          >
            Ajuster la calibration
          </button>
          
          <button 
            @click="restart" 
            class="btn-secondary"
            title="Essayez avec une image de meilleure qualité ou un angle de vue différent"
          >
            Changer d'image
          </button>
        </div>
      </div>

      <!-- Échec en mode auto -->
      <div v-else class="results-container">
        <div class="result-status">
          <div class="status-error">
            <h2>Analyse échouée</h2>
          </div>
        </div>

        <div class="result-message">
          <p>L'analyse automatique n'a pas pu extraire les paramètres de caméra.</p>
        </div>

        <div class="result-actions">
          <button @click="goToManual" class="btn-secondary">
            Essayer en mode manuel
          </button>
          
          <button @click="restart" class="btn-tertiary">
            Nouvelle analyse
          </button>
        </div>

        <details class="result-details">
          <summary>Données complètes</summary>
          <pre class="result-data">{{ JSON.stringify(calibrationStore.results, null, 2) }}</pre>
        </details>
      </div>
    </section>
  </div>
</template>

<style scoped>
.btn-back-home {
  position: fixed;
  top: 20px;
  left: 20px;
  background: rgba(255, 255, 255, 0.1);
  color: #888;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 8px;
  padding: 10px;
  cursor: pointer;
  transition: all 0.3s ease;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(10px);
}

.btn-back-home:hover {
  background: rgba(255, 255, 255, 0.15);
  color: var(--color-primary);
  border-color: var(--color-primary);
  transform: scale(1.05);
}

.btn-back-home svg {
  transition: all 0.3s ease;
}

.home-container {
  margin: 0 auto;
  background: var(--color-secondary);
  min-height: 100vh;
}

.section {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
}

/* Section Mode */
.hero h1 {
  font-size: 3rem;
  font-weight: 700;
  margin-bottom: 1rem;
  color: white;
  letter-spacing: -0.025em;
  position: relative;
}

.hero h1::after {
  content: '';
  position: absolute;
  bottom: -10px;
  left: 50%;
  transform: translateX(-50%);
  width: 80px;
  height: 4px;
  background: var(--color-primary);
  border-radius: 2px;
}

.hero-subtitle {
  font-size: 1.1rem;
  color: #b0b0b0;
  margin-bottom: 4rem;
  max-width: 600px;
  line-height: 1.6;
  font-weight: 500;
}

.mode-selection h2 {
  font-size: 1.5rem;
  margin-bottom: 3rem;
  color: white;
  font-weight: 600;
}

.mode-cards, .video-type-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 2rem;
  width: 100%;
  max-width: 800px;
}

.mode-card, .type-card {
  background: var(--color-secondary-soft);
  border-radius: 12px;
  padding: 2rem;
  box-shadow: 0 4px 20px rgba(0,0,0,0.3);
  cursor: pointer;
  transition: all 0.3s ease;
  border: 2px solid #333;
  position: relative;
  overflow: hidden;
}

.mode-card::before, .type-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: var(--color-primary);
  transform: translateY(-4px);
  transition: transform 0.3s ease;
}

.mode-card:hover::before, .type-card:hover::before {
  transform: translateY(0);
}

.mode-card:hover, .type-card:hover {
  transform: translateY(-8px);
  box-shadow: 0 8px 30px rgba(0,0,0,0.4);
  border-color: var(--color-primary);
  background: #2a2a2a;
}

.mode-card.selected, .type-card.selected {
  border-color: var(--color-primary);
  background: #2a2a2a;
  transform: translateY(-4px);
  box-shadow: 0 6px 25px rgba(255, 255, 255, 0.3);
}

.mode-card.selected::before, .type-card.selected::before {
  transform: translateY(0);
}

.mode-card h3, .type-card h3 {
  font-size: 1.25rem;
  font-weight: 700;
  color: white;
  margin-bottom: 1rem;
}

.mode-card p, .type-card p {
  color: #b0b0b0;
  margin-bottom: 1.5rem;
  line-height: 1.5;
  font-weight: 500;
}

.mode-card ul, .type-card ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.mode-card li, .type-card li {
  padding: 0.5rem 0;
  color: #d0d0d0;
  font-size: 0.9rem;
  position: relative;
  padding-left: 1.5rem;
  font-weight: 500;
}

.mode-card li::before, .type-card li::before {
  content: '●';
  color: var(--color-primary);
  font-weight: bold;
  position: absolute;
  left: 0;
}

/* Section Upload */
.upload-section h2, .video-type-section h2, .parameters-section h2, .processing-section h2, .results-section h2 {
  font-size: 1.5rem;
  margin-bottom: 3rem;
  color: white;
  font-weight: 600;
}

/* Grid Upload */
.upload-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3rem;
  width: 100%;
  max-width: 1200px;
  align-items: start;
  padding: 2rem;
}

.upload-left, .upload-right {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.upload-right {
  justify-content: center;
  align-items: center;
}

.upload-title {
  font-size: 1.25rem;
  font-weight: 600;
  color: white;
  margin-bottom: 2rem;
  text-align: center;
}

.drop-zone {
  border: 3px dashed #555;
  border-radius: 12px;
  padding: 3rem;
  transition: all 0.3s ease;
  background: var(--color-secondary-soft);
  width: 100%;
  max-width: 600px;
  position: relative;
}

.drop-zone.active {
  border-color: var(--color-primary);
  background: #2a2a2a;
  box-shadow: 0 4px 20px rgba(217, 255, 4, 0.2);
}

.drop-zone.has-file {
  border-color: var(--color-primary);
  border-style: solid;
  background: #2a2a2a;
}

.upload-icon {
  font-size: 3rem;
  color: #888;
  margin-bottom: 1rem;
  font-weight: 300;
}

.drop-content h4 {
  font-size: 1.25rem;
  color: white;
  margin-bottom: 1rem;
  font-weight: 600;
}

/* Image de test */
.test-image-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.test-image-card.single {
  background: var(--color-secondary-soft);
  border-radius: 12px;
  overflow: hidden;
  cursor: pointer;
  transition: all 0.3s ease;
  border: 2px solid transparent;
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
}

.test-image-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
  border-color: rgba(255, 255, 255, 0.2);
}

.test-image-card.selected {
  border-color: var(--color-primary);
  box-shadow: 0 4px 20px rgba(217, 255, 4, 0.3);
}

.test-image-card.selected::after {
  content: '✓';
  position: absolute;
  top: 8px;
  right: 8px;
  background: var(--color-primary);
  color: var(--color-secondary);
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 0.8rem;
}

.test-image-thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.test-image-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 1;
  transition: opacity 0.3s ease;
  backdrop-filter: blur(2px);
}

.test-image-card.single:hover .test-image-overlay {
  opacity: 0;
}

.overlay-content {
  text-align: center;
  color: white;
}



.overlay-content p {
  font-size: 0.9rem;
  margin: 0;
  color: #e0e0e0;
  font-weight: 500;
}



.or-text {
  color: #888;
  margin: 1.5rem 0;
  font-size: 0.9rem;
  font-weight: 500;
}

.file-input-label {
  display: inline-block;
  background: var(--color-primary);
  color: var(--color-secondary);
  padding: 0.875rem 2rem;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-weight: 700;
  font-size: 0.9rem;
  position: relative;
  overflow: hidden;
}

.file-input-label::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
  transition: left 0.5s ease;
}

.file-input-label:hover::before {
  left: 100%;
}

.file-input-label:hover {
  background: white;
  transform: translateY(-2px);
  box-shadow: 0 4px 15px rgba(255, 255, 255, 0.4);
}

.format-info {
  color: #888;
  font-size: 0.85rem;
  margin-top: 1.5rem;
  font-weight: 500;
}

.file-preview {
  text-align: center;
}

.file-info h4 {
  color: var(--color-primary);
  margin-bottom: 1.5rem;
  font-weight: 600;
}

.file-name {
  font-weight: 700;
  color: white;
  margin-bottom: 1rem;
}

.file-details {
  color: #b0b0b0;
  font-size: 0.9rem;
  margin-bottom: 2rem;
  font-weight: 500;
}

.file-details span {
  margin-right: 1rem;
}

.preview-media {
  max-width: 100%;
  max-height: 300px;
  border-radius: 8px;
  box-shadow: 0 4px 20px rgba(0,0,0,0.3);
  margin: 2rem 0;
  /* border: 2px solid var(--color-primary); */
}

/* Section Paramètres */
.parameters-form {
  background: var(--color-secondary-soft);
  padding: 2.5rem;
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0,0,0,0.3);
  width: 100%;
  max-width: 500px;
  text-align: left;
  border: 1px solid #333;
}

.param-group {
  margin-bottom: 2rem;
}

.param-group label {
  display: block;
  margin-bottom: 0.75rem;
  font-weight: 600;
  color: white;
  font-size: 0.9rem;
}

.param-group input[type="range"] {
  width: 100%;
  height: 6px;
  background: #333;
  border-radius: 3px;
  outline: none;
  margin: 0.5rem 0;
  -webkit-appearance: none;
}

.param-group input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--color-primary);
  cursor: pointer;
  border: 3px solid var(--color-secondary);
  box-shadow: 0 2px 6px rgba(0,0,0,0.3);
}

.param-group input[type="range"]::-moz-range-thumb {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--color-primary);
  cursor: pointer;
  border: 3px solid var(--color-secondary);
  box-shadow: 0 2px 6px rgba(0,0,0,0.3);
}

.param-value {
  font-weight: 700;
  float: right;
  background: var(--color-primary);
  color: var(--color-secondary);
  padding: 0.25rem 0.5rem;
  border-radius: 4px;
  font-size: 0.8rem;
}

.launch-btn {
  width: 100%;
  margin-top: 1rem;
  font-size: 1rem;
  padding: 1rem;
  font-weight: 700;
}

/* Section Erreur */
.error-section h2 {
  font-size: 1.5rem;
  margin-bottom: 3rem;
  color: white;
  font-weight: 600;
}

.error-card {
  background: var(--color-secondary-soft);
  border-radius: 12px;
  padding: 3rem;
  box-shadow: 0 4px 20px rgba(0,0,0,0.3);
  width: 100%;
  max-width: 400px;
  border: 1px solid #333;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.error-message {
  color: #b0b0b0;
  font-size: 0.95rem;
  font-weight: 500;
  margin: 0;
}

.btn-manual-primary {
  background: var(--color-primary);
  color: var(--color-secondary);
  border: none;
  padding: 1rem 2rem;
  border-radius: 8px;
  font-weight: 700;
  font-size: 1rem;
  cursor: pointer;
  transition: all 0.3s ease;
}

.btn-manual-primary:hover {
  background: var(--color-primary-soft);
  transform: translateY(-2px);
  box-shadow: 0 4px 15px rgba(217, 255, 4, 0.4);
}

.btn-restart-small {
  background: transparent;
  color: #888;
  border: none;
  padding: 0.5rem;
  font-size: 0.85rem;
  cursor: pointer;
  transition: color 0.3s ease;
  text-decoration: underline;
}

.btn-restart-small:hover {
  color: white;
}

/* Section Traitement */
.processing-card {
  background: var(--color-secondary-soft);
  border-radius: 12px;
  padding: 3rem;
  box-shadow: 0 4px 20px rgba(0,0,0,0.3);
  width: 100%;
  max-width: 500px;
  border: 1px solid #333;
}

.processing-spinner {
  width: 48px;
  height: 48px;
  border: 4px solid #333;
  border-top: 4px solid var(--color-primary);
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin: 0 auto 2rem;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.processing-card h3 {
  font-size: 1.1rem;
  color: white;
  margin-bottom: 2rem;
  font-weight: 600;
}

.progress-container {
  margin: 2rem 0;
}

.progress-bar {
  width: 100%;
  height: 10px;
  background: #333;
  border-radius: 5px;
  overflow: hidden;
  margin-bottom: 0.75rem;
}

.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--color-primary), var(--color-primary-soft));
  transition: width 0.3s ease;
  border-radius: 5px;
}

.progress-text {
  font-weight: 700;
  color: white;
  font-size: 0.9rem;
}

.processing-info {
  margin-top: 2rem;
  text-align: left;
}

.info-item {
  display: flex;
  justify-content: space-between;
  margin-bottom: 0.5rem;
  font-size: 0.9rem;
}

.info-item .label {
  color: #b0b0b0;
  font-weight: 500;
}

.info-item .value {
  color: white;
  font-weight: 600;
}

/* Section Résultats */
.results-summary {
  background: var(--color-secondary-soft);
  border-radius: 12px;
  margin-bottom: 3rem;
  box-shadow: 0 4px 20px rgba(0,0,0,0.3);
  width: 100%;
  max-width: 600px;
  border: 1px solid #333;
}

/* Section Résultats */
.results-container {
  max-width: 800px;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.result-status h2 {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 600;
}

.status-success h2 {
  color: var(--color-primary);
}

.status-error h2 {
  color: #dc3545;
}

.result-message {
  background: var(--color-secondary-soft);
  border-radius: 8px;
  padding: 1.5rem;
  border-left: 4px solid var(--color-primary);
}

.result-message p {
  margin: 0;
  color: #e0e0e0;
  line-height: 1.5;
  font-size: 0.95rem;
}

.result-actions {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.btn-primary, .btn-secondary, .btn-tertiary {
  padding: 0.875rem 1.5rem;
  border-radius: 8px;
  border: none;
  cursor: pointer;
  font-weight: 600;
  font-size: 0.9rem;
  transition: all 0.3s ease;
}

.btn-primary {
  background: var(--color-primary);
  color: var(--color-secondary);
}

.btn-primary:hover {
  background: var(--color-primary-soft);
  transform: translateY(-1px);
}

.btn-secondary {
  background: #555;
  color: white;
  border: 1px solid #666;
}

.btn-secondary:hover {
  background: #666;
  transform: translateY(-1px);
}

.btn-tertiary {
  background: transparent;
  color: #888;
  border: 1px solid #555;
}

.btn-tertiary:hover {
  color: white;
  border-color: #777;
  background: #333;
}

.result-details {
  margin-top: 1rem;
}

.result-details summary {
  color: #888;
  font-size: 0.9rem;
  cursor: pointer;
  padding: 0.5rem 0;
  transition: color 0.3s ease;
}

.result-details summary:hover {
  color: white;
}

.result-details[open] summary {
  color: var(--color-primary);
  margin-bottom: 1rem;
}

.result-data {
  background: #0d1117;
  color: #e6edf3;
  padding: 1.5rem;
  border-radius: 8px;
  font-family: 'Monaco', 'Consolas', 'Ubuntu Mono', monospace;
  font-size: 0.875rem;
  line-height: 1.6;
  overflow-x: auto;
  white-space: pre;
  border: 1px solid #30363d;
  max-height: 400px;
  overflow-y: auto;
  text-align: left;
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
  
  /* Syntax highlighting simulation */
  color: #c9d1d9;
}

.result-details {
  position: relative;
}

.confidence-score {
  font-size: 1rem;
  color: white;
  font-weight: 600;
}

    .quick-info {
    margin-top: 2rem;
    padding-top: 1.5rem;
    border-top: 1px solid #333;
  }

  .quick-info .info-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.75rem;
    font-size: 0.9rem;
  }

  .quick-info .info-item span:first-child {
    color: #b0b0b0;
    font-weight: 500;
  }

  .quick-info .info-item span:last-child {
    color: white;
    font-weight: 600;
    font-family: monospace;
  }



/* Error Card simple pour mode manuel */
.error-card-simple {
  max-width: 500px;
  width: 100%;
  text-align: center;
}

.error-card-simple h2 {
  color: #dc3545;
  font-size: 1.5rem;
  font-weight: 600;
  margin-bottom: 1rem;
}

.error-card-simple .error-message {
  color: #b0b0b0;
  font-size: 1rem;
  margin-bottom: 2rem;
  line-height: 1.5;
}

.error-actions {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 300px;
  margin: 0 auto;
}

.manual-error-actions, .auto-error-actions {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  width: 100%;
  max-width: 300px;
  margin: 0 auto;
}

.btn-manual-primary {
  background: var(--color-primary);
  color: var(--color-secondary);
  border: none;
  padding: 1rem 2rem;
  border-radius: 8px;
  font-weight: 600;
  font-size: 0.95rem;
  cursor: pointer;
  transition: all 0.3s ease;
}

.btn-manual-primary:hover {
  background: var(--color-primary-soft);
  transform: translateY(-2px);
  box-shadow: 0 4px 15px rgba(217, 255, 4, 0.4);
}

.btn-restart-small {
  background: transparent;
  color: #888;
  border: 1px solid #555;
  padding: 0.75rem 1.5rem;
  border-radius: 8px;
  font-weight: 500;
  font-size: 0.9rem;
  cursor: pointer;
  transition: all 0.3s ease;
}

.btn-restart-small:hover {
  color: white;
  border-color: #777;
  background: #333;
}



/* Boutons */
.btn-primary, .btn-secondary, .btn-export {
  border: none;
  padding: 0.875rem 1.5rem;
  border-radius: 8px;
  cursor: pointer;
  font-weight: 600;
  transition: all 0.3s ease;
  text-decoration: none;
  display: inline-block;
  font-size: 0.9rem;
  position: relative;
  overflow: hidden;
}

.btn-primary {
  background: var(--color-primary);
  color: var(--color-secondary);
}

.btn-primary::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
  transition: left 0.5s ease;
}

.btn-primary:hover::before {
  left: 100%;
}

.btn-primary:hover {
  background: var(--color-primary-soft);
  transform: translateY(-2px);
  box-shadow: 0 4px 15px rgba(217, 255, 4, 0.4);
}

.btn-secondary {
  background: #555;
  color: white;
  border: 1px solid #666;
}

.btn-secondary:hover {
  background: #666;
  transform: translateY(-2px);
  box-shadow: 0 4px 15px rgba(255, 255, 255, 0.1);
}

.btn-export {
  background: var(--color-primary);
  color: var(--color-secondary);
  padding: 0.5rem 1rem;
  font-size: 0.85rem;
  font-weight: 700;
}

.btn-export:hover {
  background: var(--color-primary-soft);
  transform: translateY(-2px);
  box-shadow: 0 4px 15px rgba(217, 255, 4, 0.4);
}

/* Section manuelle */
.manual-section {
  height: 100svh;
  min-height: 100svh;
  padding: 0;
}

.manual-container {
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column;
}

.manual-content {
  flex: 1;
  display: flex;
  gap: 15px;
  padding: 15px;
  overflow: hidden;
  height: 100%;
}

.manual-section .calibration-container {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.manual-section .field-container {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
}

.manual-section .field-container :deep(svg) {
  width: 100%;
  height: 100%;
  object-fit: contain;
  margin-top: -10px;
}

.manual-section .calibration-container :deep(.video-frame-container) {
  height: 100%;
}

.manual-section .calibration-container :deep(.video-frame) {
  height: calc(100% - 80px);
}

/* Section graphique dans les résultats */
.result-chart {
  width: 100%;
  max-width: 1000px;
  margin: 2rem 0;
  background: rgba(255, 255, 255, 0.02);
  border-radius: 12px;
  padding: 1.5rem;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.result-chart h3 {
  font-size: 1.25rem;
  color: white;
  margin-bottom: 1rem;
  text-align: center;
  font-weight: 600;
}

/* Responsive */
@media (max-width: 768px) {
  .home-container {
    padding: 0 1rem;
  }
  
  .section {
    min-height: auto;
  }
  
  .mode-cards, .video-type-cards {
    grid-template-columns: 1fr;
  }
  
  .main-actions {
    grid-template-columns: 1fr;
  }
  
  .hero h1 {
    font-size: 2.5rem;
  }
  
  .manual-content {
    flex-direction: column;
  }

  .result-chart {
    padding: 1rem;
    margin: 1rem 0;
  }
}
</style>
