<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, maximum-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="theme-color" content="#111827">
<title>OBD Face Editor</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.js"></script>
<script src="https://cdn.jsdelivr.net/npm/html5-qrcode@2.3.8/html5-qrcode.min.js"></script>
<link rel="stylesheet" href="css/styles.css">
<style>
@font-face { font-family: 'Orbitron'; src: url('fonts/orbitron.ttf') format('truetype'); font-weight: 700; }
@font-face { font-family: 'Russo One'; src: url('fonts/russo.ttf') format('truetype'); font-weight: 400; }
@font-face { font-family: 'Teko'; src: url('fonts/teko.ttf') format('truetype'); font-weight: 500; }
@font-face { font-family: 'Rajdhani'; src: url('fonts/rajdhani.ttf') format('truetype'); font-weight: 600; }
@font-face { font-family: 'Share Tech Mono'; src: url('fonts/mono.ttf') format('truetype'); font-weight: 400; }
@font-face { font-family: 'Audiowide'; src: url('fonts/audiowide.ttf') format('truetype'); font-weight: 400; }
@font-face { font-family: 'DSEG7'; src: url('fonts/dseg7.ttf') format('truetype'); font-weight: 700; }
@font-face { font-family: 'Barlow Semi Condensed'; src: url('fonts/barlow.ttf') format('truetype'); font-weight: 500; }
@font-face { font-family: 'Saira Condensed'; src: url('fonts/saira.ttf') format('truetype'); font-weight: 600; }
@font-face { font-family: 'Play'; src: url('fonts/play.ttf') format('truetype'); font-weight: 400; }
</style>
</head>
<body>
<div id="app" v-cloak>

<!-- ═══ HEADER / MENU BAR ═══ -->
<header class="ed-header">
  <!-- Hamburger (mobile) -->
  <button class="ed-icon-btn ed-hamburger" @click="activeMenu = activeMenu==='mobile' ? null : 'mobile'">
    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
  </button>
  <!-- Desktop menu bar -->
  <nav class="ed-menubar">
    <button ref="menuFichier" class="ed-menubar-btn" :class="{active:activeMenu==='fichier'}" :disabled="noCell" @click="toggleMenu('fichier')" @mouseenter="hoverMenu('fichier')">Fichier</button>
    <button ref="menuEdition" class="ed-menubar-btn" :class="{active:activeMenu==='edition'}" :disabled="noCell" @click="toggleMenu('edition')" @mouseenter="hoverMenu('edition')">Edition</button>
    <button ref="menuInsertion" class="ed-menubar-btn" :class="{active:activeMenu==='insertion'}" :disabled="noCell" @click="toggleMenu('insertion')" @mouseenter="hoverMenu('insertion')">Insertion</button>
  </nav>
  <input v-model="face.name" class="ed-face-name" placeholder="Nom du cadran" :disabled="noCell" :style="noCell ? {opacity:0.3} : {}">
  <span v-if="(multiSelected || selectedElement) && !noCell" class="ed-sel-badge ed-hide-mobile">{{selectedName}}</span>
  <div class="ed-header-actions">
    <button class="ed-icon-btn ed-btn-accent ed-mobile-only" @click="showPalette=true" title="Ajouter" :disabled="noCell">
      <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
    </button>
    <button class="ed-icon-btn" @click="undo" :disabled="!canUndo || noCell" title="Annuler (Ctrl+Z)">
      <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1 4 1 10 7 10"/><path d="M3.5 15a9 9 0 1 0 2.1-9.4L1 10"/></svg>
    </button>
    <button class="ed-icon-btn" @click="redo" :disabled="!canRedo || noCell" title="Retablir (Ctrl+Shift+Z)">
      <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.5 15a9 9 0 1 1-2.1-9.4L23 10"/></svg>
    </button>
    <button class="ed-icon-btn" @click="showPreviewSettings=!showPreviewSettings" title="Reglages">
      <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="4" y1="21" x2="4" y2="14"/><line x1="4" y1="10" x2="4" y2="3"/><line x1="12" y1="21" x2="12" y2="12"/><line x1="12" y1="8" x2="12" y2="3"/><line x1="20" y1="21" x2="20" y2="16"/><line x1="20" y1="12" x2="20" y2="3"/><line x1="1" y1="14" x2="7" y2="14"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="17" y1="16" x2="23" y2="16"/></svg>
    </button>
  </div>
</header>

<!-- ═══ MAIN ═══ -->
<div class="ed-main">

  <!-- ── Canvas column ── -->
  <div class="ed-canvas-col">
    <div class="ed-canvas-area" @click.self="selectedIds=[]; cellMenu.show=false; if(previewLayout!=='1x1') activeCell=-1; renderCanvas()" @contextmenu.self.prevent="cellMenu.show=false">
      <div class="canvas-wrapper">
        <canvas id="gaugeCanvas" width="400" height="400"></canvas>
        <!-- Grid cell overlays for switching cells (non-active cells only) -->
        <template v-if="previewLayout !== '1x1'">
          <div v-for="idx in (layoutOptions.find(l=>l.key===previewLayout)||layoutOptions[0]).cols * (layoutOptions.find(l=>l.key===previewLayout)||layoutOptions[0]).rows"
               :key="'cell-'+idx"
               v-show="(idx-1) !== activeCell || activeCell === -1"
               :style="cellOverlayStyle(idx-1)"
               class="grid-cell-overlay"
               @mousedown.left.stop.prevent="onCellOverlayClick(idx-1)"
               @contextmenu.stop.prevent="onCellContextMenu($event, idx-1)">
          </div>
        </template>

        <!-- Cell context menu -->
        <div v-if="cellMenu.show" class="cell-context-menu" :style="{left: cellMenu.x+'px', top: cellMenu.y+'px'}">
          <button class="cell-ctx-item" @mousedown.stop.prevent="copyCellToClipboard(cellMenu.idx); cellMenu.show=false">Copier le cadran</button>
          <button class="cell-ctx-item" @mousedown.stop.prevent="pasteCellFromClipboard(cellMenu.idx); cellMenu.show=false" :disabled="!cellClipboard">Coller un cadran</button>
          <div class="cell-ctx-sep"></div>
          <button class="cell-ctx-item cell-ctx-danger" @mousedown.stop.prevent="clearCell(cellMenu.idx); cellMenu.show=false" :disabled="!cells[cellMenu.idx].code">Supprimer le cadran</button>
        </div>
        <div v-if="(multiSelected || selectedElement) && !(selectedElement && selectedElement.isConditional)" class="selection-badge">{{selectedName}}</div>
      </div>
    </div>
    <div class="ed-preview-bar">
      <div class="ed-layout-picker" title="Layout grille">
        <button v-for="l in layoutOptions" :key="l.key" class="ed-layout-btn" :class="{active: previewLayout===l.key}" @click="previewLayout=l.key; if(l.key==='1x1') activeCell=0; autoSaveSession(); renderCanvas()">
          <svg :width="18" :height="18" :viewBox="'0 0 20 20'">
            <rect v-for="(r,i) in l.rects" :key="i" :x="r[0]" :y="r[1]" :width="r[2]" :height="r[3]" rx="1.5" fill="none" stroke="currentColor" stroke-width="1.2"/>
          </svg>
        </button>
      </div>
      <select v-show="!noCell" v-model="previewType" @change="onPreviewTypeChange" class="ed-preview-select">
        <option value="oil_temp">Huile</option>
        <option value="boost">Turbo</option>
        <option value="rpm">RPM</option>
        <option value="speed">Vitesse</option>
        <option value="coolant">Eau</option>
        <option value="voltage">Batterie</option>
        <option value="fuel_level">Essence</option>
        <option value="fuel_rate">Conso. L/h</option>
        <option value="fuel_l100">L/100km</option>
      </select>
      <button class="ed-play-btn" :class="{active:animatePreview}" @click="toggleAnimation" :title="animatePreview?'Pause':'Animer'">
        <svg v-if="!animatePreview" width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><polygon points="6,4 20,12 6,20"/></svg>
        <svg v-else width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><rect x="5" y="4" width="4" height="16" rx="1"/><rect x="15" y="4" width="4" height="16" rx="1"/></svg>
      </button>
      <input type="range" min="0" max="100" step="1" v-model.number="renderCtx.percent" class="ed-slider" @input="onPercentChange" :disabled="animatePreview">
      <span class="ed-preview-value">{{renderCtx.formattedValue}} {{renderCtx.unit}}</span>
      <span class="ed-zone-pill" :class="'zone-'+renderCtx.zone">{{renderCtx.zone}}</span>
    </div>
  </div>

  <!-- ── Panels column ── -->
  <div class="ed-panels-col">

    <!-- No cell selected → prompt -->
    <div v-if="activeCell < 0 && previewLayout !== '1x1'" class="ed-no-cell-prompt">
      <div class="ed-no-cell-icon">
        <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#4FC3F7" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
      </div>
      <div class="ed-no-cell-text">Clique sur un cadran pour l'editer</div>
      <div class="ed-no-cell-hint">Utilise les boutons de layout pour changer la grille</div>
    </div>

    <!-- Desktop tabs (only when a cell is selected or in 1x1 mode) -->
    <template v-if="activeCell >= 0 || previewLayout === '1x1'">
    <div class="ed-desktop-tabs">
      <button class="ed-tab" :class="{active:tab==='elements'}" @click="tab='elements'">Calques</button>
      <button class="ed-tab" :class="{active:tab==='vars'}" @click="tab='vars'">Variables</button>
      <button class="ed-tab" :class="{active:tab==='code'}" @click="tab='code'">Code</button>
      <button class="ed-tab" :class="{active:tab==='io'}" @click="tab='io'">Presets</button>
    </div>

    <!-- ▸ TAB: Elements / Layers -->
    <div v-show="tab==='elements'" class="ed-panel ed-panel-layers">
      <div class="ed-layers-body" :class="{'has-props': selectedElement || multiSelected}">
        <div class="ed-layer-list" @contextmenu.self.prevent="onLayerListContextMenu($event)">
          <div v-for="(el,idx) in flatElements" :key="el.id"
            class="el-item"
            :class="{'active':selectedIds.includes(el.id), 'dragging':dragSource===el.id, 'drag-before':dragTarget===el.id && dragPos==='before', 'drag-after':dragTarget===el.id && dragPos==='after', 'drag-into':dragTarget===el.id && dragPos==='into'}"
            @click="onLayerClick($event, el)"
            @contextmenu.prevent="onLayerContextMenu($event, el)"
            draggable="true"
            @dragstart="dragLayerStart($event, el)"
            @dragover.prevent="dragLayerOver($event, el)"
            @dragleave="dragTarget===el.id && (dragTarget=null)"
            @drop="dropLayer($event, el)"
            @dragend="dragLayerEnd"
            :style="{'padding-left':(8+el.depth*16)+'px'}">
            <button v-if="el.isConditional || el.isGroup || el.isForLoop" class="el-collapse-btn" @click.stop="toggleCollapse(el.id)" :title="el.collapsed?'Deployer':'Replier'">
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" :style="{transform:el.collapsed?'rotate(-90deg)':''}"><polyline points="6 9 12 15 18 9"/></svg>
            </button>
            <canvas v-if="!el.isConditional && !el.isGroup && !el.isForLoop" :id="'thumb-'+el.id" width="32" height="32" class="el-thumb"></canvas>
            <svg v-if="el.isConditional" class="el-type-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#fbbf24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4"/><path d="M10.363 3.591l-8.106 13.534A1.914 1.914 0 0 0 3.891 20h16.218a1.914 1.914 0 0 0 1.634-2.875L13.637 3.59a1.914 1.914 0 0 0-3.274 0z"/><path d="M12 17h.01"/></svg>
            <svg v-if="el.isGroup" class="el-type-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#60a5fa" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
            <svg v-if="el.isForLoop" class="el-type-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#c084fc" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3l4 4-4 4"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><path d="M7 21l-4-4 4-4"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg>
            <span class="flex-1 truncate" :class="el.isConditional?'text-yellow-300':el.isGroup?'text-blue-300':el.isForLoop?'text-purple-300':'text-gray-300'">
              <span class="text-gray-500">{{idx+1}}.</span>
              {{el.display}}
            </span>
            <button class="el-action-btn" :class="{'el-vis-off':el.hidden}" @click.stop="toggleVisibility(el.id)" :title="el.hidden?'Afficher':'Masquer'">
              <svg v-if="!el.hidden" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
              <svg v-else width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/><path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/><line x1="1" y1="1" x2="23" y2="23"/></svg>
            </button>
            <button class="el-action-btn" @click.stop="moveEl(el.id,-1)" title="Monter">
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
            </button>
            <button class="el-action-btn" @click.stop="moveEl(el.id,1)" title="Descendre">
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
            </button>
            <button class="el-action-btn el-action-del" @click.stop="deleteEl(el.id)" title="Supprimer">
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
            </button>
          </div>
          <div v-if="flatElements.length===0" class="ed-empty-layers">
            <div class="text-gray-500 text-xs mb-3">Aucun element sur le cadran.</div>
            <button class="btn btn-primary" @click="showPalette=true">+ Ajouter un element</button>
          </div>
        </div>

        <!-- Layer toolbar -->
        <div class="ed-layer-toolbar">
          <button class="ed-layer-toolbar-btn ed-layer-add-btn" @click="showPalette=true" title="Ajouter un element">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
          </button>
          <button class="ed-layer-toolbar-btn" @click="addGroup" title="Nouveau groupe">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
          </button>
          <button class="ed-layer-toolbar-btn" @click="addConditional" title="Bloc conditionnel">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4"/><path d="M10.363 3.591l-8.106 13.534A1.914 1.914 0 0 0 3.891 20h16.218a1.914 1.914 0 0 0 1.634-2.875L13.637 3.59a1.914 1.914 0 0 0-3.274 0z"/><path d="M12 17h.01"/></svg>
          </button>
          <button class="ed-layer-toolbar-btn" @click="addForLoop" title="Boucle for">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3l4 4-4 4"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><path d="M7 21l-4-4 4-4"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg>
          </button>
          <span class="ed-layer-toolbar-sep"></span>
          <button class="ed-layer-toolbar-btn" :disabled="selectedIds.length===0" @click="deleteSelection" title="Supprimer">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
          </button>
          <button class="ed-layer-toolbar-btn" :disabled="selectedIds.length<2 && !(selectedElement && !selectedElement.isGroup)" @click="groupSelection" title="Grouper">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/><path d="M14 3h3a2 2 0 0 1 2 2v3"/><path d="M3 14v3a2 2 0 0 0 2 2h3"/></svg>
          </button>
        </div>

        <!-- Multi-selection panel -->
        <div v-if="multiSelected" class="ed-props">
          <div class="ed-props-header">
            <span>{{selectedIds.length}} elements</span>
          </div>
          <div class="ed-props-body">
            <div class="text-xs text-gray-400 mb-3">
              <span class="text-cyan-400">Ctrl+Clic</span> pour ajouter/retirer,
              <span class="text-cyan-400">Shift+Clic</span> pour une plage.
            </div>
            <div class="flex flex-wrap gap-2">
              <button class="btn btn-ghost text-xs" @click="copySelection">Copier</button>
              <button class="btn btn-ghost text-xs" @click="duplicateSelection">Dupliquer</button>
              <button class="btn btn-ghost text-xs" @click="groupSelection">Grouper</button>
              <button class="btn btn-danger text-xs" @click="deleteSelectedElements">Supprimer</button>
            </div>
          </div>
        </div>

        <!-- Property editor -->
        <div v-if="selectedElement" class="ed-props">
          <div class="ed-props-header">
            <span>{{selectedElement.isGroup ? (selectedElement.name || 'Groupe') : selectedElement.isForLoop ? ('for ' + selectedElement.varName) : (selectedElement.type || ('if ' + selectedElement.condition))}}</span>
            <button class="ed-close-btn" @click="selectedIds=[];renderCanvas()" title="Fermer">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="6 9 12 15 18 9"/></svg>
            </button>
          </div>
          <div class="ed-props-body">
            <template v-if="selectedElement.isGroup">
              <div class="prop-row">
                <span class="prop-label">Nom</span>
                <input class="prop-input" v-model="selectedElement.name" @input="onPropChange" placeholder="Groupe">
              </div>
              <div class="text-xs text-gray-500 mt-3">
                <span class="text-blue-400">{{selectedElement.children ? selectedElement.children.length : 0}}</span> element(s) dans ce groupe.<br>
                Glissez des calques dans ce groupe pour les organiser.
              </div>
              <div class="flex gap-2 mt-3">
                <button class="btn btn-ghost text-xs" @click="ungroupSelected">Degrouper</button>
              </div>
            </template>
            <template v-else-if="selectedElement.isConditional">
              <div class="prop-row">
                <span class="prop-label">Condition</span>
                <input class="prop-input" v-model="selectedElement.condition" @input="onPropChange" placeholder="$zone==danger">
              </div>
              <div class="text-xs text-gray-500 mt-2">
                Operateurs: <code class="text-cyan-400">== != &gt; &lt; &gt;= &lt;=</code><br>
                Combinaisons: <code class="text-cyan-400">&amp;&amp; ||</code><br>
                Ex: <code class="text-yellow-300">$zone==danger &amp;&amp; $progress&gt;0.5</code>
              </div>
            </template>
            <template v-else-if="selectedElement.isForLoop">
              <div class="prop-row"><span class="prop-label">Variable</span><input class="prop-input" v-model="selectedElement.varName" @input="onPropChange" placeholder="$i"></div>
              <div class="prop-row"><span class="prop-label">De</span><input class="prop-input" v-model="selectedElement.from" @input="onPropChange" placeholder="0"></div>
              <div class="prop-row"><span class="prop-label">A</span><input class="prop-input" v-model="selectedElement.to" @input="onPropChange" placeholder="11"></div>
              <div class="prop-row"><span class="prop-label">Pas</span><input class="prop-input" v-model="selectedElement.step" @input="onPropChange" placeholder="1"></div>
              <div class="text-xs text-gray-500 mt-2 px-1">
                <span class="text-purple-400">{{selectedElement.children ? selectedElement.children.length : 0}}</span> element(s) dans cette boucle.
              </div>
            </template>
            <template v-else>
              <div class="prop-section">Position</div>
              <div class="prop-row" v-for="(arg,ai) in argDefs" :key="'a'+arg.index">
                <span class="prop-label">{{arg.label}}</span>
                <div>
                  <div class="hl-wrap"><div class="hl-back" v-html="hlExpr(getArg(arg.index))"></div><input class="prop-input" :value="getArg(arg.index)" @input="onTextInput($event,'arg',arg.index)" @blur="hideAutocomplete" @keydown="onInputKeydown($event,'arg',arg.index,arg.step)" @keydown.escape="autocomplete.show=false" :placeholder="arg.label"></div>
                  <div v-if="resolvedValue(getArg(arg.index))" class="ed-resolved">= {{resolvedValue(getArg(arg.index))}}</div>
                </div>
              </div>
              <div v-if="isShape" class="flex gap-2 mt-2 mb-2 ml-1">
                <button class="btn btn-ghost text-xs" @click="addShapeVertex">+ Sommet</button>
                <button class="btn btn-ghost text-xs" @click="removeShapeVertex" :disabled="shapeVertexCount<=3">- Sommet</button>
                <span class="text-xs text-gray-500 self-center">{{shapeVertexCount}} pts</span>
              </div>
              <template v-if="stylePropDefs.length">
                <div class="prop-section">Style</div>
                <div class="prop-row" v-for="prop in stylePropDefs" :key="prop.key">
                  <span class="prop-label">{{prop.label}}</span>
                  <template v-if="prop.type==='color'">
                    <div class="flex items-center gap-1">
                      <input type="color" :value="propToHex(getProp(prop.key))" @input="setProp(prop.key,$event.target.value)" class="color-swatch">
                      <div class="hl-wrap hl-flex1"><div class="hl-back" v-html="hlExpr(getProp(prop.key))"></div><input class="prop-input" :value="getProp(prop.key)" @input="onTextInput($event,'prop',prop.key)" @blur="hideAutocomplete" @keydown.escape="autocomplete.show=false" placeholder="$accent"></div>
                    </div>
                  </template>
                  <template v-else-if="prop.type==='select'">
                    <select class="prop-input" :value="getProp(prop.key)" @change="setProp(prop.key,$event.target.value)">
                      <option value="">(defaut)</option>
                      <option v-for="o in prop.options" :key="o" :value="o">{{o}}</option>
                    </select>
                  </template>
                  <template v-else-if="prop.type==='bool'">
                    <input type="checkbox" :checked="hasProp(prop.key)" @change="toggleProp(prop.key,$event.target.checked)">
                  </template>
                  <template v-else>
                    <div>
                      <div class="hl-wrap"><div class="hl-back" v-html="hlExpr(getProp(prop.key))"></div><input class="prop-input" :value="getProp(prop.key)" @input="onTextInput($event,'prop',prop.key)" @blur="hideAutocomplete" @keydown="onInputKeydown($event,'prop',prop.key,prop.step)" @keydown.escape="autocomplete.show=false" :placeholder="prop.type==='number'?'0 ou $var':''"></div>
                      <div v-if="resolvedValue(getProp(prop.key))" class="ed-resolved">= {{resolvedValue(getProp(prop.key))}}</div>
                    </div>
                  </template>
                </div>
              </template>
              <template v-if="effectPropDefs.length">
                <div class="prop-section">Effets</div>
                <div class="prop-row" v-for="prop in effectPropDefs" :key="prop.key">
                  <span class="prop-label">{{prop.label}}</span>
                  <template v-if="prop.type==='color'">
                    <div class="flex items-center gap-1">
                      <input type="color" :value="propToHex(getProp(prop.key))" @input="setProp(prop.key,$event.target.value)" class="color-swatch">
                      <div class="hl-wrap hl-flex1"><div class="hl-back" v-html="hlExpr(getProp(prop.key))"></div><input class="prop-input" :value="getProp(prop.key)" @input="onTextInput($event,'prop',prop.key)" @blur="hideAutocomplete" @keydown.escape="autocomplete.show=false" placeholder="$accent"></div>
                    </div>
                  </template>
                  <template v-else>
                    <div>
                      <div class="hl-wrap"><div class="hl-back" v-html="hlExpr(getProp(prop.key))"></div><input class="prop-input" :value="getProp(prop.key)" @input="onTextInput($event,'prop',prop.key)" @blur="hideAutocomplete" @keydown="onInputKeydown($event,'prop',prop.key,prop.step)" @keydown.escape="autocomplete.show=false" :placeholder="prop.type==='number'?'0 ou $var':''"></div>
                      <div v-if="resolvedValue(getProp(prop.key))" class="ed-resolved">= {{resolvedValue(getProp(prop.key))}}</div>
                    </div>
                  </template>
                </div>
              </template>
            </template>
          </div>
        </div>
      </div>
    </div>

    <!-- ▸ TAB: Variables -->
    <div v-show="tab==='vars'" class="ed-panel ed-panel-scroll">
      <div class="p-3">
        <div class="flex items-center justify-between mb-3">
          <h3 class="text-sm font-semibold text-gray-300">Variables calculees (@var)</h3>
          <button class="btn btn-primary text-xs" @click="addVar">+ Ajouter</button>
        </div>
        <div class="text-xs text-gray-500 mb-3">
          Definissez des variables calculees a partir des donnees OBD.<br>
          Ex: <code class="text-cyan-400">@var $boost_psi = $raw * 0.145</code>
        </div>
        <div v-for="(v, i) in varEntries" :key="i" class="var-row">
          <div class="hl-wrap var-name-hl"><div class="hl-back" v-html="hlExpr(v.name)"></div><input class="prop-input var-name" v-model="v.name" @input="onVarsChange(); checkAutocomplete($event,'var-name',i)" @blur="hideAutocomplete" @keydown.escape="autocomplete.show=false" placeholder="$name"></div>
          <span class="text-gray-500">=</span>
          <div class="hl-wrap var-expr-hl"><div class="hl-back" v-html="hlExpr(v.expr)"></div><input class="prop-input var-expr" v-model="v.expr" @input="onVarsChange(); checkAutocomplete($event,'var-expr',i)" @blur="hideAutocomplete" @keydown.escape="autocomplete.show=false" placeholder="$raw * 0.145"></div>
          <span v-if="resolvedVarValue(v.name)" class="ed-resolved-pill">{{resolvedVarValue(v.name)}}</span>
          <button class="el-action-btn el-action-del" @click="removeVar(i)">&#10005;</button>
        </div>
        <div v-if="varEntries.length===0" class="ed-empty py-2">Aucune variable. Cliquez sur &quot;+ Ajouter&quot;.</div>

        <h3 class="text-sm font-semibold text-gray-300 mt-6 mb-3">Fonctions disponibles</h3>
        <div class="text-xs space-y-1 mb-4">
          <div><code class="text-green-400">clamp(val, min, max)</code> <span class="text-gray-500">Limiter entre min et max</span></div>
          <div><code class="text-green-400">min(a, b)</code> <span class="text-gray-500">Minimum de a et b</span></div>
          <div><code class="text-green-400">max(a, b)</code> <span class="text-gray-500">Maximum de a et b</span></div>
          <div><code class="text-green-400">abs(val)</code> <span class="text-gray-500">Valeur absolue</span></div>
          <div><code class="text-green-400">round(val)</code> <span class="text-gray-500">Arrondi</span></div>
          <div><code class="text-green-400">floor(val)</code> / <code class="text-green-400">ceil(val)</code> <span class="text-gray-500">Arrondi inf / sup</span></div>
          <div><code class="text-green-400">lerp(a, b, t)</code> <span class="text-gray-500">Interpolation lineaire</span></div>
          <div><code class="text-green-400">iif(cond, vrai, faux)</code> <span class="text-gray-500">Condition inline</span></div>
        </div>

        <h3 class="text-sm font-semibold text-gray-300 mt-4 mb-3">Variables DSL integrees</h3>
        <div class="text-xs space-y-2 mb-6">
          <div class="text-gray-500 mb-1">Texte</div>
          <div class="grid grid-cols-2 gap-x-4 gap-y-1 ml-2">
            <div><code class="text-cyan-400">$value</code> <span class="ed-resolved">{{renderCtx.formattedValue}}</span></div>
            <div><code class="text-cyan-400">$unit</code> <span class="ed-resolved">{{renderCtx.unit}}</span></div>
            <div><code class="text-cyan-400">$label</code> <span class="ed-resolved">{{renderCtx.label}}</span></div>
            <div><code class="text-cyan-400">$raw</code> <span class="ed-resolved">{{fmtNum(renderCtx.rawValue)}}</span></div>
            <div><code class="text-cyan-400">$percent</code> <span class="ed-resolved">{{Math.round(renderCtx.progress*100)}}%</span></div>
            <div><code class="text-cyan-400">$min</code> <span class="ed-resolved">{{renderCtx.minValue}}</span> / <code class="text-cyan-400">$max</code> <span class="ed-resolved">{{renderCtx.maxValue}}</span></div>
          </div>
          <div class="text-gray-500 mt-3 mb-1">Numerique</div>
          <div class="grid grid-cols-2 gap-x-4 gap-y-1 ml-2">
            <div><code class="text-green-400">$progress</code> <span class="ed-resolved">{{renderCtx.progress.toFixed(2)}}</span></div>
            <div><code class="text-green-400">$percent</code> <span class="ed-resolved">{{Math.round(renderCtx.progress*100)}}</span></div>
            <div><code class="text-green-400">$raw</code> <span class="ed-resolved">{{fmtNum(renderCtx.rawValue)}}</span></div>
            <div><code class="text-green-400">$whp</code> <span class="ed-resolved">{{renderCtx.warnHighProgress??'—'}}</span> / <code class="text-green-400">$dhp</code> <span class="ed-resolved">{{renderCtx.dangerHighProgress??'—'}}</span></div>
            <div><code class="text-green-400">$wlp</code> <span class="ed-resolved">{{renderCtx.warnLowProgress??'—'}}</span> / <code class="text-green-400">$dlp</code> <span class="ed-resolved">{{renderCtx.dangerLowProgress??'—'}}</span></div>
          </div>
          <div class="text-gray-500 mt-3 mb-1">Animation</div>
          <div class="grid grid-cols-2 gap-x-4 gap-y-1 ml-2">
            <div><code class="text-orange-400">$time</code> <span class="text-gray-500">Secondes (60fps)</span></div>
          </div>
          <div class="text-gray-500 mt-3 mb-1">Couleurs</div>
          <div class="grid grid-cols-2 gap-x-4 gap-y-1 ml-2">
            <div><code class="text-purple-400">$accent</code> <span class="ed-resolved" :style="{color:renderCtx.accentColor}">{{renderCtx.accentColor}}</span></div>
            <div><code class="text-purple-400">$zone_color</code> <span class="ed-resolved">{{renderCtx.zone}}</span></div>
          </div>
          <div class="text-gray-500 mt-3 mb-1">Conditions</div>
          <div class="ml-2">
            <div><code class="text-yellow-400">$zone==danger</code>, <code class="text-yellow-400">$progress&gt;0.8</code></div>
            <div class="text-gray-500 mt-1">Combinaisons: <code class="text-yellow-400">&amp;&amp; ||</code></div>
          </div>

          <!-- Multi-value binding variables -->
          <template v-if="dataBindings.length > 0">
            <div class="text-gray-500 mt-3 mb-1">Donnees secondaires</div>
            <div v-for="(b, bi) in dataBindings" :key="'ref-'+b.type" class="ml-2 mb-2">
              <div class="text-xs font-semibold mb-1" :style="{ color: (PREVIEW_TYPES.find(t=>t.key===b.type)||{}).accent || '#aaa' }">{{ (PREVIEW_TYPES.find(t=>t.key===b.type)||{}).label }} (#{{ bi+1 }})</div>
              <div class="grid grid-cols-2 gap-x-4 gap-y-1 ml-2">
                <div><code class="text-cyan-400">$value-{{b.type}}</code> <span class="text-gray-600">ou</span> <code class="text-cyan-400">$value-{{bi+1}}</code></div>
                <div><code class="text-green-400">$progress-{{b.type}}</code> <span class="text-gray-600">ou</span> <code class="text-green-400">$progress-{{bi+1}}</code></div>
                <div><code class="text-cyan-400">$unit-{{b.type}}</code> <span class="text-gray-600">ou</span> <code class="text-cyan-400">$unit-{{bi+1}}</code></div>
                <div><code class="text-cyan-400">$label-{{b.type}}</code> <span class="text-gray-600">ou</span> <code class="text-cyan-400">$label-{{bi+1}}</code></div>
                <div><code class="text-purple-400">$accent-{{b.type}}</code> <span class="text-gray-600">ou</span> <code class="text-purple-400">$accent-{{bi+1}}</code></div>
                <div><code class="text-green-400">$zone-{{b.type}}</code> <span class="text-gray-600">ou</span> <code class="text-green-400">$zone-{{bi+1}}</code></div>
                <div><code class="text-green-400">$raw-{{b.type}}</code> <span class="text-gray-600">ou</span> <code class="text-green-400">$raw-{{bi+1}}</code></div>
                <div><code class="text-green-400">$min-{{b.type}}</code> / <code class="text-green-400">$max-{{b.type}}</code></div>
              </div>
            </div>
          </template>
          <div v-else class="text-gray-600 mt-3 text-xs italic">
            Ajoutez des donnees secondaires dans les <button class="text-cyan-500 underline" style="font-size:inherit;background:none;border:none;padding:0;cursor:pointer" @click="showPreviewSettings=true">reglages de previsualisation</button> pour utiliser des variables multi-valeur.
          </div>
        </div>
      </div>
    </div>

    <!-- ▸ TAB: Code -->
    <div v-show="tab==='code'" class="ed-panel ed-panel-code">
      <div class="ed-panel-toolbar">
        <span class="text-xs text-gray-400">Edition bidirectionnelle</span>
        <button class="btn btn-ghost text-xs" @click="formatCode">Formater</button>
      </div>
      <textarea class="ed-code-area" v-model="codeText" @input="onCodeInput" spellcheck="false"></textarea>
    </div>

    <!-- ▸ TAB: Presets -->
    <div v-show="tab==='io'" class="ed-panel ed-panel-scroll">
      <div class="p-3">
        <h3 class="text-sm font-semibold text-gray-300 mb-3">Presets</h3>
        <div class="mb-3">
          <div class="text-xs text-gray-500 mb-2">Basiques</div>
          <div class="grid grid-cols-3 gap-2">
            <button v-for="p in basicPresets" :key="p.name" class="preset-card" @click="loadPreset(p)">
              <canvas :id="'preset-'+p.name.replace(/\s+/g,'_')" width="80" height="80" class="preset-thumb"></canvas>
              <div class="preset-name">{{p.name}}</div>
            </button>
          </div>
        </div>
        <div class="mb-6">
          <div class="text-xs text-gray-500 mb-2">Avances <span class="text-cyan-600">(@var, fonctions, conditions)</span></div>
          <div class="grid grid-cols-3 gap-2">
            <button v-for="p in advancedPresets" :key="p.name" class="preset-card" @click="loadPreset(p)">
              <canvas :id="'preset-'+p.name.replace(/\s+/g,'_')" width="80" height="80" class="preset-thumb"></canvas>
              <div class="preset-name">{{p.name}}</div>
              <div class="preset-tags" v-if="p.tags">{{p.tags.join(' ')}}</div>
            </button>
          </div>
        </div>

        <h3 class="text-sm font-semibold text-gray-300 mb-3">Mes cadrans</h3>
        <div v-if="savedFaces.length===0" class="ed-empty mb-4">Aucun cadran sauvegarde.</div>
        <div v-else class="space-y-1 mb-4">
          <div v-for="(sf,si) in savedFaces" :key="si"
            class="flex items-center gap-2 px-3 py-2 rounded bg-gray-800 hover:bg-gray-700 cursor-pointer group"
            @click="loadFaceFromLibrary(si)">
            <span class="flex-1 text-xs text-gray-300">{{sf.name}}</span>
            <button class="text-xs text-red-400 opacity-0 group-hover:opacity-100 transition-opacity" @click.stop="deleteFaceFromLibrary(si)" title="Supprimer">&#10005;</button>
          </div>
        </div>
      </div>
    </div>

  </div>
</div>

<!-- ═══ MOBILE BOTTOM NAV ═══ -->
<nav class="ed-bottom-nav">
  <button class="ed-nav-item" :class="{active:tab==='elements'}" @click="tab='elements'">
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></svg>
    <span>Calques</span>
  </button>
  <button class="ed-nav-item" :class="{active:tab==='vars'}" @click="tab='vars'">
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="4" y1="9" x2="20" y2="9"/><line x1="4" y1="15" x2="20" y2="15"/><line x1="10" y1="3" x2="8" y2="21"/><line x1="16" y1="3" x2="14" y2="21"/></svg>
    <span>Variables</span>
  </button>
  <button class="ed-nav-item" :class="{active:tab==='code'}" @click="tab='code'">
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
    <span>Code</span>
  </button>
  <button class="ed-nav-item" :class="{active:tab==='io'}" @click="tab='io'">
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
    <span>Presets</span>
  </button>
</nav>

<!-- ═══ ADD ELEMENT MODAL ═══ -->
<div v-if="showPalette" class="ed-overlay" @click.self="showPalette=false">
  <div class="ed-add-panel" @click.stop>
    <div class="ed-sheet-handle"></div>
    <div class="ed-add-header">
      <h3 class="text-sm font-semibold text-gray-200">Ajouter un element</h3>
      <button class="ed-close-btn" @click="showPalette=false">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
      </button>
    </div>
    <div class="ed-add-body">
      <div v-for="cat in categories" :key="cat.key">
        <div class="cat-header">{{cat.icon}} {{cat.label}}</div>
        <div class="palette-grid">
          <div v-for="(def, type) in typesInCategory(cat.key)" :key="type"
            class="palette-item" @click="addElementOfType(type)">
            <span class="palette-icon">{{def.icon}}</span>
            <div class="palette-info">
              <div class="palette-name">{{type}}</div>
              <div class="palette-desc">{{def.desc}}</div>
            </div>
          </div>
        </div>
      </div>
      <div class="ed-add-conditional" @click="addConditional">
        <span class="text-yellow-400 text-base">&#9888;</span>
        <div>
          <div class="text-xs text-yellow-300 font-medium">Bloc conditionnel (if)</div>
          <div class="text-xs text-gray-500">Afficher des elements selon une condition</div>
        </div>
      </div>
      <div class="ed-add-conditional" @click="addGroup" style="border-color:rgba(96,165,250,0.3)">
        <span class="text-blue-400 text-base">&#128193;</span>
        <div>
          <div class="text-xs text-blue-300 font-medium">Groupe</div>
          <div class="text-xs text-gray-500">Regrouper des elements ensemble</div>
        </div>
      </div>
      <div class="ed-add-conditional" @click="addForLoop" style="border-color:rgba(192,132,252,0.3)">
        <span class="text-purple-400 text-base">&#128260;</span>
        <div>
          <div class="text-xs text-purple-300 font-medium">Boucle for</div>
          <div class="text-xs text-gray-500">Repeter des elements avec une variable</div>
        </div>
      </div>
      <div class="ed-add-conditional" @click="importSVGFile()" style="border-color:rgba(168,85,247,0.3)">
        <span class="text-purple-400 text-base">&#10697;</span>
        <div>
          <div class="text-xs text-purple-300 font-medium">Importer un SVG</div>
          <div class="text-xs text-gray-500">Convertir un fichier SVG en elements DSL</div>
        </div>
      </div>
      <input type="file" ref="svgFileInput" accept=".svg" style="display:none" @change="onSVGFileSelected">
    </div>
  </div>
  </template><!-- /v-if activeCell >= 0 -->
</div>

<!-- ═══ DESKTOP MENU CLICK-AWAY ═══ -->
<div v-if="activeMenu && activeMenu!=='mobile'" class="ed-menu-clickaway" @click="activeMenu=null"></div>

<!-- ═══ DESKTOP: Fichier dropdown ═══ -->
<div v-if="activeMenu==='fichier'" class="ed-dropdown" :style="menuStyle('fichier')">
  <button class="ed-dropdown-item" @click="saveFaceToLibrary(); activeMenu=null">
    <span>Sauvegarder</span><span class="ed-dropdown-sc">Ctrl+S</span>
  </button>
  <div class="ed-dropdown-sep"></div>
  <button class="ed-dropdown-item" @click="importFile(); activeMenu=null">
    <span>Importer un fichier</span>
  </button>
  <button class="ed-dropdown-item" @click="startQrScan(); activeMenu=null">
    <span>Scanner un QR code</span>
  </button>
  <div class="ed-dropdown-sep"></div>
  <button class="ed-dropdown-item" @click="exportFile(); activeMenu=null">
    <span>Exporter en fichier</span>
  </button>
  <button class="ed-dropdown-item" @click="showQrExport(); activeMenu=null">
    <span>Exporter en QR code</span>
  </button>
  <div class="ed-dropdown-sep"></div>
  <button class="ed-dropdown-item" @click="copyCode(); activeMenu=null">
    <span>Copier le code DSL</span>
  </button>
</div>

<!-- ═══ DESKTOP: Edition dropdown ═══ -->
<div v-if="activeMenu==='edition'" class="ed-dropdown" :style="menuStyle('edition')">
  <button class="ed-dropdown-item" @click="undo(); activeMenu=null" :disabled="!canUndo">
    <span>Annuler</span><span class="ed-dropdown-sc">Ctrl+Z</span>
  </button>
  <button class="ed-dropdown-item" @click="redo(); activeMenu=null" :disabled="!canRedo">
    <span>Retablir</span><span class="ed-dropdown-sc">Ctrl+Shift+Z</span>
  </button>
  <div class="ed-dropdown-sep"></div>
  <button class="ed-dropdown-item" :disabled="selectedIds.length===0" @click="copySelection(); activeMenu=null">
    <span>{{multiSelected ? 'Copier '+selectedIds.length+' elements' : 'Copier l\'element'}}</span><span class="ed-dropdown-sc">Ctrl+C</span>
  </button>
  <button class="ed-dropdown-item" @click="pasteClipboard(); activeMenu=null">
    <span>Coller</span><span class="ed-dropdown-sc">Ctrl+V</span>
  </button>
  <button class="ed-dropdown-item" :disabled="selectedIds.length===0" @click="duplicateSelection(); activeMenu=null">
    <span>Dupliquer</span><span class="ed-dropdown-sc">Ctrl+D</span>
  </button>
  <div class="ed-dropdown-sep"></div>
  <button class="ed-dropdown-item" :disabled="selectedIds.length===0 || (selectedIds.length===1 && selectedElement && selectedElement.isGroup)" @click="groupSelection(); activeMenu=null">
    <span>Grouper</span>
  </button>
  <button class="ed-dropdown-item" :disabled="!selectedElement || !selectedElement.isGroup" @click="ungroupSelected(); activeMenu=null">
    <span>Degrouper</span>
  </button>
  <div class="ed-dropdown-sep"></div>
  <button class="ed-dropdown-item ed-dropdown-danger" :disabled="selectedIds.length===0" @click="deleteSelection(); activeMenu=null">
    <span>Supprimer</span><span class="ed-dropdown-sc">Suppr</span>
  </button>
</div>

<!-- ═══ DESKTOP: Insertion dropdown ═══ -->
<div v-if="activeMenu==='insertion'" class="ed-dropdown ed-dropdown-insert" :style="menuStyle('insertion')">
  <template v-for="cat in categories" :key="cat.key">
    <div class="ed-dropdown-header">{{cat.icon}} {{cat.label}}</div>
    <button v-for="(def, type) in typesInCategory(cat.key)" :key="type"
      class="ed-dropdown-item" @click="addElementOfType(type); activeMenu=null">
      <span class="ed-dropdown-icon">{{def.icon}}</span>
      <span>{{type}}</span>
      <span class="ed-dropdown-desc">{{def.desc}}</span>
    </button>
  </template>
  <div class="ed-dropdown-sep"></div>
  <button class="ed-dropdown-item" @click="addConditional(); activeMenu=null">
    <span class="ed-dropdown-icon" style="color:#fbbf24">&#9888;</span>
    <span>Bloc conditionnel (if)</span>
  </button>
  <button class="ed-dropdown-item" @click="addGroup(); activeMenu=null">
    <span class="ed-dropdown-icon" style="color:#60a5fa">&#128193;</span>
    <span>Groupe</span>
  </button>
  <button class="ed-dropdown-item" @click="addForLoop(); activeMenu=null">
    <span class="ed-dropdown-icon" style="color:#c084fc">&#128260;</span>
    <span>Boucle for</span>
  </button>
</div>

<!-- ═══ MOBILE MENU SHEET ═══ -->
<div v-if="activeMenu==='mobile'" class="ed-overlay" @click.self="activeMenu=null">
  <div class="ed-sheet" @click.stop>
    <div class="ed-sheet-handle"></div>
    <div class="ed-mobile-section">Fichier</div>
    <button class="ed-mobile-menu-item" @click="saveFaceToLibrary(); activeMenu=null">Sauvegarder</button>
    <button class="ed-mobile-menu-item" @click="importFile(); activeMenu=null">Importer un fichier</button>
    <button class="ed-mobile-menu-item" @click="exportFile(); activeMenu=null">Exporter en fichier</button>
    <button class="ed-mobile-menu-item" @click="copyCode(); activeMenu=null">Copier le code DSL</button>
    <button class="ed-mobile-menu-item" @click="startQrScan(); activeMenu=null">Scanner un QR code</button>
    <button class="ed-mobile-menu-item" @click="showQrExport(); activeMenu=null">Exporter en QR code</button>
    <div class="ed-mobile-section">Edition</div>
    <button class="ed-mobile-menu-item" @click="undo(); activeMenu=null" :disabled="!canUndo">Annuler</button>
    <button class="ed-mobile-menu-item" @click="redo(); activeMenu=null" :disabled="!canRedo">Retablir</button>
    <button class="ed-mobile-menu-item" :disabled="selectedIds.length===0" @click="copySelection(); activeMenu=null">{{multiSelected ? 'Copier '+selectedIds.length+' elements' : 'Copier l\'element'}}</button>
    <button class="ed-mobile-menu-item" @click="pasteClipboard(); activeMenu=null">Coller</button>
    <button class="ed-mobile-menu-item" :disabled="selectedIds.length===0" @click="duplicateSelection(); activeMenu=null">Dupliquer</button>
    <button class="ed-mobile-menu-item" :disabled="selectedIds.length===0 || (selectedIds.length===1 && selectedElement && selectedElement.isGroup)" @click="groupSelection(); activeMenu=null">Grouper</button>
    <button class="ed-mobile-menu-item" :disabled="!selectedElement || !selectedElement.isGroup" @click="ungroupSelected(); activeMenu=null">Degrouper</button>
    <button class="ed-mobile-menu-item ed-dropdown-danger" :disabled="selectedIds.length===0" @click="deleteSelection(); activeMenu=null">Supprimer</button>
    <div class="ed-mobile-section">Insertion</div>
    <button class="ed-mobile-menu-item" @click="showPalette=true; activeMenu=null">Ajouter un element...</button>
    <div class="ed-mobile-shortcuts">
      <div><kbd>Ctrl+Z</kbd> / <kbd>Ctrl+Shift+Z</kbd> Annuler / Retablir</div>
      <div><kbd>Ctrl+C</kbd> / <kbd>V</kbd> / <kbd>D</kbd> Copier / Coller / Dupliquer</div>
      <div><kbd>&#8593;&#8595;&#8592;&#8594;</kbd> Deplacer &bull; <kbd>Suppr</kbd> Effacer</div>
    </div>
  </div>
</div>

<!-- ═══ PREVIEW SETTINGS SHEET ═══ -->
<div v-if="showPreviewSettings" class="ed-overlay" @click.self="showPreviewSettings=false">
  <div class="ed-sheet" @click.stop>
    <div class="ed-sheet-handle"></div>
    <h3 class="text-sm font-semibold text-gray-200 mb-4">Previsualisation</h3>
    <div class="ed-setting-row">
      <span class="text-xs text-gray-400">Couleur d'accent</span>
      <input type="color" v-model="renderCtx.accentColor" @input="renderCanvas" class="ed-color-input">
    </div>
    <div class="ed-setting-row">
      <span class="text-xs text-gray-400">Fond</span>
      <div class="flex items-center gap-2">
        <input type="color" v-model="previewBg" @input="renderCanvas(); savePreviewBg()" class="ed-color-input">
        <button class="btn btn-ghost text-xs" @click="loadPreviewBgImage">&#128444; Image</button>
        <button v-if="previewBgImage" class="btn btn-ghost text-xs" @click="clearPreviewBg">&#10005;</button>
      </div>
    </div>
    <div class="ed-setting-row">
      <span class="text-xs text-gray-400">Seuils</span>
      <label class="ed-switch">
        <input type="checkbox" v-model="showThresholds" @change="renderCanvas">
        <span class="ed-switch-track"><span class="ed-switch-thumb"></span></span>
      </label>
    </div>
    <template v-if="showThresholds">
      <div class="ed-setting-row">
        <span class="text-xs text-yellow-400">Warning (%)</span>
        <input type="number" v-model.number="thresholdWarnHigh" min="0" max="100" step="5" class="ed-num-input" @input="updateThresholds">
      </div>
      <div class="ed-setting-row">
        <span class="text-xs text-red-400">Danger (%)</span>
        <input type="number" v-model.number="thresholdDangerHigh" min="0" max="100" step="5" class="ed-num-input" @input="updateThresholds">
      </div>
    </template>

    <!-- Data Bindings (multi-value) -->
    <h4 class="text-xs font-semibold text-gray-300 mt-4 mb-2">Donnees secondaires</h4>
    <div v-for="(b, idx) in dataBindings" :key="b.type" class="ed-setting-row" style="flex-wrap:wrap;gap:4px">
      <span class="text-xs" :style="{ color: (PREVIEW_TYPES.find(t=>t.key===b.type)||{}).accent || '#aaa' }">{{ (PREVIEW_TYPES.find(t=>t.key===b.type)||{}).label }}</span>
      <div class="flex items-center gap-2" style="flex:1;min-width:0">
        <input type="range" :min="(PREVIEW_TYPES.find(t=>t.key===b.type)||{}).min||0" :max="(PREVIEW_TYPES.find(t=>t.key===b.type)||{}).max||100" :step="(PREVIEW_TYPES.find(t=>t.key===b.type)||{}).decimals>0?0.1:1" v-model.number="b.value" @input="onBindingValueChange" style="flex:1;min-width:60px">
        <span class="text-xs text-gray-500" style="width:40px;text-align:right">{{ (PREVIEW_TYPES.find(t=>t.key===b.type)||{}).decimals>0 ? b.value.toFixed(1) : Math.round(b.value) }}</span>
        <button class="btn btn-ghost text-xs" style="padding:2px 6px;color:#FF6B6B" @click="removeDataBinding(idx)">&times;</button>
      </div>
      <div class="text-xs text-gray-600" style="width:100%">$value-{{ b.type }}, $progress-{{ b.type }}...</div>
    </div>
    <div class="ed-setting-row">
      <select class="ed-num-input" style="flex:1" @change="addDataBinding($event.target.value); $event.target.value=''">
        <option value="">+ Ajouter une donnee...</option>
        <option v-for="t in availableBindingTypes()" :key="t.key" :value="t.key">{{ t.label }} ({{ t.unit }})</option>
      </select>
    </div>

    <div class="flex justify-end mt-4 pt-3 border-t border-gray-700">
      <button class="btn btn-primary" @click="showPreviewSettings=false">Fermer</button>
    </div>
  </div>
</div>

<!-- Hidden file inputs -->
<input type="file" ref="bgInput" accept="image/*" @change="onBgImport" class="hidden">
<input type="file" ref="fileInput" accept=".txt,.face,.dsl" @change="onFileImport" class="hidden">
<input type="file" ref="cellFileInput" accept=".txt,.face,.dsl" @change="onCellFileImport" class="hidden">

<!-- New Cell Modal -->
<div v-if="cellPickerModal.show" class="ed-overlay" @click.self="cellPickerModal.show=false">
  <div class="ed-modal ed-cell-picker">
    <h3 class="text-sm font-semibold mb-4" style="color:#ccc">Ajouter un cadran</h3>

    <div class="cell-picker-section">
      <button class="cell-picker-btn" @click="cellPickerNewBlank">
        <span class="cell-picker-icon">+</span>
        <span>Cadran vide</span>
      </button>
      <button class="cell-picker-btn" @click="cellPickerImportFile">
        <span class="cell-picker-icon">&#128194;</span>
        <span>Importer un fichier</span>
      </button>
    </div>

    <div v-if="savedFaces.length" class="cell-picker-section">
      <div class="cell-picker-label">Cadrans sauvegardes</div>
      <div class="cell-picker-grid">
        <button v-for="(f,i) in savedFaces" :key="'saved-'+i" class="cell-picker-card" @click="cellPickerLoadSaved(i)">
          <canvas :id="'cellpick-saved-'+i" width="64" height="64" class="cell-picker-thumb"></canvas>
          <span class="cell-picker-name">{{f.name}}</span>
        </button>
      </div>
    </div>

    <div class="cell-picker-section">
      <div class="cell-picker-label">Presets</div>
      <div class="cell-picker-grid">
        <button v-for="(p,i) in presets" :key="'preset-'+i" class="cell-picker-card" @click="cellPickerLoadPreset(i)">
          <canvas :id="'cellpick-preset-'+i" width="64" height="64" class="cell-picker-thumb"></canvas>
          <span class="cell-picker-name">{{p.name}}</span>
        </button>
      </div>
    </div>

    <div class="flex justify-end mt-3">
      <button class="btn" @click="cellPickerModal.show=false">Annuler</button>
    </div>
  </div>
</div>

<!-- QR Export Modal -->
<div v-if="qrModal" class="ed-overlay" @click.self="qrModal=false;qrFullscreen=false">
  <div :class="qrFullscreen ? 'fixed inset-0 bg-gray-900 flex flex-col items-center justify-center z-50 cursor-pointer' : 'ed-modal'" @click.self="qrFullscreen && (qrFullscreen=false)">
    <h3 v-if="!qrFullscreen" class="text-sm font-semibold mb-4">QR Code du cadran</h3>
    <div :class="qrFullscreen ? 'flex items-center justify-center flex-1' : 'flex justify-center mb-4'">
      <canvas id="qrCanvas"></canvas>
    </div>
    <div :class="qrFullscreen ? 'flex gap-2 pb-6' : 'flex justify-end gap-2'">
      <button class="btn btn-ghost" @click.stop="qrFullscreen=!qrFullscreen;$nextTick(()=>showQrExport())">
        {{ qrFullscreen ? 'Réduire' : 'Plein écran' }}
      </button>
      <button class="btn btn-ghost" @click="qrModal=false;qrFullscreen=false">Fermer</button>
    </div>
  </div>
</div>

<!-- QR Scan Modal -->
<div v-if="qrScanModal" class="ed-overlay" @click.self="stopQrScan">
  <div class="ed-modal">
    <h3 class="text-sm font-semibold mb-4">Scanner un QR code</h3>
    <div id="qr-reader" style="width:100%"></div>
    <div class="mt-4 border-t border-gray-700 pt-3">
      <p class="text-xs text-gray-400 mb-2">Ou depuis une image :</p>
      <input type="file" accept="image/*" @change="onQrFileScan" class="text-xs text-gray-400">
    </div>
    <div class="flex justify-end mt-4">
      <button class="btn btn-ghost" @click="stopQrScan">Fermer</button>
    </div>
  </div>
</div>

<!-- Autocomplete dropdown -->
<div v-if="autocomplete.show" class="ac-dropdown" :style="{left:autocomplete.x+'px',top:autocomplete.y+'px'}" ref="acList">
  <div v-for="item in autocomplete.items" :key="item.name" class="ac-item" tabindex="-1"
    @mousedown.prevent="insertAutocomplete(item.name)">
    <span :class="item.name.startsWith('$') ? 'text-cyan-400' : 'text-green-400'" class="font-mono">{{item.name}}</span>
    <span class="text-gray-500 ml-2">{{item.desc}}</span>
  </div>
</div>

<!-- Toast -->
<div v-if="toast" class="ed-toast">{{toast}}</div>

</div>

<!-- Scripts -->
<script src="js/dsl/presets.js"></script>
<script src="js/dsl/parser.js"></script>
<script src="js/dsl/expr.js"></script>
<script src="js/dsl/svg-import.js"></script>
<script src="js/renderer.js"></script>
<script src="js/editor/types.js"></script>
<script src="js/editor/interactions.js"></script>
<script src="js/editor/elements.js"></script>
<script src="js/editor/sync.js"></script>
<script src="js/editor/props.js"></script>
<script src="js/editor/app.js"></script>
</body>
</html>
