/* Fichier genere par build-assets.py. Ne pas modifier directement. */

/* source: vendor/pannellum.css */
/* Pannellum 2.5.6 — MIT, https://github.com/mpetroff/pannellum */
/* Pannellum 2.5.6, https://github.com/mpetroff/pannellum */
.pnlm-container{margin:0;padding:0;overflow:hidden;position:relative;cursor:default;width:100%;height:100%;font-family:Helvetica,"Nimbus Sans L","Liberation Sans",Arial,sans-serif;background:#f4f4f4 url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2267%22%20height%3D%22100%22%20viewBox%3D%220%200%2067%20100%22%3E%0A%3Cpath%20stroke%3D%22%23ccc%22%20fill%3D%22none%22%20d%3D%22M33.5%2C50%2C0%2C63%2C33.5%2C75%2C67%2C63%2C33.5%2C50m-33.5-50%2C67%2C25m-0.5%2C0%2C0%2C75m-66.5-75%2C67-25m-33.5%2C75%2C0%2C25m0-100%2C0%2C50%22%2F%3E%0A%3C%2Fsvg%3E%0A') repeat;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none;outline:0;line-height:1.4;contain:content}.pnlm-container *{box-sizing:content-box}.pnlm-ui{position:absolute;width:100%;height:100%;z-index:1}.pnlm-grab{cursor:grab;cursor:url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20height%3D%2226%22%20width%3D%2226%22%3E%0A%3Cpath%20stroke%3D%22%23000%22%20stroke-width%3D%221px%22%20fill%3D%22%23fff%22%20d%3D%22m15.3%2020.5s6.38-6.73%204.64-8.24-3.47%201.01-3.47%201.01%203.61-5.72%201.41-6.49c-2.2-0.769-3.33%204.36-3.33%204.36s0.873-5.76-1.06-5.76-1.58%205.39-1.58%205.39-0.574-4.59-2.18-4.12c-1.61%200.468-0.572%205.51-0.572%205.51s-1.58-4.89-2.93-3.79c-1.35%201.11%200.258%205.25%200.572%206.62%200.836%202.43%202.03%202.94%202.17%205.55%22%2F%3E%0A%3C%2Fsvg%3E%0A') 12 8,default}.pnlm-grabbing{cursor:grabbing;cursor:url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20height%3D%2226%22%20width%3D%2226%22%3E%0A%3Cpath%20stroke%3D%22%23000%22%20stroke-width%3D%221px%22%20fill%3D%22%23fff%22%20d%3D%22m15.3%2020.5s5.07-5.29%203.77-6.74c-1.31-1.45-2.53%200.14-2.53%200.14s2.74-3.29%200.535-4.06c-2.2-0.769-2.52%201.3-2.52%201.3s0.81-2.13-1.12-2.13-1.52%201.77-1.52%201.77-0.261-1.59-1.87-1.12c-1.61%200.468-0.874%202.17-0.874%202.17s-0.651-1.55-2-0.445c-1.35%201.11-0.68%202.25-0.365%203.62%200.836%202.43%202.03%202.94%202.17%205.55%22%2F%3E%0A%3C%2Fsvg%3E%0A') 12 8,default}.pnlm-sprite{background-image:url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2226%22%20height%3D%22208%22%3E%0A%3Ccircle%20fill-opacity%3D%22.78%22%20cy%3D%22117%22%20cx%3D%2213%22%20r%3D%2211%22%20fill%3D%22%23fff%22%2F%3E%0A%3Ccircle%20fill-opacity%3D%22.78%22%20cy%3D%22143%22%20cx%3D%2213%22%20r%3D%2211%22%20fill%3D%22%23fff%22%2F%3E%0A%3Ccircle%20cy%3D%22169%22%20cx%3D%2213%22%20r%3D%227%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%222%22%2F%3E%0A%3Ccircle%20cy%3D%22195%22%20cx%3D%2213%22%20r%3D%227%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%222%22%2F%3E%0A%3Ccircle%20cx%3D%2213%22%20cy%3D%22195%22%20r%3D%222.5%22%2F%3E%0A%3Cpath%20d%3D%22m5%2083v6h2v-4h4v-2zm10%200v2h4v4h2v-6zm-5%205v6h6v-6zm-5%205v6h6v-2h-4v-4zm14%200v4h-4v2h6v-6z%22%2F%3E%0A%3Cpath%20d%3D%22m13%20110a7%207%200%200%200%20-7%207%207%207%200%200%200%207%207%207%207%200%200%200%207%20-7%207%207%200%200%200%20-7%20-7zm-1%203h2v2h-2zm0%203h2v5h-2z%22%2F%3E%0A%3Cpath%20d%3D%22m5%2057v6h2v-4h4v-2zm10%200v2h4v4h2v-6zm-10%2010v6h6v-2h-4v-4zm14%200v4h-4v2h6v-6z%22%2F%3E%0A%3Cpath%20d%3D%22m17%2038v2h-8v-2z%22%2F%3E%0A%3Cpath%20d%3D%22m12%209v3h-3v2h3v3h2v-3h3v-2h-3v-3z%22%2F%3E%0A%3Cpath%20d%3D%22m13%20136-6.125%206.125h4.375v7.875h3.5v-7.875h4.375z%22%2F%3E%0A%3Cpath%20d%3D%22m10.428%20173.33v-5.77l5-2.89v5.77zm1-1.73%203-1.73-3.001-1.74z%22%2F%3E%0A%3C%2Fsvg%3E%0A')}.pnlm-container:-moz-full-screen{height:100%!important;width:100%!important;position:static!important}.pnlm-container:-webkit-full-screen{height:100%!important;width:100%!important;position:static!important}.pnlm-container:-ms-fullscreen{height:100%!important;width:100%!important;position:static!important}.pnlm-container:fullscreen{height:100%!important;width:100%!important;position:static!important}.pnlm-render-container{cursor:inherit;position:absolute;height:100%;width:100%}.pnlm-controls{margin-top:4px;background-color:#fff;border:1px solid #999;border-color:rgba(0,0,0,0.4);border-radius:3px;cursor:pointer;z-index:2;-webkit-transform:translateZ(9999px);transform:translateZ(9999px)}.pnlm-control:hover{background-color:#f8f8f8}.pnlm-controls-container{position:absolute;top:0;left:4px;z-index:1}.pnlm-zoom-controls{width:26px;height:52px}.pnlm-zoom-in{width:100%;height:50%;position:absolute;top:0;border-radius:3px 3px 0 0}.pnlm-zoom-out{width:100%;height:50%;position:absolute;bottom:0;background-position:0 -26px;border-top:1px solid #ddd;border-top-color:rgba(0,0,0,0.10);border-radius:0 0 3px 3px}.pnlm-fullscreen-toggle-button,.pnlm-orientation-button,.pnlm-hot-spot-debug-indicator{width:26px;height:26px}.pnlm-hot-spot-debug-indicator{position:absolute;top:50%;left:50%;width:26px;height:26px;margin:-13px 0 0 -13px;background-color:rgba(255,255,255,0.5);border-radius:13px;display:none}.pnlm-orientation-button-inactive{background-position:0 -156px}.pnlm-orientation-button-active{background-position:0 -182px}.pnlm-fullscreen-toggle-button-inactive{background-position:0 -52px}.pnlm-fullscreen-toggle-button-active{background-position:0 -78px}.pnlm-panorama-info{position:absolute;bottom:4px;background-color:rgba(0,0,0,0.7);border-radius:0 3px 3px 0;padding-right:10px;color:#fff;text-align:left;display:none;z-index:2;-webkit-transform:translateZ(9999px);transform:translateZ(9999px)}.pnlm-title-box{position:relative;font-size:20px;display:table;padding-left:5px;margin-bottom:3px}.pnlm-author-box{position:relative;font-size:12px;display:table;padding-left:5px}.pnlm-load-box{position:absolute;top:50%;left:50%;width:200px;height:150px;margin:-75px 0 0 -100px;background-color:rgba(0,0,0,0.7);border-radius:3px;text-align:center;font-size:20px;display:none;color:#fff}.pnlm-load-box p{margin:20px 0}.pnlm-lbox{position:absolute;top:50%;left:50%;width:20px;height:20px;margin:-10px 0 0 -10px;display:none}.pnlm-loading{animation-duration:1.5s;-webkit-animation-duration:1.5s;animation-name:pnlm-mv;-webkit-animation-name:pnlm-mv;animation-iteration-count:infinite;-webkit-animation-iteration-count:infinite;animation-timing-function:linear;-webkit-animation-timing-function:linear;height:10px;width:10px;background-color:#fff;position:relative}@keyframes pnlm-mv{from{left:0;top:0}25%{left:10px;top:0}50%{left:10px;top:10px}75%{left:0;top:10px}to{left:0;top:0}}@-webkit-keyframes pnlm-mv{from{left:0;top:0}25%{left:10px;top:0}50%{left:10px;top:10px}75%{left:0;top:10px}to{left:0;top:0}}.pnlm-load-button{position:absolute;top:50%;left:50%;width:200px;height:100px;margin:-50px 0 0 -100px;background-color:rgba(0,0,0,.7);border-radius:3px;text-align:center;font-size:20px;display:table;color:#fff;cursor:pointer}.pnlm-load-button:hover{background-color:rgba(0,0,0,.8)}.pnlm-load-button p{display:table-cell;vertical-align:middle}.pnlm-info-box{font-size:15px;position:absolute;top:50%;left:50%;width:200px;height:150px;margin:-75px 0 0 -100px;background-color:#000;border-radius:3px;display:table;text-align:center;color:#fff;table-layout:fixed}.pnlm-info-box a,.pnlm-author-box a{color:#fff;word-wrap:break-word;overflow-wrap:break-word}.pnlm-info-box p{display:table-cell;vertical-align:middle;padding:0 5px 0 5px}.pnlm-error-msg{display:none}.pnlm-about-msg{font-size:11px;line-height:11px;color:#fff;padding:5px 8px 5px 8px;background:rgba(0,0,0,0.7);border-radius:3px;position:absolute;top:50px;left:50px;display:none;opacity:0;-moz-transition:opacity .3s ease-in-out;-webkit-transition:opacity .3s ease-in-out;-o-transition:opacity .3s ease-in-out;-ms-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out;z-index:1}.pnlm-about-msg a:link,.pnlm-about-msg a:visited{color:#fff}.pnlm-about-msg a:hover,.pnlm-about-msg a:active{color:#eee}.pnlm-hotspot-base{position:absolute;visibility:hidden;cursor:default;vertical-align:middle;top:0;z-index:1}.pnlm-hotspot{height:26px;width:26px;border-radius:13px}.pnlm-hotspot:hover{background-color:rgba(255,255,255,0.2)}.pnlm-hotspot.pnlm-info{background-position:0 -104px}.pnlm-hotspot.pnlm-scene{background-position:0 -130px}div.pnlm-tooltip span{visibility:hidden;position:absolute;border-radius:3px;background-color:rgba(0,0,0,0.7);color:#fff;text-align:center;max-width:200px;padding:5px 10px;margin-left:-220px;cursor:default}div.pnlm-tooltip:hover span{visibility:visible}div.pnlm-tooltip:hover span:after{content:'';position:absolute;width:0;height:0;border-width:10px;border-style:solid;border-color:rgba(0,0,0,0.7) transparent transparent transparent;bottom:-20px;left:-10px;margin:0 50%}.pnlm-compass{position:absolute;width:50px;height:50px;right:4px;bottom:4px;border-radius:25px;background-image:url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20height%3D%2250%22%20width%3D%2250%22%3E%0A%3Cpath%20d%3D%22m24.5078%206-3.2578%2018h7.5l-3.25781-18h-0.984376zm-3.2578%2020%203.2578%2018h0.9844l3.2578-18h-7.5zm1.19531%200.9941h5.10938l-2.5547%2014.1075-2.5547-14.1075z%22%2F%3E%0A%3C%2Fsvg%3E%0A');cursor:default;display:none}.pnlm-world{position:absolute;left:50%;top:50%}.pnlm-face{position:absolute;-webkit-transform-origin:0 0;transform-origin:0 0}.pnlm-dragfix,.pnlm-preview-img{position:absolute;height:100%;width:100%}.pnlm-preview-img{background-size:cover;background-position:center}.pnlm-lbar{width:150px;margin:0 auto;border:#fff 1px solid;height:6px}.pnlm-lbar-fill{background:#fff;height:100%;width:0}.pnlm-lmsg{font-size:12px}.pnlm-fade-img{position:absolute;top:0;left:0}.pnlm-pointer{cursor:pointer}

/* source: plan.css */
:root{
  /* ─── Méditerranée · Djerba (mode clair) ─── */
  --papier:#f4ece0; --page:#e9e0d1; --carte:#faf5ec;
  --encre:#3a332a; --encre2:#6e6457; --mur:#2f2a24;
  --vert:#1a6b3e; --vert2:#2e8b57; --vert-pale:#e6f0e8;
  --jour:#fbeed6; --nuit:#dfeaf2; --eau:#dbeef1; --cuisine:#f7ddc0;
  --circ:#ede4d5; --ext:#e8dcc7; --veg:#cfdcb6; --sable:#ecdfc9;
  --bassin:#3fb0cd; --eaub:#136d88;
  --trait:#9c8f79; --trait2:#b8ab94; --grille:#c9bda6;
  --meuble:#f3ece0; --meuble2:#fdfaf3; --veg2:#6f9455; --bati:#fffefb;
  --select2:#2e7dd2; --ombre:rgba(0,0,0,.12);
  --ligne:#ddd2bf; --alerte:#c1622a; --route:#e0d5c2; --routeb:#c0b39c;
  /* Textes d'annotation du plan (cotes, echelle, notes) : distincts du trait,
     pour qu'ils suivent le contraste du fond et non l'epaisseur des lignes.
     --cote valait #9c8f79, la couleur du trait : 2,71:1 sur le papier pour la
     barre d'echelle et 2,34:1 sur une zone exterieure. Une annotation est du
     texte, pas un trait ; elle prend donc une encre a elle, assez sombre pour
     tenir 4,5:1 sur toutes les teintes claires du plan. */
  --cote:#5f5548; --vert-txt:#1a6b3e; --sur-vert:#e6f0e8;
  /* Pastilles inversees (etiquette de repere, barre d'echelle, toast) */
  --puce-fond:#3a332a; --puce-txt:#ffffff;
  /* Bandeau de modale. Il etait sur --vert, la seule teinte du plan qui
     n'appartienne ni a la palette Mediterranee ni a celle du site (navy /
     creme / or) : un aplat vert vif autour d'un panorama tire l'oeil sur le
     cadre au lieu de l'image. Il reprend donc la PASTILLE INVERSEE, le
     vocabulaire deja employe par la plaque d'echelle, le toast, le bandeau de
     mode et les etiquettes de reperes : encre pleine, texte sur fond, sobre
     dans les deux themes. Aucune teinte nouvelle n'est introduite — --tete-*
     nomme des valeurs deja presentes dans la charte. */
  --tete-fond:#2f2a24; --tete-txt:#ffffff; --tete-sous:#cbbfa8;
  --tete-trait:#8d8272; --tete-btn:#f4ece0;
  --mono:ui-monospace,'Cascadia Mono','SF Mono',Consolas,'Liberation Mono',monospace;
  --disp:'Futura','Avenir Next','Century Gothic','Segoe UI',system-ui,sans-serif;
  --corps:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',sans-serif;
}
body[data-theme="nuit"]{
  /* ─── Nuit (mode sombre) — navy Ethic Village ───
     Le papier reprend le navy du site (#16293f) : pose dans une page du site,
     le plan se lit comme une surface, pas comme un trou noir. Les teintes de
     zones et les encres sont recalees pour tenir 4,5:1 sur ce fond plus clair. */
  --papier:#16293f; --page:#101f31; --carte:#1e344e;
  --encre:#eaf0f6; --encre2:#bcc9d6; --mur:#060d16;
  --vert:#2a7f54; --vert2:#5fd39b; --vert-pale:#1b3a2c;
  --jour:#3b382e; --nuit:#2a3441; --eau:#23414a; --cuisine:#3f3327;
  --circ:#243347; --ext:#26333d; --veg:#2f3f31; --sable:#1d3047;
  --bassin:#0e4b57; --eaub:#7ff0fa;
  --trait:#8a99a8; --trait2:#5a6b7d; --grille:#2e4157;
  --meuble:#24384f; --meuble2:#2c4159; --veg2:#5c8a58; --bati:#223851;
  --select2:#5aa9ff; --ombre:rgba(0,0,0,.5);
  --ligne:#2b445e; --alerte:#eb9a5c; --route:#28394d; --routeb:#3c526b;
  --cote:#aebccb; --vert-txt:#7fd6a4; --sur-vert:#f2fbf6;
  --puce-fond:#0d1a28; --puce-txt:#eaf0f6;
  --tete-fond:#0b1725; --tete-txt:#eaf0f6; --tete-sous:#9db0c4;
  --tete-trait:#6b8299; --tete-btn:#dce6f0;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{font-family:var(--corps);background:var(--page);color:var(--encre);display:flex;flex-direction:column;overflow:hidden}

/* ── Cartouche ─────────────────────────────────────────────────── */
header{background:var(--carte);border-bottom:2px solid var(--encre);display:flex;align-items:stretch;flex-wrap:wrap}
.brand{display:flex;align-items:center;gap:14px;padding:10px 18px;border-right:1px solid var(--ligne)}
/* Logo EVD : l'asset officiel du site, inline (aucun appel reseau) et STATIQUE.
   Les animations de lightweight.css (evd-rays-grow, evd-symbol-in...) ne sont
   pas importees : un plan technique n'a pas a bouger. Le lettrage ETHIC VILLAGE
   fait partie du trace, il n'est donc pas repete en texte a cote. */
.brand h1{display:block;line-height:0}
.brand .logo-evd{display:block;height:42px;width:auto;flex:none}
/* Nativement blanc + or : lisible tel quel sur le fond sombre du mode nuit.
   En clair on reprend exactement le filtre du site
   (body[data-pp-theme="light"] .lw-header .evd-logo, provider-portal.css:2321).
   Le :not() couvre aussi l'instant ou data-theme n'est pas encore pose par JS. */
body:not([data-theme="nuit"]) .brand .logo-evd{filter:brightness(0.15) sepia(0.3)}
.brand small{display:block;font-family:var(--mono);font-size:10.5px;color:var(--encre2);letter-spacing:.06em;border-inline-start:1px solid var(--ligne);padding-inline-start:14px;padding-top:5px;padding-bottom:5px}
nav{display:flex;align-items:stretch;flex:1}
nav button{flex:1;max-width:190px;border:none;background:none;cursor:pointer;font-family:var(--disp);font-size:12.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--encre2);border-right:1px solid var(--ligne);padding:8px 10px;display:flex;flex-direction:column;align-items:center;gap:4px;transition:background .15s}
nav button:hover{background:var(--papier)}
nav button .puce{width:12px;height:12px;border-radius:50%;border:2px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,.25)}
nav button .sc{font-family:var(--mono);font-size:10px;letter-spacing:0;text-transform:none;color:var(--encre2)}
nav button.actif{background:var(--vert);color:#fff}
nav button.actif .sc{color:var(--sur-vert)}
.progress-global{display:flex;flex-direction:column;justify-content:center;align-items:flex-end;gap:5px;padding:10px 18px;border-left:1px solid var(--ligne);min-width:170px}
.progress-global .txt{font-family:var(--mono);font-size:11.5px;color:var(--encre2)}
.progress-global .txt b{color:var(--vert-txt);font-size:14px}
.barre{width:140px;height:6px;background:var(--ligne);border-radius:3px;overflow:hidden}
.barre i{display:block;height:100%;background:var(--vert2);width:0;transition:width .3s}

/* ── Corps ─────────────────────────────────────────────────────── */
main{flex:1;display:flex;min-height:0}
/* `overflow:hidden` : l'animation de bascule de la rose fait pivoter le <svg>
   lui-meme le temps d'une demi-seconde ; ses coins sortiraient du cadre et
   passeraient sur le panneau lateral. Rien d'autre ne deborde de #stage — les
   boutons de zoom, l'echelle, la rose et le bandeau de mode sont tous poses en
   absolu A L'INTERIEUR, a 10-14 px des bords. */
#stage{flex:1;position:relative;background:var(--papier);min-width:0;overflow:hidden}
#plan{width:100%;height:100%;display:block;touch-action:none;cursor:grab}
#plan.pan{cursor:grabbing}
#plan.crosshair{cursor:crosshair}
#plan.edplan [data-c]{cursor:move}
#plan.edplan .site-parc{cursor:move}
.ctrl-zoom{position:absolute;left:14px;bottom:14px;display:flex;flex-direction:column;gap:6px}
.ctrl-zoom button{width:38px;height:38px;border-radius:8px;border:1px solid var(--ligne);background:var(--carte);cursor:pointer;font-size:17px;color:var(--encre);box-shadow:0 2px 6px rgba(0,0,0,.12)}
.ctrl-zoom button:hover{background:var(--carte)}
/* Rose des vents — habillage du cadre, plus un objet du plan. Coin bas-droit :
   le seul libre partout (bas-gauche = .ctrl-zoom, haut-centre = .bandeau-mode,
   haut-fin = la carte de statistiques flottante en mode embarque une villa).
   Positions PHYSIQUES a dessein : #stage est force en direction:ltr meme en
   arabe, donc `right` reste `right` et ne vient jamais rejoindre le zoom.
   Taille en px, hors viewBox : identique a 414 px et en plein ecran, et
   insensible au zoom comme au panoramique. Regle de placement et orientation
   documentees dans roseNord() (plan-render.js). */
/* Taille et marge de la rose : elles sont des JETONS, pas des valeurs locales.
   La regression du 06/08 vient de la : la rose etait posee a 52px/14px ici, et
   la carte laterale flottante du mode embarque etait bornee ailleurs, sans
   rapport avec elle. Tant que la liste des points etait vide ou courte, les
   deux ne se rencontraient pas ; les onze points de Diamant ont fait descendre
   la colonne jusqu'en bas et elle est passee PAR-DESSUS la rose (z-index 4
   contre 3). La reservation de place est donc calculee A PARTIR de ces jetons
   (cf. `body[data-embed][data-solo] aside`) : redimensionner la rose deplace
   automatiquement le plafond de la carte, et le nombre de points n'entre pas
   dans l'equation — onze aujourd'hui, trente demain, aucun sur la loge. */
:root{--rose-taille:52px;--rose-marge:14px}
@media (max-width:700px){:root{--rose-taille:44px;--rose-marge:10px}}
.rose-nord{position:absolute;right:var(--rose-marge);bottom:var(--rose-marge);
 width:var(--rose-taille);height:var(--rose-taille);
 pointer-events:none;z-index:3;filter:drop-shadow(0 2px 5px var(--ombre))}
.rose-nord svg{display:block;width:100%;height:100%}
/* Sur une vue d'unite, la rose est un BOUTON : elle aligne le plan sur le nord
   et le rend a la vue d'usage. Elle reste un simple pictogramme sur le plan de
   masse, ou les deux etats seraient identiques. Cible tactile portee a 44 px
   minimum par la taille du badge lui-meme (52 px, 44 px sous 700 px). */
/* Le curseur dit les DEUX gestes : `grab` annonce qu'on peut la tirer pour
   tourner le plan librement, le clic reste la bascule. `touch-action:none` est
   indispensable — sans lui le navigateur prend le glissement pour un
   defilement et le pointeur n'est jamais capture. */
button.rose-nord{pointer-events:auto;cursor:grab;border:0;padding:0;
 background:none;-webkit-appearance:none;appearance:none;color:inherit;
 border-radius:50%;transition:transform .15s;touch-action:none}
button.rose-nord:hover{transform:scale(1.06)}
button.rose-nord.tourne{cursor:grabbing;transform:none}
button.rose-nord:focus-visible{outline:3px solid var(--select2);outline-offset:3px}
@media (prefers-reduced-motion:reduce){button.rose-nord{transition:none}
 button.rose-nord:hover{transform:none}}
/* Échelle graphique — habillage elle aussi. Elle se range CONTRE le bloc de
   zoom, en bas à gauche, et non au centre : le bas-centre est l'endroit où le
   portail d'Opale tombe, et la plaque venait s'y coller. Le bas de cadre reste
   ainsi partagé entre trois choses qui ne se touchent pas — zoom, échelle,
   rose — et la bande centrale est rendue au dessin. Sa
   longueur est recalculée à chaque changement de cadrage (echelleMaj(),
   plan-render.js), donc elle reste métriquement vraie à n'importe quel zoom
   au lieu d'annoncer 5 m en permanence. Plaque opaque : sa lisibilité ne
   dépend pas de ce que le dessin met dessous. */
.ech-graph{position:absolute;left:60px;bottom:14px;
 background:var(--carte);border:1px solid var(--encre2);border-radius:7px;
 padding:4px 9px 3px;line-height:0;pointer-events:none;z-index:3;
 box-shadow:0 2px 5px var(--ombre)}
.ech-graph svg{display:block}
.ech-lab{font-family:var(--mono);fill:var(--encre)}
@media (max-width:700px){.ech-graph{left:56px;bottom:10px;padding:3px 7px 2px}}
.bandeau-mode{position:absolute;top:12px;left:50%;transform:translateX(-50%);background:var(--puce-fond);color:var(--puce-txt);font-family:var(--mono);font-size:12px;padding:8px 16px;border-radius:20px;display:none;align-items:center;gap:10px;box-shadow:0 4px 14px rgba(0,0,0,.25);white-space:nowrap;z-index:5;max-width:92%;overflow:hidden}
.bandeau-mode.on{display:flex}
.bandeau-mode b{color:var(--sur-vert)}
/* Jetons de CARTE, pas de bouton d'en-tete. `--tete-btn` reste pale dans
   les deux themes : posee sur le plan de nuit, la pastille devenait un
   bloc blanc qui trouait le dessin (Ahmed, 21/09/2026). Les jetons de
   carte suivent le theme comme l'infobulle des pastilles juste en
   dessous, qui a toujours eu l'air native. */
.action-guide{display:flex;align-items:center;justify-content:center;gap:8px 18px;padding:10px 15px;background:var(--carte);color:var(--encre);border:1px solid var(--ligne);font-family:var(--corps);font-size:12.5px;font-weight:600;line-height:1.25;box-shadow:0 6px 22px rgba(0,0,0,.28)}
.action-guide>span{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
/* --vert2, pas --vert : sur la carte de nuit le vert sombre tombait a
   2,57:1, sous les 3:1 exiges d'un objet graphique. --vert2 est le vert
   clair du theme, lisible sur les deux fonds de carte. */
.action-guide b{display:inline-flex;align-items:center;justify-content:center;min-width:20px;font-family:var(--mono);font-size:16px;color:var(--vert2)}
/* Le guide se pose EN HAUT A GAUCHE, pas au centre bas : le bas de la
   scene est deja occupe par les boutons de zoom (left 14), l'echelle
   graphique (left 60) et la rose des vents (a droite). Centre en bas, il
   les recouvrait des que la fenetre se resserrait (signale par Ahmed le
   21/09/2026, capture a l'appui) — un bandeau d'aide qui masque les
   commandes qu'il explique. Le haut a gauche est libre : rien n'y est
   pose sauf le bandeau de mode, lui-meme centre. Inset logique pour que
   l'arabe le place a droite sans regle supplementaire. */
.action-guide-plan{position:absolute;inset-block-start:12px;inset-inline-start:12px;z-index:4;
 flex-direction:column;align-items:flex-start;justify-content:flex-start;gap:7px;
 width:max-content;max-width:min(300px,calc(100% - 24px));
 padding:11px 16px;border-radius:14px;pointer-events:none}
/* Empiles, les conseils se lisent comme une liste et la largeur cesse
   d'etre une contrainte : en ligne, le plafond de largeur coupait le
   troisieme hors du fond blanc, gris sur bleu nuit, illisible.
   `width:max-content` fait tenir la pastille exactement au plus long
   conseil, jamais plus. */
.action-guide-plan>span{width:100%}
/* La puce de la consigne imite la pastille du plan : disque vert PLEIN,
   libelle blanc. Elle etait en contour vert sur fond clair, quand la
   pastille est pleine — une legende qui ne ressemble pas a la chose
   qu'elle nomme apprend la mauvaise cible. */
.action-guide-pin{font-size:8px!important;width:24px;height:24px;background:var(--vert);border:2px solid var(--vert);border-radius:50%;color:#fff!important}
.action-guide-pano{border-bottom:1px solid var(--ligne)}
@media (max-width:900px){.action-guide-plan{inset-block-start:10px;inset-inline-start:10px;max-width:calc(100% - 20px);gap:6px;padding:9px 13px}.action-guide{font-size:10.5px}}
@media (max-width:560px){.action-guide-plan{inset-inline-start:10px;inset-block-start:10px;width:max-content;max-width:calc(100% - 20px);transform:none}.action-guide-plan>span:first-child{display:none}.action-guide-pano{flex-wrap:wrap;justify-content:center}.action-guide-pano>span{white-space:nowrap}}

/* ── Rail latéral ──────────────────────────────────────────────── */
aside{width:340px;background:var(--carte);border-left:1px solid var(--ligne);display:flex;flex-direction:column;overflow:hidden}
.villa-fiche{padding:13px 16px 10px;border-bottom:2px solid var(--encre)}
.villa-fiche h2{font-family:var(--disp);font-size:20px;letter-spacing:.14em;text-transform:uppercase;display:flex;align-items:center;gap:10px}
.villa-fiche h2 .puce{width:14px;height:14px;border-radius:50%;border:2px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,.25)}
.villa-stats{margin-top:8px;display:grid;grid-template-columns:auto 1fr;gap:2px 12px;font-size:11.5px}
.villa-stats dt{font-family:var(--mono);color:var(--encre2);font-size:10.5px}
.villa-stats dd{font-weight:600}
.villa-src{margin-top:7px;font-size:10.5px;color:var(--encre2);font-style:italic}
.villa-prog{margin-top:8px;display:flex;align-items:center;gap:9px;font-family:var(--mono);font-size:11px;color:var(--encre2)}
.villa-prog .barre{flex:1;width:auto}
.spots-head{padding:8px 16px 4px;font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--encre2);display:flex;justify-content:space-between;align-items:center}
#liste-spots{flex:1;overflow-y:auto;border-top:1px solid var(--ligne);min-height:60px}
/* ── Ligne de point de prise de vue : survol / selection / focus ──────
   Les trois etats sont DISTINCTS et aucun ne repose sur la seule couleur.
   L'etat selectionne valait `--vert-pale` + un filet `--vert` : le meme vert
   hors palette que l'ancien bandeau de modale, et un simple aplat.
     · survol     — la surface papier, rien d'autre : c'est un survol ;
     · selection  — la surface passe a --page, un FILET D'ENCRE de 4px se
                    deploie sur le bord d'attaque, le libelle passe en 700 et
                    la pastille de numero s'INVERSE (encre pleine au lieu du
                    vert des pastilles du plan). Quatre signaux, dont trois
                    non chromatiques (filet, graisse, inversion, decalage) ;
     · focus      — le contour --select2, exactement celui de la rose des
                    vents, jamais confondu avec les deux autres.
   Le filet est en --encre et non en --puce-fond : en mode nuit --puce-fond
   (#0d1a28) sur --page (#101f31) ne fait que 1,1:1, il disparaitrait. --encre
   est la seule encre qui s'inverse avec le theme. */
.spot-row{display:flex;align-items:center;gap:10px;padding:7px 16px;border-bottom:1px solid var(--ligne);cursor:pointer;
 box-shadow:inset 0 0 0 0 var(--encre);
 transition:background .18s ease,box-shadow .18s ease,padding-inline-start .18s ease}
.spot-row:hover{background:var(--papier)}
.spot-row:focus-visible{outline:3px solid var(--select2);outline-offset:-3px}
.spot-row.sel{background:var(--page);box-shadow:inset 4px 0 0 0 var(--encre);padding-inline-start:20px}
.spot-row.sel .nm{font-weight:700}
.spot-row.sel .num{background:var(--encre);color:var(--carte);transform:scale(1.08)}
.spot-row .num{width:25px;height:25px;border-radius:50%;background:var(--vert);color:#fff;font-family:var(--mono);font-size:11.5px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0;
 transition:background .18s ease,color .18s ease,transform .18s ease}
@media (prefers-reduced-motion:reduce){.spot-row,.spot-row .num{transition:none}}
.spot-row.fait .num{background:var(--encre2)}
.spot-row .nm{flex:1;font-size:13px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.spot-row .ok{font-size:13px;color:var(--vert2);opacity:0;font-weight:700}
.spot-row.fait .ok{opacity:1}
/* Chevron « cette ligne ouvre une villa ». Il etait pose a opacity:.5, ce qui
   le laissait a 2,07:1 en clair et 3,05:1 en nuit : une opacite sur du texte
   delave l'encre ET le fond, elle ne fait jamais gagner du contraste. La
   discretion vient maintenant de l'encre secondaire, a pleine opacite. */
.spot-row .ok.chevron{opacity:1;color:var(--encre2)}
.spot-row .nm-sous{font-family:var(--mono);font-size:10px;color:var(--encre2)}
/* Ligne d'information non cliquable (communs, parking). Le voile opacity:.72
   qui la signalait faisait tomber son libelle a 3,02:1 ; la nuance de fond dit
   la meme chose sans toucher aux textes. */
.spot-row.inerte{cursor:default;background:var(--papier)}
.spot-row.fait .nm{color:var(--encre2)}
.detail{border-top:2px solid var(--encre);padding:11px 16px;display:none;background:var(--papier)}
.detail.on{display:block}
.detail h3{font-size:14px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.detail h3 .id{font-family:var(--mono);font-size:11px;background:var(--puce-fond);color:var(--puce-txt);padding:2px 7px;border-radius:4px}
.detail .pos{font-family:var(--mono);font-size:10.5px;color:var(--encre2);margin-top:5px;line-height:1.5}
.detail .fichier{font-family:var(--mono);font-size:11px;background:var(--papier);border:1px dashed var(--ligne);padding:5px 8px;border-radius:5px;margin-top:7px;word-break:break-all;white-space:pre-line}
.detail .btns{display:flex;flex-wrap:wrap;gap:6px;margin-top:9px}
.nums{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-top:9px}
.champ{display:flex;flex-direction:column;font-family:var(--mono);font-size:10px;color:var(--encre2);gap:2px}
.champ input,.champ select{border:1px solid var(--ligne);border-radius:6px;padding:5px 7px;font-size:12.5px;font-family:var(--mono);background:var(--carte);color:var(--encre);width:100%}
.champ input:focus,.champ select:focus{outline:2px solid var(--vert2)}
.btn{border:1px solid var(--ligne);background:var(--carte);border-radius:7px;padding:6px 10px;font-size:12px;cursor:pointer;color:var(--encre);display:inline-flex;align-items:center;gap:6px}
.btn:hover{border-color:var(--encre2)}
.btn:disabled{opacity:.4;cursor:default}
.btn.principal{background:var(--vert);border-color:var(--vert);color:#fff;font-weight:600}
.btn.principal:hover{background:var(--vert2)}
.btn.danger{color:var(--alerte)}
.btn.danger.arme{background:var(--alerte);color:#fff;border-color:var(--alerte)}
.btn.actif{background:var(--puce-fond);color:var(--puce-txt);border-color:var(--puce-fond)}
.outils{border-top:1px solid var(--ligne);padding:9px 16px 12px}
.outils .rang{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px;align-items:center}
.outils .titre{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--encre2)}
.outils input[type=range]{accent-color:var(--vert2)}

/* ── Modales ───────────────────────────────────────────────────── */
.voile{position:fixed;inset:0;background:rgba(20,20,16,.72);display:none;align-items:center;justify-content:center;z-index:50;padding:18px}
.voile.on{display:flex}
.boite{background:var(--carte);border-radius:12px;max-width:960px;width:100%;max-height:94vh;display:flex;flex-direction:column;overflow:hidden;box-shadow:0 24px 70px rgba(0,0,0,.45)}
/* Bandeau : encre pleine, texte inverse, un seul filet. Il est volontairement
   MINCE (38px au lieu de 58) — c'est autant de hauteur rendue au panorama a
   toutes les tailles, et 12 % du cadre embarque de la page villa (468px). */
.boite-tete{background:var(--tete-fond);color:var(--tete-txt);padding:8px 14px;display:flex;align-items:center;gap:12px;min-height:38px}
.boite-tete h3{font-family:var(--disp);font-size:13px;letter-spacing:.11em;text-transform:uppercase;flex:1;font-weight:600}
/* Le sous-titre etait a `opacity:.85` : une opacite delave l'encre ET le fond,
   elle ne fait jamais gagner du contraste. Il prend une encre a lui. */
.boite-tete .sous{font-family:var(--mono);font-size:11px;color:var(--tete-sous)}
/* Croix : bouton a contour, pas pastille translucide. Le filet --tete-trait
   tient les 3:1 exiges d'un objet graphique sur --tete-fond dans les deux
   themes, et la cible reste a 32px (38px de zone tactile avec le padding du
   bandeau). */
.fermer{background:none;border:1px solid var(--tete-trait);color:var(--tete-btn);width:32px;height:32px;border-radius:50%;font-size:19px;cursor:pointer;line-height:1;flex:none;transition:background .15s,border-color .15s}
/* Survol : le bouton se REMPLIT de son encre claire et la croix reprend le fond
   du bandeau. Un remplissage sur --tete-trait laissait la croix a 3,77:1 —
   suffisant pour un objet graphique, pas pour un glyphe qu'on lit. */
.fermer:hover{background:var(--tete-btn);border-color:var(--tete-btn);color:var(--tete-fond)}
.fermer:focus-visible{outline:3px solid var(--select2);outline-offset:2px}
@media (prefers-reduced-motion:reduce){.fermer{transition:none}}
.boite-corps{padding:0;overflow:auto;flex:1;min-height:0}
#pano{width:100%;height:min(62vh,560px);background:var(--mur)}

/* ── Cadrage de la visionneuse 360° ────────────────────────────────
   Les panoramas sont CYLINDRIQUES : 360° x ~70-83° de champ vertical, tires
   d'images de 1600px de large. La boite avait une hauteur fixe
   (`min(62vh,560px)`) independante de sa largeur, donc des proportions qui ne
   correspondaient a rien :
     · 1440x900  — 960x558 (1,72), soit 84 % seulement du champ vertical
                   visible, dans un ecran de 1404x826 disponibles ;
     · 414x896   — 378x556 (0,68), un PORTRAIT pose sur un cylindre de 83° :
                   52 % de la fenetre en bandes noires (mesure au pixel) ;
     · cadre embarque 812x468 — 776x290 (2,67), 70 % du champ vertical.
   La regle est donc inversee : la fenetre prend le plus grand rectangle qui
   tient dans le cadre, `--pano-ar` est le rapport que le moteur peut honorer
   (borne entre les rapports correspondant a hfov 60° et 110°, cf.
   cadrerPano(), plan-panorama.js), et c'est le CHAMP de la visionneuse qui
   s'aligne dessus — jamais l'inverse.

   `--pano-max` est une limite d'HONNETETE, pas de mise en page. Les sources
   font 1600px de large pour 360° : au champ de 110° servi par defaut sur les
   panoramiques de Diamant, la tranche reellement visible fait
   110/360 x 1600 = 489px. La rendre sur 1120px, c'est 2,29x d'agrandissement,
   soit exactement l'ordre de grandeur deja servi aujourd'hui (2,16x : 444px
   etires sur 960). Laisser la fenetre prendre les 1404px disponibles d'un
   ecran de 1440 donnerait 2,76x — +47 % de surface, mais uniquement du flou
   agrandi. La fenetre s'arrete donc a 1120px et se centre.

   --pano-extra : hauteur de la barre d'outils de l'editeur, posee par
   cadrerPano(). Nulle sur le fichier public. --pano-tete y est egalement
   remesuree, la hauteur du bandeau dependant de la langue. */
#v-pano{--pano-ar:1.7;--pano-max:1120px;--pano-pad:10px;--pano-tete:38px;--pano-extra:0px;padding:var(--pano-pad)}
#v-pano .boite{
 max-width:min(var(--pano-max),calc((100dvh - 2*var(--pano-pad) - var(--pano-tete) - var(--pano-extra))*var(--pano-ar)));
 max-height:calc(100dvh - 2*var(--pano-pad));
 /* En mode nuit, une boite d'encre sur un voile sombre ne se detache que par son
    ombre portee, qui ne se voit pas sur du sombre : un filet clair borne la
    fenetre (4,54:1 sur le fond du bandeau). */
 background:var(--tete-fond);border:1px solid var(--tete-trait)}
#v-pano #pano{width:100%;height:auto;aspect-ratio:var(--pano-ar);overflow:hidden;
 max-height:calc(100dvh - 2*var(--pano-pad) - var(--pano-tete) - var(--pano-extra))}
/* La fenetre est calculee au pixel : rien n'a a defiler. Pannellum arrondit la
   hauteur de son conteneur de rendu a l'entier SUPERIEUR — mesure dans le cadre
   embarque : #pano fait 390,4px et son enfant 397px. Avec `overflow:auto` herite
   de .boite-corps, cet ecart de 7px faisait apparaitre une barre de defilement
   verticale de 15px QUI ROGNAIT L'IMAGE sur toute sa largeur. Les placeholders
   (panorama absent, WebGL indisponible) gardent le defilement : eux ont un
   contenu de hauteur libre. */
#v-pano .boite-corps{overflow:hidden}
#v-pano .boite-corps:has(.placeholder){overflow:auto}
/* Placeholders (panorama absent, WebGL indisponible) : ils n'ont pas de ratio
   a respecter, ils reprennent la surface de carte et se dimensionnent seuls. */
#v-pano .boite-corps:not(:has(#pano)){background:var(--carte);color:var(--encre)}
#v-pano .boite:has(.placeholder){max-width:520px}
.pano-barre{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--papier);border-bottom:1px solid var(--ligne);font-size:12px;color:var(--encre2);flex-wrap:wrap}
/* Selecteur jour/nuit du panorama. Il reprend le vocabulaire de la PASTILLE
   INVERSEE deja employe par la plaque d'echelle, le toast et le bandeau de
   mode : segment actif en encre pleine, segment dormant en carte. Aucune
   teinte nouvelle. Centre, parce qu'il ne commande rien d'autre que l'image
   qu'il surmonte, et un peu plus haut que la barre d'outils de l'editeur :
   c'est le seul contenu de sa ligne, il a de la place pour respirer. */
.pano-heure{justify-content:center;gap:0;padding:16px 12px}
.pano-heure .heure-b{border:1px solid var(--ligne);background:var(--carte);color:var(--encre);font-family:inherit;font-size:12.5px;padding:6px 17px;cursor:pointer}
.pano-heure .heure-b+.heure-b{margin-left:-1px}
.pano-heure .heure-b:first-child{border-radius:7px 0 0 7px}
.pano-heure .heure-b:last-child{border-radius:0 7px 7px 0}
.pano-heure .heure-b:hover{border-color:var(--encre2)}
.pano-heure .heure-b:focus-visible{outline:2px solid var(--select2);outline-offset:2px;z-index:1}
.pano-heure .heure-b.on{background:var(--puce-fond);border-color:var(--puce-fond);color:var(--puce-txt);font-weight:600}
.pano-heure .heure-mention{font-size:12.5px;color:var(--encre2)}
/* Champs de chemin de la fiche d'un point (image de jour, image de nuit).
   Les regles vivaient en style inline dans la coquille de l'editeur ; elles
   sont ici parce qu'il y a desormais DEUX champs a tenir identiques. */
.champ-chemin{margin-top:8px;display:block}
.champ-chemin input{width:100%;border:1px solid var(--ligne);border-radius:6px;padding:5px 7px;font-size:12px;font-family:var(--mono);background:var(--carte);color:var(--encre);margin-top:4px}
.hs-evd{width:30px;height:30px;margin-left:-15px;margin-top:-15px;border-radius:50%;background:rgba(26,107,62,.94);border:2.5px solid #fff;box-shadow:0 2px 10px rgba(0,0,0,.55);cursor:pointer;transition:transform .15s}
.hs-evd:hover{transform:scale(1.18)}
.hs-evd::before{content:'';position:absolute;left:50%;top:50%;width:9px;height:9px;margin:-4.5px 0 0 -4.5px;border-radius:50%;background:#fff}
.hs-evd span{position:absolute;left:38px;top:3px;transition:top .15s;white-space:nowrap;background:rgba(18,18,15,.86);color:#fff;padding:3px 10px;border-radius:13px;font-family:var(--corps);font-size:12.5px;font-weight:600;pointer-events:none}
.hs-evd.lien span::after{content:' ›';opacity:.75}
.placeholder{padding:34px 30px;text-align:center}
.placeholder .ico{font-size:44px}
.placeholder h4{font-size:17px;margin-top:10px}
.placeholder p{font-size:13px;color:var(--encre2);margin-top:7px;line-height:1.55}
.placeholder .chemin{font-family:var(--mono);font-size:12.5px;background:var(--papier);border:1px dashed var(--ligne);display:inline-block;padding:7px 13px;border-radius:6px;margin-top:11px}
.placeholder ol{text-align:left;max-width:520px;margin:14px auto 0;font-size:12.5px;color:var(--encre2);line-height:1.65;padding-left:20px}
.aide-corps{padding:20px 26px;font-size:13.5px;line-height:1.65}
.aide-corps h4{font-family:var(--disp);letter-spacing:.09em;text-transform:uppercase;font-size:12.5px;color:var(--vert-txt);margin:16px 0 5px}
.aide-corps h4:first-child{margin-top:0}
.aide-corps code{font-family:var(--mono);font-size:12px;background:var(--papier);padding:1px 6px;border-radius:4px}
.aide-corps p+p{margin-top:6px}
.aide-corps .kbd{display:inline-block;font-family:var(--mono);font-size:11px;border:1px solid var(--ligne);border-bottom-width:2px;border-radius:4px;padding:0 6px;background:var(--carte)}
.mini{max-width:380px}
.mini .corps{padding:18px}
.mini label{font-size:12.5px;font-weight:600;display:block;margin-bottom:7px}
.mini input{width:100%;border:1px solid var(--ligne);border-radius:7px;padding:9px 11px;font-size:14px;font-family:var(--corps);background:var(--carte);color:var(--encre)}
.mini input:focus{outline:2px solid var(--vert2);border-color:var(--vert2)}
.mini .btns{display:flex;justify-content:flex-end;gap:8px;margin-top:13px}
#toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%) translateY(20px);background:var(--puce-fond);color:var(--puce-txt);font-size:13px;padding:10px 18px;border-radius:9px;opacity:0;pointer-events:none;transition:all .25s;z-index:99;font-family:var(--mono)}
#toast.on{opacity:1;transform:translateX(-50%) translateY(0)}

/* ── SVG plan ──────────────────────────────────────────────────── */
text{user-select:none}
.piece-nom{font-family:var(--disp);font-weight:700;letter-spacing:.06em;fill:var(--encre);stroke:var(--carte);stroke-width:7px;stroke-linejoin:round;paint-order:stroke fill;pointer-events:none}
/* Cote d'une piece : c'est une annotation, elle prend l'encre des annotations.
   Sur --encre2 elle restait entre 4,02:1 et 4,43:1 sur le gazon, le sable et la
   cuisine — sous le seuil, alors que --cote couvre toute la palette claire. */
.piece-dim{font-family:var(--mono);fill:var(--cote);stroke:var(--carte);stroke-width:5px;stroke-linejoin:round;paint-order:stroke fill;pointer-events:none}
/* Libellé du repère d'entrée de villa. Recette de .site-nom : encre pleine sur
   un liseré --carte, pour rester lisible sur le gazon comme sur le sable, en
   clair comme en nuit (--encre tient 8,58:1 au pire sur les fonds du plan). */
.entree-nom{font-family:var(--disp);font-weight:700;letter-spacing:.04em;
 fill:var(--encre);paint-order:stroke;stroke:var(--carte);stroke-width:7px;
 stroke-linejoin:round;pointer-events:none}
/* Destination d'un passage mitoyen (« vers Saphir »). Il ne doit PAS
   concurrencer le badge du portail d'entree, qui est le repere principal de la
   vue : pas de pastille, pas de fleche pleine, pas de capitales — la hierarchie
   se fait par la taille (0,62x celle du libelle de portail), l'italique et
   l'absence de tout objet graphique. L'encre reste --encre, la seule qui tienne
   4,5:1 sur les sept teintes du plan (le gazon, le sable et l'eau des bassins
   compris) ; le lisere --carte pose SOUS le remplissage la degage du fond sans
   lui faire un cartouche. `unicode-bidi:plaintext` : en arabe l'etiquette melange
   un mot RTL et un nom propre latin — sans lui, la direction de base LTR du SVG
   fait lire « Saphir إلى », donc l'etiquette a l'envers. */
.passage-nom{font-family:var(--disp);font-weight:600;font-style:italic;
 fill:var(--encre);paint-order:stroke;stroke:var(--carte);stroke-width:6px;
 stroke-linejoin:round;pointer-events:none;unicode-bidi:plaintext}
/* Nom d'une zone exterieure. L'encre secondaire (--encre2) suffisait sur le
   sable et le gazon, mais ces etiquettes tombent aussi sur le bleu des bassins
   (--bassin) : 2,29:1 pour « Piscine · 8,00 × 5,00 ». Elles passent donc a
   l'encre pleine ; l'italique et la graisse 600 continuent de les distinguer
   des noms de pieces. */
.ext-nom{font-family:var(--disp);font-weight:600;letter-spacing:.05em;fill:var(--encre);font-style:italic;pointer-events:none}
.note{font-family:var(--mono);fill:var(--cote)}
.lab-fixe{font-family:var(--mono);fill:var(--cote);pointer-events:none}
.estompe{opacity:.35;pointer-events:none}
body[data-lecture="1"] .edit-only{display:none!important}
body[data-lecture="1"] .outils{padding-bottom:10px}
/* respiration des blocs cote invite : un intitule ne touche jamais son contenu */
body[data-lecture="1"] .spots-head{padding-bottom:10px}
body[data-lecture="1"] .outils .titre{margin-bottom:10px}
/* provenance interne (noms de fichiers source) : editeur seulement */
body[data-lecture="1"] .villa-src{display:none}
/* mode embarque : la page hote fournit deja titre et habillage */
body[data-embed="1"] .brand,
body[data-embed="1"] .progress-global,
body[data-embed="1"] .villa-prog,
body[data-embed="1"] .outils{display:none!important}
/* une seule villa embarquee : plus rien a montrer dans l'en-tete, et le
   titre du panneau repete celui de la page hote — on garde les statistiques */
body[data-embed="1"][data-solo="1"] header,
body[data-embed="1"][data-solo="1"] .villa-fiche h2{display:none!important}
body[data-embed="1"] .villa-fiche{padding-bottom:14px}
/* une seule villa embarquee : la liste des points est masquee, donc la colonne
   laterale n'a plus qu'un bloc de statistiques. On la pose en carte flottante
   pour rendre toute la largeur au plan au lieu de garder une colonne vide. */
body[data-embed="1"][data-solo="1"] main{position:relative}
/* Le plan doit tenir ENTIER dans le cadre que la page hote lui donne.
   Sous 920px de large, `main` passe en colonne et un element flex vaut alors
   `min-height:auto` : #stage refuse de descendre sous la hauteur intrinseque
   du SVG, soit largeur x (hauteur viewBox / largeur viewBox). L'iframe de la
   section « Plan & piscine » fait 812px de large : 812 x 3586 / 2985 = 975px
   demandes dans une fenetre de 468px, et `body{overflow:hidden}` coupait la
   moitie basse du dessin sans rien dire. Le plancher a 0 rend la hauteur au
   conteneur et `preserveAspectRatio` fait tenir tout le plan des le premier
   rendu ; le zoom manuel (+ / - / ⤢ / molette / pincement) est intact.
   Volontairement limite au mode une-villa-embarquee : c'est le seul ou le
   panneau lateral est flottant, donc le seul ou #stage peut prendre toute la
   hauteur sans reduire autre chose. */
body[data-embed="1"][data-solo="1"] #stage{min-height:0}
/* La carte flottante etait en `height:auto` SANS plafond. Tant que la liste
   des points etait vide, elle ne portait que les statistiques et tenait dans
   le cadre. Les onze points de Diamant la font monter a 676px dans un cadre de
   468 : `body{overflow:hidden}` coupait la liste en plein milieu d'une ligne,
   sans molette ni affordance, et un point selectionne hors champ n'etait
   simplement pas visible. Elle est donc bornee au cadre et c'est la LISTE qui
   defile (elle est deja `overflow-y:auto`), la fiche de la villa restant
   epinglee en tete.

   Le plafond reserve EN PLUS la place de la rose des vents, qui vit dans le
   coin bas-droit du meme cadre : hauteur du cadre moins les 12px de marge haute
   et basse de la carte, moins l'encombrement de la rose (jeton --rose-taille +
   ses deux marges). C'est ce qui garantit qu'elle reste apparente quel que soit
   le nombre de points de prise de vue. */
body[data-embed="1"][data-solo="1"] aside{
 position:absolute;top:12px;inset-inline-end:12px;width:auto;max-width:min(320px,46%);
 height:auto;max-height:calc(100% - 24px - var(--rose-taille) - var(--rose-marge)*2);
 border:1px solid var(--ligne);border-radius:10px;
 box-shadow:0 8px 24px rgba(0,0,0,.28);z-index:4}

/* ── Cartouche depliable (mode embarque, une seule villa) ─────────────
   La carte flottante porte les statistiques ET la liste des points : sur un
   cadre de 1015x520 elle prenait 320px de large sur 400px de haut, soit le
   tiers droit du dessin, en permanence. Elle devient donc un COMPOSANT
   DEPLIABLE, plie au chargement : au repos il ne reste qu'une pastille de
   44px de haut dans le meme coin, aux memes marges de 12px, et toute la
   surface du plan est rendue au dessin.

   Strictement limite a `body[data-embed][data-solo]` : une URL /plans/
   ouverte hors du site garde son rail lateral complet et non depliable, et
   l'editeur ne voit rien changer — l'en-tete et l'enveloppe du contenu ne
   sont meme pas construits ailleurs (monterCartouche(), plan-sidebar.js).
   Sous 700px l'aside entier disparait (regle ci-dessous, la page hote donne
   les chiffres) : la pastille part avec lui, aucun bouton fantome. */
.cartouche-tete{display:none}
body[data-embed="1"][data-solo="1"] .cartouche-tete{display:block;flex:none}
/* `[hidden]` seul perdrait contre `display:flex` — la regle UA a une
   specificite nulle. Les deux vont toujours par paire. */
#cartouche-corps{display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden}
#cartouche-corps[hidden]{display:none}
/* Un vrai <button> : nom accessible visible, aria-expanded/aria-controls poses
   en JS, focus visible avec le meme contour --select2 que la rose des vents.
   Hauteur minimale 44px — cible tactile — tenue par le padding et min-height
   dans les DEUX etats. */
.cartouche-bascule{display:flex;align-items:center;gap:9px;width:100%;
 min-height:44px;padding:11px 14px;border:0;background:none;cursor:pointer;
 color:var(--encre);font-family:var(--mono);font-size:11px;letter-spacing:.09em;
 text-transform:uppercase;text-align:start;transition:background .15s}
.cartouche-bascule:hover{background:var(--papier)}
.cartouche-bascule:focus-visible{outline:3px solid var(--select2);outline-offset:-3px}
.cartouche-bascule .cartouche-lib{flex:1;unicode-bidi:plaintext}
.cartouche-bascule svg{display:block;flex:none;width:17px;height:17px;
 fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.cartouche-bascule .cartouche-chev{transition:transform .18s ease}
/* Deplie : l'en-tete est une barre du cartouche, separee de son contenu par le
   meme filet que les autres blocs, et le chevron pointe vers le haut (replier). */
body[data-embed="1"][data-solo="1"] aside:not([data-plie="1"]) .cartouche-tete{
 border-bottom:1px solid var(--ligne)}
body[data-embed="1"][data-solo="1"] aside:not([data-plie="1"]) .cartouche-chev{
 transform:rotate(180deg)}
/* Plie : l'aside n'est plus une carte, il n'est plus QUE la pastille. Fond,
   filet, ombre et plafond de hauteur passent du conteneur au bouton, et
   `max-width:none` laisse le libelle tenir sur une ligne. */
body[data-embed="1"][data-solo="1"] aside[data-plie="1"]{
 background:none;border-color:transparent;box-shadow:none;
 overflow:visible;max-width:none;max-height:none}
body[data-embed="1"][data-solo="1"] aside[data-plie="1"] .cartouche-bascule{
 min-width:44px;padding:11px 16px;border:1px solid var(--ligne);border-radius:22px;
 background:var(--carte);box-shadow:0 6px 18px var(--ombre)}
@media (prefers-reduced-motion:reduce){
 .cartouche-bascule,.cartouche-bascule .cartouche-chev{transition:none}
}
/* Narrow embedded frame: the stats card is dropped, not stacked.
   Below 700px the floating card no longer fits over the drawing, so it used to
   fall back into the flow and take 106px of a 300px frame — leaving 147x180px
   of actual drawing. The host page owns those figures (see the theme's
   `.cs-villa-plan-embed__footprint`, shown on exactly the same threshold), so
   the frame is handed over to the drawing entirely. Embedded mode only: a
   /plans/ URL opened outside the site keeps its full panel at every width. */
@media (max-width:700px){
 body[data-embed="1"][data-solo="1"] aside{display:none}
 body[data-embed="1"][data-solo="1"] main{flex-direction:column}
}
/* langues RTL : le plan reste en LTR, seule l'interface bascule */
html[dir="rtl"] #stage{direction:ltr}
html[dir="rtl"] .brand{border-right:none;border-left:1px solid var(--ligne)}
html[dir="rtl"] aside{border-left:none;border-right:1px solid var(--ligne)}
html[dir="rtl"] .progress-global{border-left:none;border-right:1px solid var(--ligne);align-items:flex-start}
html[dir="rtl"] .aide-corps ul{padding-left:0;padding-right:20px}
/* valeurs chiffrees : sens de lecture deduit du contenu, pas du conteneur */
html[dir="rtl"] .villa-stats dd,html[dir="rtl"] .spot-row small,
html[dir="rtl"] .progress-global .txt,html[dir="rtl"] #f-prog-txt,
html[dir="rtl"] .brand small{unicode-bidi:plaintext}
body[data-solo="1"] nav,body[data-solo="1"] .progress-global{display:none}
body[data-solo="1"] #sidebar{width:262px}
@media (max-width:780px){body[data-solo="1"] #sidebar{display:none}}
.spot{cursor:pointer}
.spot .pin{fill:var(--vert);stroke:#fff;stroke-width:9}
.spot.fait .pin{fill:var(--encre2)}
.spot .spot-360{fill:#fff;font-family:var(--mono);font-weight:700;letter-spacing:-.08em;pointer-events:none}
.spot .halo{fill:none;stroke:var(--vert2);stroke-width:10;opacity:0;transform-box:fill-box;transform-origin:center}
.spot.sel .halo{opacity:1;animation:pulse 1.6s ease-out infinite}
.spot .etiq-fond{fill:var(--puce-fond);opacity:.92}
.spot .etiq-txt{fill:var(--puce-txt);font-family:var(--corps);font-weight:600}
@keyframes pulse{0%{transform:scale(.72);opacity:.9}70%{transform:scale(1.25);opacity:0}100%{opacity:0}}
@media (prefers-reduced-motion:reduce){.spot.sel .halo{animation:none;opacity:.75}}

/* ── Pastilles 360° du plan PUBLIC (body[data-lecture="1"]) ───────
   Sur le plan de production, le vocabulaire est celui du photographe :
   pastille verte = reste a photographier, pastille grise = prise de vue
   faite. Pour un visiteur la lecture s'inverse — le gris se lit
   « desactive », et c'est justement la pastille CLIQUABLE, la seule qui
   ouvre un panorama. Mesure du 20/09/2026 sur le plan de Jade : 14 px de
   diametre, libelle « 360° » en blanc sur #bcc9d6, soit 1,68:1 en theme
   nuit. Personne ne pouvait ni la voir ni la lire (Ahmed : « les pastilles
   360 ne sont pas assez mises en avant, on ne comprend pas »).
   En lecture, la pastille disponible prend donc l'encre pleine du vert
   (blanc sur --vert : 6,5:1 en clair, 4,9:1 en nuit), un anneau clair qui
   la detache de toutes les teintes de zone, et une ombre portee qui la
   pose AU-DESSUS du dessin. Celle qui n'a pas encore de panorama s'efface
   au lieu de capter l'oeil. Le diametre, lui, est tenu en pixels par
   rendreSpots() : une pastille est un bouton, sa taille ne suit pas le
   zoom du dessin. */
body[data-lecture="1"] .spot .pin{
 transform-box:fill-box;transform-origin:center;
 transition:transform .15s ease;
 filter:drop-shadow(0 1px 2px rgba(0,0,0,.45));
}
body[data-lecture="1"] .spot.fait .pin{fill:var(--vert);stroke:var(--carte)}
body[data-lecture="1"] .spot.fait .spot-360{fill:#fff}
/* Pas encore de panorama : presente, discrete, elle n'appelle pas le clic.
   L'etat est transitoire au chargement — les panoramas sont detectes par
   sonde HTTP (scanPanos), donc toute pastille demarre ici puis s'allume. */
body[data-lecture="1"] .spot:not(.fait) .pin{fill:var(--encre2);opacity:.5;filter:none}
body[data-lecture="1"] .spot:not(.fait) .spot-360{opacity:.5}
body[data-lecture="1"] .spot.fait:hover .pin,
body[data-lecture="1"] .spot.fait:focus-visible .pin{transform:scale(1.14)}
/* ── Sphere qui tourne ────────────────────────────────────────────
   Une pastille verte marquee « 360° » dit CE QUE C'EST, pas ce qu'on
   peut en faire. Deux meridiens balayent le disque en opposition de
   phase : l'oeil lit un globe qui tourne, donc « ici on regarde
   autour de soi ». C'est scaleX sur une ellipse pleine largeur — un
   meridien vu de face est un cercle, vu de profil un trait, et le
   passage de l'un a l'autre EST la rotation. Pas de rx anime (mal
   supporte), pas de sprite, pas de JS : deux formes et une transform
   composite, que le compositeur GPU traite sans repeindre.
   Seules les pastilles `.fait` tournent — celles qui ouvrent vraiment
   un panorama. Une pastille sans panorama qui tournerait promettrait
   un clic qui ne repond pas.
   Les meridiens passent SOUS le texte (opacite 0,55) : le libelle
   reste le premier lu, l'animation est peripherique. Elle s'arrete au
   survol, quand le grossissement prend le relais et qu'on n'a plus
   besoin d'attirer l'oeil. */
body[data-lecture="1"] .spot .pin-globe{display:none}
body[data-lecture="1"] .spot.fait .pin-globe{display:block}
body[data-lecture="1"] .spot.fait .pin-meridien{
 fill:none;stroke:#fff;opacity:.55;
 transform-box:fill-box;transform-origin:center;
 animation:meridien 3.2s cubic-bezier(.45,0,.55,1) infinite;
}
body[data-lecture="1"] .spot.fait .pin-meridien--b{animation-delay:-1.6s}
body[data-lecture="1"] .spot.fait:hover .pin-meridien,
body[data-lecture="1"] .spot.fait:focus-visible .pin-meridien{animation-play-state:paused}
@keyframes meridien{
 0%,100%{transform:scaleX(1)}
 50%{transform:scaleX(.06)}
}
/* Mouvement reduit : le globe reste, fige sur deux meridiens croises —
   la forme dit encore « sphere », sans rien animer. */
@media (prefers-reduced-motion:reduce){
 body[data-lecture="1"] .spot.fait .pin-meridien{animation:none}
 body[data-lecture="1"] .spot.fait .pin-meridien--b{transform:scaleX(.3)}
}
@media (prefers-reduced-motion:reduce){
 body[data-lecture="1"] .spot .pin{transition:none}
}
/* Infobulle des pastilles : nom du point + bande d'aperçu du panorama.
   Couche HTML dans #stage (voir plan-interactions.js) — jamais un élément
   SVG, qui tournerait avec la vue. `pointer-events:none` : elle ne bloque
   ni le clic ni le glisser. Les images sont des bandes cylindriques ~5:1 :
   un recadrage horizontal (`object-fit:cover`) rend mieux qu'une vignette
   carrée. Tokens de carte : contrastes garantis dans les deux thèmes. */
.spot-tip{position:absolute;z-index:60;transform:translate(-50%,-100%);display:flex;flex-direction:column;gap:6px;padding:8px;background:var(--carte);color:var(--encre);border:1px solid var(--ligne);border-radius:10px;box-shadow:0 6px 22px rgba(0,0,0,.28);pointer-events:none;opacity:0;visibility:hidden;transition:opacity .15s ease;max-width:224px}
.spot-tip.on{opacity:1;visibility:visible}
.spot-tip .spot-tip-nom{font-size:12.5px;font-weight:600;text-align:center;line-height:1.35;unicode-bidi:plaintext}
.spot-tip .spot-tip-bande{display:block;width:180px;height:70px;border-radius:6px;overflow:hidden;background:var(--papier)}
.spot-tip .spot-tip-bande[hidden]{display:none}
.spot-tip .spot-tip-bande.charge{background:linear-gradient(100deg,var(--papier) 40%,var(--ligne) 50%,var(--papier) 60%);background-size:200% 100%;animation:tipCharge 1.1s linear infinite}
@keyframes tipCharge{from{background-position:200% 0}to{background-position:0 0}}
@media (prefers-reduced-motion:reduce){.spot-tip{transition:none}.spot-tip .spot-tip-bande.charge{animation:none}}
/* Piste de rotation des miniatures 360 (poserPanoDefile, plan-bootstrap.js) :
   n copies de l'image côte à côte, glissées par transform d'exactement une
   largeur de copie — le raccord du 360 est invisible par construction.
   `max-width:none` : une copie doit garder sa largeur naturelle, jamais être
   compressée dans la fenêtre. */
.pano-defile{display:flex;height:100%;width:max-content;will-change:transform}
.pano-defile img{height:100%;width:auto;max-width:none;display:block}
/* Miniature du panorama dans la fiche du point (surface tactile + desktop) :
   même fenêtre défilante que l'infobulle. */
.detail .apercu-pano{display:block;width:100%;height:84px;border-radius:8px;border:1px solid var(--ligne);margin-top:8px;overflow:hidden;background:var(--papier)}
.detail .apercu-pano[hidden]{display:none}
.mesure line{stroke:var(--alerte);stroke-width:2.5;vector-effect:non-scaling-stroke}
.mesure .tick{stroke-width:2}
.mesure text{font-family:var(--mono);font-weight:700;fill:var(--alerte);paint-order:stroke;stroke:#fff;stroke-linejoin:round}
.mesure circle{fill:var(--alerte)}
.site-parc{cursor:pointer;transition:fill-opacity .12s}
.site-parc:hover{fill-opacity:.55}
.site-nom{font-family:var(--disp);font-weight:700;letter-spacing:.06em;fill:var(--encre);paint-order:stroke;stroke:var(--carte);stroke-width:9px;pointer-events:none}
/* Surface d'une parcelle, posee sur la teinte de cette parcelle. Le liseré
   --carte est un contour de 7 unites autour d'un glyphe de 66 : il degage la
   lettre, il ne lui fait pas un fond. L'encre secondaire tombait a 2,91:1 sur
   le vert des communs ; c'est l'encre pleine qui tient sur les sept teintes. */
.site-surf{font-family:var(--mono);fill:var(--encre);paint-order:stroke;stroke:var(--carte);stroke-width:7px;pointer-events:none}
.handle{fill:#fff;stroke:var(--alerte);stroke-width:2.5;vector-effect:non-scaling-stroke;cursor:move}
.poig-m{fill:var(--alerte);stroke:#fff}
.sel-out{fill:none;stroke:var(--alerte);stroke-width:2.5;stroke-dasharray:7 5;vector-effect:non-scaling-stroke;pointer-events:none}
.guide{stroke:#e07a2e;stroke-width:1.5;stroke-dasharray:6 5;vector-effect:non-scaling-stroke;pointer-events:none}
[data-h="n"],[data-h="s"]{cursor:ns-resize}
[data-h="e"],[data-h="w"]{cursor:ew-resize}
[data-h="nw"],[data-h="se"]{cursor:nwse-resize}
[data-h="ne"],[data-h="sw"]{cursor:nesw-resize}

/* ── Impression ───────────────────────────────────────────────── */
#feuille-print{display:none}
@media print{
  body>header,body>main,#toast,.voile{display:none!important}
  body{overflow:visible;background:var(--carte)}
  #feuille-print{display:block;padding:8mm;font-family:var(--corps)}
  #feuille-print h1{font-family:var(--disp);font-size:18pt;letter-spacing:.1em;text-transform:uppercase}
  #feuille-print .sous{font-family:var(--mono);font-size:9pt;color:#555;margin:2mm 0 4mm}
  #feuille-print svg{width:100%;height:auto;max-height:165mm;border:1px solid #999}
  #feuille-print table{width:100%;border-collapse:collapse;margin-top:5mm;font-size:9pt}
  #feuille-print th,#feuille-print td{border:1px solid #999;padding:1.6mm 2.5mm;text-align:left}
  #feuille-print th{background:#eee;font-family:var(--mono);font-size:8pt;text-transform:uppercase;letter-spacing:.05em}
  #feuille-print td.mono{font-family:var(--mono);font-size:8.5pt}
}
@media (max-width:920px){
  header{display:block;min-width:0}
  nav{width:100%;min-width:0;max-width:100%;overflow-x:auto}
  nav button{flex:0 0 76px}
  main{flex-direction:column}
  aside{width:100%;height:46vh;border-left:none;border-top:2px solid var(--encre)}
  .brand .logo-evd{height:34px}
  .brand small{padding-inline-start:10px}
  nav button{font-size:10.5px;letter-spacing:.06em}
  .progress-global{display:none}
}

/* ---- Calques (private layers) ----
   One colour per layer; the label is always --encre with a --papier halo so it
   keeps >= 4.5:1 on the paper in both themes, whatever the layer colour. */
:root{
  --calq-cameras:#b4302c; --calq-reseau:#2f5fa8; --calq-electricite:#b0700a;
  --calq-eau:#127a8a; --calq-piscines:#1f6fc0; --calq-securite:#8e2f7a;
  --calq-acces:#5b4a2e; --calq-capteurs:#4f7a2a; --calq-irrigation:#2e7d4f;
}
body[data-theme="nuit"]{
  --calq-cameras:#ff8a80; --calq-reseau:#82b1ff; --calq-electricite:#ffc857;
  --calq-eau:#6fd6e3; --calq-piscines:#7fc4ff; --calq-securite:#e59ad6;
  --calq-acces:#d9c39a; --calq-capteurs:#a5d67a; --calq-irrigation:#7ed6a1;
}
.calque-cameras{--calq:var(--calq-cameras)}
.calque-reseau{--calq:var(--calq-reseau)}
.calque-electricite{--calq:var(--calq-electricite)}
.calque-eau{--calq:var(--calq-eau)}
.calque-piscines{--calq:var(--calq-piscines)}
.calque-securite{--calq:var(--calq-securite)}
.calque-acces{--calq:var(--calq-acces)}
.calque-capteurs{--calq:var(--calq-capteurs)}
.calque-irrigation{--calq:var(--calq-irrigation)}
.calque-obj circle{fill:var(--carte);stroke:var(--calq,var(--encre))}
.calque-obj text{fill:var(--calq,var(--encre));font-family:var(--mono);font-weight:700;pointer-events:none}
.calque-obj .calque-nom{fill:var(--encre);font-family:var(--corps);font-weight:600;paint-order:stroke;stroke:var(--papier);stroke-linejoin:round}
.calque-fov{fill:var(--calq,var(--encre));fill-opacity:.18;stroke:none;pointer-events:none}
.calque-run{fill:none;stroke:var(--calq,var(--encre));stroke-linecap:round;stroke-linejoin:round}
.calque-zone{fill:var(--calq,var(--encre));fill-opacity:.12;stroke:var(--calq,var(--encre))}
/* Dashed: the dash lengths are geometry scaled to the zoom, so rendreCalques()
   writes them as the stroke-dasharray attribute; this rule only shapes them. */
.calque-to_survey circle,.calque-run.calque-to_survey,.calque-zone.calque-to_survey{stroke-linecap:butt}
.calque-to_survey circle{fill-opacity:.7}
.calque-retired{opacity:.4}

/* ---- Relevé des calques (survey mode, editor only) ----
   Panel + card live in the aside; below 900 px they become bottom sheets
   with a handle, capped at 45 vh. The tool bar is pinned (sticky) above
   them (z-index), so a sheet never covers it; the sheet's extra bottom
   padding keeps its last lines reachable above the bar. */
#calques-panneau,#calque-fiche{
 border-top:2px solid var(--encre);background:var(--papier);padding:12px 16px;margin-top:16px;
 display:flex;flex-direction:column;gap:16px;
}
#calques-panneau[hidden],#calque-fiche[hidden]{display:none}
.calques-tete{display:flex;align-items:center;justify-content:space-between;gap:12px}
.calques-tete h3{font-size:14px;margin:0;display:flex;align-items:baseline;gap:8px}
.calques-tete h3 .nb{font-family:var(--mono);font-size:11px;color:var(--encre2)}
.calques-poignee{display:none;width:44px;height:5px;border-radius:3px;background:var(--ligne);margin:0 auto}
.calques-filtres{display:flex;flex-wrap:wrap;gap:8px}
.chip{
 min-height:44px;min-width:44px;padding:0 14px;border:1px solid var(--ligne);border-radius:999px;
 background:var(--carte);color:var(--encre);font-size:12.5px;font-family:var(--corps);cursor:pointer;
}
.chip[aria-pressed="true"]{background:var(--encre);border-color:var(--encre);color:var(--papier)}
#calques-recherche{
 width:100%;min-height:44px;border:1px solid var(--ligne);border-radius:8px;
 padding:8px 12px;font-size:14px;background:var(--carte);color:var(--encre);
}
#calques-recherche:focus{outline:2px solid var(--vert2)}
.a-placer{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.a-placer li{
 min-height:44px;display:flex;flex-direction:column;justify-content:center;gap:2px;
 padding:8px 12px;border:1px solid var(--ligne);border-radius:8px;background:var(--carte);cursor:pointer;
}
.a-placer li .ref{font-family:var(--mono);font-size:10.5px;color:var(--encre2)}
.a-placer li[aria-selected="true"]{border-color:var(--vert);box-shadow:0 0 0 2px var(--vert)}
.a-placer .vide{padding:16px;font-size:12.5px;color:var(--encre2);border:none;background:none;cursor:default}
.cf-meta{font-size:12px;color:var(--encre2)}
.cf-cap{display:flex;flex-wrap:wrap;gap:16px;align-items:flex-end}
.cf-cap[hidden]{display:none}
.cf-cap .champ{flex:1;min-width:110px}
.cf-cap-btns{display:flex;gap:8px}
#calque-fiche textarea{
 border:1px solid var(--ligne);border-radius:6px;padding:8px;font-size:12.5px;
 font-family:var(--corps);background:var(--carte);color:var(--encre);width:100%;resize:vertical;
}
#calque-fiche textarea:focus{outline:2px solid var(--vert2)}
#calque-fiche .btns{display:flex;flex-wrap:wrap;gap:8px}
.btn.sale{border-color:var(--alerte);color:var(--alerte)}

/* ---- Tracé de câbles, tuyaux et zones (survey mode, editor only) ----
   rendreTraceEnCours() (plan-interactions.js) draws into #lyr-calque-edit:
   the dashed preview, its vertices, and the handles of the selected run /
   zone. Dash lengths and radii are screen px written as attributes. */
#lyr-calques .calque-run{pointer-events:stroke}
#calque-trace{fill:none;stroke:var(--calq,var(--encre));stroke-linecap:butt;stroke-linejoin:round;pointer-events:none}
.calque-trace-pt{fill:var(--carte);stroke:var(--calq,var(--encre));pointer-events:none}
.calque-trace-pt.dernier{fill:var(--calq,var(--encre));stroke:var(--carte)}
/* 44 px tap target: a transparent circle (r 22 px) around a 6 px dot. */
.calque-sommet{cursor:grab;touch-action:none}
.calque-sommet .cible{fill:transparent;stroke:none;pointer-events:all}
.calque-sommet .point{fill:var(--carte);stroke:var(--calq,var(--encre));pointer-events:none}
.calques-actions{display:flex;flex-wrap:wrap;gap:16px}
.calques-actions .btn,.trace-form .btn,.cf-trace .btn{min-height:44px;padding:0 16px;font-size:13px}
.trace-form{display:flex;flex-direction:column;gap:16px;padding:12px;border:1px solid var(--ligne);border-radius:8px;background:var(--carte)}
.trace-form[hidden]{display:none}
.trace-form .champ input,.trace-form .champ select,.cf-trace .champ input{min-height:44px;font-size:14px}
.trace-form .champ[hidden],.cf-trace .champ[hidden]{display:none}
.trace-form .btns{display:flex;flex-wrap:wrap;gap:16px;justify-content:flex-end}
.cf-trace{display:flex;flex-direction:column;gap:16px}
.cf-trace[hidden]{display:none}
.cf-mesure{font-family:var(--mono);font-size:13px;color:var(--encre)}
/* Floating bar while tracing: bottom of the plan, clear of the zoom column
   (left, 52 px wide) and of the north rose (bottom right). The sheets are
   hidden while tracing; z-index keeps the bar above them anyway. */
#trace-barre{
 position:absolute;left:68px;right:16px;
 bottom:calc(var(--rose-marge) + var(--rose-taille) + 16px);z-index:65;
 display:flex;gap:16px;
}
#trace-barre[hidden]{display:none}
#trace-barre .btn{flex:1;justify-content:center;text-align:center;min-height:44px;padding:4px 8px;font-size:13px;line-height:1.2;box-shadow:0 2px 8px rgba(0,0,0,.18)}
@media print{#lyr-calque-edit{display:none}}
@media (max-width:899px){
 aside{overflow-y:auto}
 .outils{position:sticky;bottom:0;z-index:70;background:var(--carte)}
 #calques-panneau,#calque-fiche{
  position:fixed;left:0;right:0;bottom:0;z-index:60;margin-top:0;
  max-height:45vh;overflow-y:auto;
  background:var(--carte);border-top:2px solid var(--encre);border-radius:14px 14px 0 0;
  box-shadow:0 -8px 28px rgba(0,0,0,.22);padding:8px 16px 120px;
 }
 .calques-poignee{display:block}
}

/* ---- Visionneuse des calques (admin-plans/calques.html, read only) ----
   Phone first: header, layer strip, plan, card stacked with 16 px between
   blocks. Below 900 px the card is a bottom sheet and the page keeps 16 px
   of free space above its highest position; above, it is a right column. */
.page-calques aside.calques-moteur[hidden]{display:none}
.page-calques #lyr-spots{display:none}
.page-calques #calques-barre{
 display:flex;flex-wrap:wrap;gap:8px;flex:none;
 margin:16px 0;padding:0 16px;
}
.page-calques #calques-barre:empty{display:none}
/* The strip is a <nav>: undo the villa-tab look of `nav button` (header). */
.page-calques #calques-barre .chip{
 display:inline-flex;flex-direction:row;align-items:center;gap:8px;flex:none;max-width:none;
 border:1px solid var(--ligne);font-family:var(--corps);font-size:13px;letter-spacing:0;text-transform:none;
}
.page-calques #calques-barre .chip[aria-pressed="true"]{border-color:var(--encre)}
.page-calques #calques-barre .chip[aria-pressed="false"]{color:var(--encre2);border-style:dashed}
.chip-puce{width:12px;height:12px;border-radius:50%;flex:none;background:var(--calq,var(--encre));box-shadow:0 0 0 2px var(--carte)}
.page-calques main{gap:16px;padding:0 16px 16px}
@media (min-width:900px){.page-calques main{flex-direction:row}}
.page-calques #stage{border:1px solid var(--ligne);border-radius:10px}
/* rendreCalques() leaves the layer group inert outside survey mode; on this
   page only, the shapes themselves take taps (labels and wedges stay inert). */
.page-calques #lyr-calques .calque-obj circle,
.page-calques #lyr-calques .calque-run,
.page-calques #lyr-calques .calque-zone{pointer-events:visiblePainted;cursor:pointer}
.calque-obj.sel circle{fill:var(--calq,var(--encre))}
.calque-obj.sel text:not(.calque-nom){fill:var(--carte)}
.calque-run.sel,.calque-zone.sel{stroke:var(--select2)}
.page-calques #calque-fiche{
 margin-top:0;border:1px solid var(--ligne);border-top:2px solid var(--encre);border-radius:10px;
 background:var(--carte);padding:16px;
 width:360px;flex:none;overflow-y:auto;
}
.page-calques #calque-fiche[hidden]{display:none}
.fiche-tete{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}
.fiche-tete h2{font-size:17px;line-height:1.25;margin:0 0 4px}
.fiche-fermer{min-width:44px;min-height:44px;justify-content:center;font-size:20px;flex:none}
.statut{display:inline-block;padding:3px 10px;border-radius:999px;font-size:11.5px;font-weight:600;border:1px solid currentColor}
.statut-placed{color:var(--vert-txt)}
.statut-to_survey{color:var(--alerte)}
.statut-retired{color:var(--encre2)}
.fiche-attrs{display:grid;grid-template-columns:max-content 1fr;gap:6px 16px;font-size:13px;margin:0}
.fiche-attrs dt{color:var(--encre2)}
.fiche-attrs dd{margin:0;font-family:var(--mono);overflow-wrap:anywhere}
.fiche-note{font-size:13px;line-height:1.5;white-space:pre-line}
#calque-fiche .btns .btn{min-height:44px;padding:0 16px;font-size:13px;text-decoration:none}
@media (max-width:899px){
 .page-calques main{padding:0 0 16px}
 .page-calques #stage{border-radius:0;border-left:none;border-right:none}
 .page-calques #calque-fiche{
  width:auto;border-radius:14px 14px 0 0;border-left:none;border-right:none;border-bottom:none;
  padding:8px 16px 16px;
 }
 .page-calques.fiche-ouverte main{margin-bottom:calc(45vh + 16px)}
}
