
  /* ── Vocabulaire visuel du player Slider client (slider.css), repris à l'identique ── */
  :root{
    --dls-accent:#BE222F;
    --dls-white:rgba(255,255,255,.95);
    --dls-dim:rgba(255,255,255,.55);
    --dls-glass:rgba(17,17,17,.62);
    --dls-border:rgba(255,255,255,.18);
    --dls-font:'Barlow',sans-serif;
    --dls-label:'Barlow Condensed',sans-serif;
  }
  *{box-sizing:border-box}
  html,body{margin:0;height:100%;overflow:hidden;background:transparent;
    color:var(--dls-white);font-family:var(--dls-font);user-select:none;-webkit-user-select:none}
  /* ⚠️ touch-action:none SUR LA RACINE, pas seulement sur le canevas.
     Il n'était posé que sur #view. La poignée de la glissière est un élément
     FIXE, hors du canevas : au doigt, le navigateur laissait passer les
     premiers pixels puis réclamait le geste pour son propre défilement, tirait
     un `pointercancel`, et la glissière se figeait après avoir à peine bougé.
     Le player Slider photo, lui, le pose sur sa racine depuis toujours — et sa
     poignée n'a jamais eu ce défaut. Même remède ici. */
  #root{position:fixed;inset:0;overflow:hidden;border-radius:16px;background:#0a0a0a;
    touch-action:none}
  #root.flush{border-radius:0}
  #view{width:100%;height:100%;display:block;touch-action:none}

  /* Auto-masquage : tout sauf le logo et la poignée disparaît au repos */
  .fade{transition:opacity .35s ease}
  body.ui-idle .fade{opacity:0;pointer-events:none}

  /* Logo (haut gauche), toujours affiché */
  .dls-logo{position:fixed;top:calc(13px + env(safe-area-inset-top,0px));left:calc(14px + env(safe-area-inset-left,0px));
    z-index:6;height:48px;width:auto;opacity:.92;pointer-events:none;-webkit-user-drag:none;
    filter:drop-shadow(0 2px 6px rgba(0,0,0,.55))}

  /* Boutons ronds haut-droite (style .dls-fs/.dls-play du player) */
  /* `overflow:visible` explicite : l'œil déborde du cercle */
  .rbtn{position:fixed;overflow:visible;top:calc(12px + env(safe-area-inset-top,0px));z-index:7;
    width:38px;height:38px;border-radius:50%;border:1px solid var(--dls-border);
    background:var(--dls-glass);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
    color:var(--dls-white);cursor:pointer;display:grid;place-items:center;transition:border-color .15s;padding:0}
  .rbtn:hover{border-color:var(--dls-accent)}
  .rbtn svg{width:18px;height:18px;fill:var(--dls-white)}
  .rbtn.on{border-color:var(--dls-accent);background:rgba(190,34,47,.32)}
  /* ── L'ŒIL DU CALQUE ────────────────────────────────────────────────────
     Voir et modifier sont deux choses : le bouton entre dans l'outil, l'œil
     dit si le calque s'affiche. Posé en pastille sur le coin du bouton, comme
     dans toute liste de calques — c'est le geste que les gens connaissent.
     Au survol seulement sur souris : sinon deux pastilles rouges permanentes
     dans une rangée déjà chargée. Au DOIGT il n'y a pas de survol, donc il
     reste visible : un contrôle qu'on ne peut pas atteindre n'existe pas. */
  .rbtn .oeil{position:absolute;right:-5px;bottom:-5px;width:19px;height:19px;
    border-radius:50%;display:grid;place-items:center;cursor:pointer;
    background:#1b1b1d;border:1px solid var(--dls-border);
    opacity:0;transform:scale(.7);transition:opacity .13s ease, transform .13s ease}
  .rbtn:hover .oeil,.rbtn .oeil:hover{opacity:1;transform:scale(1)}
  .rbtn .oeil svg{width:11px;height:11px;fill:rgba(255,255,255,.85);display:block}
  .rbtn .oeil.barre{background:var(--dls-accent);border-color:rgba(255,255,255,.4)}
  .rbtn .oeil.barre svg{fill:#fff}
  .rbtn .oeil[hidden]{display:none}
  /* calque éteint : le bouton le dit sans s'effacer — il reste cliquable, et
     y entrer rallumera le calque */
  .rbtn.eteint{opacity:.55}
  .rbtn.eteint .oeil{opacity:1;transform:scale(1)}
  @media (hover:none){ .rbtn .oeil{opacity:1;transform:scale(1)} }
  /* mesures affichées hors de l'outil : on regarde, on ne saisit pas */
  #mesLabels.lecture .mes-som{pointer-events:none;cursor:default}
  /* subordonné au balayage : visible mais hors d'atteinte */
  .rbtn.grise{opacity:.32;pointer-events:none;cursor:default}
  /* ⚠️ PLUS D'OFFSETS FIGÉS PAR BOUTON. Ils sont calculés par disposerOutils()
     dans gs.js, à partir de la place réellement disponible : l'ordre visuel
     est Maison · Mesure · Repères · Photo · Double · Comparateur · Lecture ·
     Visite · Plein écran, et les deux outils de chantier se replient derrière
     « … » quand la largeur ne suffit plus. Les boutons gardent leur
     `position:fixed` et ne changent JAMAIS de parent — un nœud déplacé sous
     le doigt perd son clic, et la zone tactile ::after s'ancre sur eux. */
  /* L'aide vit seule en bas à gauche, hors de la rangée d'outils : c'est le
     premier réflexe d'un client perdu, et le coin opposé au logo est libre. */
  #aideBtn{top:auto;right:auto;left:calc(14px + env(safe-area-inset-left,0px));
    bottom:calc(24px + env(safe-area-inset-bottom,0px))}

  /* Points de vue : pastille centrale repliée, exactement .dls-views du player */
  .dls-views{position:fixed;top:calc(12px + env(safe-area-inset-top,0px));left:50%;transform:translateX(-50%);z-index:6;
    display:flex;gap:0;flex-wrap:nowrap;justify-content:center;max-width:92%;
    background:var(--dls-glass);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
    border:1px solid var(--dls-border);border-radius:999px;padding:5px}
  .dls-view{border:0;background:transparent;color:var(--dls-dim);cursor:pointer;
    font-family:var(--dls-font);font-weight:600;font-size:12.5px;
    padding:6px 12px;border-radius:999px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:240px;
    transition:max-width .28s ease, opacity .2s ease, padding .28s ease, margin .28s ease, color .15s, background .15s;
    display:inline-flex;align-items:center;gap:6px}
  .dls-view + .dls-view{margin-left:4px}
  .dls-view:hover{color:var(--dls-white)}
  .dls-view.active{background:var(--dls-accent);color:#fff}
  /* La croix est un bouton, pas une prise : elle annule le `grab` de la pastille
     déplaçable. Une déclaration sur l'enfant l'emporte toujours sur la valeur
     héritée du parent, quelle que soit la spécificité. */
  .dls-view .x{opacity:0;font-size:11px;transition:opacity .15s;padding:0 1px;cursor:pointer}
  .dls-view:hover .x{opacity:.8}
  .dls-view .x:hover{opacity:1}
  .dls-view.addbtn{color:var(--dls-dim);font-weight:600}
  .dls-view.addbtn:hover{color:var(--dls-white)}
  .dls-views:not(:hover) .dls-view:not(.active){max-width:0;opacity:0;padding-left:0;padding-right:0;margin-left:0;pointer-events:none}
  .dls-views:not(:hover) .dls-view.active{margin-left:0}
  /* aucun PDV encore : la pastille « + » reste visible seule */
  .dls-views.empty:not(:hover) .dls-view.addbtn{max-width:240px;opacity:1;padding:6px 12px;pointer-events:auto}
/* mesure : état déplié figé, transitions coupées — sert uniquement à calculer
   le chevauchement avec les boutons, jamais visible à l'écran */
.dls-views.mesure .dls-view{transition:none!important}
.dls-views.mesure .dls-view:not(.active){max-width:240px;opacity:1;padding:6px 12px}
.dls-views.mesure .dls-view + .dls-view{margin-left:4px}
/* la barre descend sous la rangée de boutons quand elles se toucheraient */
.dls-views.sous{top:calc(58px + env(safe-area-inset-top,0px))}
  /* Une vue composée par Dronelapse porte un repère discret : le client doit
     pouvoir distinguer la visite qu'on lui propose de celle qu'il se fabrique,
     sans que ça devienne une décoration. */
  .dls-view.publie::before{content:"";width:5px;height:5px;border-radius:50%;
    background:var(--dls-accent);opacity:.85;flex:0 0 auto}
  .dls-view.active.publie::before{background:#fff;opacity:.9}
  /* Déplacement : la vue saisie s'efface, celle qu'on survole montre le bord
     où elle sera déposée. */
  .dls-view[draggable="true"]{cursor:grab}
  .dls-view.drag{opacity:.35;cursor:grabbing}
  .dls-view.over{box-shadow:inset 2px 0 0 var(--dls-accent)}
  .dls-view.resetbtn{color:var(--dls-dim);font-size:14px;padding:6px 10px}
  .dls-view.resetbtn:hover{color:var(--dls-white)}

  /* Barre basse : états Avant/Après + badge Comparer (structure .dls-controls du player) */
  .dls-controls{position:fixed;left:50%;bottom:calc(24px + env(safe-area-inset-bottom,0px));transform:translateX(-50%);z-index:6;
    display:flex;align-items:center;gap:10px;
    background:var(--dls-glass);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
    border:1px solid var(--dls-border);border-radius:999px;padding:6px 8px;max-width:94%}
  .dls-nav{display:flex;align-items:center;gap:4px}
  .dls-arrow{position:relative;width:30px;height:30px;border-radius:50%;border:0;cursor:pointer;
    background:rgba(255,255,255,.08);color:var(--dls-white);
    display:grid;place-items:center;font-size:15px;transition:background .15s}
  .dls-arrow:hover:not(:disabled){background:var(--dls-accent)}
  .dls-arrow:disabled{opacity:.3;cursor:default}
  .dls-date{min-width:74px;text-align:center;font-family:var(--dls-label);font-weight:700;font-size:14px;letter-spacing:.03em;white-space:nowrap}
  .dls-side-lab{font-family:var(--dls-label);font-weight:700;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--dls-dim);text-align:center;margin-bottom:1px}
  .dls-delta{font-family:var(--dls-label);font-weight:700;font-size:12px;letter-spacing:.05em;
    color:var(--dls-white);background:rgba(190,34,47,.22);border:1px solid rgba(190,34,47,.4);
    border-radius:999px;padding:5px 11px;white-space:nowrap;cursor:pointer;user-select:none;transition:background .15s}
  .dls-delta:hover{background:rgba(190,34,47,.36)}
  /* Inverser : le bouton du CMP, ramené dans la barre du comparateur */
  .dls-swap{width:30px;height:30px;border-radius:50%;border:0;cursor:pointer;padding:0;
    background:rgba(255,255,255,.08);color:var(--dls-white);display:grid;place-items:center;
    transition:background .15s;position:relative}
  .dls-swap:hover{background:var(--dls-accent)}
  .dls-swap svg{width:16px;height:16px}
  /* hors comparaison : un seul sélecteur de date, ni delta ni inversion */
  #navB,#delta,#swapBtn{display:none}
  body.comparing #navB{display:flex}
  body.comparing #delta{display:block}
  body.comparing #swapBtn{display:grid}

  /* Poignée du comparateur : ligne 2px + bouton 44px à chevrons, comme le player */
  #wipe{position:fixed;top:0;bottom:0;width:0;display:none;z-index:5;pointer-events:none}
#dblSep{position:fixed;top:0;bottom:0;left:50%;width:2px;margin-left:-1px;display:none;
  z-index:5;pointer-events:none;background:rgba(255,255,255,.85);
  box-shadow:0 0 6px rgba(0,0,0,.55)}
  #wipe::before{content:"";position:absolute;top:0;bottom:0;left:-1px;width:2px;
    background:rgba(255,255,255,.9);box-shadow:0 0 0 1px rgba(0,0,0,.25)}
  #wipe .dls-knob{position:absolute;top:50%;left:0;transform:translate(-50%,-50%);
    width:44px;height:44px;border-radius:50%;
    background:var(--dls-glass);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
    border:1.5px solid var(--dls-border);display:grid;place-items:center;cursor:ew-resize;pointer-events:auto;
    touch-action:none;
    box-shadow:0 6px 20px rgba(0,0,0,.45);transition:border-color .15s ease}
  #wipe .dls-knob svg{width:22px;height:22px;fill:var(--dls-white)}
  #wipe.dragging .dls-knob{border-color:var(--dls-accent)}

  /* Voile de capture : l'écran garde l'image du client pendant que la pleine
     qualité est chargée et photographiée derrière. `object-fit:fill` et non
     `cover` — c'est une copie exacte du canevas, au même format : la recadrer
     ferait sauter l'image au moment où le voile se pose. */
  .gel{position:absolute;inset:0;z-index:50;background:#0a0a0a}
  .gel canvas{width:100%;height:100%;display:block;object-fit:fill}
  .gel-mot{position:absolute;left:50%;bottom:26px;transform:translateX(-50%);
    padding:8px 14px;border-radius:999px;background:var(--dls-glass);
    backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
    border:1px solid var(--dls-border);font-size:12.5px;color:var(--dls-white);
    white-space:nowrap}

  /* ⚠️ `hidden` NE MASQUE RIEN dès qu'une règle d'auteur impose `display`.
     L'attribut agit par la feuille du navigateur (`[hidden]{display:none}`),
     que la moindre déclaration `display:flex` écrase — silencieusement.
     Les modales de repère (`.pin-form`, display:flex) restaient donc à
     l'écran pour toujours, alors que `form.hidden` valait bien `true` : un
     test qui lit l'ATTRIBUT les croit fermées, l'utilisateur les voit.
     Cette règle rétablit l'attribut pour TOUT le viewer, présent et à venir. */
  [hidden]{display:none !important}

  /* ── Repères : pastilles 2D façon réalité augmentée ─────────────────────
     Éléments DOM projetés chaque image — le conteneur laisse passer les
     gestes, chaque pastille les capte. Un repère CACHÉ par la matière reste
     visible mais s'efface : on sait qu'il est là, on voit qu'il est derrière. */
  #gsPins{position:absolute;inset:0;z-index:6;pointer-events:none;overflow:hidden}
  /* ⚠️ LARGEUR DÉFINIE, JAMAIS DÉDUITE DE LA PLACE DISPONIBLE. Sans `width`,
     la carte se dimensionne au gré de ce qui reste à sa droite : mesuré sur le
     Pixel, un repère posé à 336 px du bord d'un écran de 411 se retrouvait dans
     une colonne de 63 px, le commentaire haché en trois lignes illisibles.
     `max-content` borné par `max-width` lui donne toujours la même largeur ;
     au bord, elle déborde et se fait couper par le conteneur — un repère au
     bord de l'écran est de toute façon à demi sorti, autant que ce qui reste
     se lise. */
  .gpin{position:absolute;transform:translate(-50%,-100%);display:flex;flex-direction:column;
    align-items:center;width:max-content;max-width:190px;
    pointer-events:auto;cursor:pointer;user-select:none;-webkit-user-select:none}
  @media (hover:none){ .gpin{max-width:150px} }
  /* déplaçable UNIQUEMENT quand l'outil Repères est actif : hors de ce mode un
     repère se consulte, il ne se bouge pas — et le curseur le dit */
  body.mode-reperes .gpin{cursor:grab}
  /* le repère mis en édition par « Modifier » : saisissable lui seul, et il
     le montre — halo d'accent, main ouverte */
  .gpin.edition{cursor:grab}
  .gpin.edition .puce{background:#fff;border-color:var(--dls-accent);
    box-shadow:0 0 0 6px rgba(190,34,47,.32)}
  .gpin .puce{width:15px;height:15px;border-radius:50%;background:rgba(190,34,47,.92);
    border:2px solid rgba(255,255,255,.92);box-shadow:0 2px 8px rgba(0,0,0,.5)}
  .gpin .tige{width:2px;height:10px;background:rgba(255,255,255,.75)}
  /* ── L'étiquette de chantier ───────────────────────────────────────────
     Choisie par Hugo parmi six propositions, éprouvée sur son Pixel avant
     d'être posée. Un seul objet, en deux étages : le titre en plein rouge
     nomme, la note dessous commente. Le rouge se voit de loin et par-dessus
     n'importe quel fond de chantier — béton clair, terre, herbe — là où le
     verre sombre de l'ancienne pilule se perdait sur du béton.

     Les deux étages sont deux nœuds FRÈRES, pas un conteneur : ils se
     rejoignent par leurs bordures — l'un sans bordure basse, l'autre sans
     bordure haute — ce qui évite un niveau d'imbrication et garde la
     structure DOM inchangée.

     Texte à GAUCHE, jamais centré : dès que le commentaire dépasse une ligne,
     le centrage casse la colonne du regard. */
  .gpin .etiq{max-width:190px;padding:4px 10px;
    border-radius:10px 10px 0 0;background:var(--dls-accent);
    border:1px solid rgba(255,255,255,.14);border-bottom:0;color:#fff;
    font-family:var(--dls-label);font-weight:700;font-size:12px;letter-spacing:.04em;
    text-align:left;align-self:stretch;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* pas de commentaire : le titre redevient un bloc à lui seul */
  .gpin:not(.avec-note) .etiq{border-radius:10px;border-bottom:1px solid rgba(255,255,255,.14);
    margin-bottom:5px}
  /* La note s'allonge jusqu'à HUIT lignes, puis la fiche prend le relais. Trois
     lignes coupaient la plupart des commentaires en plein milieu d'une phrase ;
     huit en laissent passer l'écrasante majorité tout en gardant une carte qui
     reste une étiquette et non un pavé planté au milieu du chantier, lequel
     masquerait ce qu'on est venu voir.

     ⚠️ `overflow:hidden` ROGNE À LA BOÎTE DE PADDING, PAS À CELLE DU CONTENU.
     C'est ce qui faisait apparaître, SOUS le texte coupé et son ellipse, le haut
     d'une ligne supplémentaire illisible : la ligne en trop débordait dans les
     5 px de padding bas, où rien ne la rognait. La carte semblait alors tronquée
     deux fois. Vérifié au banc le 18 août 2026 en annulant ce padding : la ligne
     fantôme disparaît, ce qui désigne le coupable sans ambiguïté.

     `overflow:clip` avec `overflow-clip-margin:content-box` rogne au contenu et
     garde le padding. La déclaration `hidden` reste devant : un navigateur qui
     ignore `clip` retombe simplement sur le comportement d'avant, jamais sur
     pire. L'interligne est posé en pixels entiers pour la même raison de
     propreté — 1,35 sur 11 px donnait 14,85 px et des lignes à cheval sur le
     sous-pixel. */
  .gpin .note{max-width:190px;margin-bottom:5px;padding:5px 10px;
    border-radius:0 0 10px 10px;background:rgba(17,17,17,.78);
    backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
    border:1px solid rgba(255,255,255,.14);border-top:0;color:rgba(255,255,255,.68);
    font-family:var(--dls-font);font-size:11px;line-height:15px;text-align:left;
    display:-webkit-box;-webkit-line-clamp:8;-webkit-box-orient:vertical;
    overflow:hidden;overflow:clip;overflow-clip-margin:content-box}
  /* au doigt, l'écran est petit et les repères se chevauchent vite : la carte
     reste plus courte, mais cinq lignes valent mieux que deux. */
  @media (hover:none){
    .gpin .etiq,.gpin .note{max-width:150px}
    .gpin .note{-webkit-line-clamp:5;font-size:10.5px;line-height:14px}
  }
  .gpin:hover .puce,.gpin.ouverte .puce{background:#fff;border-color:var(--dls-accent)}
  /* Caché derrière la matière : l'état doit se LIRE d'un coup d'œil, sinon on
     croit qu'il ne se déclenche jamais. Pointillé sur la puce ET l'étiquette,
     tige en tirets, fond de l'étiquette effacé. */
  .gpin.cache{opacity:.5}
  .gpin.cache .puce{background:transparent;border-style:dashed;border-color:rgba(255,255,255,.85)}
  /* Derrière la matière, le rouge plein s'éteint : il attire trop l'œil pour
     un repère dont on dit justement qu'il est hors de vue. */
  .gpin.cache .etiq{background:transparent;border:1px dashed rgba(255,255,255,.5);
    color:var(--dls-dim);font-weight:600}
  .gpin.cache .tige{background:repeating-linear-gradient(to bottom,
    rgba(255,255,255,.75) 0 3px, transparent 3px 6px)}
  /* le viseur de survol : fantômes, jamais cliquables — ils n'existent pas encore */
  #gsViseur{position:absolute;inset:0;z-index:6;pointer-events:none;overflow:hidden}
  #gsViseur .gpin{pointer-events:none;opacity:.6}
  #gsViseur .gpin .puce{background:rgba(255,255,255,.3);border-style:dashed}
  #gsViseur .gpin .etiq{font-size:13px;padding:1px 8px}
  .mes-som.fantome{opacity:.6;border-style:dashed}
  /* le fantôme d'ajout sur une arête : là où le point atterrira */
  .mes-som.fantome-arete{opacity:.85;border-style:dashed;width:11px;height:11px;
    pointer-events:none;background:rgba(255,255,255,.9)}
  .mes-chip.fantome{opacity:.8}

  /* ── La frise des dates ───────────────────────────────────────────────────
     Elle s'ouvre AU-DESSUS de la barre, centrée comme elle, et ne pousse rien :
     la vue 3D ne doit pas sauter quand on cherche une date. Même verre, même
     bordure et même ombre que le menu de capture — c'est le même geste,
     un panneau qui se pose et se referme.

     La bande d'écoute occupe TOUTE la hauteur de la zone, pas seulement la ligne
     des traits : sur Aquavert, deux dates tombent à 22 px l'une de l'autre, et
     viser un trait de 2 px au doigt serait impossible. On clique l'axe, la date
     la plus proche gagne. */
  .dls-frise{position:fixed;left:50%;transform:translateX(-50%);
    bottom:calc(96px + env(safe-area-inset-bottom,0px));z-index:12;
    width:min(460px,92vw);padding:12px 14px 10px;border-radius:14px;
    background:var(--dls-glass);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
    border:1px solid var(--dls-border);box-shadow:0 12px 36px rgba(0,0,0,.55);
    color:var(--dls-white);font-family:var(--dls-font)}
  .dls-frise[hidden]{display:none}
  .frise-tete{display:flex;justify-content:space-between;align-items:baseline;gap:10px;
    font-family:var(--dls-label);font-size:11px;letter-spacing:.06em;text-transform:uppercase;
    color:rgba(255,255,255,.5);margin-bottom:8px}
  /* la date pointee, en clair : le SEUL libelle complet de la frise, a place fixe */
  .frise-lu{font-family:var(--dls-font);font-size:14px;font-weight:600;letter-spacing:0;
    text-transform:none;color:var(--dls-white);white-space:nowrap}
  .frise-zone{position:relative;height:46px;cursor:pointer;outline:none}
  .frise-zone:focus-visible{box-shadow:0 0 0 2px var(--dls-accent);border-radius:8px}

  /* ── DEUX ETAGES, DEUX LANGUES ────────────────────────────────────────────
     Sur le rail : les dates, en pastilles. Sous le rail : l'echelle, en bandes
     nommees. La premiere version melangeait les deux — des traits verticaux
     blancs pour les dates ET pour les graduations, sur la meme ligne — et on ne
     savait plus ce qu'on lisait. */
  .frise-rail{position:absolute;left:0;right:0;top:15px;height:2px;
    background:rgba(255,255,255,.14);border-radius:2px}
  .frise-fond,.frise-pts{position:absolute;inset:0;pointer-events:none}
  /* la frontiere entre deux bandes : sous le rail, fine, et elle ne monte
     jamais dessus — c'est ce qui la distingue d'une date au premier coup d'oeil */
  .frise-bord{position:absolute;top:17px;width:1px;height:8px;
    background:rgba(255,255,255,.12)}
  .frise-bande{position:absolute;top:29px;transform:translateX(-50%);
    font-size:10px;letter-spacing:.04em;color:rgba(255,255,255,.38);white-space:nowrap}

  /* ── LES DATES, POSEES SUR LE RAIL ────────────────────────────────────────
     Boite de taille FIXE centree sur la ligne, disque interieur variable : quel
     que soit l'etat, la pastille reste centree sur le rail. La version d'avant
     dessinait un trait puis une bille en dessous, qui ne touchait rien. */
  .frise-pt{position:absolute;top:7px;width:18px;height:18px;margin-left:-9px;
    display:grid;place-items:center}
  /* ⚠️ UNE SEULE REGLE : PLEIN = A L'ECRAN, CREUX = PAS A L'ECRAN.

     La version d'avant avait DEUX pastilles creuses de sens differents — celle
     de l'autre cote de la comparaison, et celle dont le modele n'est pas encore
     telecharge. Deux sens pour une meme forme : Hugo n'a pas su les distinguer,
     et il avait raison de ne pas y arriver.

     Desormais la forme dit l'AFFICHAGE et rien d'autre. Les deux dates a l'ecran
     sont les seules pleines, donc les seules qui sautent aux yeux ; toutes les
     autres sont des anneaux. La couleur, elle, dit lequel des deux cotes le clic
     va remplacer. Et la disponibilite du modele passe par l'OPACITE, qui ne
     dispute sa place a personne. */
  .frise-pt::before{content:"";width:9px;height:9px;border-radius:50%;
    background:transparent;
    box-shadow:0 0 0 3px rgba(17,17,17,.55),inset 0 0 0 2px rgba(255,255,255,.5);
    transition:width .12s ease,height .12s ease,box-shadow .12s ease,background .12s ease}
  /* pas encore telechargee : meme forme, moins de presence — le clic la fera
     venir, et l'attente qui suit ne doit pas surprendre */
  .frise-pt.absente::before{box-shadow:0 0 0 3px rgba(17,17,17,.55),
    inset 0 0 0 2px rgba(255,255,255,.22)}
  /* a l'ecran, de l'autre cote de la comparaison : PLEINE, blanche */
  .frise-pt.autre::before{width:12px;height:12px;background:rgba(255,255,255,.95);
    box-shadow:0 0 0 3px rgba(17,17,17,.55)}
  /* a l'ecran, de CE cote-ci : pleine et rouge, c'est elle que le clic remplace */
  .frise-pt.actif::before{width:14px;height:14px;background:var(--dls-accent);
    box-shadow:0 0 0 3px rgba(17,17,17,.55),0 0 0 5px rgba(190,34,47,.3)}
  /* le survol ne change que la TAILLE : il designe, il ne requalifie pas */
  .frise-pt.pointe::before{width:13px;height:13px}
  .frise-pt.pointe:not(.actif):not(.autre)::before{box-shadow:0 0 0 3px rgba(17,17,17,.55),
    inset 0 0 0 2px #fff}
  .frise-pt.autre.pointe::before{width:15px;height:15px}
  .frise-pt.actif.pointe::before{width:16px;height:16px}

  /* au doigt, la barre est plus haute et la cible doit rester genereuse */
  @media (hover:none){
    .dls-frise{bottom:calc(104px + env(safe-area-inset-bottom,0px));padding:10px 12px 8px}
    .frise-zone{height:52px}
    .frise-rail{top:18px}
    .frise-bord{top:20px}
    .frise-bande{top:33px}
    .frise-pt{top:10px}
  }
  /* le libellé de date devient une commande : on le dit à l'œil aussi */
  .dls-date{cursor:pointer}
  .dls-date:hover{color:#fff}

  /* ── Barres de défilement ─────────────────────────────────────────────────
     Le viewer laissait la barre du SYSTÈME sur ses zones qui défilent : une
     glissière claire, large, plantée dans un panneau sombre. Le builder et
     l'aligner portaient déjà la règle maison ; celui qui la montre au client ne
     l'avait pas.

     On la reprend telle quelle plutôt que d'en écrire une variante : trois
     produits qui se ressemblent doivent se ressembler jusque-là.

     `scrollbar-width` et `scrollbar-color` servent Firefox, `::-webkit-*` tout
     le reste. La bordure transparente avec `background-clip:content-box` affine
     le curseur À L'ŒIL sans rétrécir la zone qu'on peut saisir au doigt : un
     curseur de 8 px se saisit encore, un curseur de 4 px se manque.

     Les trois zones sont nommées explicitement, sans règle générale sur `*` :
     le canevas et les listes de dates ne défilent pas, et une règle globale
     irait aussi toucher les pages clientes qui embarquent le viewer. */
  .cap-menu,.cap-dates,.aide-boite{
    scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.18) transparent}
  .cap-menu::-webkit-scrollbar,.cap-dates::-webkit-scrollbar,
  .aide-boite::-webkit-scrollbar{width:8px;height:8px}
  .cap-menu::-webkit-scrollbar-track,.cap-dates::-webkit-scrollbar-track,
  .aide-boite::-webkit-scrollbar-track{background:transparent}
  .cap-menu::-webkit-scrollbar-thumb,.cap-dates::-webkit-scrollbar-thumb,
  .aide-boite::-webkit-scrollbar-thumb{background:rgba(255,255,255,.16);
    border-radius:99px;border:2px solid transparent;background-clip:content-box}
  .cap-menu::-webkit-scrollbar-thumb:hover,.cap-dates::-webkit-scrollbar-thumb:hover,
  .aide-boite::-webkit-scrollbar-thumb:hover{background:rgba(190,34,47,.65);
    background-clip:content-box}

  /* ── Menu de capture ── */
  .cap-menu{position:fixed;top:calc(58px + env(safe-area-inset-top,0px));
    /* au-dessus des fiches de repère (40/41) et du voile d'aide (20), sous le
       gel de capture (50) qui doit tout recouvrir pendant la prise de vue */
    right:calc(12px + env(safe-area-inset-right,0px));z-index:42;width:270px;max-width:82vw;
    max-height:calc(100% - 90px);overflow:auto;padding:14px;border-radius:14px;
    background:var(--dls-glass);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
    border:1px solid var(--dls-border);box-shadow:0 12px 36px rgba(0,0,0,.55);color:var(--dls-white)}
  .cap-titre{font-family:var(--dls-label);font-size:15px;font-weight:700;letter-spacing:.04em;margin-bottom:10px}
  .cap-sous{font-family:var(--dls-label);font-size:10.5px;letter-spacing:.14em;
    text-transform:uppercase;color:var(--dls-dim);margin:12px 0 6px}
  /* la ligne de section porte son raccourci à droite */
  .cap-sous-ligne{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
  /* Un lien, pas un bouton plein : c'est un raccourci de confort, il ne doit
     pas rivaliser avec « Capturer » — une seule action franche par formulaire. */
  .cap-tout{background:none;border:0;padding:0;cursor:pointer;
    font-family:var(--dls-font);font-size:11px;letter-spacing:0;text-transform:none;
    color:var(--dls-dim);text-decoration:underline;text-underline-offset:2px}
  .cap-tout:hover{color:var(--dls-white)}
  .cap-tout[hidden]{display:none}
  @media (hover:none){ .cap-tout{font-size:12px;padding:4px 0} }
  .cap-ligne{display:flex;align-items:center;gap:9px;font-size:13px;cursor:pointer;padding:4px 0}
  .cap-ligne input{width:16px;height:16px;accent-color:var(--dls-accent);flex:0 0 auto;cursor:pointer}
  .cap-dates{display:flex;flex-direction:column;gap:2px;max-height:180px;overflow:auto}
  .cap-date{display:flex;align-items:center;gap:9px;font-size:13px;cursor:pointer;
    padding:5px 4px;border-radius:7px}
  .cap-date:hover{background:rgba(255,255,255,.07)}
  .cap-date input{width:15px;height:15px;accent-color:var(--dls-accent);flex:0 0 auto;cursor:pointer}
  .cap-info{margin-top:10px;font-size:11px;line-height:1.4;color:var(--dls-dim)}
  .cap-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:12px}
  .cap-actions .mes-btn[disabled]{opacity:.4;pointer-events:none}
  /* au doigt, les cases à cocher d'une liste de dates sont la cible la plus
     ratée de toute l'interface : la rangée entière devient cliquable */
  @media (hover:none){
    .cap-date{padding:9px 6px}
    .cap-date input{width:18px;height:18px}
    .cap-ligne{padding:8px 0}
  }
  /* progression d'une grille : « image 2/4 · 45 % » sur le voile */
  .gel-prog{position:absolute;left:50%;bottom:64px;transform:translateX(-50%);
    width:min(280px,70%);height:4px;border-radius:99px;background:rgba(255,255,255,.18);overflow:hidden}
  .gel-prog i{display:block;height:100%;width:0;background:var(--dls-accent);transition:width .2s}

  /* fiche d'un repère : titre + commentaire, boutons discrets */
  .pin-fiche{position:absolute;z-index:40;max-width:260px;padding:12px 14px;border-radius:12px;
    background:var(--dls-glass);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
    border:1px solid var(--dls-border);box-shadow:0 10px 34px rgba(0,0,0,.5);color:var(--dls-white)}
  .pin-fiche .pf-titre{font-family:var(--dls-label);font-size:14px;font-weight:600;letter-spacing:.03em}
  .pin-fiche .pf-note{margin-top:6px;font-size:12.5px;line-height:1.45;color:var(--dls-dim);white-space:pre-wrap}
  .pin-fiche .pf-pied{display:flex;gap:8px;justify-content:flex-end;margin-top:10px}

  /* formulaire de création / édition */
  .pin-form{position:absolute;z-index:41;width:240px;padding:12px;border-radius:12px;display:flex;
    flex-direction:column;gap:8px;background:var(--dls-glass);
    backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
    border:1px solid var(--dls-border);box-shadow:0 10px 34px rgba(0,0,0,.5)}
  .pin-form input,.pin-form textarea{width:100%;padding:8px 10px;border-radius:8px;resize:none;
    background:rgba(0,0,0,.35);border:1px solid var(--dls-border);color:var(--dls-white);
    font-family:var(--dls-font);font-size:12.5px}
  .pin-form input:focus,.pin-form textarea:focus{outline:none;border-color:var(--dls-accent)}
  .pin-astuce{font-size:11px;color:var(--dls-dim);line-height:1.35}
  /* La plage de validité : repliée par défaut, parce que neuf repères sur dix
     sont permanents et qu'un formulaire de 240 px ne peut pas faire payer à
     tout le monde une option que presque personne n'ouvre. La tête DIT l'état
     au lieu de nommer un réglage. */
  .pin-quand{display:flex;flex-direction:column;gap:7px}
  .pq-tete{display:flex;align-items:center;justify-content:space-between;gap:8px;
    width:100%;padding:6px 9px;border-radius:8px;cursor:pointer;
    background:rgba(255,255,255,.05);border:1px solid var(--dls-border);
    color:var(--dls-dim);font-family:var(--dls-font);font-size:11.5px;text-align:left}
  .pq-tete:hover{background:rgba(255,255,255,.09);color:var(--dls-white)}
  .pq-chev{transition:transform .15s ease;font-size:14px;line-height:1;flex:0 0 auto}
  .pq-tete.ouvert .pq-chev{transform:rotate(90deg)}
  .pq-corps{display:flex;flex-direction:column;gap:6px}
  .pin-form .pq-corps select{width:100%;padding:7px 9px;border-radius:8px;cursor:pointer;
    background:rgba(0,0,0,.35);border:1px solid var(--dls-border);color:var(--dls-white);
    font-family:var(--dls-font);font-size:12px}
  .pin-form .pq-corps select:focus{outline:none;border-color:var(--dls-accent)}
  .pq-dit{font-size:11px;color:var(--dls-dim);line-height:1.35}
  /* une plage qui ne couvre rien se signale ici, avant l'enregistrement :
     c'est plus utile qu'un refus au moment de valider */
  .pq-dit.vide{color:#ff8a90}
  /* la règle « hors-plage » vit plus bas, après .gpin.cache : voir là-bas */
  .pin-form-actions{display:flex;gap:8px;justify-content:flex-end}

  /* ── Mesure ── */
  #mesLabels{position:absolute;inset:0;z-index:6;pointer-events:none;overflow:hidden}
  /* ⚠️ Les traits sont en SVG, PAS en lignes 3D : `app.drawLine` ne fait qu'un
     pixel, non stylable, et disparaissait sur une photo de chantier. Ici on
     choisit l'épaisseur — et surtout on pose un HALO sombre dessous, qui rend
     le rouge lisible sur du béton clair comme sur de la terre. */
  .mes-fond{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;overflow:visible}
  /* Le remplissage était à .20 : sur du béton clair ou une toiture blanche il
     s'effaçait, et Hugo l'a vu à l'export — « tendance à disparaître ». Le JPEG
     achevait le travail, son sous-échantillonnage de chrominance mangeant les
     grands aplats translucides. À .30 la surface se lit sur tous les fonds
     sans masquer ce qu'elle recouvre, et le contour rouge la borne. */
  .mes-fond .mes-aire{fill:rgba(190,34,47,.30);stroke:none}
  .mes-fond .mes-halo{fill:none;stroke:rgba(0,0,0,.55);stroke-width:6;
    stroke-linecap:round;stroke-linejoin:round}
  /* Le SECTEUR d'angle : le disque coupé entre les deux segments, au survol
     d'un sommet. Plus opaque que la surface d'une mesure — il est momentané et
     doit se voir tout de suite, là où l'aire est un fond permanent qu'on
     regarde à travers. */
  .mes-fond .mes-secteur{fill:rgba(190,34,47,.55);stroke:rgba(255,255,255,.55);
    stroke-width:1.2;pointer-events:none}
  /* L'arête sous le curseur s'épaissit : sans ce signal, personne ne devine
     qu'une ligne est cliquable. Blanc translucide et non rouge — le rouge est
     la couleur de ce qui EST mesuré, pas de ce qui est proposé. */
  .mes-fond .mes-arete-cible{fill:none;stroke:rgba(255,255,255,.85);stroke-width:6;
    stroke-linecap:round;pointer-events:none;opacity:.5}
  .mes-fond .mes-trait{fill:none;stroke:#E8323F;stroke-width:2.6;
    stroke-linecap:round;stroke-linejoin:round}
  /* ── DERRIÈRE LA MATIÈRE ─────────────────────────────────────────────────
     Même parti que les repères : on n'efface pas, on éteint. Faire disparaître
     un segment couperait la forme en deux et on croirait à une mesure perdue ;
     le laisser plein ferait lire comme « devant » ce qui est derrière. Il reste
     donc visible, en pointillé, sans son halo noir — le halo sert à détacher un
     trait de la matière, or ce trait est justement dedans. */
  .mes-fond .mes-trait.cache{stroke:rgba(232,50,63,.42);stroke-width:2;
    stroke-dasharray:7 6}
  .mes-fond .mes-halo.cache{stroke:transparent}
  .mes-fond .mes-aire.cache{fill:rgba(190,34,47,.10)}
  /* un sommet caché garde sa place mais perd son plein : il reste saisissable,
     puisqu'on doit pouvoir corriger un point qu'on ne voit qu'à moitié */
  .mes-som.cache{opacity:.5;background:transparent;border-style:dashed;
    border-color:rgba(255,255,255,.85);box-shadow:none}
  .mes-som{position:absolute;transform:translate(-50%,-50%);width:9px;height:9px;border-radius:50%;
    background:#fff;border:2px solid rgba(0,0,0,.55);box-shadow:0 1px 5px rgba(0,0,0,.5)}
  /* les sommets POSÉS se saisissent — le fantôme de visée, jamais */
  .mes-som.actif{pointer-events:auto;cursor:grab;width:13px;height:13px}
  .mes-som.actif:hover{border-color:var(--dls-accent)}
  .mes-som.tire{cursor:grabbing}
  /* aimanté : le sommet le dit tout de suite, sinon le point « saute » et
     l'utilisateur croit à un défaut de visée */
  .mes-som.aimante{border-color:var(--dls-accent);background:var(--dls-accent);
    box-shadow:0 0 0 6px rgba(190,34,47,.35)}
  /* le viseur aimanté cesse d'être un fantôme : tant qu'il est en pointillé et
     à demi transparent, rien ne distingue « je vise » de « je suis accroché ».
     Il prend en plus la TEINTE de la contrainte, la même que son trait guide :
     l'œil relie les deux sans avoir à lire quoi que ce soit. */
  .mes-som.fantome.aimante{opacity:1;border-style:solid;
    background:var(--aim,var(--dls-accent));border-color:var(--aim,var(--dls-accent));
    box-shadow:0 0 0 6px color-mix(in srgb,var(--aim,#BE222F) 32%,transparent)}
  /* ── le lieu de l'aimant, dessiné dans la scène ──────────────────────────
     Tireté : c'est un repère de construction, pas de la matière mesurée. La
     couleur arrive en style calculé, elle dépend de la contrainte accrochée. */
  .mes-guide{fill:none;stroke-width:1.6;stroke-dasharray:7 5;stroke-linecap:round;
    opacity:.95;pointer-events:none}
  .mes-guide-surf{stroke-width:1.4;stroke-dasharray:5 4;opacity:.85;pointer-events:none}
  /* la croix du croisement : PLEINE et plus épaisse là où les guides sont
     tiretés. Un point tenu dans ses trois dimensions ne doit pas se lire comme
     une ligne de construction de plus — c'est la prise la plus forte. */
  .mes-croix{fill:none;stroke-width:2.6;stroke-linecap:round;pointer-events:none;
    filter:drop-shadow(0 0 3px rgba(0,0,0,.75))}
  /* le segment qui manque pour boucler, montré pendant le survol de l'extrémité */
  .mes-fermeture{fill:none;stroke:var(--dls-accent);stroke-width:2;stroke-dasharray:6 5;
    opacity:.9;stroke-linecap:round;pointer-events:none}
  /* l'extrémité qui bouclerait : un anneau franc, sinon le geste reste un
     secret pour qui ne l'a pas découvert par hasard */
  .mes-som.ferme-ici{border-color:var(--dls-accent);background:var(--dls-accent);
    box-shadow:0 0 0 4px rgba(190,34,47,.30), 0 0 0 8px rgba(190,34,47,.16);
    cursor:pointer}
  /* la pastille qui nomme l'aimant, posée au curseur */
  .mes-chip.aimant{background:var(--aim,var(--dls-accent));color:#fff;
    border-color:transparent;font-weight:600;letter-spacing:.02em;
    box-shadow:0 2px 10px rgba(0,0,0,.45);transform:translate(0,-50%)}
  .mes-som.choisi{border-color:var(--dls-accent);box-shadow:0 0 0 5px rgba(190,34,47,.35)}
  /* ⚠️ APRÈS .gpin.cache, SINON L'OCCLUSION L'ÉCRASE : à spécificité égale
     c'est le dernier écrit qui gagne, et .gpin.cache pose déjà une opacité.
     Hors de sa plage, en RÉGIE seulement — le client, lui, ne voit rien du
     tout. La pastille reste saisissable, sans quoi un repère qui n'est pas de
     la date affichée deviendrait impossible à rouvrir. */
  .gpin.hors-plage{opacity:.3}
  .gpin.hors-plage:hover{opacity:.75}
  .gpin.tire{z-index:2}
  .gpin.tire .puce{background:#fff;border-color:var(--dls-accent)}
  .mes-chip{position:absolute;transform:translate(-50%,-50%);padding:2px 8px;border-radius:999px;
    background:rgba(17,17,17,.78);border:1px solid var(--dls-border);color:var(--dls-white);
    font-family:ui-monospace,Consolas,monospace;font-size:11px;white-space:nowrap}
  .mes-chip.total{border-color:var(--dls-accent)}
  /* Derrière la matière. La pastille reste LISIBLE, elle ne fait que reculer :
     c'est le chiffre qu'on vient chercher, l'effacer au point de le deviner
     rendrait la mesure inutile là où elle est justement la plus difficile à
     reprendre. Fond effacé, contour en pointillé, texte atténué. */
  .mes-chip.cache{background:rgba(17,17,17,.32);border-style:dashed;
    border-color:rgba(255,255,255,.28);color:rgba(255,255,255,.62)}
  /* ⚠️ `.mes-chip.aire` est déclarée PLUS BAS à specificité égale : elle
     reprendrait le fond et la bordure. Cette règle-ci doit donc citer les deux
     classes pour la battre, et redire la bordure que `.cache` seule ne
     parviendrait plus à imposer. */
  .mes-chip.aire.cache{background:rgba(190,34,47,.30);color:rgba(255,255,255,.72);
    border-color:rgba(255,255,255,.30);box-shadow:none}
  /* L'angle, au survol d'un sommet seulement. Fond d'accent pour qu'on le
     distingue d'une cote au premier coup d'œil : une longueur et un angle
     posés côte à côte en monospace se confondent sinon. Il ne capte aucun
     geste — il apparaît sous le curseur, il ne doit pas s'interposer. */
  .mes-chip.angle{background:rgba(190,34,47,.88);border-color:rgba(255,255,255,.35);
    pointer-events:none;font-weight:600}
  /* l'aire, inscrite DANS la forme : plus lisible que les cotes de segments,
     c'est elle qu'on lit d'abord sur une capture */
  .mes-chip.aire{font-family:var(--dls-label);font-size:14px;font-weight:700;
    letter-spacing:.04em;padding:4px 12px;background:rgba(190,34,47,.82);
    border-color:rgba(255,255,255,.5);box-shadow:0 3px 12px rgba(0,0,0,.5)}
  .mes-panneau{position:fixed;left:calc(14px + env(safe-area-inset-left,0px));
    top:calc(64px + env(safe-area-inset-top,0px));z-index:8;min-width:190px;padding:12px 14px;
    border-radius:12px;background:var(--dls-glass);backdrop-filter:blur(10px);
    -webkit-backdrop-filter:blur(10px);border:1px solid var(--dls-border);color:var(--dls-white)}
  .mes-ligne{display:flex;justify-content:space-between;gap:14px;font-size:13px;margin:2px 0}
  .mes-cle{color:var(--dls-dim)}
  .mes-nb{margin-top:4px;font-family:var(--dls-label);font-size:11px;
    letter-spacing:.06em;color:var(--dls-accent)}
  .mes-nb:empty{display:none}
  .mes-hint{margin-top:6px;font-size:11px;color:var(--dls-dim);max-width:210px}
  .mes-actions{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
  .mes-btn{padding:6px 11px;border-radius:8px;border:1px solid var(--dls-accent);cursor:pointer;
    background:rgba(190,34,47,.32);color:var(--dls-white);font-family:var(--dls-font);
    font-size:12px;font-weight:600}
  .mes-btn:hover{background:rgba(190,34,47,.5)}
  .mes-btn.ghost{border-color:var(--dls-border);background:rgba(255,255,255,.06)}
  .mes-btn.ghost:hover{background:rgba(255,255,255,.12)}
  /* armé : le bouton doit CHANGER D'ASPECT, pas seulement de mot. Un libellé
     seul se lit après le clic, quand il est trop tard ; la couleur se voit
     avant. Le battement dit qu'il y a un délai, donc qu'attendre suffit. */
  .mes-btn.ghost.arme{border-color:var(--dls-accent);background:rgba(190,34,47,.55);
    color:#fff;animation:effBat 1.1s ease-in-out infinite}
  .mes-btn.ghost.arme:hover{background:rgba(190,34,47,.75)}
  @keyframes effBat{50%{box-shadow:0 0 0 5px rgba(190,34,47,.28)}}
  /* le retour en arrière : offert, jamais criard — il ne doit pas ressembler
     à une seconde action destructrice */
  .mes-btn.ghost.repli{border-color:rgba(255,255,255,.55);background:rgba(255,255,255,.14)}
  @media (prefers-reduced-motion:reduce){ .mes-btn.ghost.arme{animation:none} }
  body.mode-viser #view{cursor:crosshair}

  /* Indicateur discret (prototype) */
  #stats{position:fixed;right:calc(14px + env(safe-area-inset-right,0px));bottom:calc(10px + env(safe-area-inset-bottom,0px));
    z-index:4;font-family:ui-monospace,Consolas,monospace;font-size:10px;color:var(--dls-dim);opacity:.55;text-align:right}

  /* Chargement */
  #load{position:fixed;inset:0;background:#0a0a0a;display:flex;flex-direction:column;gap:22px;
    align-items:center;justify-content:center;z-index:50;transition:opacity .5s}
  #load.off{opacity:0;pointer-events:none}
  #load img{height:56px;filter:drop-shadow(0 2px 6px rgba(0,0,0,.55))}
  #load .bars{display:flex;flex-direction:column;gap:9px;width:min(400px,80vw)}
  #load .row{display:flex;align-items:center;gap:10px}
  #load .row .lab{width:64px;font-family:var(--dls-label);font-weight:700;font-size:11px;
    letter-spacing:.14em;text-transform:uppercase;color:var(--dls-dim)}
  #load .bar{flex:1;height:5px;border-radius:99px;background:rgba(255,255,255,.10);overflow:hidden}
  #load .bar i{display:block;height:100%;width:0;background:var(--dls-accent);transition:width .2s}
  /* ── LE CARTOUCHE DE CHARGEMENT ────────────────────────────────────────
     Quatre rangs, du plus général au plus contingent : le genre de l'objet,
     son nom, ses faits, puis le seul geste utile. C'est la hiérarchie d'un
     cartouche de plan, et elle se lit sans être lue. Le bloc remplace un
     alignement de onze raccourcis qui, lui, se lisait comme une notice
     d'appareil ménager. */
  /* ⚠️ La police reste posée sur le conteneur : les messages d'erreur y sont
     écrits en texte NU, sans balise ni classe. Sans elle, « Modèle
     indisponible » s'afficherait dans la police du document. */
  #load .hint{display:flex;flex-direction:column;align-items:center;gap:7px;
    text-align:center;max-width:min(560px,86vw);
    font-family:var(--dls-label);font-weight:600;font-size:13px;
    letter-spacing:.05em;color:var(--dls-dim)}
  #load .hint .genre{font-family:var(--dls-label);font-weight:700;font-size:10.5px;
    letter-spacing:.2em;text-transform:uppercase;color:rgba(255,255,255,.42)}
  #load .hint .nom{font-family:var(--dls-label);font-weight:700;
    font-size:clamp(20px,4.4vw,28px);letter-spacing:.02em;line-height:1.1;
    color:rgba(255,255,255,.96);text-wrap:balance}
  /* les faits en chiffres tabulaires : ce sont des données, pas du discours */
  #load .hint .faits{font-family:ui-monospace,Consolas,monospace;font-size:11.5px;
    letter-spacing:.03em;color:rgba(255,255,255,.62);font-variant-numeric:tabular-nums;
    line-height:1.5}
  /* le geste passe après, et volontairement en retrait : il ne doit pas
     reprendre la place que le pense-bête occupait */
  #load .hint .geste{font-family:var(--dls-font);font-size:12px;font-weight:500;
    color:rgba(255,255,255,.34);margin-top:5px;line-height:1.45}
  @media (max-width:520px){
    #load .hint .genre{letter-spacing:.14em;font-size:9.5px}
    #load .hint .faits{font-size:10.5px}
  }

  .toast{position:fixed;left:50%;top:calc(64px + env(safe-area-inset-top,0px));transform:translateX(-50%);
    padding:8px 16px;border-radius:999px;background:var(--dls-glass);backdrop-filter:blur(8px);
    border:1px solid var(--dls-border);font-family:var(--dls-label);font-weight:600;font-size:13px;
    letter-spacing:.04em;z-index:40;opacity:0;transition:opacity .25s;pointer-events:none}
  .toast.show{opacity:1}

  @media (max-width:560px){
    .dls-logo{height:26px;top:calc(10px + env(safe-area-inset-top,0px));left:calc(10px + env(safe-area-inset-left,0px))}
    .rbtn{width:40px;height:40px;top:calc(9px + env(safe-area-inset-top,0px))}
    /* Sur petit écran la barre de dates, centrée en bas, atteint le coin en
       mode comparaison : l'aide se pose JUSTE AU-DESSUS d'elle, pas dedans. */
    #aideBtn{top:auto;right:auto;left:calc(10px + env(safe-area-inset-left,0px));
      bottom:calc(64px + env(safe-area-inset-bottom,0px))}
    .dls-views{max-width:62%;top:calc(56px + env(safe-area-inset-top,0px));padding:4px}
    .dls-controls{bottom:calc(10px + env(safe-area-inset-bottom,0px));gap:3px;padding:4px}
    .dls-date{min-width:0;font-size:11px;padding:0 2px}
    .dls-side-lab{font-size:8px;letter-spacing:.06em}
    #wipe .dls-knob{width:46px;height:46px}
    #stats{display:none}
  }
  @media (hover:none){
    .dls-arrow::after,.rbtn::after{content:"";position:absolute;inset:-8px;border-radius:50%}
  }

  /* Pseudo plein écran (iframe iPhone) : la page hôte agrandit l'iframe via
     postMessage, et le viewer remplit son propre viewport sans coins arrondis */
  #root.is-fs{border-radius:0}

/* ── Modale d'accueil ── */
.aide-voile{position:absolute;inset:0;z-index:20;display:grid;place-items:center;
  background:rgba(0,0,0,.55);backdrop-filter:blur(3px)}
.aide-voile[hidden]{display:none}
/* ⚠️ C'EST LE CORPS QUI DÉFILE, PAS LA BOÎTE. Elle défilait en entier : dans une
   iframe basse — le cas des pages clientes sur téléphone — le pied passait sous
   la ligne de flottaison, et avec lui le bouton principal. On aurait donc
   proposé « Passer en plein écran » sur une commande invisible.

   La boîte est maintenant une colonne : logo et titre en tête, pied en bas, et
   seule la liste défile entre les deux. Quelle que soit la hauteur disponible,
   la sortie reste sous les yeux. */
.aide-boite{position:relative;width:min(400px,calc(100% - 40px));max-height:calc(100% - 40px);
  display:flex;flex-direction:column;overflow:hidden;
  background:rgba(17,17,17,.92);border:1px solid var(--dls-border);border-radius:14px;
  padding:22px 22px 16px;font-family:var(--dls-font);color:var(--dls-white);
  box-shadow:0 18px 60px rgba(0,0,0,.5)}
.aide-corps{overflow:auto;min-height:0;scrollbar-width:thin;
  scrollbar-color:rgba(255,255,255,.18) transparent}
.aide-corps::-webkit-scrollbar{width:8px}
.aide-corps::-webkit-scrollbar-track{background:transparent}
.aide-corps::-webkit-scrollbar-thumb{background:rgba(255,255,255,.16);border-radius:99px;
  border:2px solid transparent;background-clip:content-box}
/* la croix : toujours au même endroit, jamais emportée par le défilement */
.aide-croix{position:absolute;top:10px;right:10px;z-index:2;width:30px;height:30px;
  border:0;border-radius:50%;background:transparent;color:var(--dls-dim);cursor:pointer;
  display:grid;place-items:center;transition:color .15s,background .15s}
.aide-croix:hover{color:var(--dls-white);background:rgba(255,255,255,.08)}
.aide-croix svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2.2;
  stroke-linecap:round}
.aide-logo{height:30px;display:block;margin:0 auto 14px;opacity:.95}
.aide-titre{font-family:var(--dls-label);font-weight:700;font-size:21px;text-align:center;
  letter-spacing:.3px;margin-bottom:14px}
.aide-ligne{display:flex;gap:11px;align-items:center;font-size:13.5px;color:var(--dls-dim);
  padding:5.5px 0;line-height:1.35}
.aide-ligne b{color:var(--dls-white);font-weight:600}
.aide-ico{flex:0 0 auto;width:26px;height:26px;display:grid;place-items:center;
  border-radius:7px;background:rgba(255,255,255,.07)}
.aide-ico svg{width:16px;height:16px;fill:var(--dls-white);opacity:.85}
.aide-pied{display:flex;justify-content:space-between;align-items:center;gap:10px;
  margin-top:16px;flex:0 0 auto}
.aide-btn{border:0;cursor:pointer;font-family:var(--dls-font);font-weight:600;font-size:13.5px;
  padding:9px 18px;border-radius:999px;background:var(--dls-accent);color:#fff}
.aide-btn:hover{filter:brightness(1.12)}
.aide-btn.ghost{background:transparent;color:var(--dls-dim);padding:9px 10px}
.aide-btn.ghost:hover{color:var(--dls-white)}
/* ── Le feuilletage de la notice ──────────────────────────────────────────
   Les points disent COMBIEN il reste : sans eux, « Suivant » donne
   l'impression d'un tunnel sans fond et on ferme au lieu de lire. */
.aide-nav{display:flex;align-items:center;gap:12px}
.aide-fl{border:0;background:transparent;cursor:pointer;color:var(--dls-dim);
  padding:6px;line-height:0;border-radius:999px}
.aide-fl svg{width:19px;height:19px}
.aide-fl:hover{color:var(--dls-white);background:rgba(255,255,255,.09)}
.aide-fl[hidden]{display:none}
.aide-points{display:flex;gap:6px;align-items:center}
.aide-pt{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.28)}
.aide-pt.on{background:var(--dls-accent);transform:scale(1.25)}
