/*
 * L'ESPACE DE COMMANDE — ce qui n'existe que sur ce site.
 *
 * Les jetons de la charte, la coquille d'explorateur, l'arbre et les cartes
 * viennent des feuilles communes : une feuille de style ne porte aucun
 * savoir-faire, et deux chartes séparées divergeraient au premier réglage.
 * Ne vit ici que la FICHE, qui n'a d'équivalent nulle part.
 */

/* Deux colonnes : ce qu'on regarde, ce qu'on renseigne. Le dessin prend la
   place restante, le formulaire garde sa largeur — un champ de cote n'a aucune
   raison de s'étirer avec la fenêtre, un dessin en a toutes. */
.fiche {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 20rem;
  gap: 1rem;
  align-items: start;
}
@media (max-width: 900px) {
  /* Le dessin d'abord : c'est ce qu'on est venu voir. */
  .fiche { grid-template-columns: minmax(0, 1fr); }
}

.fiche-vue {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: 4px;
  overflow: hidden;
  background: var(--carte);
  box-shadow: 0 1px 3px rgb(0 0 0 / 18%);
}

.fiche-barre {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border);
}
.fiche-barre h2 { margin: 0; font-size: 1rem; display: flex; align-items: center; gap: 0.45rem; }
.fiche-barre h2 .icone { --picto-encre: 1.15em; }
/* Ce qui pousse les touches à droite sans les y coller par une marge. */
.fiche-espace { flex: 1 1 auto; }

/* LA HAUTEUR EST DÉCLARÉE, et il le faut : le peintre 2D comme la scène 3D
   mesurent leur hôte au moment de peindre. Un conteneur réglé sur son contenu
   leur donnerait zéro, et ils dessineraient dans le vide sans lever d'erreur.

   `vh` plutôt qu'une hauteur fixe : sur un portable la fiche doit tenir à
   l'écran sans faire défiler pour atteindre les cotes.

   POURQUOI LE PANNEAU NE DÉPASSE JAMAIS LE CARRÉ. La scène 3D cale son échelle
   sur la PLUS PETITE dimension de son hôte — `min(w, h)` dans `Scene3D` — pour
   qu'un ouvrage tienne quelle que soit sa rotation. Toute hauteur gagnée au-delà
   de la largeur ne grossit donc rien : elle ajoute du ciel et du sol vides
   au-dessus et au-dessous. C'est ce qui se passait à 34 rem sur un écran étroit,
   et c'est ce qui se passe encore à l'atelier, où la toile est large.

   `aspect-ratio: 1/1` borné par la hauteur d'écran donne donc le plus grand
   ouvrage possible à chaque largeur, sans un pixel perdu. */
.vue-plan {
  position: relative;
  /* LA LARGEUR EST DÉCLARÉE, et il le faut sur tablette (15/09 : « la 2D n'est
     pas centrée »). Avec un rapport imposé et une hauteur bornée, un moteur peut
     reporter la borne sur la LARGEUR : la vue rétrécit, reste calée à gauche, et
     le dessin centré dans une boîte décentrée paraît décalé. Pleine largeur
     déclarée, la hauteur seule se déduit du rapport. */
  width: 100%;
  aspect-ratio: 1 / 1;
  max-height: min(76vh, 46rem);
  min-height: 20rem;
  background: var(--scene);
}

/* ---------------------------------------------------------------------------
   LE PLEIN ÉCRAN.

   Élargir le panneau ne grossit pas l'ouvrage : la scène cale son échelle sur la
   PLUS PETITE dimension de son hôte, et sur une fiche c'est toujours la hauteur.
   Celle-ci est mangée par l'en-tête, le fil d'Ariane et la barre de la vue — d'où
   ce mode, qui rend la fenêtre entière et fait gagner un bon tiers.

   `position: fixed` et non un simple agrandissement : la vue est imbriquée dans
   des panneaux à `overflow: hidden`, qui la rogneraient.
   --------------------------------------------------------------------------- */
.fiche-vue.plein {
  position: fixed;
  inset: 0;
  z-index: 60;
  border-radius: 0;
  border: 0;
}
.fiche-vue.plein .vue-plan {
  /* Le rapport et le plafond sautent : ici on prend tout ce qui reste sous la
     barre, et c'est précisément ce qu'on était venu chercher. */
  aspect-ratio: auto;
  max-height: none;
  height: auto;
  flex: 1 1 auto;
  min-height: 0;
}
/* La page dessous ne défile plus : le fond bougerait derrière un plein écran
   qu'on croit fixe, et la molette sert déjà à zoomer dans la vue. */
body.vue-pleine { overflow: hidden; }
/* Sous 900 px la fiche passe en une colonne : les cotes repassent SOUS le
   dessin, et une vue trop haute les renverrait hors de l'écran. */
@media (max-width: 900px) {
  .vue-plan { height: min(56vh, 26rem); }
}

/* Le plan lui-même. `touch-action: none` parce que le glissé déplace la vue :
   sans lui, le doigt fait défiler la page par-dessous. */
.plan-svg {
  display: block;
  width: 100%;
  height: 100%;
  cursor: grab;
  touch-action: none;
}
.plan-svg:active { cursor: grabbing; }

/* LA POIGNÉE D'UNE ACCROCHE RÉGLABLE — migration 177 : un rond de brique cerné
   de blanc, lisible sur un portail sombre comme sur un clair, et ses flèches
   disent dans quel sens elle glisse. La cible, invisible, est plus large que
   le dessin : c'est un doigt qui la prend. */
/* LA COTATION HORS TOUT — migration 250. Sourde : elle annote le dessin, elle
   ne lui dispute rien. Les traits ne réagissent pas au doigt, sans quoi ils
   voleraient le glissé d'une poignée qui passe dessous. */
.plan-cotes { pointer-events: none; }
/* Le cartouche ne sort qu'à l'impression — migration 250. */
.fiche-cartouche { display: none; }
.plan-cote-trait, .plan-cote-attache { fill: none; stroke: var(--muted); stroke-width: 1.2; vector-effect: non-scaling-stroke; }
.plan-cote-attache { stroke-dasharray: 4 3; }
/* LE HORS TOUT EST SECOND : c'est le détail qu'on lit, l'ensemble qu'on vérifie. */
.plan-cote-hors-tout { opacity: 0.6; }
.plan-cote-texte { fill: var(--texte); font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; }

.plan-poignees .poignee { cursor: move; }
.poignee-cible { fill: transparent; }
.poignee-rond {
  fill: color-mix(in srgb, var(--accent) 55%, transparent);
  stroke: #fff;
}
.poignee-fleches {
  fill: none;
  stroke: #fff;
  stroke-linecap: round;
  stroke-linejoin: round;
  paint-order: stroke;
}
.poignee-coeur { fill: #fff; }
.poignee.saisie .poignee-rond { fill: var(--accent); }

/* La colonne de droite : ce qu'on renseigne, empilé dans le même pas que la
   grille. Les panneaux sont FRÈRES et non imbriqués — les cotes et la teinte
   sont deux décisions indépendantes, et un seul cadre autour des deux dirait
   qu'elles se tiennent. */
.fiche-reglages {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Le formulaire, dans le même cadre que le dessin : des panneaux frères. */
.fiche-cotes,
.fiche-teinte {
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.9rem 1rem 1.1rem;
  background: var(--carte);
  box-shadow: 0 1px 3px rgb(0 0 0 / 18%);
}
.fiche-cotes h2,
.fiche-teinte h2 { margin: 0 0 0.5rem; font-size: 1rem; display: flex; align-items: center; gap: 0.45rem; }
.fiche-cotes h2 .icone { --picto-encre: 1.15em; }
.fiche-cotes .explication,
.fiche-teinte .explication { margin: 0 0 0.9rem; }

/* Le nuancier tient dans une colonne de 20 rem : ses trois éléments passent à
   la ligne plutôt que de déborder. */
.fiche-teinte .ral-picker { flex-wrap: wrap; }

/* Ce que la borne autorise, sous le champ : la règle se lit AVANT d'être
   enfreinte. La dire seulement au refus, c'est laisser essayer pour voir. */
.field-aide {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.75rem;
  color: var(--muted);
}

/* LE VERDICT est toujours là — il dit « réalisable » autant que le contraire.
   Un mot qui n'apparaît qu'en cas d'erreur laisse croire, tant qu'il se tait,
   qu'on n'a pas encore été vérifié. */
.cotes-verdict {
  margin: 0.9rem 0 0;
  font-size: 0.8125rem;
  color: var(--muted);
}
.cotes-verdict.erreur { color: var(--danger); }
/* Un avertissement de règle n'est pas une erreur : la commande passe. Le
   même ambre que les mises en garde de l'atelier (`.field-help.warn`). */
.cotes-verdict.avertissement { color: #b45309; }

/* L'ESPACE DE COMMANDE N'A PLUS D'ARBRE : la coquille d'explorateur garde son
   en-tête et son défilement, mais sur une seule colonne. Chargée après
   `app.css`, cette règle l'emporte sur les deux colonnes de `.explorateur`. */
.explorateur-seul { grid-template-columns: minmax(0, 1fr); }

/* ---------------------------------------------------------------------------
   L'OUVRAGE SUR UNE PHOTO — voir `sur-photo.js`.

   La toile couvre la vue ; les poignées sont posées dessus en coordonnées
   d'écran. Ce sont des disques à l'ACCENT, assez gros pour le doigt : on les
   vise sur une photo chargée, où rien d'autre ne les distingue.
   --------------------------------------------------------------------------- */
.vue-photo { overflow: hidden; touch-action: none; }
.photo-toile { position: absolute; inset: 0; width: 100%; height: 100%; display: block; cursor: move; }
.photo-toile.tenue { cursor: grabbing; }
.photo-poignee {
  position: absolute;
  width: 18px;
  height: 18px;
  margin: -9px 0 0 -9px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45), 0 2px 6px rgba(0, 0, 0, 0.35);
  cursor: grab;
  touch-action: none;
  z-index: 2;
}
.photo-poignee.tenue { cursor: grabbing; transform: scale(1.15); }
.photo-outils {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  /* Huit commandes ne tiennent pas sur une ligne dans une fiche étroite : elles
     passent à la suivante plutôt que de sortir de la vue. */
  max-width: calc(100% - 1rem);
  flex-wrap: wrap;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 0.4rem 0.5rem;
  padding: 0.3rem 0.5rem;
  border-radius: 6px;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  font-size: 0.8rem;
}
.photo-opacite { display: flex; align-items: center; gap: 0.35rem; }
.photo-vide {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 1.5rem;
  text-align: center;
}
.photo-vide p { margin: 0; max-width: 28rem; }
.photo-discret { font-size: 0.8rem; color: var(--muted); }

/* LE CALQUE 3D posé sur la photo : transparent, et traversé par la souris — ce
   sont les poignées et la toile dessous qui se saisissent. */
.photo-volume { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
.photo-volume canvas { background: transparent; pointer-events: none; cursor: default; }

/* L'EFFACEMENT EN COURS : dit au milieu de la photo, sans rien masquer d'autre.
   Quelques secondes de calcul, 208 Mo au premier usage : sans ce mot, on
   croirait que le clic n'a rien fait. */
.photo-travail {
  position: absolute;
  left: 50%;
  bottom: 1rem;
  transform: translateX(-50%);
  z-index: 3;
  padding: 0.45rem 0.8rem;
  border-radius: 6px;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  font-size: 0.85rem;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.photo-travail[hidden] { display: none; }
/* EN PIPETTE : la croix pour viser un barreau, et les poignées hors d'atteinte —
   un clic sur un coin ne doit pas le déplacer quand on vise le portail. */
.vue-photo.en-pipette .photo-toile { cursor: crosshair; }
.vue-photo.en-pipette .photo-poignee { pointer-events: none; opacity: 0.5; }

/* ---------------------------------------------------------------------------
   LE RELEVÉ DU CHANTIER, puis l'ouvrage — voir `commande.js`.

   Le relevé se saisit seul, dans le même cadre que les cotes, borné en largeur :
   quelques champs courts n'ont rien à gagner à s'étirer sur toute la page. Son
   rappel se pose en tête de la colonne des réglages, sobre — on le relit, on ne
   le ressaisit pas.
   --------------------------------------------------------------------------- */
.releve,
.releve-resume {
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.9rem 1rem 1.1rem;
  background: var(--carte);
  box-shadow: 0 1px 3px rgb(0 0 0 / 18%);
}
.releve { max-width: 34rem; }
.releve h2,
.releve-resume h2 { margin: 0 0 0.5rem; font-size: 1rem; display: flex; align-items: center; gap: 0.45rem; }
.releve h2 .icone { --picto-encre: 1.15em; }
.releve .explication { margin: 0 0 0.9rem; }
.releve-suite { margin-top: 1rem; min-height: 44px; }
.releve-lignes { margin: 0 0 0.6rem; font-size: 0.875rem; }

/* ---------------------------------------------------------------------------
   LE PROJET DE L'INSTALLATEUR — migrations 124 et 126 : le bandeau, la liste, le
   nouveau projet. Des cibles au doigt : c'est ici qu'on arrive, sur place.
   --------------------------------------------------------------------------- */
.projets, .nouveau-projet {
  max-width: 34rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.9rem 1rem 1.1rem;
  /* LES BLOCS SUR LE FOND DE CARTE — voir `.pane-contenu` dans `app.css` : le
     contenu est en retrait, ce qu'on remplit remonte au-dessus. */
  background: var(--carte);
  box-shadow: 0 1px 3px rgb(0 0 0 / 18%);
}
.projets h2, .nouveau-projet h2 { margin: 0 0 0.8rem; font-size: 1rem; }
.liste-projets { display: flex; flex-direction: column; gap: 0.5rem; }
.ligne-projet {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  min-height: 44px;
  padding: 0.55rem 0.75rem;
  text-align: left;
}
.ligne-projet.actif { border-color: var(--accent); }
/* L'ÉTOILE EST POSÉE SUR LA LIGNE, pas dedans : un bouton dans un bouton n'est
   pas du HTML valide. L'hôte les porte tous les deux, la ligne prend toute la
   place et l'étoile se pose dans son coin. */
.ligne-projet-hote { position: relative; display: flex; }
.ligne-projet-hote .ligne-projet { flex: 1 1 auto; min-width: 0; padding-right: 2.6rem; }
.ligne-projet-etoile {
  position: absolute;
  top: 0; right: 0;
  /* 44 px de côté : c'est la cible au doigt, et le pro se tient au doigt. */
  width: 2.6rem; min-height: 44px;
  display: flex; align-items: center; justify-content: center;
  border: 0; background: none; box-shadow: none;
  color: var(--muted); font-size: 1.05rem; line-height: 1;
  cursor: pointer;
}
.ligne-projet-etoile:hover, .ligne-projet-etoile.active { color: var(--accent); }
.ligne-projet-detail { font-size: 0.8rem; color: var(--muted); }
.projets-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }
.projets-actions button, .nouveau-projet input { min-height: 44px; }
.nouveau-projet input { font-size: 1rem; }
.releve-projet { margin-top: 0; }
/* LES COTES DE CHANTIER PAR GROUPES — voir `formulaireDuReleve`. Chaque groupe
   est une partie du même cadre, séparée d'un filet : le pilier droit, le pilier
   gauche, le reste. */
.releve-groupe + .releve-groupe,
.nouveau-projet-client + .releve-groupe {
  margin-top: 1.1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}
.releve-groupe > h2 { margin: 0 0 0.5rem; font-size: 1rem; display: flex; align-items: center; gap: 0.45rem; }
.releve-groupe > .explication { margin: 0 0 0.9rem; }
.releve-identique { margin: 0 0 0.9rem; }
/* Les touches d'étape ne servent qu'au téléphone — voir plus bas. */
.releve-etapes { display: none; }
.releve-compteur { color: var(--muted); font-size: 0.875rem; white-space: nowrap; }

/* UN CHOIX COURT EN GROS BOUTONS — voir `boutonsDeChoix`. Le bouton allumé se
   dit par le filet actif, pas par le minium plein : celui-là est l'action. */
.choix-boutons { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.choix-bouton { flex: 1 1 5rem; min-height: 44px; font-size: 1rem; }
.choix-bouton.actif {
  border-color: var(--filet-actif);
  box-shadow: inset 0 0 0 1px var(--filet-actif);
  background: var(--choix);
  color: var(--texte);
  font-weight: 600;
}

/* LA PHOTO D'UN MODÈLE, SUR BLANC. Les photos sont prises en 3D sur fond clair,
   et ce fond est DANS l'image. Le 15/09, pour ne pas éblouir sur une page
   sombre, la vignette était posée sur un sable qui teintait ce fond en pierre ;
   le 17/09, Benjamin n'aime plus ce sable : la vignette repasse sur BLANC, la
   photo telle qu'elle a été prise. Le fondu `multiply` reste — sur blanc il ne
   change rien, et une autre teinte se reposerait ici seulement. Un liseré de
   brique cerne la vignette. */
.carte-ouvrage .carte-apercu:has(> img.apercu-ouvrage) {
  padding: 0;
  background: #FFFFFF;
  border: 2px solid color-mix(in srgb, var(--accent) 55%, var(--border));
  border-radius: 6px;
  overflow: hidden;
  isolation: isolate;
}
.carte-ouvrage .carte-apercu > img.apercu-ouvrage { mix-blend-mode: multiply; border-radius: 0; }

/* UN MODÈLE ÉCARTÉ PAR LE RELEVÉ — migration 128 : l'aperçu et le nom passent en
   sourdine, la raison reste lisible — c'est elle qu'on vient lire. */
.carte-ouvrage.ecartee { cursor: not-allowed; }
.carte-ouvrage.ecartee .carte-apercu { filter: grayscale(1); opacity: 0.4; }
.carte-ouvrage.ecartee .carte-titre,
.carte-ouvrage.ecartee .carte-code { color: var(--muted); }
.carte-ouvrage.ecartee .carte-note { color: var(--danger); font-size: 0.8rem; line-height: 1.35; white-space: normal; overflow: visible; text-overflow: clip; font-style: normal; }

/* UNE VALEUR CALCULÉE — migration 123 : le champ et « Revenir au calcul » côte à côte. */
.reglage-calcule { display: flex; gap: 0.5rem; align-items: center; }
.reglage-calcule input { flex: 1 1 auto; min-width: 0; }
.reglage-revenir { white-space: nowrap; }

/* ===========================================================================
   AU DOIGT — l'espace de commande se consulte sur tablette et sur téléphone,
   chez le client (décision du 15/09 : pro optimisé tablette et smartphone,
   l'atelier reste un outil de bureau). Tout ce qui suit ne vaut qu'ici : cette
   feuille n'est chargée que par les pages pro.
   =========================================================================== */

/* LA PAGE DÉFILE, PAS UN PANNEAU. La coquille d'explorateur fait défiler un
   panneau dans un écran fixe — juste sur un bureau. Au doigt, un défilement
   imbriqué accroche : la barre d'adresse du navigateur ne se replie plus, et le
   geste s'arrête au bord du panneau. C'est la page qui défile ici, sous un
   en-tête collé en haut. */
.page-explorateur { height: auto; min-height: 100vh; min-height: 100dvh; }
/* LE CORPS NE FIGE PLUS LA FENÊTRE. `app.css` le met à `overflow: hidden` — l'atelier
   fait défiler ses panneaux — et ce `hidden` passe à la fenêtre entière : la page
   du projet, plus haute que l'écran, ne défilait plus. La vue plein écran, elle,
   reste figée. */
body.page-explorateur:not(.vue-pleine) { overflow: visible; }
.page-explorateur .explorateur { display: flex; flex-direction: column; }
/* PAS DE POIGNÉE DE LARGEUR : ici la liste est AU-DESSUS du contenu, sur toute
   la largeur. La poignée de l'atelier se calait sur son bord droit — le bord de
   la fenêtre — et le dépassait de 5 px : les barres de défilement apparaissaient,
   la largeur rétrécissait, la poignée suivait, les barres repartaient… en boucle.
   Benjamin (19/09) : « les scrollbars clignotent ». */
.page-explorateur .explorateur-separateur { display: none; }
/* Le panneau descend jusqu'au bas de l'écran même quand la page est courte : le
   fond ne change pas de teinte sous les cartes. */
.page-explorateur .pane-contenu { overflow: visible; flex: 1 1 auto; }
.page-explorateur .app-header { position: sticky; top: 0; z-index: 40; }

/* 44 PIXELS : la cible d'un doigt (WCAG 2.5.5). Les touches de l'outil, pensées
   pour la souris, en faisaient 30. */
.app-header .view,
.app-header .marque-lien,
.app-header button,
.pane-contenu button,
.pane-contenu select,
.pane-contenu input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
.app-header select { min-height: 44px; }
.app-header .btn-icone { width: 44px; height: 44px; }
/* LE PROJET EN COURS, en pastille dans l'en-tête — voir `peintProjet`. Le nom
   se coupe plutôt que de pousser le compte hors de l'écran. */
.app-header .projet-entete { display: flex; min-width: 0; flex: 0 1 auto; }
.projet-menu-hote { position: relative; display: inline-flex; min-width: 0; max-width: 100%; }
.projet-puce {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  max-width: 22rem;
  padding: 0 0.8rem 0 0.9rem;
  border-radius: 999px;
  font-weight: 600;
  color: var(--texte);
}
.projet-puce-nom { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.projet-puce::after {
  content: '';
  flex: 0 0 auto;
  width: 0.4rem;
  height: 0.4rem;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: translateY(-2px) rotate(45deg);
}
.projet-puce.vide { font-weight: 400; color: var(--muted); }
.app-header .projet-menu { position: absolute; top: calc(100% + 0.4rem); left: 0; min-width: 15rem; }
.projet-menu .menu-item { min-height: 44px; }
.projet-menu-explication { display: block; padding: 0.4rem 0.75rem; font-size: 0.8125rem; color: var(--muted); }
/* LES INITIALES SE TOUCHENT : une pastille de 44 pixels, et sous elle le menu
   du compte — qui est connecté, et la sortie. */
.app-header .compte-capsule { min-width: 44px; height: 44px; font-size: 0.8rem; }
.app-header .compte-menu { min-width: 14rem; }
.compte-menu .compte-sortie, .compte-menu .compte-lien { display: flex; align-items: center; gap: 0.6rem; min-height: 44px; }
.compte-menu .compte-sortie svg, .compte-menu .compte-lien svg { width: 1.1rem; height: 1.1rem; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.app-header .view,
.app-header .marque-lien { display: inline-flex; align-items: center; }
.pane-contenu .field input,
.pane-contenu .field select { padding: 0.45rem 0.6rem; }

/* 16 PIXELS DANS LES CHAMPS : en dessous, Safari zoome la page au moment où
   l'on touche un champ, et elle ne revient pas. */
.pane-contenu input,
.pane-contenu select,
.pane-contenu textarea,
.app-header select { font-size: 1rem; }

/* LE FIL D'ARIANE se touche aussi : ses maillons prennent la hauteur d'une cible. */
/* CHAQUE MAILLON DANS SON CADRE — demande du 15/09 : un mot souligné au survol
   ne se devine pas comme une touche au doigt. Les maillons qui remontent sont des
   touches neutres ; celui où l'on est porte le filet actif, comme un choix
   allumé, et ne mène nulle part. Un nom trop long se coupe plutôt que de pousser
   le fil hors de l'écran. */
.fil { gap: 0.35rem; margin-bottom: 0.6rem; }
.fil-lien,
.fil-ici {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  min-width: 44px;
  max-width: 100%;
  padding: 0 0.85rem;
  border: 1px solid var(--filet-champ);
  border-radius: 6px;
  background: var(--neutre);
  color: var(--texte-2);
  font-size: 0.875rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.fil-lien:hover { text-decoration: none; border-color: var(--filet-actif); color: var(--texte); }
.fil-ici {
  border-color: var(--filet-actif);
  box-shadow: inset 0 0 0 1px var(--filet-actif);
  background: var(--choix);
  color: var(--texte);
  font-weight: 600;
}
.fil-sep { color: var(--muted); }

/* DES CHAMPS QUI RESPIRENT : un intitulé collé au champ du dessus se lit comme
   son aide, pas comme le titre du suivant. */
.releve .field,
.fiche-cotes .field,
.nouveau-projet .field { margin-bottom: 0.9rem; }

/* « FICHE ENTREPRISE » — migration 363 : la fiche, par groupes. */
.entreprise-groupe { border: 0; border-top: 1px solid var(--border); margin: 0 0 0.6rem; padding: 0.8rem 0 0; min-width: 0; }
.entreprise-groupe legend { padding: 0 0.4rem 0 0; font-weight: 600; font-size: 0.9rem; }
.entreprise-groupe .explication { margin: 0.2rem 0 0; }
.entreprise textarea { font: inherit; }
.entreprise > .primary { min-height: 44px; }
/* LA PRÉSENTATION DE LA FEUILLE — migration 370 : trois cases. */
.entreprise-cases { display: flex; flex-direction: column; gap: 0.4rem; margin-top: 0.4rem; }
.entreprise-sous-titre { font-size: 0.875rem; font-weight: 600; }
.entreprise-case { display: flex; align-items: center; gap: 0.5rem; min-height: 36px; font-size: 0.9rem; }
.pane-contenu .field label { font-size: 0.9rem; }

/* UNE CASE À COCHER se vise par son libellé entier. */
.pane-contenu label:has(> input[type="checkbox"]) { display: inline-flex; align-items: center; gap: 0.5rem; min-height: 44px; }
.pane-contenu input[type="checkbox"] { width: 1.25rem; height: 1.25rem; }

/* LE NUANCIER : sa pastille et son code à la taille du doigt. */
.fiche-teinte .ral-pastille { width: 44px; height: 44px; }
.fiche-teinte .ral-picker .ral-code { width: 7rem; }

/* LE RELEVÉ RAPPELÉ, REPLIÉ sur une ligne : son titre, le nombre de cotes, et un
   chevron qui dit qu'il se déplie. */
.releve-resume { padding-top: 0; padding-bottom: 0; }
.releve-resume > summary {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 44px;
  cursor: pointer;
  list-style: none;
  font-weight: 600;
}
.releve-resume > summary::-webkit-details-marker { display: none; }
.releve-resume > summary::after {
  content: '';
  width: 0.5rem;
  height: 0.5rem;
  margin-left: auto;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(45deg);
  transition: transform 120ms;
}
.releve-resume[open] > summary::after { transform: rotate(-135deg); }
.releve-resume-compte { color: var(--muted); font-weight: 400; font-size: 0.875rem; }
.releve-resume[open] { padding-bottom: 0.8rem; }

/* LE NUANCIER EN FENÊTRE — voir `ral-picker.js`. Hors du panneau de contenu :
   les règles « au doigt » de `.pane-contenu` ne l'atteignent pas, il porte les
   siennes. */
.ral-fenetre {
  width: min(40rem, calc(100vw - 2rem));
  max-height: min(46rem, calc(100dvh - 2rem));
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--texte);
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.5);
}
.ral-fenetre[open] { display: flex; flex-direction: column; }
.ral-fenetre::backdrop { background: rgba(0, 0, 0, 0.55); }
.ral-fenetre-tete {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.4rem 0.4rem 1rem;
  border-bottom: 1px solid var(--border);
}
.ral-fenetre-tete h2 { margin: 0; font-size: 1rem; flex: 1 1 auto; }
.ral-fenetre-fermer { width: 44px; height: 44px; padding: 0; font-size: 1.5rem; line-height: 1; background: none; border: 0; }
.ral-fenetre .ral-panneau {
  position: static;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  width: auto;
  padding: 0.75rem 1rem 1rem;
  border: 0;
  box-shadow: none;
}
.ral-fenetre .ral-recherche { min-height: 44px; font-size: 1rem; margin-bottom: 0.6rem; }
/* Les familles défilent de côté plutôt que de s'empiler sur trois lignes. */
.ral-fenetre .ral-familles { flex-wrap: nowrap; overflow-x: auto; gap: 0.35rem; margin-bottom: 0.7rem; padding-bottom: 0.2rem; }
.ral-fenetre .ral-famille { flex: 0 0 auto; min-height: 44px; padding: 0 0.9rem; font-size: 0.9rem; white-space: nowrap; }
.ral-fenetre .ral-grille {
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;
  grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));
  gap: 4px;
}
.ral-fenetre .ral-case { min-height: 56px; font-size: 0.85rem; border-radius: 4px; }
.fiche-teinte .ral-pastille { cursor: pointer; }
@media (max-width: 640px) {
  /* Au téléphone, toute la hauteur : on choisit une couleur, rien d'autre. */
  .ral-fenetre { width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh; margin: 0; border: 0; border-radius: 0; }
}

/* LE RELEVÉ RAPPELÉ, en liste : un nom, sa valeur. En ligne continue séparée de
   points, on cherchait la hauteur du pilier dans un paragraphe. */
.releve-lignes {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.35rem 1rem;
  margin: 0.2rem 0 0.8rem;
  font-size: 0.875rem;
}
.releve-lignes dt { color: var(--muted); }
.releve-lignes dd { margin: 0; font-weight: 600; text-align: right; font-variant-numeric: tabular-nums; }

/* LA BARRE DE LA VUE passe à la ligne : le nom de l'ouvrage garde sa ligne, les
   touches la suivante. Serrées sur une seule, le nom tombait en quatre lignes
   et « Recadrer », « Agrandir » sortaient de l'écran. */
.fiche-barre { flex-wrap: wrap; row-gap: 0.25rem; }
.fiche-barre h2 { min-width: 0; }

/* LE DESSIN RESTE SOUS LES YEUX pendant qu'on règle : on change une cote, on
   regarde. Collé sous l'en-tête, il laisse défiler les réglages dessous. Le
   plein écran, lui, garde sa place fixe. */
.fiche-vue { position: sticky; top: 3.6rem; z-index: 5; }
.fiche-vue.plein { position: fixed; }

.status:empty { display: none; }

@media (max-width: 900px) {
  /* Une colonne : le dessin collé en haut prend moins de la moitié de l'écran,
     les réglages défilent dessous. */
  /* Une hauteur fixée : le rapport carré ne dit plus rien, et il ne doit pas
     rogner la largeur. */
  .vue-plan { height: min(42vh, 26rem); min-height: 14rem; aspect-ratio: auto; }
  .fiche-barre h2 { flex: 1 1 100%; }
  .fiche-barre .fiche-espace { display: none; }
}

@media (min-width: 641px) and (max-width: 900px) {
  /* SOUS LE DESSIN, DEUX COLONNES sur une tablette en portrait : le relevé à
     gauche, ce qui se choisit à droite. Sur une seule, la valeur d'une cote
     tombait à l'autre bout de l'écran, loin de son nom. */
  .fiche-reglages { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
  .fiche-reglages > .releve-resume[hidden] + * { grid-column: 1 / -1; }
}

@media (min-width: 700px) {
  /* LES COTES DE CHANTIER SUR DEUX COLONNES dès la tablette : dix champs courts
     n'ont rien à gagner à s'empiler sur une seule. */
  .nouveau-projet { max-width: 46rem; }
  .nouveau-projet .releve-groupe,
  .releve-projet .releve-groupe { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 1rem; align-items: start; }
  .releve-groupe > :not(.field) { grid-column: 1 / -1; }
  .releve-projet { max-width: 46rem; }
  .entreprise-groupe { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 1rem; align-items: start; }
  .entreprise-groupe > legend, .entreprise-groupe > .entreprise-large { grid-column: 1 / -1; }
}

@media (max-width: 640px) {
  /* L'EN-TÊTE D'UN TÉLÉPHONE : la marque, la langue, le thème, le compte, la
     sortie. « Commander » part — c'est la seule page, et la marque y ramène. */
  .page-explorateur .app-header, .page-accueil-pro .app-header { gap: 0.35rem; padding: 0.35rem 0.6rem; }
  .app-header .views:not(.projet-entete) { display: none; }
  /* AVEC UN PROJET OUVERT, LA BARRE PASSE SUR DEUX LIGNES — tour au doigt du
     07/10 : la pastille et « Les modèles » passaient SOUS les icônes du
     compte. La marque et le compte d'abord, le projet dessous, sur toute la
     largeur ; la barre reste collée en haut. */
  .app-header:has(> .projet-entete) { flex-wrap: wrap; row-gap: 0.25rem; }
  .app-header .projet-entete { flex: 1 1 100%; order: 10; min-width: 0; }
  /* « MON BUREAU » (28/09) cède sa place au téléphone : la barre de la page
     projet débordait de 80 px. Le logotype y reste, touche de 44 px, et fait
     le même chemin — « Revenir à mon bureau ». */
  .app-header .view-bureau { display: none; }
  .projet-puce { max-width: 100%; padding: 0 0.6rem; }
  .app-header .marque-mot { display: none; }
  .app-header .marque-lien { min-width: 44px; justify-content: center; }
  .app-header .compte { gap: 0.1rem; }
  .app-header .compte .filet { display: none; }
  /* LE MOT DE L'EN-TÊTE, en bulle au bas de l'écran : il n'a plus la place au
     milieu de la barre. */
  .app-header > .status:not(:empty) {
    position: fixed;
    left: 0.75rem;
    right: 0.75rem;
    bottom: 0.75rem;
    z-index: 70;
    margin: 0;
    padding: 0.7rem 0.9rem;
    border-radius: 6px;
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
    color: var(--texte);
  }
  /* LE RELEVÉ PAR ÉTAPES : un groupe par écran — le client d'abord, pour un
     nouveau projet —, « Précédent », « Suivant », et la touche finale à la
     dernière étape seulement. */
  .releve-par-etapes > .releve-groupe:not(.courante),
  .releve-par-etapes > .nouveau-projet-client:not(.courante) { display: none; }
  .releve-par-etapes > .courante { margin-top: 0; padding-top: 0; border-top: 0; }
  .releve-etapes { display: flex; align-items: center; gap: 0.5rem; margin-top: 1rem; }
  .releve-etapes button { flex: 1 1 0; }
  .releve-etapes button[hidden] { display: block; visibility: hidden; }
  .releve-par-etapes:not(.derniere-etape) > .releve-suite { display: none; }
  .releve-par-etapes > .releve-suite { width: 100%; }
  .pane-contenu { padding: 0.75rem; }
  .fiche-vue { top: 3.4rem; }
  .vue-plan { height: 38vh; min-height: 13rem; aspect-ratio: auto; }
  /* LES TOUCHES DE LA VUE, à parts égales sur une ligne : le code de l'ouvrage
     part sur celle du nom. */
  .fiche-barre { column-gap: 0.25rem; }
  .fiche-barre h2 { flex: 1 1 calc(100% - 6rem); }
  .fiche-barre > button { flex: 1 1 auto; min-width: 44px; padding: 0.35rem 0.4rem; font-size: 0.875rem; }
  .projets, .nouveau-projet, .releve, .releve-resume, .fiche-cotes, .fiche-teinte { padding: 0.75rem; }
}

/* LES POIGNÉES DE LA PHOTO se visent au doigt : le disque reste petit pour ne
   rien cacher de l'ouverture, sa zone de prise fait 44 pixels. */
.photo-poignee::before { content: ''; position: absolute; inset: -13px; border-radius: 50%; }

/* ── LE DEVIS — migration 170 ───────────────────────────────────────────────
   Un tableau qu'on remplit sur place : la désignation, la quantité et le prix
   se tapent dans la ligne même, et le champ ne se montre qu'au survol et à la
   saisie — au repos, c'est un devis qu'on lit. Chaque case se vise au doigt. */
.devis { max-width: 52rem; }
.devis-tete { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 0.3rem; }
.devis-tete h2 { margin: 0; font-size: 1rem; }
.devis-client { color: var(--muted); }
.devis-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
  background: var(--carte);
  border: 1px solid var(--border);
}
.devis-table th { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); font-weight: 600; }
.devis-table th, .devis-table td { text-align: left; padding: 0.4rem 0.5rem; border-bottom: 1px solid var(--border); vertical-align: top; }
.devis-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.devis-designation { display: flex; flex-direction: column; gap: 0.15rem; }
.devis-detail { font-size: 0.78rem; color: var(--muted); }
.devis-info { display: block; }
.devis-rouvrir { align-self: flex-start; font-size: 0.75rem; }
/* LE TIROIR — migration 368 : les sections, et le détail de chaque ligne. */
.devis-section th { padding: 0; border-bottom: 1px solid var(--border); background: var(--neutre); }
.devis-section-bouton {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  width: 100%; min-height: 44px; padding: 0.4rem 0.5rem; border: 0; border-radius: 0;
  background: transparent; color: var(--text); font: inherit; text-transform: none; letter-spacing: 0; text-align: left; cursor: pointer;
}
.devis-section-titre { font-weight: 600; font-size: 0.875rem; }
.devis-section-total { font-size: 0.8125rem; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.devis-tiroir { align-self: flex-start; padding: 0.1rem 0.3rem; border: 0; background: transparent; color: var(--muted); font-size: 0.75rem; cursor: pointer; }
.devis-tiroir:hover, .devis-tiroir:focus-visible { color: var(--accent); }
.devis-outils { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.devis-case { display: flex; align-items: center; gap: 0.4rem; font-size: 0.875rem; }
.devis-champ {
  width: 100%;
  min-height: 44px;
  padding: 0.15rem 0.35rem;
  font-size: 0.9375rem;
  background: transparent;
  border: 1px solid transparent;
}
.devis-champ:hover { border-color: var(--border); }
.devis-champ:focus { background: var(--surface); border-color: var(--accent); }
.devis-nombre { width: 6.5rem; text-align: right; font-variant-numeric: tabular-nums; }
.devis-nombre::-webkit-outer-spin-button,
.devis-nombre::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.devis-total { white-space: nowrap; font-weight: 600; padding-top: 0.75rem; }
/* UN PRIX QUI MANQUE se voit — jaune, comme ce qui reste à faire — sans crier :
   c'est du travail qui reste, pas une erreur. */
.devis-a-saisir { color: var(--alerte); font-style: italic; font-weight: 400; }
/* LE PRIX CALCULÉ — migration 372 : sous le prix, discret ; forcé, il le dit. */
.devis-calcule { display: flex; flex-direction: column; align-items: flex-end; gap: 0.2rem; margin-top: 0.15rem; font-size: 0.72rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.devis-calcule.force { color: var(--alerte); }
.devis-gestes button { min-height: 44px; min-width: 44px; }
.devis-outils { margin: 0.6rem 0 1rem; }
.devis-outils button { min-height: 44px; }
.devis-pied { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-start; gap: 1rem 2rem; }
.devis-reglages { display: flex; flex-direction: column; gap: 0.4rem; }
.devis-taux { display: flex; align-items: center; gap: 0.4rem; font-size: 0.875rem; }
.devis-taux .devis-nombre { width: 5rem; }
.devis-totaux { display: grid; grid-template-columns: auto auto; gap: 0.25rem 1.5rem; margin: 0; min-width: 18rem; }
.devis-totaux dt { color: var(--muted); }
.devis-totaux dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
.devis-totaux .devis-ttc { font-weight: 700; font-size: 1.05rem; color: var(--text); border-top: 1px solid var(--border); padding-top: 0.3rem; }
.devis-manque { flex-basis: 100%; margin: 0; color: var(--alerte); font-size: 0.85rem; }
.devis-note { display: flex; flex-direction: column; gap: 0.3rem; margin-top: 1rem; font-size: 0.875rem; }
/* LES DEVIS ENVOYÉS — migration 366 : une ligne par version, l'état en pastille. */
.devis-versions { margin: 0.6rem 0 1rem; padding: 0.6rem 0.8rem; border: 1px solid var(--border); border-radius: 4px; }
.devis-versions h3 { margin: 0 0 0.4rem; font-size: 0.875rem; }
.devis-versions ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.3rem; }
.devis-version { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem 0.8rem; font-size: 0.875rem; }
.devis-version.remplacee { color: var(--muted); }
.devis-version-numero { font-family: var(--police-valeur); font-weight: 600; }
.devis-version-montant { font-variant-numeric: tabular-nums; }
.devis-version-gestes { display: flex; gap: 0.3rem; margin-left: auto; }
.devis-version-gestes button, .devis-version-gestes a { min-height: 36px; }
.devis-versions .explication { margin: 0.5rem 0 0; }
/* LE DEVIS PAR COURRIEL — migration 553 : le dernier envoi sur la ligne, le
   panneau d'envoi sous la tête de la version. */
.devis-version-courriel { font-size: 0.8rem; color: var(--muted); }
.devis-courriel { display: grid; gap: 0.6rem; max-width: 44rem; margin: 0.4rem 0 0.8rem; padding: 0.8rem; border: 1px solid var(--border); border-radius: 4px; }
.devis-courriel[hidden] { display: none; }
.devis-courriel-champ { display: grid; gap: 0.2rem; font-size: 0.875rem; }
.devis-courriel-champ input, .devis-courriel-champ textarea { width: 100%; box-sizing: border-box; font: inherit; padding: 0.45rem 0.55rem; min-height: 44px; }
.devis-courriel-copie { display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; min-height: 44px; }
.devis-courriel .explication { margin: 0; }
.devis-courriel-gestes { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.devis-courriel-gestes button { min-height: 44px; }
.devis-etat { font-size: 0.72rem; border: 1px solid currentColor; border-radius: 999px; padding: 0 0.5rem; }
.devis-etat-envoye { color: var(--accent); }
.devis-etat-accepte { color: var(--succes); }
.devis-etat-refuse, .devis-etat-expire { color: var(--danger); }
.devis-etat-remplace { color: var(--muted); }
.devis-note textarea { width: 100%; font: inherit; padding: 0.4rem 0.5rem; }
.fiche-devis { display: flex; flex-direction: column; gap: 0.5rem; }
.fiche-devis .primary { min-height: 44px; }
.fiche-devis .explication { margin: 0; }
/* LE PRIX D'ACHAT — migration 371 : pour l'installateur, sous le bouton. */
.fiche-prix { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; }

/* LA FEUILLE DU DEVIS — migration 367 : dessinée par le serveur (voir
   `Pro\FeuilleDevis`), affichée dans un cadre blanc, imprimée depuis lui. */
.devis-feuille {
  display: block;
  width: 100%;
  max-width: 52rem;
  min-height: 20rem;
  margin-top: 0.8rem;
  border: 0;
  background: #fff;
  box-shadow: 0 1px 4px rgb(0 0 0 / 30%);
}
/* Le cadre qu'on imprime sans le montrer : hors de la vue, sans place. */
.devis-feuille-cachee { position: fixed; right: 0; bottom: 0; width: 0; height: 0; border: 0; }
.devis-pdf { display: inline-flex; align-items: center; text-decoration: none; }
.devis-tete .devis-pdf { align-self: stretch; }
@media print {
  body * { visibility: hidden; }
  /* LA VUE D'UN OUVRAGE SUR PAPIER — migration 250 : le dessin coté et son
     cartouche, rien d'autre. En noir sur blanc, quel que soit le thème. */
  .fiche-vue, .fiche-vue * { visibility: visible; }
  .fiche-vue {
    position: absolute; inset: 0 auto auto 0; width: 100%; margin: 0; padding: 1cm;
    box-sizing: border-box; background: #fff;
    --surface: #fff; --border: #999; --texte: #000; --texte-2: #333; --muted: #555;
  }
  /* La barre sert à manœuvrer, les poignées à régler : ni l'une ni les autres
     n'ont de sens sur une feuille. */
  .fiche-vue .fiche-barre, .fiche-vue .plan-poignees { display: none; }
  /* BLANC DERRIÈRE LE DESSIN : la fiche pose un fond de carte, sombre pour qui
     travaille le soir. Sur une feuille, c'est un aplat d'encre pour rien. */
  .fiche-vue, .fiche-vue .plan-svg, .fiche-vue > div { background: #fff; box-shadow: none; border: none; }
  .fiche-vue .plan-svg { max-height: 16cm; }
  .fiche-cartouche {
    display: flex; flex-wrap: wrap; gap: 0.2cm 0.8cm; align-items: baseline;
    margin-top: 0.5cm; padding-top: 0.3cm; border-top: 1px solid #999;
    color: #000; font: 10pt/1.4 system-ui, sans-serif;
  }
  .fiche-cartouche-nom { font-weight: 600; font-size: 13pt; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   LA PAGE NE PARAÎT QU'UNE FOIS LA SESSION CONNUE.

   Sans session, l'atelier se dessinait une demi-seconde avant d'être remplacé
   par l'écran de connexion. Le HTML des pages qui demandent une session porte
   donc `data-session="attente"` sur <html> ; `paraitre()`, dans `http.js`,
   remplace la valeur dès qu'on sait qui est là — et la page sort.

   L'animation est le FILET DE SÉCURITÉ : si le JavaScript ne répond pas du
   tout, la page paraît au bout de quatre secondes plutôt que de rester
   blanche. `visibility` et non `display` : la mise en page est déjà faite
   quand la page sort, il n'y a pas de saut.
   ═══════════════════════════════════════════════════════════════════════════ */
html[data-session="attente"] body {
  visibility: hidden;
  animation: session-secours 4s step-end forwards;
}
@keyframes session-secours { to { visibility: visible; } }

/* LES RÉGLAGES SUR DEUX COLONNES, sur un écran large — Benjamin, 18/09 : « le
   formulaire des cotes réglables prend trop de hauteur et on ne voit pas le
   bout ». Une colonne de 20rem empilait un réglage par ligne : quinze champs
   courts faisaient trois écrans. La colonne s'élargit et les champs s'y rangent
   par deux ; le titre, l'explication et le verdict gardent toute la largeur.
   Sous 1100px, la colonne de droite resterait trop étroite pour deux champs
   lisibles : on garde l'empilement, et la tablette a déjà sa propre mise en
   page plus haut. */
@media (min-width: 1100px) {
  .fiche { grid-template-columns: minmax(0, 1fr) 31rem; }
  .fiche-cotes {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 1rem;
    align-content: start;
  }
  .fiche-cotes > :not(.field) { grid-column: 1 / -1; }
  /* LES RUBRIQUES gardent les deux colonnes, leur titre en travers. */
  .fiche-cotes .reglages-rubrique { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 1rem; align-content: start; }
  .fiche-cotes .reglages-rubrique > :not(.field) { grid-column: 1 / -1; }
}

/* LES RÉGLAGES PAR RUBRIQUES — 12/10 : le titre de l'objet importé (un vantail,
   un pilier), un filet au-dessus ; un réglage qui dépend d'un autre en retrait,
   un trait à gauche le rattache à lui. */
.reglages-rubrique[hidden] { display: none; }
.reglages-rubrique + .reglages-rubrique { border-top: 1px solid var(--border); padding-top: 0.8rem; }
.reglages-rubrique-titre { margin: 0 0 0.6rem; font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.reglage-dependant { margin-left: 0.9rem; padding-left: 0.7rem; border-left: 2px solid var(--border); }

/* La ligne d'un emplacement du projet — migration 211. */
.devis-emplacement { display: inline-block; margin-top: 0.2rem; font-size: 0.72rem; color: var(--muted); border: 1px solid var(--border); border-radius: 999px; padding: 0 0.45rem; }

/* Le nouveau projet : ce qu'il accueille, puis ce qu'il fixe — migration 217. */
.nouveau-projet-types { margin-top: 1.2rem; display: flex; flex-direction: column; gap: 0.6rem; }
.nouveau-projet-types .type-coches { display: flex; flex-wrap: wrap; gap: 0.5rem 1.2rem; }
.nouveau-projet-types .type-coche { min-height: 44px; }
.nouveau-projet > .primary { margin-top: 1.2rem; }

/* LE PROJET SE CONFIGURE AU BUREAU — Benjamin (19/09) : « rends les champs
   de formulaire plus petits, à ce stade ça se configure pas sur tablette ».
   `body.compact` (pro/projet.html) défait, dans le contenu seulement, les 44
   pixels et les 16 pixels posés plus haut pour le doigt ; l'en-tête garde les
   siens. Le jour où le projet se configurera sur tablette, on retire la classe. */
body.compact .pane-contenu button,
body.compact .pane-contenu select,
body.compact .pane-contenu input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]) { min-height: 0; }
body.compact .pane-contenu input,
body.compact .pane-contenu select,
body.compact .pane-contenu textarea,
body.compact .pane-contenu button { font-size: 0.8125rem; }
body.compact .pane-contenu input:not([type="checkbox"]):not([type="radio"]),
body.compact .pane-contenu select { padding: 0.25rem 0.45rem; }
body.compact .pane-contenu button { padding: 0.25rem 0.6rem; }
body.compact .pane-contenu label:has(> input[type="checkbox"]) { min-height: 0; }
body.compact .pane-contenu input[type="checkbox"] { width: 1rem; height: 1rem; }
body.compact .cha-plus { width: 2rem; min-height: 2rem; font-size: 1.05rem; padding: 0; }
body.compact button.cha-boite { min-height: 2rem; padding: 0.3rem 0.5rem; }
body.compact .cha-bande-tete { min-height: 1.8rem; }
body.compact .cha-panneau-gestes button,
body.compact .cha-panneau-gestes a { min-height: 0; }
body.compact .cha-commune { grid-template-columns: 1fr 6rem 3rem; gap: 0.3rem; }
body.compact .cha-commune.avec-sourd { grid-template-columns: 1fr 6rem 3rem auto; }
body.compact .cha-forme { width: 4.6rem; }
body.compact .cha-commune .ral-picker { flex-wrap: nowrap; gap: 0.25rem; }
body.compact .cha-commune .ral-picker .ral-pastille { width: 1.4rem; height: 1.4rem; flex: none; }
body.compact .cha-commune .ral-picker .ral-code { width: 3.4rem; }
body.compact .cha-commune .ral-picker .ral-nom { display: none; }

/* UN SEGMENT EST LONG ET BAS, et sa vue doit l'être aussi — migration 258.
   Le rapport carré de `.vue-plan` convient à un ouvrage, qui tient dans un
   carré ; une ligne de dix-huit mètres sur deux de haut s'y perdrait au milieu
   de deux grandes bandes vides, et il faudrait faire défiler pour rien. Pleine
   largeur conservée, hauteur libre : elle suit ce qu'on regarde.
   APRÈS les media queries de `.vue-plan`, pour les emporter à toutes les
   tailles — c'est la forme de l'objet regardé qui décide, pas celle de
   l'écran. */
.cha-plat-vue { aspect-ratio: auto; height: min(34vh, 18rem); min-height: 10rem; }
.cha-plat-barre { display: flex; align-items: center; gap: 0.5rem; margin: 0.6rem 0 0.3rem; }

/* ── LE PROJET À GABARIT — brique 6 de « Tout par le projet », 23/09 ─────────
   Au palier `ouvrage`, le projet n'est pas tracé : il est donné. Deux supports
   et un ouvrage, trois places qu'on ne déplace ni ne retire. Tout ce qui sert
   à DESSINER un chantier perd donc son objet, et l'écran le retire au lieu de
   le griser : griser dirait « tu n'y as pas droit », alors qu'il n'y a rien à
   faire de ces outils-là.

   Le marqueur vient de `droits.js`, sur la racine. Le style d'abord, le JS
   ensuite : ce qui peut se dire en CSS ne doit pas attendre un rendu. */
:root[data-niveau-projet="ouvrage"] #cha-plan,
:root[data-niveau-projet="ouvrage"] #cha-vue-tete,
:root[data-niveau-projet="ouvrage"] #cha-plat,
:root[data-niveau-projet="ouvrage"] .cha-bande-plus {
  display: none;
}

/* LA BANDE RESPIRE, faute de plan sous elle : c'est elle qu'on regarde
   maintenant, et elle avait la place d'un aperçu parmi d'autres. */
:root[data-niveau-projet="ouvrage"] .cha-bandes-segment { margin-bottom: 0; }

/* ---------------------------------------------------------------------------
   L'ACCUEIL DU PRO — migration 375. Les blocs du bureau de l'atelier
   (`accueil.css`) : les trois chemins de la journée, puis ce qu'on garde sous
   la main, qui défile seul. UNE colonne : pas de notes ici, l'écran se montre
   au client (28/09) — elles restent dans le post-it de la barre haute.
   --------------------------------------------------------------------------- */
.bureau.bureau-pro {
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  max-width: 48rem;
}
.bureau-acces { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 0.6rem; }
/* AU DOIGT : 44 px de haut au moins, comme toutes les touches du pro. */
.bureau-acces a {
  display: inline-flex; align-items: center; min-height: 2.75rem; padding: 0 1.1rem;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--carte); color: var(--texte); font-weight: 600; text-decoration: none;
}
.bureau-acces a:hover { border-color: var(--accent); }
.bureau-acces a.primary { background: var(--action); color: var(--action-texte); border-color: transparent; }
@media (max-width: 1100px) {
  .bureau.bureau-pro { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
}
@media (max-width: 640px) {
  .bureau.bureau-pro { padding: 0.8rem; gap: 0.8rem; }
  .bureau-acces a { flex: 1 1 auto; justify-content: center; }
}
