/* ============================================================
   BUREAU DE BEAUFORT — ÉDITEUR DE TEMPLATE (css/editeur.css)
   ------------------------------------------------------------
   theme.css contient déjà tout le vocabulaire visuel de l'éditeur
   (.editeur/.panneau/.chips/.chip/.recap-prix/.scene-apercu/
   .carte-physique/.texte-manuscrit/.curseur-plume/.bascule…).
   Ce fichier n'ajoute QUE ce qui manque : le champ « Votre message »
   (highlighted textarea), l'aperçu police vivante dans la carte et
   les notes d'aperçu (débordement / variables).
   ============================================================ */

/* Message inline de l'éditeur (état d'enregistrement / info ponctuelle),
   au-dessus du bouton « Enregistrer le template ». */
#msg-rendu-reel{background:var(--papier-2); border-radius:var(--rayon-ctrl); padding:10px 12px; margin-top:0}

/* Spinner + message d'erreur PARTAGÉS avec l'aperçu témoin des campagnes
   (campagnes.js réutilise .rendu-reel-spinner / .roue / .rendu-reel-erreur) —
   conservés ici tant que campagnes.css n'a pas ses propres classes. */
.rendu-reel-spinner{
  display:flex; flex-direction:column; align-items:center; gap:10px;
  color:var(--encre-doux); font-size:.85rem;
}
.rendu-reel-spinner .roue{
  width:26px; height:26px; border-radius:50%;
  border:3px solid var(--ligne); border-top-color:var(--accent);
  animation:tourne .8s linear infinite;
}
@keyframes tourne{to{transform:rotate(360deg)}}
.rendu-reel-erreur{color:var(--cire); font-size:.85rem}

/* ============================================================
   CHAMP « VOTRE MESSAGE » — éditeur de texte CLAIR (highlighted
   textarea). Un textarea TRANSPARENT au-dessus d'un div de
   surlignage : le caret natif se place au clic, le div peint le
   même texte avec les {{variables}} en jetons colorés + littéraux.
   PIÈGE CLÉ : le textarea et le div DOIVENT avoir des métriques
   STRICTEMENT identiques (font, line-height, padding, box-sizing,
   white-space, word-break) sinon le surlignage se décale du texte.
   -> la classe commune ci-dessous fixe ces métriques pour les deux.
   ============================================================ */
.editeur-texte{position:relative}
.editeur-texte .saisie-claire,
.editeur-texte .surlignage{
  /* métriques PARTAGÉES (doivent coïncider au pixel près) */
  font-family:'Inter',sans-serif; font-size:.92rem; line-height:1.55;
  letter-spacing:normal; padding:11px 13px;
  border:1px solid transparent; border-radius:var(--rayon-ctrl);
  box-sizing:border-box; width:100%;
  white-space:pre-wrap; word-break:break-word; overflow-wrap:break-word;
  min-height:170px; max-height:340px;
  /* La gouttière de barre de défilement DOIT être réservée IDENTIQUEMENT sur
     les deux couches : sinon, quand le textarea affiche sa scrollbar (texte
     long > max-height), sa largeur de texte rétrécit alors que le div reste
     pleine largeur -> le retour à la ligne diverge et le surlignage se
     décale du caret (piège classique du highlighted-textarea). */
  scrollbar-gutter:stable;
}
/* Textarea au-dessus : texte transparent, SEUL le caret est visible,
   il reçoit les clics/frappe (caret natif positionnable = clic = curseur). */
.editeur-texte .saisie-claire{
  position:relative; z-index:2; display:block; margin:0; resize:none;
  background:transparent; color:transparent; caret-color:var(--encre);
  border-color:var(--ligne); overflow:auto; -webkit-text-fill-color:transparent;
}
.editeur-texte .saisie-claire:focus{outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-voile)}
/* Div de surlignage dessous : peint le texte + les jetons. Ne reçoit
   aucun clic (le textarea au-dessus s'en charge). overflow:hidden : le
   scroll est recopié depuis le textarea par editeur.js. */
.editeur-texte .surlignage{
  position:absolute; inset:0; z-index:1; margin:0;
  color:var(--encre); background:var(--blanc-carte);
  overflow:hidden; pointer-events:none; user-select:none;
}
/* Jeton {{variable}} : littéral, coloré. Le padding horizontal est ANNULÉ par
   une marge négative égale -> l'avance inline du jeton = celle du texte brut du
   textarea (sinon chaque jeton pousserait le texte suivant de 4px et décalerait
   le caret, cumulativement). box-decoration-break:clone garde le fond correct. */
.editeur-texte .surlignage .jeton{
  color:var(--accent-fonce); background:var(--accent-voile);
  border-radius:5px; padding:0 2px; margin:0 -2px;
  box-decoration-break:clone; -webkit-box-decoration-break:clone;
}
/* Jeton mal formé ({{...}} non-\w, jamais substitué côté serveur) : signalé. */
.editeur-texte .surlignage .jeton.invalide{
  color:var(--cire); background:color-mix(in srgb, var(--cire) 14%, transparent);
}
#note-variables code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.86em;background:var(--papier-2);padding:1px 4px;border-radius:4px}

/* ============================================================
   OPTIONS DE TEXTE (T-079) — alignement + taille du bloc manuscrit.
   Réglages qui se répercutent à l'écran ET sur le tracé (police vivante).
   ============================================================ */
.opt-texte{display:flex;flex-direction:column;gap:12px}
.opt-alignement{display:flex;gap:6px;flex-wrap:wrap}
.opt-alignement button{
  flex:1;min-width:64px;padding:7px 8px;font-size:.8rem;
  border:1px solid var(--ligne);border-radius:var(--rayon-ctrl);
  background:var(--blanc-carte);color:var(--encre-doux);cursor:pointer;
}
.opt-alignement button:hover{border-color:var(--accent);color:var(--accent-fonce)}
.opt-alignement button.actif{border-color:var(--accent);background:var(--accent-voile);color:var(--accent-fonce);font-weight:600}
.opt-taille{display:flex;flex-direction:column;gap:4px}
.opt-taille .lib-sec{font-size:.8rem;color:var(--encre-doux)}
.opt-taille input[type=range]{width:100%;accent-color:var(--accent)}
#opt-taille-val{color:var(--accent-fonce);font-weight:600}

/* ============================================================
   ÉLÉMENTS IMPRIMÉS COMPOSABLES (T-079) — logo + texte imprimé.
   Overlay % sur la carte (couche laser, distincte du manuscrit).
   Le conteneur est pointer-events:none : seuls les éléments captent
   la souris (les clics à vide retombent sur l'aperçu manuscrit).
   ============================================================ */
/* ============================================================
   MODÈLE « DIAPO » (refonte type PowerPoint) : la carte EST la slide.
   Barre d'insertion au-dessus, blocs déplaçables dedans, barre d'outils
   FLOTTANTE au-dessus du bloc sélectionné, guides d'alignement.
   ============================================================ */
/* ---- RUBAN (façon PowerPoint) : commandes groupées, toujours visibles ---- */
.ruban{
  /* ★ Le ruban COLLE à la zone d'édition (demande d'Hubert, 30/07/2026 :
     « un peu d'espace entre la barre d'outils et le haut de la zone
     d'édition ... pour que ça colle »). Mesuré au banc de gestes : 14 px
     de vide pur ici + 8 px sous la barre de vue. Rendus à la feuille — la
     boîte de référence de l'échelle est globale et figée, les 3 formats
     grandissent donc du MÊME ratio (invariant D-088 préservé). */
  display:flex;align-items:stretch;gap:0;flex-wrap:wrap;margin:0 0 2px;
  background:var(--blanc-carte);border:1px solid var(--ligne);border-radius:var(--rayon);
  padding:6px 4px 3px;box-shadow:var(--ombre);
}
.ruban .grp{display:flex;flex-direction:column;gap:3px;padding:0 10px;border-right:1px solid var(--ligne)}
.ruban .grp:last-child{border-right:0}
.ruban .grp-corps{display:flex;align-items:center;gap:3px;flex-wrap:wrap;min-height:30px}
.ruban .grp-nom{font-size:.63rem;letter-spacing:.05em;text-transform:uppercase;color:var(--encre-doux);text-align:center}
.ruban .rb-col{display:flex;flex-direction:column;gap:4px}
.ruban .rb-ligne{display:flex;align-items:center;gap:4px}
.ruban button{
  font:inherit;font-size:.85rem;line-height:1;cursor:pointer;min-width:28px;height:28px;
  padding:0 7px;border:1px solid transparent;border-radius:6px;background:transparent;color:var(--encre);
  display:inline-flex;align-items:center;justify-content:center;
}
/* Icônes fines (alignement, organiser) — même gabarit que le ruban PowerPoint. */
.ruban .ic-al{width:16px;height:16px;fill:currentColor;display:block}
/* Boutons d'INSERTION : icône AU-DESSUS, libellé DESSOUS (format PPT). */
.ruban .ins-btn{
  flex-direction:column;gap:3px;height:auto;min-width:60px;padding:5px 8px 4px;
  font-size:.7rem;color:var(--encre);white-space:nowrap;
}
.ruban .ins-btn .ic-ins{width:26px;height:26px;display:block;color:var(--accent-fonce)}
.ruban .ins-btn:hover .ic-ins{color:var(--accent)}
.ruban .ins-btn span{line-height:1.1}
.ruban .tb-sep{width:1px;height:18px;background:var(--ligne);margin:0 3px;display:inline-block}
.ruban button:hover:not(:disabled){background:var(--papier-2);border-color:var(--ligne)}
.ruban button.actif{background:var(--accent-voile);border-color:var(--accent);color:var(--accent-fonce)}
.ruban button:disabled{opacity:.32;cursor:default}
.ruban button sup,.ruban button sub{font-size:.6em}
.ruban select,.ruban input[type=number]{
  font:inherit;font-size:.82rem;height:28px;padding:0 6px;border:1px solid var(--ligne);
  border-radius:6px;background:var(--blanc-carte);color:var(--encre);width:auto;
}
.ruban select{max-width:150px}
.ruban select:disabled,.ruban input:disabled{opacity:.4}
.ruban input[type=number]{width:52px}
.ruban input[type=color]{width:28px;height:28px;padding:0;border:1px solid var(--ligne);border-radius:6px;background:none;cursor:pointer}
/* Icônes d'alignement : on rend les 4 boutons distincts visuellement. */
#rb-aligns button[data-al="gauche"]{text-align:left}
#rb-aligns button[data-al="centre"]{text-align:center}
#rb-aligns button[data-al="droite"]{text-align:right}
#rb-aligns button[data-al="justifie"]{letter-spacing:-1px}

/* ---- Grille 3 colonnes SANS SCROLL : réglages | diapo | prix ---- */
/* ============================================================
   MISE EN PAGE PLEIN ÉCRAN (façon PowerPoint) : ruban en haut (centré),
   réglages à gauche (largeur fixe), PRIX calé à droite, et la VISIONNEUSE
   au centre qui prend tout l'espace restant, sur tous les écrans.
   ============================================================ */
/* ★ L'éditeur est un ATELIER plein écran : on lève le gabarit de lecture
   (.page{max-width:1240px}) qui laissait ~470 px inutilisés à droite, et on
   réduit les marges pour que la visionneuse et le panneau prix aillent
   jusqu'aux bords. */
#page-editeur.page.actif{
  display:flex;flex-direction:column;height:var(--h-editeur, calc(100vh - 104px));min-height:520px;
  max-width:none;width:100%;padding:14px 10px 12px;
}
.editeur.editeur-ppt{
  display:grid;   /* explicite : ne dépend plus de theme.css */
  grid-template-columns:248px minmax(0,1fr) 250px;gap:16px;align-items:stretch;
  flex:1;min-height:0;
}
@media (max-width:1450px){.editeur.editeur-ppt{grid-template-columns:226px minmax(0,1fr) 228px;gap:12px}}
@media (max-width:1180px){
  #page-editeur.page.actif{height:auto;display:block}
  .editeur.editeur-ppt{grid-template-columns:1fr;gap:16px}
}
/* Ruban : contenu CENTRÉ, quelle que soit la largeur d'écran. */
.ruban{justify-content:center;flex-wrap:nowrap;overflow-x:auto;position:sticky;top:0;z-index:16}
/* Le groupe « Fichier » reste DANS le flux centré : un margin-left:auto le
   collait à droite et cassait le centrage demandé sur les grands écrans. */
.ruban .grp-fin{border-right:0}
@media (max-width:1340px){.ruban{gap:0}.ruban .grp{padding:0 6px}}
.ins-btn-primaire{color:var(--accent-fonce)}
.ins-btn-primaire .ic-ins{color:var(--accent)}
/* Colonnes : chacune défile pour elle-même, jamais la page entière. */
.editeur-ppt .panneau{min-height:0;overflow:auto;padding-right:4px}
/* ★ `top:0` OBLIGATOIRE. theme.css:134 (NO-TOUCH) pose
   `.scene-apercu{position:sticky;top:92px}` ; en passant en `relative` sans
   neutraliser `top`, ces 92 px deviennent un DÉCALAGE SEC et permanent.
   Mesuré au banc : colonne centrale à 318,8 px alors que la colonne de
   gauche démarre à 226,8 px — c'est l'essentiel de « l'espace entre la
   barre d'outils et le haut de la zone d'édition » signalé par Hubert
   (les marges de 14 et 8 px ne pesaient que 22 px sur 136). */
.editeur-ppt .scene-apercu{position:relative;top:0;display:flex;flex-direction:column;min-height:0}
.editeur-ppt .colonne-prix{
  /* ★ .colonne-prix est un <aside> : theme.css lui impose width:244px, height:100vh,
     position:sticky et une bordure de barre latérale. C'est ce qui forçait la
     grille à déborder (scroll vertical) et dépassait la colonne (scroll
     horizontal). On neutralise TOUT ici. */
  position:static;width:auto;height:auto;min-height:0;max-height:100%;
  overflow:auto;border-right:0;flex-shrink:1;top:auto;
}
.editeur-ppt .panneau{gap:13px}
.editeur-ppt .panneau .champ label.lib{margin-bottom:5px}
/* La planche défile quand le format dépasse (A4 au zoom 100 %), comme la zone
   de travail de PowerPoint. */
/* LA VISIONNEUSE : prend toute la hauteur restante de la colonne centrale
   (comme la zone de diapo de PowerPoint) et défile si le format dépasse. */
.editeur-ppt .planche{
  padding:22px;min-height:0;flex:1;max-height:none;overflow:auto;
  /* « exactement comme ppt » : la feuille est centrée dans les DEUX sens.
     `safe` = si elle est plus grande que le cadre (zoom manuel), on repart du
     haut au lieu de couper le sommet, ce que ferait un `center` sec. */
  align-items:safe center;justify-content:safe center;
}
/* MISE EN PAGE EMPILÉE (< 1180 px) : la visionneuse est plafonnée à 70vh.
   ⚠ LIMITE CONNUE ET MESURÉE : dans cette mise en page seulement, la hauteur de
   la visionneuse dépend encore de son contenu, donc l'échelle physique dérive
   entre formats (rapports 1,169 / 1,985 au lieu de 1,4832 / 1,4293) et l'A6
   s'affiche à 98 % au lieu de 100 %. Tentative de correction faite et MESURÉE
   (`height:70vh` fixe) : elle règle la dérive mais sort 4 commandes de zoom du
   cadre à 1024 px — pire. Le produit est un outil B2B de bureau : on préserve
   les tailles réellement utilisées (≥ 1280 px, toutes exactes) plutôt que de
   les dégrader pour cette mise en page de secours. */
@media (max-width:1180px){.editeur-ppt .planche{max-height:70vh}}
/* Écran court : la marge de la visionneuse (22 px en haut ET en bas) coûtait
   44 px sur les 249 px disponibles en 1280×800 — 18 % de la place, pour du
   vide. On la réduit là où chaque pixel compte. */
@media (max-height:860px){.editeur-ppt .planche{padding:10px}}
/* Écran COURT : le ruban prend 90 px, soit ~20 % de tout l'espace utile en
   1280×625. On le compacte (icônes plus petites, noms de groupes retirés) :
   les commandes restent toutes là, la feuille récupère la place. */
@media (max-height:780px){
  .ruban .grp-nom{display:none}
  .ruban .grp{gap:0}
  .ruban .ins-btn .ic-ins{width:20px;height:20px}
  .ruban .grp-corps{min-height:26px}
}
/* ★ LE RUBAN RESTE SUR UN RANG. Mesuré à 1280×705 : ses groupes se repliaient
   sur deux rangs (`.grp-corps{flex-wrap:wrap}`) -> ruban à 107 px au lieu de 71,
   soit 36 px volés à la feuille sur un écran déjà court. La barre elle-même
   défile déjà horizontalement si besoin (`.ruban{overflow-x:auto}`). */
/* ⚠ PAS de préfixe `.editeur-ppt` : le ruban est un FRÈRE de `.editeur-ppt`
   (app.html:186 vs 261), pas un descendant — la règle préfixée ne s'appliquait
   à rien (ruban resté à 107 px en 1280, mesuré). */
.ruban .grp-corps{flex-wrap:nowrap}
/* ⚠ MAIS PAS SOUS 1280 px : mesuré, le ruban n'y tient pas sur un rang et
   débordait de 43 px (1024) à 53 px (1180) — une quinzaine de commandes
   devenaient INATTEIGNABLES à la souris, sans barre de défilement visible.
   Sous ce seuil, le repli sur deux rangs est le bon comportement : il coûte
   36 px de hauteur mais garde tout accessible. */
@media (max-width:1279px){.ruban .grp-corps{flex-wrap:wrap}}
/* ÉCRAN À LA FOIS ÉTROIT ET COURT (portable 1280×720 typique) : on serre le
   ruban juste assez pour qu'il tienne sur UN rang — sinon il en prend deux et
   vole 36 px à la feuille, qui n'occupe plus que 26 % de la hauteur. Toutes les
   commandes restent présentes ; c'est leur habillage qui maigrit. */
@media (min-width:1181px) and (max-width:1299px) and (max-height:820px){
  .ruban .grp-corps{flex-wrap:nowrap}
  .ruban .grp{padding:0 4px}
  .ruban .ins-btn{padding:2px 5px}
  .ruban .ins-btn .ic-ins{width:18px;height:18px}
  .ruban .ins-btn span{font-size:.64rem}
  .ruban button{font-size:.68rem}
}
/* MISE EN PAGE EMPILÉE (< 1180 px) : là, c'est la PAGE qui défile. Un ruban
   collant à `top:0` viendrait alors se ranger DERRIÈRE l'entête, elle-même
   collante et translucide (`theme.css .entete{sticky; top:0; z-index:20}` contre
   `z-index:16` pour le ruban) : on verrait les deux se superposer. Dans cette
   mise en page, le ruban défile donc avec le contenu.
   (Ce n'est pas ce qui rendait des commandes « inatteignables » au banc :
   c'était le banc qui mesurait après avoir fait défiler la page.) */
@media (max-width:1180px){.ruban{position:static}}
/* ★ LA VISIONNEUSE D'ABORD, sur les écrans étroits aussi.
   Mesuré à 1366×768 : la barre de vue passait sur DEUX lignes (39 -> 77 px) et
   les bandeaux sous la planche prenaient 39 px chacun -> 54 à 61 % de la
   colonne centrale mangés par autre chose que la feuille, réduite à 19 % de la
   hauteur de fenêtre. On compacte ce qui entoure la visionneuse. */
.editeur-ppt .barre-vue{flex-wrap:nowrap;overflow-x:auto;gap:8px;margin-bottom:2px;align-items:center}
.editeur-ppt .barre-vue::-webkit-scrollbar{height:0}
/* ⚠ RÉGRESSION MESURÉE PUIS CORRIGÉE : avec `nowrap` seul, le libellé
   « Aperçu · votre texte tel quel » était COMPRIMÉ à 40 px de large et cassait
   sur 5 lignes -> la barre montait à 97 px (pire que les 77 px d'origine).
   On lui interdit de se comprimer, et sous 1340 px on le retire : c'est une
   redite, la visionneuse se suffit à elle-même. */
.editeur-ppt .barre-vue > *{flex:none}
/* ⚠ Le libellé est le SEUL élément qui a le droit de rétrécir, et il le fait
   avec une ellipse (jamais sur plusieurs lignes). Rendre TOUTE la barre rigide
   la faisait déborder de 37 à 62 px entre 1341 et ~1400 px de large : le bouton
   « Ajuster » sortait du cadre à 1366 px — la largeur de portable la plus
   courante — sans aucune barre de défilement pour le rattraper. */
.editeur-ppt .apercu-libelle{
  flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
@media (max-width:1340px){.editeur-ppt .apercu-libelle{display:none}}
.editeur-ppt #alerte-deborde,
.editeur-ppt .note-rendu,
.editeur-ppt .scene-apercu > .alerte-min{margin-top:6px;font-size:.72rem;line-height:1.2}
/* ★ La planche est un conteneur FLEX : sans ceci la carte est COMPRIMÉE pour
   tenir dedans (un A4 se retrouvait à la largeur d'un A6) et l'échelle entre
   formats était fausse. flex:none => la carte garde sa taille physique et la
   planche défile. */
.editeur-ppt .carte-physique{flex:none;max-width:none}
/* Barre de zoom (bas de barre de vue) */
.zoom-barre{display:inline-flex;align-items:center;gap:6px;margin-left:auto}
.zoom-barre button{
  font:inherit;font-size:.9rem;line-height:1;cursor:pointer;width:24px;height:24px;
  border:1px solid var(--ligne);border-radius:6px;background:var(--blanc-carte);color:var(--encre);
  display:inline-flex;align-items:center;justify-content:center;
}
.zoom-barre button:hover{border-color:var(--accent);color:var(--accent-fonce)}
.zoom-barre input[type=range]{width:96px;accent-color:var(--accent)}
.zoom-barre #zoom-val{font-size:.76rem;color:var(--encre-doux);min-width:42px;text-align:right;font-variant-numeric:tabular-nums}

/* ---- Colonne PRIX (live, ligne par ligne) ---- */
.colonne-prix{position:sticky;top:92px;display:flex;flex-direction:column;gap:12px}
.prix-carte{background:var(--encre);color:#fff;border-radius:var(--rayon);padding:16px 18px}
.prix-titre{font-size:.68rem;letter-spacing:.09em;text-transform:uppercase;color:rgba(255,255,255,.55);margin-bottom:11px}
.prix-lignes{display:flex;flex-direction:column;gap:6px;font-size:.82rem}
.prix-lignes .pl{display:flex;justify-content:space-between;gap:10px;color:rgba(255,255,255,.78)}
.prix-lignes .pl b{color:#fff;font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap}
.prix-lignes .pl.base{color:rgba(255,255,255,.92)}
.prix-lignes .pl.remise,.prix-lignes .pl.remise b{color:#7fd6a9}
.prix-lignes .pl.vide{color:rgba(255,255,255,.4);font-style:italic}
.prix-tot{border-top:1px solid rgba(255,255,255,.18);margin-top:12px;padding-top:11px;display:flex;flex-direction:column;gap:8px}
.prix-tot .prix-l{display:flex;justify-content:space-between;align-items:center;gap:10px;font-size:.84rem;color:rgba(255,255,255,.7)}
.prix-tot .prix-l b{color:#fff;font-size:1.1rem;font-variant-numeric:tabular-nums}
.prix-tot .prix-l.qte label{color:rgba(255,255,255,.7);margin:0}
.prix-tot .prix-l.qte input{
  width:78px;padding:5px 8px;font-size:.86rem;text-align:right;background:rgba(255,255,255,.1);
  border:1px solid rgba(255,255,255,.22);color:#fff;border-radius:8px;
}
.prix-tot .prix-l.grand{border-top:1px solid rgba(255,255,255,.14);padding-top:9px}
.prix-tot .prix-l.grand b{font-family:'Fraunces',serif;font-size:1.5rem;font-weight:600}
.colonne-prix .alerte-min{color:#ffb4a2;margin:8px 0 0;font-size:.78rem}

/* ---- SAISIE DIRECTE sur la carte (le message se tape dans la diapo) ---- */
.saisie-carte{
  position:absolute;inset:0;width:100%;height:100%;margin:0;padding:0;border:0;outline:none;
  background:transparent;color:transparent;caret-color:var(--accent);resize:none;overflow:hidden;
  font-family:'Inter',sans-serif;font-size:12px;line-height:1.5;z-index:5;
  min-height:0;border-radius:0;
  /* Inerte par défaut : 1 clic sélectionne le BLOC (comme PowerPoint) ;
     la saisie s'active au 2e clic / double-clic (classe .edite). */
  pointer-events:none;
}
/* En saisie : le champ passe AU-DESSUS de la couche des blocs (z-index 3),
   sinon le cadre du bloc capte le clic et on ne peut jamais taper. */
.saisie-carte.edite{pointer-events:auto;z-index:30;background:rgba(255,255,255,.28);box-shadow:inset 0 0 0 2px var(--accent)}
/* ...et le cadre du bloc d'écriture cesse de capter la souris pendant la saisie. */
.el-composable.el-manuscrit.en-saisie{pointer-events:none}
.el-composable.el-manuscrit.en-saisie .el-poignee{pointer-events:auto}
/* Placeholder d'écriture (pas encore matérialisé) : visible au survol seulement. */
.el-composable.el-virtuel{border-color:transparent;background:transparent}
.el-composable.el-virtuel:hover{border-color:var(--accent-voile);border-style:dashed}
.el-composable.el-virtuel .el-badge{opacity:0;transition:opacity .12s}
.el-composable.el-virtuel:hover .el-badge{opacity:1}
.saisie-carte::placeholder{color:var(--encre-doux);opacity:.55}
/* Le caret NATIF est masqué : il tomberait au mauvais endroit (les lettres du
   textarea n'ont rien à voir avec les glyphes tracés). On dessine le nôtre à la
   position EXACTE du glyphe (BDB_VIVANTE.rectCaret). */
.saisie-carte.edite{caret-color:transparent}
/* Accolades des variables : la banque de la plume ne les contient pas, on les
   pose en typo d'écran à la position EXACTE (repère, jamais du texte). */
.reperes-var{position:absolute;inset:0;pointer-events:none;z-index:6}
.marque-var{
  position:absolute;color:var(--accent);opacity:.75;font-family:'Inter',sans-serif;
  font-weight:600;line-height:1;white-space:pre;
}
.caret-vivant{
  position:absolute;width:2px;background:var(--accent);z-index:31;display:none;
  pointer-events:none;border-radius:1px;animation:caret-clignote 1.05s step-end infinite;
}
/* ---- SURLIGNAGE DE SÉLECTION (D-089) ----------------------------------
   Le texte visible est un SVG de glyphes : le surlignage natif du textarea
   transparent est peint aux métriques d'une police d'écran, donc à côté des
   traits. On dessine nos propres bandes, à la géométrie du moteur, et SOUS
   l'encre (z-index 0 dans une zone-ecriture où le SVG suit) pour ne jamais
   masquer l'écriture. */
/* ★ Le surlignage NATIF doit rester totalement invisible. Un <textarea> en
   color:transparent redevient VISIBLE dès qu'on le sélectionne : le style
   de sélection du navigateur repeint le texte (constaté en capture — le
   texte machine s'affichait en bleu foncé PAR-DESSUS l'écriture). On neutralise
   donc la sélection native ; la nôtre est dessinée ci-dessous. */
.saisie-carte::selection{background:transparent;color:transparent}
.saisie-carte::-moz-selection{background:transparent;color:transparent}
.selection-vivante{position:absolute;inset:0;pointer-events:none;z-index:0}
.selection-vivante .sel-bande{
  position:absolute;background:var(--accent);opacity:.24;border-radius:2px;
}
@media (prefers-contrast:more){.selection-vivante .sel-bande{opacity:.38}}
@keyframes caret-clignote{0%,100%{opacity:1}50%{opacity:0}}
@media (prefers-reduced-motion:reduce){.caret-vivant{animation:none}}
.saisie-carte:focus{box-shadow:none;border:0}

.barre-insert{
  display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:0 0 10px;padding:7px 9px;
  background:var(--blanc-carte);border:1px solid var(--ligne);border-radius:var(--rayon-ctrl);
}
.barre-insert .ins-lib{font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;color:var(--encre-doux);margin-right:2px}
.ins-btn{
  display:inline-flex;align-items:center;gap:6px;font:inherit;font-size:.84rem;cursor:pointer;
  padding:6px 11px;border:1px solid var(--ligne);border-radius:999px;
  background:var(--papier-2);color:var(--encre);
}
.ins-btn:hover{border-color:var(--accent);color:var(--accent-fonce);background:var(--accent-voile)}
.ins-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.ins-btn .ins-ic{font-size:.95rem;line-height:1}
.barre-insert .ins-sep{flex:1}
.barre-insert .ins-astuce{font-size:.74rem;color:var(--encre-doux)}
.planche{position:relative}

/* Barre d'outils flottante (contextuelle au bloc sélectionné). */
.el-toolbar{
  position:absolute;z-index:20;display:flex;align-items:center;gap:4px;flex-wrap:nowrap;
  white-space:nowrap;max-width:none;
  padding:4px 6px;background:var(--blanc-carte);border:1px solid var(--ligne);
  border-radius:10px;box-shadow:0 6px 22px rgba(38,48,63,.18);
}
.el-toolbar[hidden]{display:none}
/* La barre flottante ne doit JAMAIS créer de défilement dans la visionneuse
   (22 px mesurés en 1280×625 dès qu'un bloc était sélectionné) : elle est
   posée en overlay, hors du flux de défilement de la planche. */
.editeur-ppt .el-toolbar{position:absolute;z-index:22}
/* AVIS EN SURIMPRESSION (enregistrement, erreurs).
   ⚠ TROIS PIEGES DEJA PAYES, tous mesures :
   1. En FLUX dans `.planche` (conteneur flex) il devenait un item et chassait
      la feuille de son centre, definitivement (marges 96/96 -> 10/183).
   2. En `position:absolute` DANS `.planche` (overflow:auto) il defile avec la
      carte : au zoom il partait jusqu'a 1362 px hors du cadre -> invisible,
      alors que c'est son unique raison d'etre.
   3. `transform` declare DEUX FOIS dans la meme regle : la seconde ecrasait le
      `translate(-50%)`, donc l'avis cache restait colle a left:50% et depassait
      de 243 px -> 362 px de defilement horizontal PERMANENT des qu'un message
      un peu long s'affichait (le repli « Erreur inconnue » suffisait).
   -> Il vit donc dans `.scene-apercu` (qui ne defile pas), hors flux, avec UNE
   SEULE declaration `transform`, et un texte qui passe a la ligne au lieu de
   deborder du fond. La transition ne porte que sur l'opacite : pas de
   glissement horizontal parasite. */
.avis-visionneuse{
  position:absolute;left:50%;top:46px;transform:translateX(-50%);
  z-index:30;max-width:min(88%,520px);width:max-content;
  padding:6px 14px;border-radius:8px;background:var(--encre,#26303F);color:#fff;
  font-size:.78rem;line-height:1.25;text-align:center;
  white-space:normal;overflow-wrap:anywhere;
  box-shadow:0 6px 16px -8px rgba(0,0,0,.45);
  opacity:0;visibility:hidden;transition:opacity .16s;pointer-events:none;
}
.avis-visionneuse.visible{opacity:1;visibility:visible}
.el-toolbar .tb-titre{font-size:.72rem;color:var(--encre-doux);padding:0 4px;white-space:nowrap}
.el-toolbar .tb-sep{width:1px;height:18px;background:var(--ligne);margin:0 2px}
.el-toolbar button{
  font:inherit;font-size:.8rem;cursor:pointer;padding:4px 8px;border-radius:7px;
  border:1px solid transparent;background:transparent;color:var(--encre);line-height:1.2;
}
.el-toolbar button:hover{background:var(--papier-2);border-color:var(--ligne)}
.el-toolbar button.actif{background:var(--accent-voile);border-color:var(--accent);color:var(--accent-fonce);font-weight:600}
.el-toolbar button.danger{color:var(--cire)}
.el-toolbar select,.el-toolbar input[type=number]{
  font:inherit;font-size:.8rem;padding:3px 5px;border:1px solid var(--ligne);
  border-radius:7px;background:var(--blanc-carte);color:var(--encre);
}
.el-toolbar select{max-width:150px}
.el-toolbar input[type=number]{width:52px}
.el-toolbar input[type=color]{width:26px;height:24px;padding:0;border:1px solid var(--ligne);border-radius:6px;background:none;cursor:pointer}

/* Guides d'alignement (magnétisme). */
.guides{position:absolute;inset:0;pointer-events:none;z-index:12}
.guides .guide{position:absolute;background:var(--accent);opacity:.9}
.guides .guide.v{width:1px;top:0;bottom:0}
.guides .guide.h{height:1px;left:0;right:0}

.couche-elements{position:absolute;inset:0;pointer-events:none;z-index:3}
/* Le BLOC ne coupe rien lui-même (ses poignées doivent dépasser) : c'est
   .el-contenu, à l'intérieur, qui masque ce qui sort du cadre — c'est lui la
   « fenêtre » du rognage. */
.el-composable{
  position:absolute;pointer-events:auto;cursor:move;box-sizing:border-box;
  border:1px dashed transparent;overflow:visible;
}
.el-contenu{position:absolute;inset:0;overflow:hidden}
.el-composable:hover{border-color:var(--accent-voile)}
.el-composable.actif{border-color:var(--accent);border-style:solid}
/* Bloc d'ÉCRITURE manuscrite : cadre transparent (le tracé vit au-dessus,
   dans .zone-ecriture) — on ne voit le cadre qu'au survol/sélection. */
.el-composable.el-manuscrit{background:transparent}
.el-composable.el-manuscrit.actif{border-style:dashed;border-color:var(--accent)}
/* Débordement : le bloc d'écriture le montre TOUT DE SUITE (cadre rouge). */
.el-composable.el-manuscrit.deborde{border-color:var(--cire);border-style:solid;background:rgba(190,60,50,.06)}
.el-composable.el-manuscrit.deborde .el-badge{background:var(--cire)}
/* PDF affiché comme une page (la visionneuse est masquée par le fragment #toolbar=0). */
.el-pdf-page{width:100%;height:100%;border:0;display:block;pointer-events:none}
/* Mode ROGNER : l'image déborde volontairement de son cadre. */
.el-composable.en-crop{outline:2px dashed var(--accent);outline-offset:2px}
/* Étiquette « ✍ Écriture » : repère DISCRET. Elle n'apparaît qu'au survol ou
   quand le bloc est sélectionné, et disparaît pendant la frappe — sinon elle
   recouvre en permanence le haut de la carte (logo, première ligne). */
.el-composable.el-manuscrit .el-badge{
  position:absolute;left:0;top:-17px;font-size:.65rem;line-height:1;padding:2px 6px;
  background:var(--accent);color:#fff;border-radius:5px 5px 0 0;white-space:nowrap;
  opacity:0;transition:opacity .12s;pointer-events:none;
}
/* Uniquement au SURVOL : en simple sélection il restait affiché par-dessus le
   logo et la première ligne (constat Hubert). Jamais pendant la frappe. */
.el-composable.el-manuscrit:hover .el-badge{opacity:1}
.el-composable.el-manuscrit.en-saisie .el-badge,
.el-composable.el-manuscrit.en-saisie:hover .el-badge{opacity:0}
/* ★ NI EN SÉLECTION. Constat d'Hubert re-signalé : « quand je clique sur la
   zone de texte manuscrite, j'ai toujours le truc "Écriture" avec le logo qui
   reste ». Un clic sélectionne SANS entrer en saisie -> la règle ci-dessus ne
   mordait pas et le survol laissait l'étiquette à opacity 1 (mesuré). Dès que
   la zone est sélectionnée, l'étiquette disparaît : on sait déjà où on est. */
.el-composable.el-manuscrit.actif .el-badge,
.el-composable.el-manuscrit.actif:hover .el-badge{opacity:0}
/* Édition de texte EN PLACE (double-clic), façon PowerPoint. */
.el-texte-contenu[contenteditable="true"]{outline:2px solid var(--accent);cursor:text;pointer-events:auto;background:rgba(255,255,255,.6)}
.el-composable img{width:100%;height:100%;object-fit:contain;display:block;pointer-events:none;user-select:none}
/* PDF « fond de page » composable : l'embed remplit l'élément et ne capte
   jamais la souris (sinon il volerait le drag/resize). */
.el-composable embed{width:100%;height:100%;border:0;display:block;pointer-events:none}
.el-texte-contenu{width:100%;height:100%;overflow:hidden;line-height:1.25;pointer-events:none;word-break:break-word}
/* Poignée de redimensionnement (coin bas-droite), visible sur l'élément actif. */
/* 8 poignées façon PowerPoint : 4 angles + 4 milieux.
   ZONE D'ACCROCHE GÉNÉREUSE (22 px) avec une pastille visible plus petite au
   centre : attraper un angle ne demande plus de viser au pixel près. */
.el-poignee{
  position:absolute;width:22px;height:22px;border:0;background:transparent;
  pointer-events:auto;display:none;z-index:14;touch-action:none;
}
.el-poignee::after{
  content:"";position:absolute;left:50%;top:50%;width:11px;height:11px;
  transform:translate(-50%,-50%);border-radius:50%;
  background:#fff;border:1.5px solid var(--accent);box-shadow:0 1px 3px rgba(20,30,60,.28);
}
.el-poignee:hover::after{background:var(--accent-voile);transform:translate(-50%,-50%) scale(1.15)}
.el-composable.actif .el-poignee{display:block}
.el-poignee.p-nw{left:-11px;top:-11px;cursor:nwse-resize}
.el-poignee.p-n {left:calc(50% - 11px);top:-11px;cursor:ns-resize}
.el-poignee.p-ne{right:-11px;top:-11px;cursor:nesw-resize}
.el-poignee.p-e {right:-11px;top:calc(50% - 11px);cursor:ew-resize}
.el-poignee.p-se{right:-11px;bottom:-11px;cursor:nwse-resize}
.el-poignee.p-s {left:calc(50% - 11px);bottom:-11px;cursor:ns-resize}
.el-poignee.p-sw{left:-11px;bottom:-11px;cursor:nesw-resize}
.el-poignee.p-w {left:-11px;top:calc(50% - 11px);cursor:ew-resize}
/* Le bloc SÉLECTIONNÉ (et ses poignées) passe au-dessus des autres. */
.el-composable.actif{z-index:10}

/* ---- Mode ROGNER : poignées noires façon PowerPoint (équerres + barres) ---- */
.el-composable.en-crop .el-poignee::after{
  background:#1b1b1b;border:0;border-radius:0;box-shadow:0 0 0 1px rgba(255,255,255,.85);
}
.el-composable.en-crop .el-poignee.p-nw::after,
.el-composable.en-crop .el-poignee.p-ne::after,
.el-composable.en-crop .el-poignee.p-sw::after,
.el-composable.en-crop .el-poignee.p-se::after{width:15px;height:15px}
.el-composable.en-crop .el-poignee.p-n::after,
.el-composable.en-crop .el-poignee.p-s::after{width:22px;height:5px}
.el-composable.en-crop .el-poignee.p-e::after,
.el-composable.en-crop .el-poignee.p-w::after{width:5px;height:22px}
/* Pendant le rognage, la partie coupée reste visible en fantôme (repère PPT). */
.el-crop-ghost{position:absolute;pointer-events:none;opacity:.28;z-index:1}
.el-crop-ghost img{width:100%;height:100%;object-fit:contain;display:block}
/* Le placeholder virtuel n'a pas de poignées (rien à redimensionner encore). */
.el-composable.el-virtuel .el-poignee{display:none}

/* Actions + panneau d'édition de l'élément sélectionné (dans le panneau). */
.el-actions{display:flex;gap:8px;flex-wrap:wrap}
.el-editeur{margin-top:10px;padding:10px;border:1px solid var(--ligne);border-radius:var(--rayon-ctrl);background:var(--papier-2)}
.el-ed-titre{font-size:.82rem;font-weight:600;color:var(--encre);margin-bottom:2px}
.el-ed-ligne{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:8px}
.el-ed-texte{width:100%;font-size:.85rem;padding:6px 8px;border:1px solid var(--ligne);border-radius:var(--rayon-ctrl);resize:vertical;box-sizing:border-box;font-family:'Inter',sans-serif}
.el-ed-num{font-size:.8rem;color:var(--encre-doux);display:flex;align-items:center;gap:4px}
.el-ed-num input{width:56px}
.el-editeur select{width:auto;flex:1;min-width:120px}
.el-ed-suppr{color:var(--cire);border-color:var(--cire)}

/* ============================================================
   IMPORT RECTO PDF (prestation « imprimée », T-079) — la carte devient
   une zone d'import (non éditable), qui COUVRE la carte (z au-dessus des
   couches manuscrite + éléments). L'enveloppe reste éditable.
   ============================================================ */
.import-recto{position:absolute;inset:0;z-index:4;background:var(--blanc-carte);display:flex;flex-direction:column}
.import-recto-corps{flex:1;display:flex;flex-direction:column;min-height:0}
.import-recto-apercu{flex:1;width:100%;border:0;min-height:0}
.import-recto-barre{padding:6px;text-align:center;border-top:1px solid var(--ligne)}
.import-recto-vide{
  flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;
  color:var(--encre-doux);border:2px dashed var(--ligne);border-radius:8px;margin:10px;text-align:center;padding:16px;
}
.import-recto-txt{font-size:.9rem}

/* ============================================================
   ZONE D'ÉCRITURE DANS LA CARTE = APERÇU PASSIF (plus de saisie).
   Positionnée en px par editeur.js depuis les marges physiques mm
   (ui.json > editeur.zone_mm) ; sert à dimensionner le rendu.
   ============================================================ */
/* z-index:4 = la PLUME AU-DESSUS du laser (réalité physique : on imprime
   d'abord, le robot trace ensuite PAR-DESSUS). pointer-events:none -> les
   clics traversent quand même vers les éléments composables (z:3). */
.zone-ecriture{position:absolute;overflow:hidden;pointer-events:none;z-index:4}

/* Conteneur du rendu SVG vivante : plein cadre de la zone ; le SVG suit
   la largeur (viewBox 1:1 avec les px calculés -> width:100%). */
.rendu-vivant{position:absolute;inset:0}
.rendu-vivant svg{display:block;width:100%;height:auto}

/* #rendu-texte vit DANS la zone (aperçu) : borné par la zone. */
.zone-ecriture .texte-manuscrit{max-height:100%;height:100%;overflow:hidden}

/* Libellé statique « Aperçu · données d'exemple » (remplace l'ancien toggle). */
.apercu-libelle{font-size:.78rem;color:var(--encre-doux)}

/* Barre des variables (sous le champ message, dans le panneau) + notes. */
#boutons-vars{margin-top:12px}
/* Variable présente dans le texte : liseré appuyé (repère « utilisée »). */
.vars button.utilisee{border-color:var(--accent)}
/* Variable CUSTOM (tapée/créée par le client, hors des 4 standards). */
.vars button.custom{background:color-mix(in srgb, var(--dore) 16%, transparent);color:var(--dore)}
.vars button.custom:hover{border-color:var(--dore)}
/* Bouton « + variable » : neutre, discret. */
.vars button.ajout-var{background:transparent;color:var(--encre-doux);border:1px dashed var(--ligne)}
.vars button.ajout-var:hover{border-color:var(--accent);color:var(--accent-fonce)}
/* Formulaire inline « + variable » (remplace la barre le temps de saisir). */
.ajout-var-form{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.ajout-var-form input{width:auto;flex:1;min-width:150px;font-size:.82rem;padding:6px 10px}
.ajout-var-form .btn.discret{padding:5px 10px}
.ajout-var-err{font-size:.76rem;color:var(--cire)}
.indication.centre{text-align:center}
/* .alerte-min de theme.css est calibrée pour le récap SOMBRE (rose pâle) :
   sous la planche claire on repasse sur la couleur cire, lisible. */
#alerte-deborde{color:var(--cire);text-align:center}
